Pi classes to support P4Runtime action profiles
+ modified default.p4 with ECMP capabilities (via action profiles)
+ sketched translation logic of ONOS groups (in Bmv2GroupProgrammable)
+ replaced existing instances of default.json/p4info with symlinks to
p4src build directory (to avoid inconsistencies)
Change-Id: If82f0b8ce296c9b616415d99864d216b77645a87
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2GroupProgrammable.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2GroupProgrammable.java
new file mode 100644
index 0000000..0bca13b
--- /dev/null
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2GroupProgrammable.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.bmv2;
+
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.group.GroupBucket;
+import org.onosproject.net.group.GroupDescription;
+import org.onosproject.net.group.GroupOperation;
+import org.onosproject.net.group.GroupOperations;
+import org.onosproject.net.group.GroupProgrammable;
+import org.onosproject.net.pi.model.PiPipelineInterpreter;
+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.PiTableId;
+
+import java.nio.ByteBuffer;
+
+public class Bmv2GroupProgrammable extends AbstractHandlerBehaviour implements GroupProgrammable {
+
+ /*
+ Work in progress.
+ */
+
+ private Device device;
+
+ /*
+ About action groups in P4runtime:
+ The type field is a place holder in p4runtime.proto right now, and we haven't defined it yet. You can assume all
+ the groups are "select" as per the OF spec. As a remainder, in the P4 terminology a member corresponds to an OF
+ bucket. Each member can also be used directly in the match table (kind of like an OF indirect group).
+ */
+
+ @Override
+ public void performGroupOperation(DeviceId deviceId, GroupOperations groupOps) {
+
+ for (GroupOperation groupOp : groupOps.operations()) {
+ switch (groupOp.opType()) {
+ case ADD:
+ addGroup(deviceId, groupOp);
+ break;
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+
+ private void addGroup(DeviceId deviceId, GroupOperation groupOp) {
+
+ // 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)
+ .withType(PiActionGroup.Type.SELECT);
+
+ if (groupOp.groupType() != GroupDescription.Type.SELECT) {
+ // log error
+ }
+
+ int bucketIdx = 0;
+ for (GroupBucket bucket : groupOp.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.
+ */
+ int memberId = ByteBuffer.allocate(4)
+ .putShort((short) (piActionGroupId.id() % 2 ^ 16))
+ .putShort((short) (bucketIdx % 2 ^ 16))
+ .getInt();
+
+ // Need an interpreter to map the bucket treatment to a PI action
+
+ if (!device.is(PiPipelineInterpreter.class)) {
+ // log error
+ }
+
+ PiPipelineInterpreter interpreter = device.as(PiPipelineInterpreter.class);
+
+ /*
+ 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:
+ - Change GroupDescription to allow applications to specify a table where this group will be called from.
+
+ Hack:
+ Assume we support pipelines with only one action profile associated to only one table, i.e. derive the
+ table ID by looking at the P4Info.
+ */
+
+ PiTableId piTableId = PiTableId.of("derive from P4Info");
+
+
+ PiAction action = null;
+ try {
+ action = interpreter.mapTreatment(bucket.treatment(), piTableId);
+ } catch (PiPipelineInterpreter.PiInterpreterException e) {
+ // log error
+ }
+
+ PiActionGroupMember member = PiActionGroupMember.builder()
+ .withId(PiActionGroupMemberId.of(memberId))
+ .withAction(action)
+ .withWeight(bucket.weight())
+ .build();
+
+ piActionGroupBuilder.addMember(member);
+
+ // Use P4RuntimeClient to install member;
+ // TODO: implement P4RuntimeClient method.
+ }
+
+ PiActionGroup piActionGroup = piActionGroupBuilder.build();
+
+ // Use P4RuntimeClient to insert group.
+ // TODO: implement P4RuntimeClient method.
+ }
+}