Various improvements to PI group handling
- Moved group translation logic to core service
- Removed dependency on KRYO
- Fixed bug where tratments with PI instructions where not supported if
an interpreter was present
- Fixed bug where action profile name was not found during protobuf
encoding (always perform P4Info lookup by name and alias)
- Improved reading of members by issuing one big request for all
groups
Change-Id: Ifcf8380b09293e70be15cf4999bd2845caf5d01e
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java
index 8a5a2dd..35de9ed 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java
@@ -24,6 +24,7 @@
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.runtime.PiPipeconfService;
+import org.onosproject.net.pi.runtime.PiTranslationService;
import org.onosproject.p4runtime.api.P4RuntimeClient;
import org.onosproject.p4runtime.api.P4RuntimeController;
import org.slf4j.Logger;
@@ -47,6 +48,7 @@
protected P4RuntimeController controller;
protected PiPipeconf pipeconf;
protected P4RuntimeClient client;
+ protected PiTranslationService piTranslationService;
/**
* Initializes this behaviour attributes. Returns true if the operation was successful, false otherwise. This method
@@ -80,6 +82,8 @@
}
pipeconf = piPipeconfService.getPipeconf(piPipeconfService.ofDevice(deviceId).get()).get();
+ piTranslationService = handler().get(PiTranslationService.class);
+
return true;
}
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java
index c2cc0b5..c9fe49d83 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java
@@ -31,7 +31,7 @@
import org.onosproject.net.pi.runtime.PiCounterCellId;
import org.onosproject.net.pi.runtime.PiCounterId;
import org.onosproject.net.pi.runtime.PiDirectCounterCellId;
-import org.onosproject.net.pi.runtime.PiFlowRuleTranslationService;
+import org.onosproject.net.pi.runtime.PiTranslationService;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.runtime.PiTableId;
import org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType;
@@ -95,7 +95,6 @@
private PiPipelineModel pipelineModel;
private PiPipelineInterpreter interpreter;
- private PiFlowRuleTranslationService piFlowRuleTranslationService;
@Override
protected boolean setupBehaviour() {
@@ -110,7 +109,6 @@
}
interpreter = device.as(PiPipelineInterpreter.class);
pipelineModel = pipeconf.pipelineModel();
- piFlowRuleTranslationService = handler().get(PiFlowRuleTranslationService.class);
return true;
}
@@ -249,8 +247,8 @@
PiTableEntry piTableEntry;
try {
- piTableEntry = piFlowRuleTranslationService.translate(rule, pipeconf);
- } catch (PiFlowRuleTranslationService.PiFlowRuleTranslationException e) {
+ piTableEntry = piTranslationService.translateFlowRule(rule, pipeconf);
+ } catch (PiTranslationService.PiTranslationException e) {
log.warn("Unable to translate flow rule: {} - {}", e.getMessage(), rule);
continue; // next rule
}
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeGroupProgrammable.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeGroupProgrammable.java
index e108123..b9f9766 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeGroupProgrammable.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeGroupProgrammable.java
@@ -16,42 +16,28 @@
package org.onosproject.drivers.p4runtime;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-import org.onlab.util.KryoNamespace;
import org.onosproject.core.GroupId;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.instructions.Instruction;
-import org.onosproject.net.flow.instructions.PiInstruction;
import org.onosproject.net.group.Group;
-import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.group.GroupOperation;
import org.onosproject.net.group.GroupOperations;
import org.onosproject.net.group.GroupProgrammable;
import org.onosproject.net.group.GroupStore;
-import org.onosproject.net.pi.model.PiPipelineInterpreter;
-import org.onosproject.net.pi.runtime.PiActionProfileId;
-import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionGroup;
import org.onosproject.net.pi.runtime.PiActionGroupId;
-import org.onosproject.net.pi.runtime.PiActionGroupMember;
-import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
-import org.onosproject.net.pi.runtime.PiTableAction;
-import org.onosproject.net.pi.runtime.PiTableId;
+import org.onosproject.net.pi.runtime.PiActionProfileId;
+import org.onosproject.net.pi.runtime.PiTranslationService;
import org.onosproject.p4runtime.api.P4RuntimeClient;
import org.onosproject.p4runtime.api.P4RuntimeGroupReference;
import org.onosproject.p4runtime.api.P4RuntimeGroupWrapper;
-import org.onosproject.store.serializers.KryoNamespaces;
import org.slf4j.Logger;
-import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Collections;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -70,11 +56,6 @@
private static final String ACT_GRP = "action group";
private static final String INSERT = "insert";
private static final Logger log = getLogger(P4RuntimeGroupProgrammable.class);
- private static final int GROUP_ID_MASK = 0xffff;
- public static final KryoNamespace KRYO = new KryoNamespace.Builder()
- .register(KryoNamespaces.API)
- .register(DefaultP4RuntimeGroupCookie.class)
- .build("P4RuntimeGroupProgrammable");
/*
* About action groups in P4runtime:
@@ -102,28 +83,12 @@
// TODO: replace with distribute store
private static final Map<P4RuntimeGroupReference, P4RuntimeGroupWrapper> GROUP_STORE = Maps.newConcurrentMap();
- private PiPipelineInterpreter interpreter;
-
- protected boolean init() {
- if (!setupBehaviour()) {
- return false;
- }
- Device device = deviceService.getDevice(deviceId);
- // Need an interpreter to map the bucket treatment to a PI action
- if (!device.is(PiPipelineInterpreter.class)) {
- log.warn("Can't find interpreter for device {}", device.id());
- } else {
- interpreter = device.as(PiPipelineInterpreter.class);
- }
- return true;
- }
-
@Override
public void performGroupOperation(DeviceId deviceId, GroupOperations groupOps) {
- if (!init()) {
- // Ignore group operation of not initialized.
+ if (!setupBehaviour()) {
return;
}
+
Device device = handler().get(DeviceService.class).getDevice(deviceId);
for (GroupOperation groupOp : groupOps.operations()) {
@@ -136,71 +101,38 @@
GroupStore groupStore = handler().get(GroupStore.class);
Group group = groupStore.getGroup(device.id(), groupId);
- // Most of this logic can go in a core service, e.g. PiGroupTranslationService
- // From a P4Runtime perspective, we need first to insert members, then the group.
- PiActionGroupId piActionGroupId = PiActionGroupId.of(groupOp.groupId().id());
-
- PiActionGroup.Builder piActionGroupBuilder = PiActionGroup.builder()
- .withId(piActionGroupId);
-
- switch (group.type()) {
- case SELECT:
- piActionGroupBuilder.withType(PiActionGroup.Type.SELECT);
- break;
- default:
- log.warn("Group type {} not supported, ignore group {}.", group.type(), groupId);
- return;
- }
- /*
- Problem:
- In P4Runtime, action profiles (i.e. group tables) are specific to one or more tables.
- Mapping of treatments depends on the target table. How do we derive the target table from here?
-
- Solution:
- - Add table information into app cookie and put into group description
- */
- // TODO: notify group service if we get deserialize error
- DefaultP4RuntimeGroupCookie defaultP4RuntimeGroupCookie = KRYO.deserialize(group.appCookie().key());
- PiTableId piTableId = defaultP4RuntimeGroupCookie.tableId();
- PiActionProfileId piActionProfileId = defaultP4RuntimeGroupCookie.actionProfileId();
- piActionGroupBuilder.withActionProfileId(piActionProfileId);
-
- List<PiActionGroupMember> members = buildMembers(group, piActionGroupId, piTableId);
- if (members == null) {
- log.warn("Can't build members for group {} on {}", group, device.id());
+ PiActionGroup piActionGroup;
+ try {
+ piActionGroup = piTranslationService.translateGroup(group, pipeconf);
+ } catch (PiTranslationService.PiTranslationException e) {
+ log.warn("Unable translate group, aborting group operation {}: {}", groupOp.opType(), e.getMessage());
return;
}
- piActionGroupBuilder.addMembers(members);
- PiActionGroup piActionGroup = piActionGroupBuilder.build();
+ P4RuntimeGroupReference groupRef = new P4RuntimeGroupReference(deviceId, piActionGroup.actionProfileId(),
+ piActionGroup.id());
- P4RuntimeGroupReference groupRef =
- new P4RuntimeGroupReference(deviceId, piActionProfileId, piActionGroupId);
Lock lock = GROUP_LOCKS.computeIfAbsent(groupRef, k -> new ReentrantLock());
lock.lock();
-
try {
P4RuntimeGroupWrapper oldGroupWrapper = GROUP_STORE.get(groupRef);
- P4RuntimeGroupWrapper newGroupWrapper =
- new P4RuntimeGroupWrapper(piActionGroup, group, System.currentTimeMillis());
- boolean success;
+ P4RuntimeGroupWrapper newGroupWrapper = new P4RuntimeGroupWrapper(piActionGroup, group,
+ System.currentTimeMillis());
switch (groupOp.opType()) {
case ADD:
case MODIFY:
- success = writeGroupToDevice(oldGroupWrapper, piActionGroup, members);
- if (success) {
+ if (writeGroupToDevice(oldGroupWrapper, piActionGroup)) {
GROUP_STORE.put(groupRef, newGroupWrapper);
}
break;
case DELETE:
- success = deleteGroupFromDevice(piActionGroup, members);
- if (success) {
+ if (deleteGroupFromDevice(piActionGroup)) {
GROUP_STORE.remove(groupRef);
}
break;
default:
- throw new UnsupportedOperationException();
+ log.warn("Group operation {} not supported", groupOp.opType());
}
} finally {
lock.unlock();
@@ -211,13 +143,10 @@
* Installs action group and members to device via client interface.
*
* @param oldGroupWrapper old group wrapper for the group; null if not exists
- * @param piActionGroup the action group to be installed
- * @param members members of the action group
+ * @param piActionGroup the action group to be installed
* @return true if install success; false otherwise
*/
- private boolean writeGroupToDevice(P4RuntimeGroupWrapper oldGroupWrapper,
- PiActionGroup piActionGroup,
- Collection<PiActionGroupMember> members) {
+ private boolean writeGroupToDevice(P4RuntimeGroupWrapper oldGroupWrapper, PiActionGroup piActionGroup) {
boolean success = true;
CompletableFuture<Boolean> writeSuccess;
if (checkStoreBeforeUpdate && oldGroupWrapper != null &&
@@ -226,11 +155,9 @@
return true;
}
if (deleteBeforeUpdate && oldGroupWrapper != null) {
- success = deleteGroupFromDevice(oldGroupWrapper.piActionGroup(),
- oldGroupWrapper.piActionGroup().members());
+ success = deleteGroupFromDevice(oldGroupWrapper.piActionGroup());
}
writeSuccess = client.writeActionGroupMembers(piActionGroup,
- members,
P4RuntimeClient.WriteOperationType.INSERT,
pipeconf);
success = success && completeSuccess(writeSuccess, ACT_GRP_MEMS, INSERT);
@@ -242,18 +169,16 @@
return success;
}
- private boolean deleteGroupFromDevice(PiActionGroup piActionGroup,
- Collection<PiActionGroupMember> members) {
+ private boolean deleteGroupFromDevice(PiActionGroup piActionGroup) {
boolean success;
CompletableFuture<Boolean> writeSuccess;
writeSuccess = client.writeActionGroup(piActionGroup,
- P4RuntimeClient.WriteOperationType.DELETE,
- pipeconf);
+ P4RuntimeClient.WriteOperationType.DELETE,
+ pipeconf);
success = completeSuccess(writeSuccess, ACT_GRP, DELETE);
writeSuccess = client.writeActionGroupMembers(piActionGroup,
- members,
- P4RuntimeClient.WriteOperationType.DELETE,
- pipeconf);
+ P4RuntimeClient.WriteOperationType.DELETE,
+ pipeconf);
success = success && completeSuccess(writeSuccess, ACT_GRP_MEMS, DELETE);
return success;
}
@@ -268,98 +193,16 @@
}
}
- /**
- * Build pi action group members from group.
- *
- * @param group the group
- * @param piActionGroupId the PI action group id of the group
- * @param piTableId the PI table related to the group
- * @return list of PI action group members; null if can't build member list
- */
- private List<PiActionGroupMember> buildMembers(Group group, PiActionGroupId piActionGroupId, PiTableId piTableId) {
- GroupId groupId = group.id();
- ImmutableList.Builder<PiActionGroupMember> membersBuilder = ImmutableList.builder();
-
- int bucketIdx = 0;
- for (GroupBucket bucket : group.buckets().buckets()) {
- /*
- Problem:
- In P4Runtime action group members, i.e. action buckets, are associated to a numeric ID chosen
- at member insertion time. This ID must be unique for the whole action profile (i.e. the group table in
- OpenFlow). In ONOS, GroupBucket doesn't specify any ID.
-
- Solutions:
- - Change GroupBucket API to force application wanting to perform group operations to specify a member id.
- - Maintain state to dynamically allocate/deallocate member IDs, e.g. in a dedicated service, or in a
- P4Runtime Group Provider.
-
- Hack:
- Statically derive member ID by combining groupId and position of the bucket in the list.
- */
- ByteBuffer bb = ByteBuffer.allocate(4)
- .putShort((short) (piActionGroupId.id() & GROUP_ID_MASK))
- .putShort((short) bucketIdx);
- bb.rewind();
- int memberId = bb.getInt();
-
- bucketIdx++;
- PiAction action;
- if (interpreter != null) {
- // if we have interpreter, use interpreter
- try {
- action = interpreter.mapTreatment(bucket.treatment(), piTableId);
- } catch (PiPipelineInterpreter.PiInterpreterException e) {
- log.warn("Can't map treatment {} to action due to {}, ignore group {}",
- bucket.treatment(), e.getMessage(), groupId);
- return null;
- }
- } else {
- // if we don't have interpreter, accept PiInstruction only
- TrafficTreatment treatment = bucket.treatment();
-
- if (treatment.allInstructions().size() > 1) {
- log.warn("Treatment {} has multiple instructions, ignore group {}",
- treatment, groupId);
- return null;
- }
- Instruction instruction = treatment.allInstructions().get(0);
- if (instruction.type() != Instruction.Type.PROTOCOL_INDEPENDENT) {
- log.warn("Instruction {} is not a PROTOCOL_INDEPENDENT type, ignore group {}",
- instruction, groupId);
- return null;
- }
-
- PiInstruction piInstruction = (PiInstruction) instruction;
- if (piInstruction.action().type() != PiTableAction.Type.ACTION) {
- log.warn("Action {} is not an ACTION type, ignore group {}",
- piInstruction.action(), groupId);
- return null;
- }
- action = (PiAction) piInstruction.action();
- }
-
- PiActionGroupMember member = PiActionGroupMember.builder()
- .withId(PiActionGroupMemberId.of(memberId))
- .withAction(action)
- .withWeight(bucket.weight())
- .build();
-
- membersBuilder.add(member);
- }
- return membersBuilder.build();
- }
-
@Override
public Collection<Group> getGroups() {
- if (!init()) {
- return Collections.emptySet();
+ if (!setupBehaviour()) {
+ return Collections.emptyList();
}
Collection<Group> result = Sets.newHashSet();
Collection<PiActionProfileId> piActionProfileIds = Sets.newHashSet();
- // Collection action profile Ids
- // TODO: find better way to get all action profile ids....
+ // TODO: find better way to get all action profile ids. e.g. by providing them in the interpreter
GROUP_STORE.forEach((groupRef, wrapper) -> piActionProfileIds.add(groupRef.actionProfileId()));
AtomicBoolean success = new AtomicBoolean(true);
@@ -409,32 +252,4 @@
}
}
- /**
- * P4Runtime app cookie for group.
- */
- public static class DefaultP4RuntimeGroupCookie {
- private PiTableId tableId;
- private PiActionProfileId piActionProfileId;
- private Integer groupId;
-
- public DefaultP4RuntimeGroupCookie(PiTableId tableId,
- PiActionProfileId piActionProfileId,
- Integer groupId) {
- this.tableId = tableId;
- this.piActionProfileId = piActionProfileId;
- this.groupId = groupId;
- }
-
- public PiTableId tableId() {
- return tableId;
- }
-
- public PiActionProfileId actionProfileId() {
- return piActionProfileId;
- }
-
- public Integer groupId() {
- return groupId;
- }
- }
}
diff --git a/drivers/p4runtime/src/test/java/org/onosproject/drivers/p4runtime/P4runtimeGroupProgrammableTest.java b/drivers/p4runtime/src/test/java/org/onosproject/drivers/p4runtime/P4runtimeGroupProgrammableTest.java
deleted file mode 100644
index c334218..0000000
--- a/drivers/p4runtime/src/test/java/org/onosproject/drivers/p4runtime/P4runtimeGroupProgrammableTest.java
+++ /dev/null
@@ -1,291 +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.drivers.p4runtime;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import org.easymock.Capture;
-import org.easymock.EasyMock;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.onlab.util.ImmutableByteSequence;
-import org.onosproject.TestApplicationId;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.GroupId;
-import org.onosproject.drivers.p4runtime.P4RuntimeGroupProgrammable.DefaultP4RuntimeGroupCookie;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.driver.DriverData;
-import org.onosproject.net.driver.DriverHandler;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.instructions.Instructions;
-import org.onosproject.net.group.DefaultGroup;
-import org.onosproject.net.group.DefaultGroupBucket;
-import org.onosproject.net.group.DefaultGroupDescription;
-import org.onosproject.net.group.DefaultGroupKey;
-import org.onosproject.net.group.Group;
-import org.onosproject.net.group.GroupBucket;
-import org.onosproject.net.group.GroupBuckets;
-import org.onosproject.net.group.GroupDescription;
-import org.onosproject.net.group.GroupKey;
-import org.onosproject.net.group.GroupOperation;
-import org.onosproject.net.group.GroupOperations;
-import org.onosproject.net.group.GroupStore;
-import org.onosproject.net.pi.model.DefaultPiPipeconf;
-import org.onosproject.net.pi.model.PiPipeconf;
-import org.onosproject.net.pi.model.PiPipeconfId;
-import org.onosproject.net.pi.model.PiPipelineInterpreter;
-import org.onosproject.net.pi.model.PiPipelineModel;
-import org.onosproject.net.pi.runtime.PiActionProfileId;
-import org.onosproject.net.pi.runtime.PiAction;
-import org.onosproject.net.pi.runtime.PiActionGroup;
-import org.onosproject.net.pi.runtime.PiActionGroupMember;
-import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
-import org.onosproject.net.pi.runtime.PiActionId;
-import org.onosproject.net.pi.runtime.PiActionParam;
-import org.onosproject.net.pi.runtime.PiActionParamId;
-import org.onosproject.net.pi.runtime.PiPipeconfService;
-import org.onosproject.net.pi.runtime.PiTableAction;
-import org.onosproject.net.pi.runtime.PiTableId;
-import org.onosproject.p4runtime.api.P4RuntimeClient;
-import org.onosproject.p4runtime.api.P4RuntimeController;
-
-import java.net.URL;
-import java.util.Collection;
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-
-import static org.easymock.EasyMock.*;
-import static org.junit.Assert.assertEquals;
-import static org.onosproject.net.group.GroupDescription.Type.SELECT;
-import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
-import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.DELETE;
-import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.INSERT;
-
-public class P4runtimeGroupProgrammableTest {
- private static final String P4INFO_PATH = "/default.p4info";
- private static final DeviceId DEVICE_ID = DeviceId.deviceId("device:p4runtime:1");
- private static final PiPipeconfId PIPECONF_ID = new PiPipeconfId("p4runtime-mock-pipeconf");
- private static final PiPipeconf PIPECONF = buildPipeconf();
- private static final PiTableId ECMP_TABLE_ID = PiTableId.of("ecmp");
- private static final PiActionProfileId ACT_PROF_ID = PiActionProfileId.of("ecmp_selector");
- private static final ApplicationId APP_ID = TestApplicationId.create("P4runtimeGroupProgrammableTest");
- private static final GroupId GROUP_ID = GroupId.valueOf(1);
- private static final PiActionId EGRESS_PORT_ACTION_ID = PiActionId.of("set_egress_port");
- private static final PiActionParamId PORT_PARAM_ID = PiActionParamId.of("port");
- private static final List<GroupBucket> BUCKET_LIST = ImmutableList.of(
- outputBucket(1),
- outputBucket(2),
- outputBucket(3)
- );
- private static final DefaultP4RuntimeGroupCookie COOKIE =
- new DefaultP4RuntimeGroupCookie(ECMP_TABLE_ID, ACT_PROF_ID, GROUP_ID.id());
- private static final GroupKey GROUP_KEY =
- new DefaultGroupKey(P4RuntimeGroupProgrammable.KRYO.serialize(COOKIE));
- private static final GroupBuckets BUCKETS = new GroupBuckets(BUCKET_LIST);
- private static final GroupDescription GROUP_DESC =
- new DefaultGroupDescription(DEVICE_ID,
- SELECT,
- BUCKETS,
- GROUP_KEY,
- GROUP_ID.id(),
- APP_ID);
- private static final Group GROUP = new DefaultGroup(GROUP_ID, GROUP_DESC);
- private static final int DEFAULT_MEMBER_WEIGHT = 1;
- private static final int BASE_MEM_ID = 65535;
- private static final Collection<PiActionGroupMember> EXPECTED_MEMBERS =
- ImmutableSet.of(
- outputMember(1),
- outputMember(2),
- outputMember(3)
- );
-
- private P4RuntimeGroupProgrammable programmable;
- private DriverHandler driverHandler;
- private DriverData driverData;
- private P4RuntimeController controller;
- private P4RuntimeClient client;
- private PiPipeconfService piPipeconfService;
- private DeviceService deviceService;
- private Device device;
- private GroupStore groupStore;
-
- private static PiPipeconf buildPipeconf() {
- final URL p4InfoUrl = P4runtimeGroupProgrammableTest.class.getResource(P4INFO_PATH);
- return DefaultPiPipeconf.builder()
- .withId(PIPECONF_ID)
- .withPipelineModel(niceMock(PiPipelineModel.class))
- .addExtension(P4_INFO_TEXT, p4InfoUrl)
- .build();
- }
-
- private static GroupBucket outputBucket(int portNum) {
- ImmutableByteSequence paramVal = ImmutableByteSequence.copyFrom(portNum);
- PiActionParam param = new PiActionParam(PiActionParamId.of(PORT_PARAM_ID.name()), paramVal);
- PiTableAction action = PiAction.builder().withId(EGRESS_PORT_ACTION_ID).withParameter(param).build();
-
- TrafficTreatment treatment = DefaultTrafficTreatment.builder()
- .add(Instructions.piTableAction(action))
- .build();
-
- return DefaultGroupBucket.createSelectGroupBucket(treatment);
- }
-
- private static PiActionGroupMember outputMember(int portNum) {
- PiActionParam param = new PiActionParam(PORT_PARAM_ID,
- ImmutableByteSequence.copyFrom(portNum));
- PiAction piAction = PiAction.builder()
- .withId(EGRESS_PORT_ACTION_ID)
- .withParameter(param).build();
-
- return PiActionGroupMember.builder()
- .withAction(piAction)
- .withId(PiActionGroupMemberId.of(BASE_MEM_ID + portNum))
- .withWeight(DEFAULT_MEMBER_WEIGHT)
- .build();
- }
-
- @Before
- public void setup() {
- driverHandler = EasyMock.niceMock(DriverHandler.class);
- driverData = EasyMock.niceMock(DriverData.class);
- controller = EasyMock.niceMock(P4RuntimeController.class);
- client = EasyMock.niceMock(P4RuntimeClient.class);
- piPipeconfService = EasyMock.niceMock(PiPipeconfService.class);
- deviceService = EasyMock.niceMock(DeviceService.class);
- device = EasyMock.niceMock(Device.class);
- groupStore = EasyMock.niceMock(GroupStore.class);
-
- expect(controller.hasClient(DEVICE_ID)).andReturn(true).anyTimes();
- expect(controller.getClient(DEVICE_ID)).andReturn(client).anyTimes();
- expect(device.is(PiPipelineInterpreter.class)).andReturn(true).anyTimes();
- expect(device.id()).andReturn(DEVICE_ID).anyTimes();
- expect(deviceService.getDevice(DEVICE_ID)).andReturn(device).anyTimes();
- expect(driverData.deviceId()).andReturn(DEVICE_ID).anyTimes();
- expect(groupStore.getGroup(DEVICE_ID, GROUP_ID)).andReturn(GROUP).anyTimes();
- expect(piPipeconfService.ofDevice(DEVICE_ID)).andReturn(Optional.of(PIPECONF_ID)).anyTimes();
- expect(piPipeconfService.getPipeconf(PIPECONF_ID)).andReturn(Optional.of(PIPECONF)).anyTimes();
- expect(driverHandler.data()).andReturn(driverData).anyTimes();
- expect(driverHandler.get(P4RuntimeController.class)).andReturn(controller).anyTimes();
- expect(driverHandler.get(PiPipeconfService.class)).andReturn(piPipeconfService).anyTimes();
- expect(driverHandler.get(DeviceService.class)).andReturn(deviceService).anyTimes();
- expect(driverHandler.get(GroupStore.class)).andReturn(groupStore).anyTimes();
-
- programmable = new P4RuntimeGroupProgrammable();
- programmable.setHandler(driverHandler);
- programmable.setData(driverData);
- EasyMock.replay(driverHandler, driverData, controller, piPipeconfService,
- deviceService, device, groupStore);
- }
-
- /**
- * Test init function.
- */
- @Test
- public void testInit() {
- programmable.init();
- }
-
- /**
- * Test add group with buckets.
- */
- @Test
- public void testAddGroup() {
- List<GroupOperation> ops = Lists.newArrayList();
- ops.add(GroupOperation.createAddGroupOperation(GROUP_ID, SELECT, BUCKETS));
- GroupOperations groupOps = new GroupOperations(ops);
- CompletableFuture<Boolean> completeTrue = new CompletableFuture<>();
- completeTrue.complete(true);
-
- Capture<PiActionGroup> groupCapture1 = EasyMock.newCapture();
- expect(client.writeActionGroup(EasyMock.capture(groupCapture1), EasyMock.eq(INSERT), EasyMock.eq(PIPECONF)))
- .andReturn(completeTrue).anyTimes();
-
- Capture<PiActionGroup> groupCapture2 = EasyMock.newCapture();
- Capture<Collection<PiActionGroupMember>> membersCapture = EasyMock.newCapture();
- expect(client.writeActionGroupMembers(EasyMock.capture(groupCapture2),
- EasyMock.capture(membersCapture),
- EasyMock.eq(INSERT),
- EasyMock.eq(PIPECONF)))
- .andReturn(completeTrue).anyTimes();
-
- EasyMock.replay(client);
- programmable.performGroupOperation(DEVICE_ID, groupOps);
-
- // verify group installed by group programmable
- PiActionGroup group1 = groupCapture1.getValue();
- PiActionGroup group2 = groupCapture2.getValue();
- assertEquals("Groups should be equal", group1, group2);
- assertEquals(GROUP_ID.id(), group1.id().id());
- assertEquals(PiActionGroup.Type.SELECT, group1.type());
- assertEquals(ACT_PROF_ID, group1.actionProfileId());
-
- // members installed
- Collection<PiActionGroupMember> members = group1.members();
- assertEquals(3, members.size());
-
- Assert.assertTrue(EXPECTED_MEMBERS.containsAll(members));
- Assert.assertTrue(members.containsAll(EXPECTED_MEMBERS));
- }
-
- /**
- * Test remove group with buckets.
- */
- @Test
- public void testDelGroup() {
- List<GroupOperation> ops = Lists.newArrayList();
- ops.add(GroupOperation.createDeleteGroupOperation(GROUP_ID, SELECT));
- GroupOperations groupOps = new GroupOperations(ops);
- CompletableFuture<Boolean> completeTrue = new CompletableFuture<>();
- completeTrue.complete(true);
-
- Capture<PiActionGroup> groupCapture1 = EasyMock.newCapture();
- expect(client.writeActionGroup(EasyMock.capture(groupCapture1), EasyMock.eq(DELETE), EasyMock.eq(PIPECONF)))
- .andReturn(completeTrue).anyTimes();
-
- Capture<PiActionGroup> groupCapture2 = EasyMock.newCapture();
- Capture<Collection<PiActionGroupMember>> membersCapture = EasyMock.newCapture();
- expect(client.writeActionGroupMembers(EasyMock.capture(groupCapture2),
- EasyMock.capture(membersCapture),
- EasyMock.eq(DELETE),
- EasyMock.eq(PIPECONF)))
- .andReturn(completeTrue).anyTimes();
-
- EasyMock.replay(client);
- programmable.performGroupOperation(DEVICE_ID, groupOps);
-
- // verify group installed by group programmable
- PiActionGroup group1 = groupCapture1.getValue();
- PiActionGroup group2 = groupCapture2.getValue();
- assertEquals("Groups should be equal", group1, group2);
- assertEquals(GROUP_ID.id(), group1.id().id());
- assertEquals(PiActionGroup.Type.SELECT, group1.type());
- assertEquals(ACT_PROF_ID, group1.actionProfileId());
-
- // members installed
- Collection<PiActionGroupMember> members = group1.members();
- assertEquals(3, members.size());
-
- Assert.assertTrue(EXPECTED_MEMBERS.containsAll(members));
- Assert.assertTrue(members.containsAll(EXPECTED_MEMBERS));
- }
-}
diff --git a/drivers/p4runtime/src/test/resources/default.p4info b/drivers/p4runtime/src/test/resources/default.p4info
deleted file mode 120000
index 8f71cbe..0000000
--- a/drivers/p4runtime/src/test/resources/default.p4info
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../tools/test/p4src/p4-16/p4c-out/default.p4info
\ No newline at end of file