ONOS-7050 Refactored PI translation service and store

The translation store is now able to maintain mappings between
translated entities and specific instances of a PI entry in the network
(i.e. applied to a device).

The translation service has been refactored to allow users to
learn and forget translated entities.

The refactoring of the P4Runtime driver using this service will be
submitted separatelly.

Change-Id: Iaafd87d90232514853ca0dea0115dbae4f6e7886
This commit is contained in:
Carmelo Cascone 2017-11-28 18:09:13 -08:00
parent e2a1500ce0
commit 326ad2dd29
31 changed files with 1029 additions and 373 deletions

View File

@ -16,11 +16,12 @@
package org.onosproject.net.group;
import org.onosproject.core.GroupId;
import org.onosproject.net.pi.service.PiTranslatable;
/**
* ONOS representation of group that is stored in the system.
*/
public interface Group extends GroupDescription {
public interface Group extends GroupDescription, PiTranslatable {
/**
* State of the group object in ONOS.
*/

View File

@ -0,0 +1,66 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.pi.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import org.onosproject.net.DeviceId;
/**
* Global identifier of a PI action group applied to a device, uniquely defined
* by a device ID, action profile ID and group ID.
*/
@Beta
public final class PiActionGroupHandle extends PiHandle<PiActionGroup> {
private PiActionGroupHandle(DeviceId deviceId, PiActionGroup actionGroup) {
super(deviceId, actionGroup);
}
@Override
public int hashCode() {
return Objects.hashCode(deviceId(),
piEntity().actionProfileId(),
piEntity().id());
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
PiActionGroupHandle that = (PiActionGroupHandle) o;
return Objects.equal(deviceId(), that.deviceId()) &&
Objects.equal(piEntity().actionProfileId(),
that.piEntity().actionProfileId()) &&
Objects.equal(piEntity().id(), piEntity().id());
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("deviceId", deviceId())
.add("actionProfileId", piEntity().actionProfileId())
.add("groupId", piEntity().id())
.toString();
}
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.pi.runtime;
import com.google.common.annotations.Beta;
import org.onosproject.net.DeviceId;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Global identifier of a PI entity applied to a device, unique in the scope of
* the whole network.
*/
@Beta
public abstract class PiHandle<E extends PiEntity> {
private final DeviceId deviceId;
private final E piEntity;
protected PiHandle(DeviceId deviceId, E piEntity) {
this.deviceId = checkNotNull(deviceId);
this.piEntity = checkNotNull(piEntity);
}
/**
* Returns the device ID of this handle.
*
* @return device ID
*/
public final DeviceId deviceId() {
return deviceId;
}
/**
* Returns the type of entity identified by this handle.
*
* @return PI entity type
*/
public final PiEntityType entityType() {
return piEntity.piEntityType();
}
/**
* The entity to which this handle is associated.
*
* @return PI entity
*/
public final E piEntity() {
return piEntity;
}
@Override
public abstract int hashCode();
@Override
public abstract boolean equals(Object obj);
@Override
public abstract String toString();
}

View File

@ -0,0 +1,77 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.pi.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import org.onosproject.net.DeviceId;
/**
* Global identifier of a PI table entry applied on a device, uniquely defined
* by a device ID, table ID and match key.
*/
@Beta
public final class PiTableEntryHandle extends PiHandle<PiTableEntry> {
private PiTableEntryHandle(DeviceId deviceId, PiTableEntry entry) {
super(deviceId, entry);
}
/**
* Creates a new handle for the given PI table entry and device ID.
*
* @param deviceId device ID
* @param entry PI table entry
* @return PI table entry handle
*/
public static PiTableEntryHandle of(DeviceId deviceId, PiTableEntry entry) {
return new PiTableEntryHandle(deviceId, entry);
}
@Override
public int hashCode() {
return Objects.hashCode(deviceId(),
piEntity().table(),
piEntity().matchKey());
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final PiTableEntryHandle other = (PiTableEntryHandle) obj;
return Objects.equal(this.deviceId(), other.deviceId())
&& Objects.equal(this.piEntity().table(),
other.piEntity().table())
&& Objects.equal(this.piEntity().matchKey(),
other.piEntity().matchKey());
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("deviceId", deviceId())
.add("tableId", piEntity().table())
.add("matchKey", piEntity().matchKey())
.toString();
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.pi.service;
import com.google.common.annotations.Beta;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.pi.runtime.PiTableEntry;
/**
* A PI translation store that keeps track of which flow rules have been
* translated to which PI table entries.
*/
@Beta
public interface PiFlowRuleTranslationStore
extends PiTranslationStore<FlowRule, PiTableEntry> {
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.pi.service;
import com.google.common.annotations.Beta;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.pi.runtime.PiTableEntry;
/**
* A translator of flow rules to PI table entries.
*/
@Beta
public interface PiFlowRuleTranslator
extends PiTranslator<FlowRule, PiTableEntry> {
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.pi.service;
import com.google.common.annotations.Beta;
import org.onosproject.net.group.Group;
import org.onosproject.net.pi.runtime.PiActionGroup;
/**
* A PI translation store that keeps track of which groups have been
* translated to which PI action groups.
*/
@Beta
public interface PiGroupTranslationStore
extends PiTranslationStore<Group, PiActionGroup> {
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.pi.service;
import com.google.common.annotations.Beta;
import org.onosproject.net.group.Group;
import org.onosproject.net.pi.runtime.PiActionGroup;
/**
* A translator of groups to PI action groups.
*/
@Beta
public interface PiGroupTranslator
extends PiTranslator<Group, PiActionGroup> {
}

View File

@ -17,29 +17,34 @@
package org.onosproject.net.pi.service;
import com.google.common.annotations.Beta;
import org.onosproject.net.pi.model.PiPipeconfId;
import org.onosproject.net.pi.runtime.PiEntity;
import org.onosproject.net.pi.runtime.PiEntityType;
import org.onosproject.net.pi.runtime.PiHandle;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Representation of the result of a PD-to-PI translation.
* Representation of the result of a PD-to-PI translation associated to a PI
* entity handle.
*/
@Beta
public final class PiTranslatedEntity {
public final class PiTranslatedEntity<T extends PiTranslatable, E extends PiEntity> {
private final PiTranslatable original;
private final PiEntity translated;
private final PiPipeconfId pipeconfId;
private final PiEntityType type;
private final T original;
private final E translated;
private final PiHandle<E> handle;
public PiTranslatedEntity(PiTranslatable original, PiEntity translated,
PiPipeconfId pipeconfId) {
/**
* Creates a new translated entity.
*
* @param original PD entity
* @param translated PI entity
* @param handle PI entity handle
*/
public PiTranslatedEntity(T original, E translated, PiHandle<E> handle) {
this.original = checkNotNull(original);
this.translated = checkNotNull(translated);
this.pipeconfId = checkNotNull(pipeconfId);
this.type = checkNotNull(translated.piEntityType());
this.handle = checkNotNull(handle);
}
/**
@ -48,7 +53,7 @@ public final class PiTranslatedEntity {
* @return type of the translated entity
*/
public final PiEntityType entityType() {
return type;
return translated.piEntityType();
}
/**
@ -56,7 +61,7 @@ public final class PiTranslatedEntity {
*
* @return instance of PI translatable entity
*/
public final PiTranslatable original() {
public final T original() {
return original;
}
@ -65,18 +70,16 @@ public final class PiTranslatedEntity {
*
* @return PI entity
*/
public final PiEntity translated() {
public final E translated() {
return translated;
}
/**
* The ID of the pipeconf for which this translation is valid. In other
* words, the PI entity is guaranteed to be functionally equivalent to the
* PD one when applied to a device configured with such pipeconf.
* Returns the PI entity handle.
*
* @return PI pipeconf ID
* @return PI entity handle
*/
public final PiPipeconfId pipeconfId() {
return pipeconfId;
public final PiHandle<E> handle() {
return handle;
}
}

View File

@ -18,14 +18,15 @@ package org.onosproject.net.pi.service;
import com.google.common.annotations.Beta;
import org.onosproject.event.AbstractEvent;
import org.onosproject.net.pi.runtime.PiEntity;
/**
* Signals an event related to the translation of a protocol-dependent (PD)
* entity to a protocol-independent (PI) one.
*/
@Beta
public final class PiTranslationEvent
extends AbstractEvent<PiTranslationEvent.Type, PiTranslatedEntity> {
public final class PiTranslationEvent<T extends PiTranslatable, E extends PiEntity>
extends AbstractEvent<PiTranslationEvent.Type, PiTranslatedEntity<T, E>> {
/**
* Type of event.
@ -50,7 +51,7 @@ public final class PiTranslationEvent
* @param type type of event
* @param subject subject of event
*/
public PiTranslationEvent(Type type, PiTranslatedEntity subject) {
public PiTranslationEvent(Type type, PiTranslatedEntity<T, E> subject) {
super(type, subject);
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.pi.service;
import com.google.common.annotations.Beta;
/**
* Signals that an error was encountered while translating an entity.
*/
@Beta
public final class PiTranslationException extends Exception {
/**
* Creates a new exception with the given message.
*
* @param message a message
*/
public PiTranslationException(String message) {
super(message);
}
}

View File

@ -17,14 +17,6 @@
package org.onosproject.net.pi.service;
import com.google.common.annotations.Beta;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.group.Group;
import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.model.PiPipeconfId;
import org.onosproject.net.pi.runtime.PiActionGroup;
import org.onosproject.net.pi.runtime.PiTableEntry;
import java.util.Optional;
/**
* A service to translate protocol-dependent (PD) entities to
@ -34,65 +26,16 @@ import java.util.Optional;
public interface PiTranslationService {
/**
* Returns a PI table entry equivalent to the given flow rule for the given
* protocol-independent pipeline configuration.
* Returns a flow rule translator.
*
* @param rule a flow rule
* @param pipeconf a pipeline configuration
* @return a table entry
* @throws PiTranslationException if the flow rule cannot be translated
* @return flow rule translator
*/
PiTableEntry translate(FlowRule rule, PiPipeconf pipeconf)
throws PiTranslationException;
PiFlowRuleTranslator flowRuleTranslator();
/**
* Returns a PI action group equivalent to the given group for the given
* protocol-independent pipeline configuration.
* Returns a group translator.
*
* @param group a group
* @param pipeconf a pipeline configuration
* @return a PI action group
* @throws PiTranslationException if the group cannot be translated
* @return group translator
*/
PiActionGroup translate(Group group, PiPipeconf pipeconf)
throws PiTranslationException;
/**
* Returns a flow rule previously translated to the given PI table entry,
* for the given pipeconf ID, if present. If not present it means that such
* flow rule was never translated in the first place.
*
* @param piTableEntry PI table entry
* @param pipeconfId pipeconf ID
* @return optional flow rule
*/
Optional<FlowRule> lookup(PiTableEntry piTableEntry,
PiPipeconfId pipeconfId);
/**
* Returns a group previously translated to the given PI action group, for
* the given pipeconf ID, if present. If not present it means that such
* group was never translated in the first place.
*
* @param piActionGroup PI action group
* @param pipeconfId pipeconf ID
* @return optional group
*/
Optional<Group> lookup(PiActionGroup piActionGroup,
PiPipeconfId pipeconfId);
/**
* Signals that an error was encountered while translating an entity.
*/
class PiTranslationException extends Exception {
/**
* Creates a new exception with the given message.
*
* @param message a message
*/
public PiTranslationException(String message) {
super(message);
}
}
PiGroupTranslator groupTranslator();
}

View File

@ -17,55 +17,44 @@
package org.onosproject.net.pi.service;
import com.google.common.annotations.Beta;
import org.onosproject.net.pi.model.PiPipeconfId;
import org.onosproject.net.pi.runtime.PiEntity;
import org.onosproject.net.pi.runtime.PiHandle;
import org.onosproject.store.Store;
/**
* PI translation service store abstraction that acts as a multi-language
* dictionary. For each pipeconf ID (language) it maintains a mapping between a
* protocol-dependent (PD) entity and an equivalent protocol-independent (PI)
* one.
* PI translation store abstraction that maintains a mapping between a PI entity
* handle and a translated entity.
*
* @param <T> PD entity class (translatable to PI)
* @param <E> PI entity class
*/
@Beta
public interface PiTranslationStore
extends Store<PiTranslationEvent, PiTranslationStoreDelegate> {
public interface PiTranslationStore<T extends PiTranslatable, E extends PiEntity>
extends Store<PiTranslationEvent<T, E>, PiTranslationStoreDelegate<T, E>> {
/**
* Adds or update a mapping between the given PD entity (original) and the
* translated PI counterpart, for the given pipeconf ID.
* Adds or update a mapping between the given PI entity handle and
* translated entity.
*
* @param original PD entity
* @param translated PI entity
* @param pipeconfId pipeconf ID
* @param handle PI entity handle
* @param entity PI translated entity
*/
void addOrUpdate(PiTranslatable original, PiEntity translated,
PiPipeconfId pipeconfId);
void addOrUpdate(PiHandle<E> handle, PiTranslatedEntity<T, E> entity);
/**
* Removes a previously added mapping for the given PI entity and pipeconf
* Returns a PI translated entity for the given handle. Returns null if this
* store does not contain a mapping between the two for the given pipeconf
* ID.
*
* @param piEntity PI entity
* @param pipeconfId pipeconf ID
* @param handle PI entity handle
* @return PI translated entity
*/
void remove(PiEntity piEntity, PiPipeconfId pipeconfId);
PiTranslatedEntity<T, E> get(PiHandle<E> handle);
/**
* Removes all previously learned mappings for the given pipeconf ID.
* Removes a previously added mapping for the given PI entity handle.
*
* @param pipeconfId pipeconf ID
* @param handle PI entity handle
*/
void removeAll(PiPipeconfId pipeconfId);
/**
* Returns a PD entity for the given PI one and pipeconf ID. Returns null if
* this store does not contain a mapping between the two for the given
* pipeconf ID.
*
* @param piEntity PI entity
* @param pipeconfId pipeconf ID
* @return PD entity or null
*/
PiTranslatable lookup(PiEntity piEntity, PiPipeconfId pipeconfId);
void remove(PiHandle<E> handle);
}

View File

@ -17,12 +17,17 @@
package org.onosproject.net.pi.service;
import com.google.common.annotations.Beta;
import org.onosproject.net.pi.runtime.PiEntity;
import org.onosproject.store.StoreDelegate;
/**
* PI translation service store delegate abstraction.
* PI translation store delegate abstraction.
*
* @param <T> PD entity class (translatable to PI)
* @param <E> PI entity class
*/
@Beta
public interface PiTranslationStoreDelegate
extends StoreDelegate<PiTranslationEvent> {
<T extends PiTranslatable, E extends PiEntity>
extends StoreDelegate<PiTranslationEvent<T, E>> {
}

View File

@ -0,0 +1,75 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.pi.service;
import com.google.common.annotations.Beta;
import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.runtime.PiEntity;
import org.onosproject.net.pi.runtime.PiHandle;
import java.util.Optional;
/**
* A translator of PI entities to equivalent PD ones which offer means to learn
* translated entities for later use.
*
* @param <T> PD entity class (translatable to PI)
* @param <E> PI entity class
*/
@Beta
public interface PiTranslator<T extends PiTranslatable, E extends PiEntity> {
/**
* Translate the given PD entity (original) and returns a PI entity that is
* equivalent to he PD one for the given pipeconf.
*
* @param original PD entity
* @param pipeconf pipeconf
* @return PI entity
* @throws PiTranslationException if a translation is not possible (see
* message for an explanation)
*/
E translate(T original, PiPipeconf pipeconf)
throws PiTranslationException;
/**
* Stores a mapping between the given translated entity and handle.
*
* @param handle PI entity handle
* @param entity PI translated entity
*/
void learn(PiHandle<E> handle, PiTranslatedEntity<T, E> entity);
/**
* Returns a PI translated entity that was previously associated with the
* given handle, if present. If not present, it means a mapping between the
* two has not been learned by the system (via {@link #learn(PiHandle,
* PiTranslatedEntity)}) or that it has been removed (via {@link
* #forget(PiHandle)}). the
*
* @param handle PI entity handle
* @return optional PI translated entity
*/
Optional<PiTranslatedEntity<T, E>> lookup(PiHandle<E> handle);
/**
* Removes any mapping for the given PI entity handle.
*
* @param handle PI entity handle.
*/
void forget(PiHandle<E> handle);
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.pi.impl;
import org.onosproject.net.pi.runtime.PiEntity;
import org.onosproject.net.pi.runtime.PiHandle;
import org.onosproject.net.pi.service.PiTranslatable;
import org.onosproject.net.pi.service.PiTranslatedEntity;
import org.onosproject.net.pi.service.PiTranslationStore;
import org.onosproject.net.pi.service.PiTranslator;
import java.util.Optional;
/**
* Abstract implementation of a PI translator backed by a PI translation store.
*
* @param <T> PD entity class
* @param <E> PI entity class
*/
public abstract class AbstractPiTranslatorImpl
<T extends PiTranslatable, E extends PiEntity>
implements PiTranslator<T, E> {
private final PiTranslationStore<T, E> store;
AbstractPiTranslatorImpl(PiTranslationStore<T, E> store) {
this.store = store;
}
@Override
public void learn(PiHandle<E> handle, PiTranslatedEntity<T, E> entity) {
store.addOrUpdate(handle, entity);
}
@Override
public Optional<PiTranslatedEntity<T, E>> lookup(PiHandle<E> handle) {
return Optional.ofNullable(store.get(handle));
}
@Override
public void forget(PiHandle<E> handle) {
store.remove(handle);
}
}

View File

@ -86,13 +86,13 @@ import org.onosproject.net.pi.runtime.PiExactFieldMatch;
import org.onosproject.net.pi.runtime.PiFieldMatch;
import org.onosproject.net.pi.runtime.PiLpmFieldMatch;
import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
import org.onosproject.net.pi.service.PiTranslationException;
import java.util.Map;
import static java.lang.String.format;
import static org.onlab.util.ImmutableByteSequence.ByteSequenceTrimException;
import static org.onosproject.net.pi.impl.CriterionTranslator.CriterionTranslatorException;
import static org.onosproject.net.pi.service.PiTranslationService.PiTranslationException;
/**
* Helper class to translate criterion instances to PI field matches.

View File

@ -46,6 +46,7 @@ import org.onosproject.net.pi.runtime.PiRangeFieldMatch;
import org.onosproject.net.pi.runtime.PiTableAction;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
import org.onosproject.net.pi.service.PiTranslationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -62,17 +63,16 @@ import static org.onosproject.net.flow.criteria.Criterion.Type.PROTOCOL_INDEPEND
import static org.onosproject.net.pi.impl.CriterionTranslatorHelper.translateCriterion;
import static org.onosproject.net.pi.impl.PiUtils.getInterpreterOrNull;
import static org.onosproject.net.pi.impl.PiUtils.translateTableId;
import static org.onosproject.net.pi.service.PiTranslationService.PiTranslationException;
/**
* Implementation of flow rule translation logic.
*/
final class PiFlowRuleTranslator {
final class PiFlowRuleTranslatorImpl {
public static final int MAX_PI_PRIORITY = (int) Math.pow(2, 24);
private static final Logger log = LoggerFactory.getLogger(PiFlowRuleTranslator.class);
private static final Logger log = LoggerFactory.getLogger(PiFlowRuleTranslatorImpl.class);
private PiFlowRuleTranslator() {
private PiFlowRuleTranslatorImpl() {
// Hide constructor.
}

View File

@ -29,21 +29,21 @@ import org.onosproject.net.pi.runtime.PiActionGroupMember;
import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
import org.onosproject.net.pi.runtime.PiGroupKey;
import org.onosproject.net.pi.runtime.PiTableAction;
import org.onosproject.net.pi.service.PiTranslationService.PiTranslationException;
import org.onosproject.net.pi.service.PiTranslationException;
import java.nio.ByteBuffer;
import static java.lang.String.format;
import static org.onosproject.net.pi.impl.PiFlowRuleTranslator.translateTreatment;
import static org.onosproject.net.pi.impl.PiFlowRuleTranslatorImpl.translateTreatment;
import static org.onosproject.net.pi.impl.PiUtils.getInterpreterOrNull;
import static org.onosproject.net.pi.runtime.PiTableAction.Type.ACTION;
/**
* Implementation of group translation logic.
*/
final class PiGroupTranslator {
final class PiGroupTranslatorImpl {
private PiGroupTranslator() {
private PiGroupTranslatorImpl() {
// Hides constructor.
}

View File

@ -28,19 +28,19 @@ import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.group.Group;
import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.model.PiPipeconfId;
import org.onosproject.net.pi.runtime.PiActionGroup;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.service.PiTranslatable;
import org.onosproject.net.pi.service.PiFlowRuleTranslationStore;
import org.onosproject.net.pi.service.PiFlowRuleTranslator;
import org.onosproject.net.pi.service.PiGroupTranslationStore;
import org.onosproject.net.pi.service.PiGroupTranslator;
import org.onosproject.net.pi.service.PiTranslationException;
import org.onosproject.net.pi.service.PiTranslationService;
import org.onosproject.net.pi.service.PiTranslationStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Optional;
/**
* Implementation of the protocol-independent translation service.
* Implementation of the PI translation service.
*/
@Component(immediate = true)
@Service
@ -54,58 +54,76 @@ public class PiTranslationServiceImpl implements PiTranslationService {
protected DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private PiTranslationStore translationStore;
private PiFlowRuleTranslationStore flowRuleTranslationStore;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private PiGroupTranslationStore groupTranslationStore;
private PiFlowRuleTranslator flowRuleTranslator;
private PiGroupTranslator groupTranslator;
@Activate
public void activate() {
flowRuleTranslator = new InternalFlowRuleTranslator(flowRuleTranslationStore);
groupTranslator = new InternalGroupTranslator(groupTranslationStore);
log.info("Started");
}
@Deactivate
public void deactivate() {
flowRuleTranslator = null;
groupTranslator = null;
log.info("Stopped");
}
@Override
public PiTableEntry translate(FlowRule rule, PiPipeconf pipeconf)
throws PiTranslationException {
final PiTableEntry piTableEntry = PiFlowRuleTranslator
.translate(rule, pipeconf, getDevice(rule.deviceId()));
translationStore.addOrUpdate(rule, piTableEntry, pipeconf.id());
return piTableEntry;
public PiFlowRuleTranslator flowRuleTranslator() {
return flowRuleTranslator;
}
@Override
public Optional<FlowRule> lookup(PiTableEntry piTableEntry,
PiPipeconfId pipeconfId) {
final PiTranslatable original = translationStore
.lookup(piTableEntry, pipeconfId);
return original == null
? Optional.empty()
: Optional.of((FlowRule) original);
}
@Override
public PiActionGroup translate(Group group, PiPipeconf pipeconf)
throws PiTranslationException {
return PiGroupTranslator.translate(group, pipeconf,
getDevice(group.deviceId()));
}
@Override
public Optional<Group> lookup(PiActionGroup piActionGroup,
PiPipeconfId pipeconfId) {
// TODO: implement learning and lookup of groups
return Optional.empty();
public PiGroupTranslator groupTranslator() {
return groupTranslator;
}
private Device getDevice(DeviceId deviceId) throws PiTranslationException {
final Device device = deviceService.getDevice(deviceId);
if (device == null) {
throw new PiTranslationException(
"Unable to get device " + deviceId);
throw new PiTranslationException("Unable to get device " + deviceId);
}
return device;
}
private final class InternalFlowRuleTranslator
extends AbstractPiTranslatorImpl<FlowRule, PiTableEntry>
implements PiFlowRuleTranslator {
private InternalFlowRuleTranslator(PiFlowRuleTranslationStore store) {
super(store);
}
@Override
public PiTableEntry translate(FlowRule original, PiPipeconf pipeconf)
throws PiTranslationException {
return PiFlowRuleTranslatorImpl
.translate(original, pipeconf, getDevice(original.deviceId()));
}
}
private final class InternalGroupTranslator
extends AbstractPiTranslatorImpl<Group, PiActionGroup>
implements PiGroupTranslator {
private InternalGroupTranslator(PiGroupTranslationStore store) {
super(store);
}
@Override
public PiActionGroup translate(Group original, PiPipeconf pipeconf)
throws PiTranslationException {
return PiGroupTranslatorImpl
.translate(original, pipeconf, getDevice(original.deviceId()));
}
}
}

View File

@ -22,7 +22,7 @@ import org.onosproject.net.flow.TableId;
import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.model.PiPipelineInterpreter;
import org.onosproject.net.pi.model.PiTableId;
import org.onosproject.net.pi.service.PiTranslationService;
import org.onosproject.net.pi.service.PiTranslationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -60,23 +60,23 @@ final class PiUtils {
}
static PiTableId translateTableId(TableId tableId, PiPipelineInterpreter interpreter)
throws PiTranslationService.PiTranslationException {
throws PiTranslationException {
switch (tableId.type()) {
case PIPELINE_INDEPENDENT:
return (PiTableId) tableId;
case INDEX:
IndexTableId indexId = (IndexTableId) tableId;
if (interpreter == null) {
throw new PiTranslationService.PiTranslationException(format(
throw new PiTranslationException(format(
"Unable to map table ID '%d' from index to PI: missing interpreter", indexId.id()));
} else if (!interpreter.mapFlowRuleTableId(indexId.id()).isPresent()) {
throw new PiTranslationService.PiTranslationException(format(
throw new PiTranslationException(format(
"Unable to map table ID '%d' from index to PI: missing ID in interpreter", indexId.id()));
} else {
return interpreter.mapFlowRuleTableId(indexId.id()).get();
}
default:
throw new PiTranslationService.PiTranslationException(format(
throw new PiTranslationException(format(
"Unrecognized table ID type %s", tableId.type().name()));
}
}

View File

@ -67,7 +67,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
import static org.onlab.util.ImmutableByteSequence.fit;
import static org.onosproject.net.group.GroupDescription.Type.SELECT;
import static org.onosproject.net.pi.impl.PiFlowRuleTranslator.MAX_PI_PRIORITY;
import static org.onosproject.net.pi.impl.PiFlowRuleTranslatorImpl.MAX_PI_PRIORITY;
import static org.onosproject.pipelines.basic.BasicConstants.ACT_PRF_WCMP_SELECTOR_ID;
import static org.onosproject.pipelines.basic.BasicConstants.ACT_PRM_PORT_ID;
import static org.onosproject.pipelines.basic.BasicConstants.ACT_SET_EGRESS_PORT_ID;
@ -80,7 +80,7 @@ import static org.onosproject.pipelines.basic.BasicConstants.TBL_TABLE0_ID;
import static org.onosproject.pipelines.basic.BasicConstants.TBL_WCMP_TABLE_ID;
/**
* Tests for {@link PiFlowRuleTranslator}.
* Tests for {@link PiFlowRuleTranslatorImpl}.
*/
@SuppressWarnings("ConstantConditions")
public class PiTranslatorServiceTest {
@ -161,8 +161,8 @@ public class PiTranslatorServiceTest {
.withPriority(priority)
.build();
PiTableEntry entry1 = PiFlowRuleTranslator.translate(rule1, pipeconf, null);
PiTableEntry entry2 = PiFlowRuleTranslator.translate(rule1, pipeconf, null);
PiTableEntry entry1 = PiFlowRuleTranslatorImpl.translate(rule1, pipeconf, null);
PiTableEntry entry2 = PiFlowRuleTranslatorImpl.translate(rule1, pipeconf, null);
// check equality, i.e. same rules must produce same entries
new EqualsTester()
@ -236,8 +236,8 @@ public class PiTranslatorServiceTest {
@Test
public void testTranslateGroups() throws Exception {
PiActionGroup piGroup1 = PiGroupTranslator.translate(GROUP, pipeconf, null);
PiActionGroup piGroup2 = PiGroupTranslator.translate(GROUP, pipeconf, null);
PiActionGroup piGroup1 = PiGroupTranslatorImpl.translate(GROUP, pipeconf, null);
PiActionGroup piGroup2 = PiGroupTranslatorImpl.translate(GROUP, pipeconf, null);
new EqualsTester()
.addEqualityGroup(piGroup1, piGroup2)

View File

@ -0,0 +1,143 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.store.pi.impl;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onosproject.net.pi.runtime.PiEntity;
import org.onosproject.net.pi.runtime.PiHandle;
import org.onosproject.net.pi.service.PiTranslatable;
import org.onosproject.net.pi.service.PiTranslatedEntity;
import org.onosproject.net.pi.service.PiTranslationEvent;
import org.onosproject.net.pi.service.PiTranslationStore;
import org.onosproject.net.pi.service.PiTranslationStoreDelegate;
import org.onosproject.store.AbstractStore;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.store.service.EventuallyConsistentMapEvent;
import org.onosproject.store.service.EventuallyConsistentMapListener;
import org.onosproject.store.service.StorageService;
import org.onosproject.store.service.WallClockTimestamp;
import org.slf4j.Logger;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Distributed implementation of PiTranslationStore.
*/
@Component(immediate = true)
public abstract class AbstractDistributedPiTranslationStore
<T extends PiTranslatable, E extends PiEntity>
extends AbstractStore<PiTranslationEvent<T, E>, PiTranslationStoreDelegate<T, E>>
implements PiTranslationStore<T, E> {
private static final String MAP_NAME_TEMPLATE = "onos-pi-translated-%s-map";
private final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
private EventuallyConsistentMap<PiHandle<E>, PiTranslatedEntity<T, E>>
translatedEntities;
private final EventuallyConsistentMapListener
<PiHandle<E>, PiTranslatedEntity<T, E>> entityMapListener =
new InternalEntityMapListener();
/**
* Returns a string that identifies the map maintained by this store among
* others that uses this abstract class.
*
* @return string
*/
protected abstract String mapSimpleName();
@Activate
public void activate() {
final String fullMapName = format(MAP_NAME_TEMPLATE, mapSimpleName());
translatedEntities = storageService
.<PiHandle<E>, PiTranslatedEntity<T, E>>eventuallyConsistentMapBuilder()
.withName(fullMapName)
.withSerializer(KryoNamespaces.API)
.withTimestampProvider((k, v) -> new WallClockTimestamp())
.build();
translatedEntities.addListener(entityMapListener);
log.info("Started");
}
@Deactivate
public void deactivate() {
translatedEntities.removeListener(entityMapListener);
translatedEntities = null;
log.info("Stopped");
}
@Override
public void addOrUpdate(PiHandle<E> handle, PiTranslatedEntity<T, E> entity) {
checkNotNull(handle);
checkNotNull(entity);
checkArgument(handle.entityType().equals(entity.entityType()),
"Entity type must be the same for handle and translated entity");
translatedEntities.put(handle, entity);
}
@Override
public void remove(PiHandle<E> handle) {
checkNotNull(handle);
translatedEntities.remove(handle);
}
@Override
public PiTranslatedEntity<T, E> get(PiHandle<E> handle) {
checkNotNull(handle);
return translatedEntities.get(handle);
}
public Iterable<PiTranslatedEntity<T, E>> getAll() {
return translatedEntities.values();
}
private class InternalEntityMapListener
implements EventuallyConsistentMapListener
<PiHandle<E>, PiTranslatedEntity<T, E>> {
@Override
public void event(EventuallyConsistentMapEvent<PiHandle<E>,
PiTranslatedEntity<T, E>> event) {
final PiTranslationEvent.Type type;
switch (event.type()) {
case PUT:
type = PiTranslationEvent.Type.LEARNED;
break;
case REMOVE:
type = PiTranslationEvent.Type.FORGOT;
break;
default:
throw new IllegalArgumentException(
"Unknown event type " + event.type().name());
}
notifyDelegate(new PiTranslationEvent<>(type, event.value()));
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.store.pi.impl;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.service.PiFlowRuleTranslationStore;
/**
* Distributed implementation of a PI translation store for flow rules.
*/
@Component(immediate = true)
@Service
public class DistributedPiFlowRuleTranslationStore
extends AbstractDistributedPiTranslationStore<FlowRule, PiTableEntry>
implements PiFlowRuleTranslationStore {
private static final String MAP_SIMPLE_NAME = "flowrule";
@Override
protected String mapSimpleName() {
return MAP_SIMPLE_NAME;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.store.pi.impl;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.onosproject.net.group.Group;
import org.onosproject.net.pi.runtime.PiActionGroup;
import org.onosproject.net.pi.service.PiGroupTranslationStore;
/**
* Distributed implementation of a PI translation store for groups.
*/
@Component(immediate = true)
@Service
public class DistributedPiGroupTranslationStore
extends AbstractDistributedPiTranslationStore<Group, PiActionGroup>
implements PiGroupTranslationStore {
private static final String MAP_SIMPLE_NAME = "group";
@Override
protected String mapSimpleName() {
return MAP_SIMPLE_NAME;
}
}

View File

@ -1,189 +0,0 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.store.pi.impl;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.util.KryoNamespace;
import org.onosproject.net.pi.model.PiPipeconfId;
import org.onosproject.net.pi.runtime.PiEntity;
import org.onosproject.net.pi.service.PiTranslatable;
import org.onosproject.net.pi.service.PiTranslatedEntity;
import org.onosproject.net.pi.service.PiTranslationEvent;
import org.onosproject.net.pi.service.PiTranslationStore;
import org.onosproject.net.pi.service.PiTranslationStoreDelegate;
import org.onosproject.store.AbstractStore;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.store.service.EventuallyConsistentMapEvent;
import org.onosproject.store.service.EventuallyConsistentMapListener;
import org.onosproject.store.service.StorageService;
import org.onosproject.store.service.WallClockTimestamp;
import org.slf4j.Logger;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Distributed implementation of PiTranslationStore.
*/
@Component(immediate = true)
@Service
public class DistributedPiTranslationStore
extends AbstractStore<PiTranslationEvent, PiTranslationStoreDelegate>
implements PiTranslationStore {
private static final String DIST_MAP_NAME = "onos-pi-translated-entities-map";
private final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
private EventuallyConsistentMap<PiTranslatedEntityKey, PiTranslatedEntity>
translatedEntities;
private final EventuallyConsistentMapListener<PiTranslatedEntityKey,
PiTranslatedEntity> entityMapListener = new InternalEntityMapListener();
@Activate
public void activate() {
translatedEntities = storageService
.<PiTranslatedEntityKey, PiTranslatedEntity>eventuallyConsistentMapBuilder()
.withName(DIST_MAP_NAME)
.withSerializer(KryoNamespace.newBuilder()
.register(KryoNamespaces.API)
.register(PiTranslatedEntityKey.class)
.build())
.withTimestampProvider((k, v) -> new WallClockTimestamp())
.build();
translatedEntities.addListener(entityMapListener);
log.info("Started");
}
@Deactivate
public void deactivate() {
translatedEntities.removeListener(entityMapListener);
translatedEntities = null;
log.info("Stopped");
}
@Override
public void addOrUpdate(PiTranslatable original, PiEntity translated,
PiPipeconfId pipeconfId) {
translatedEntities.put(PiTranslatedEntityKey.of(pipeconfId, translated),
new PiTranslatedEntity(original, translated, pipeconfId));
}
@Override
public void remove(PiEntity piEntity, PiPipeconfId pipeconfId) {
translatedEntities.remove(
PiTranslatedEntityKey.of(pipeconfId, piEntity));
}
@Override
public void removeAll(PiPipeconfId pipeconfId) {
// FIXME: this can be heavy, but we assume it won't be called that often
// How often we expect a pipeconf to be removed from the device/system?
final Set<PiTranslatedEntityKey> keysToRemove = translatedEntities
.keySet().parallelStream()
.filter(k -> k.pipeconfId.equals(pipeconfId))
.collect(Collectors.toSet());
keysToRemove.forEach(translatedEntities::remove);
}
@Override
public PiTranslatable lookup(PiEntity piEntity, PiPipeconfId pipeconfId) {
PiTranslatedEntity translatedEntity = translatedEntities
.get(PiTranslatedEntityKey.of(pipeconfId, piEntity));
return translatedEntity == null ? null : translatedEntity.original();
}
private class InternalEntityMapListener
implements EventuallyConsistentMapListener
<PiTranslatedEntityKey, PiTranslatedEntity> {
@Override
public void event(EventuallyConsistentMapEvent<PiTranslatedEntityKey,
PiTranslatedEntity> event) {
final PiTranslationEvent.Type type;
switch (event.type()) {
case PUT:
type = PiTranslationEvent.Type.LEARNED;
break;
case REMOVE:
type = PiTranslationEvent.Type.FORGOT;
break;
default:
throw new IllegalArgumentException(
"Unknown event type " + event.type().name());
}
notifyDelegate(new PiTranslationEvent(type, event.value()));
}
}
/**
* Internal representation of a key that uniquely identifies a translated
* entity.
*/
private static final class PiTranslatedEntityKey {
private final PiPipeconfId pipeconfId;
private final PiEntity piEntity;
private PiTranslatedEntityKey(PiPipeconfId pipeconfId,
PiEntity piEntity) {
this.pipeconfId = pipeconfId;
this.piEntity = piEntity;
}
public static PiTranslatedEntityKey of(PiPipeconfId pipeconfId,
PiEntity piEntity) {
return new PiTranslatedEntityKey(pipeconfId, piEntity);
}
public static PiTranslatedEntityKey of(PiTranslatedEntity entity) {
return new PiTranslatedEntityKey(entity.pipeconfId(),
entity.translated());
}
@Override
public int hashCode() {
return Objects.hash(pipeconfId, piEntity);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final PiTranslatedEntityKey other = (PiTranslatedEntityKey) obj;
return Objects.equals(this.pipeconfId, other.pipeconfId)
&& Objects.equals(this.piEntity, other.piEntity);
}
}
}

View File

@ -119,4 +119,4 @@ public class DistributedDevicePipeconfMappingStoreTest {
store.deviceToPipeconf.clear();
}
}
}

View File

@ -0,0 +1,153 @@
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.store.pi.impl;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.RandomUtils;
import org.junit.Before;
import org.junit.Test;
import org.onosproject.net.DeviceId;
import org.onosproject.net.pi.runtime.PiEntity;
import org.onosproject.net.pi.runtime.PiEntityType;
import org.onosproject.net.pi.runtime.PiHandle;
import org.onosproject.net.pi.service.PiTranslatable;
import org.onosproject.net.pi.service.PiTranslatedEntity;
import org.onosproject.store.service.TestStorageService;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* Test for {@link AbstractDistributedPiTranslationStore}.
*/
public class DistributedPiTranslationStoreTest {
private AbstractDistributedPiTranslationStore<PiTranslatable, PiEntity> store;
private static final int HANDLE_HASH = RandomUtils.nextInt();
private static final PiTranslatable PI_TRANSLATABLE =
new PiTranslatable() {
};
private static final PiEntity PI_ENTITY = () -> PiEntityType.TABLE_ENTRY;
private static final PiHandle<PiEntity> PI_HANDLE =
new PiHandle<PiEntity>(DeviceId.NONE, PI_ENTITY) {
@Override
public int hashCode() {
return HANDLE_HASH;
}
@Override
public boolean equals(Object other) {
return other instanceof PiHandle && other.hashCode() == hashCode();
}
@Override
public String toString() {
return String.valueOf(HANDLE_HASH);
}
};
private static final PiTranslatedEntity<PiTranslatable, PiEntity> TRANSLATED_ENTITY =
new PiTranslatedEntity<>(PI_TRANSLATABLE, PI_ENTITY, PI_HANDLE);
/**
* Sets up the store and the storage service test harness.
*/
@Before
public void setUp() {
store = new AbstractDistributedPiTranslationStore<PiTranslatable, PiEntity>() {
@Override
protected String mapSimpleName() {
return "test";
}
};
store.storageService = new TestStorageService();
store.setDelegate(event -> {
});
store.activate();
}
/**
* Tests equality of key and value used in other tests.
*/
@Test
public void testEquality() {
assertEquals(PI_HANDLE, PI_HANDLE);
assertEquals(TRANSLATED_ENTITY, TRANSLATED_ENTITY);
}
/**
* Test for activate.
*/
@Test
public void activate() {
assertNotNull(store.storageService);
assertTrue("Store must have delegate",
store.hasDelegate());
assertTrue("No value should be in the map",
Lists.newArrayList(store.getAll()).isEmpty());
}
/**
* Test for deactivate.
*/
@Test(expected = NullPointerException.class)
public void deactivate() {
store.deactivate();
store.getAll();
}
/**
* Test of value add or update.
*/
@Test
public void addOrUpdate() {
store.addOrUpdate(PI_HANDLE, TRANSLATED_ENTITY);
assertTrue("Value should be in the map",
store.get(PI_HANDLE) != null);
assertTrue("Exactly 1 value should be in the map",
Lists.newArrayList(store.getAll()).size() == 1);
// Add again, expect 1 value.
store.addOrUpdate(PI_HANDLE, TRANSLATED_ENTITY);
assertTrue("Exactly 1 value should be in the map",
Lists.newArrayList(store.getAll()).size() == 1);
}
/**
* Test of value lookup.
*/
@Test
public void lookup() throws Exception {
clear();
addOrUpdate();
assertEquals("Wrong value in the map",
store.get(PI_HANDLE), TRANSLATED_ENTITY);
}
/**
* Test of value removal.
*/
@Test
public void clear() {
store.remove(PI_HANDLE);
assertTrue("Value should NOT be in the map",
store.get(PI_HANDLE) == null);
assertTrue("No value should be in the map",
Lists.newArrayList(store.getAll()).isEmpty());
}
}

View File

@ -220,6 +220,7 @@ import org.onosproject.net.pi.model.PiTableId;
import org.onosproject.net.pi.model.PiTableType;
import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionGroup;
import org.onosproject.net.pi.runtime.PiActionGroupHandle;
import org.onosproject.net.pi.runtime.PiActionGroupId;
import org.onosproject.net.pi.runtime.PiActionGroupMember;
import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
@ -232,6 +233,7 @@ import org.onosproject.net.pi.runtime.PiEntityType;
import org.onosproject.net.pi.runtime.PiExactFieldMatch;
import org.onosproject.net.pi.runtime.PiFieldMatch;
import org.onosproject.net.pi.runtime.PiGroupKey;
import org.onosproject.net.pi.runtime.PiHandle;
import org.onosproject.net.pi.runtime.PiLpmFieldMatch;
import org.onosproject.net.pi.runtime.PiMatchKey;
import org.onosproject.net.pi.runtime.PiPacketOperation;
@ -241,6 +243,7 @@ import org.onosproject.net.pi.runtime.PiTableAction;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
import org.onosproject.net.pi.runtime.PiValidFieldMatch;
import org.onosproject.net.pi.runtime.PiTableEntryHandle;
import org.onosproject.net.pi.service.PiTranslatable;
import org.onosproject.net.pi.service.PiTranslatedEntity;
import org.onosproject.net.provider.ProviderId;
@ -634,6 +637,7 @@ public final class KryoNamespaces {
// PI Runtime
PiAction.class,
PiActionGroup.class,
PiActionGroupHandle.class,
PiActionGroupId.class,
PiActionGroupMember.class,
PiActionGroupMemberId.class,
@ -646,6 +650,7 @@ public final class KryoNamespaces {
PiExactFieldMatch.class,
PiFieldMatch.class,
PiGroupKey.class,
PiHandle.class,
PiLpmFieldMatch.class,
PiMatchKey.class,
PiPacketOperation.class,
@ -656,6 +661,7 @@ public final class KryoNamespaces {
PiTernaryFieldMatch.class,
PiValidFieldMatch.class,
// PI service
PiTableEntryHandle.class,
PiTranslatedEntity.class,
PiTranslatable.class,
// Other

View File

@ -32,7 +32,7 @@ import org.onosproject.net.pi.model.PiTableModel;
import org.onosproject.net.pi.runtime.PiCounterCellData;
import org.onosproject.net.pi.runtime.PiCounterCellId;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.service.PiTranslationService;
import org.onosproject.net.pi.service.PiTranslationException;
import org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType;
import org.onosproject.p4runtime.api.P4RuntimeFlowRuleWrapper;
import org.onosproject.p4runtime.api.P4RuntimeTableEntryReference;
@ -242,8 +242,8 @@ public class P4RuntimeFlowRuleProgrammable extends AbstractP4RuntimeHandlerBehav
PiTableEntry piTableEntry;
try {
piTableEntry = piTranslationService.translate(rule, pipeconf);
} catch (PiTranslationService.PiTranslationException e) {
piTableEntry = piTranslationService.flowRuleTranslator().translate(rule, pipeconf);
} catch (PiTranslationException e) {
log.warn("Unable to translate flow rule: {} - {}", e.getMessage(), rule);
continue; // next rule
}

View File

@ -30,7 +30,7 @@ import org.onosproject.net.group.GroupStore;
import org.onosproject.net.pi.model.PiActionProfileId;
import org.onosproject.net.pi.runtime.PiActionGroup;
import org.onosproject.net.pi.runtime.PiActionGroupId;
import org.onosproject.net.pi.service.PiTranslationService;
import org.onosproject.net.pi.service.PiTranslationException;
import org.onosproject.p4runtime.api.P4RuntimeClient;
import org.onosproject.p4runtime.api.P4RuntimeGroupReference;
import org.onosproject.p4runtime.api.P4RuntimeGroupWrapper;
@ -103,8 +103,8 @@ public class P4RuntimeGroupProgrammable extends AbstractP4RuntimeHandlerBehaviou
PiActionGroup piActionGroup;
try {
piActionGroup = piTranslationService.translate(group, pipeconf);
} catch (PiTranslationService.PiTranslationException e) {
piActionGroup = piTranslationService.groupTranslator().translate(group, pipeconf);
} catch (PiTranslationException e) {
log.warn("Unable translate group, aborting group operation {}: {}", groupOp.opType(), e.getMessage());
return;
}