[ONOS-6935] ActionProfile supports in P4RuntimeClient
Change-Id: I9f0ac307985c03b7ed93e14e41ba468c481a4e4f
diff --git a/apps/p4runtime-test/src/test/java/org/onosproject/p4runtime/test/P4RuntimeTest.java b/apps/p4runtime-test/src/test/java/org/onosproject/p4runtime/test/P4RuntimeTest.java
index 74e6845..45a8716 100644
--- a/apps/p4runtime-test/src/test/java/org/onosproject/p4runtime/test/P4RuntimeTest.java
+++ b/apps/p4runtime-test/src/test/java/org/onosproject/p4runtime/test/P4RuntimeTest.java
@@ -29,9 +29,14 @@
import org.onosproject.net.pi.model.PiPipeconf;
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.PiActionId;
import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.net.pi.runtime.PiActionParamId;
+import org.onosproject.net.pi.runtime.PiActionProfileId;
import org.onosproject.net.pi.runtime.PiHeaderFieldId;
import org.onosproject.net.pi.runtime.PiMatchKey;
import org.onosproject.net.pi.runtime.PiPacketMetadata;
@@ -43,15 +48,19 @@
import org.onosproject.p4runtime.api.P4RuntimeClient;
import org.onosproject.p4runtime.ctl.P4RuntimeClientImpl;
import org.onosproject.p4runtime.ctl.P4RuntimeControllerImpl;
+import org.slf4j.Logger;
import p4.P4RuntimeGrpc;
import p4.P4RuntimeOuterClass;
import java.net.URL;
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import static org.onlab.util.ImmutableByteSequence.*;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
import static org.onosproject.net.pi.runtime.PiPacketOperation.Type.PACKET_OUT;
+import static org.slf4j.LoggerFactory.getLogger;
import static p4.P4RuntimeOuterClass.ActionProfileGroup.Type.SELECT;
import static p4.P4RuntimeOuterClass.Update.Type.INSERT;
@@ -59,6 +68,7 @@
* Class used for quick testing of P4Runtime with real devices. To be removed before release.
*/
public class P4RuntimeTest {
+ private static final Logger log = getLogger(P4RuntimeTest.class);
private static final String GRPC_SERVER_ADDR = "192.168.56.102";
private static final int GRPC_SERVER_PORT = 55044;
@@ -232,6 +242,56 @@
@Test
@Ignore
+ public void testBmv2ActionProfile() throws Exception {
+ createClient();
+ setPipelineConfig(bmv2DefaultPipeconf, BMV2_JSON);
+ PiActionProfileId actionProfileId = PiActionProfileId.of("ecmp_selector");
+ PiActionGroupId groupId = PiActionGroupId.of(1);
+
+ Collection<PiActionGroupMember> members = Lists.newArrayList();
+
+ for (int port = 1; port <= 4; port++) {
+ PiAction memberAction = PiAction.builder()
+ .withId(PiActionId.of(SET_EGRESS_PORT))
+ .withParameter(new PiActionParam(PiActionParamId.of(PORT),
+ ImmutableByteSequence.copyFrom((short) port)))
+ .build();
+ PiActionGroupMemberId memberId = PiActionGroupMemberId.of(port);
+ PiActionGroupMember member = PiActionGroupMember.builder()
+ .withId(memberId)
+ .withAction(memberAction)
+ .withWeight(port)
+ .build();
+ members.add(member);
+ }
+ PiActionGroup actionGroup = PiActionGroup.builder()
+ .withType(PiActionGroup.Type.SELECT)
+ .withActionProfileId(actionProfileId)
+ .withId(groupId)
+ .addMembers(members)
+ .build();
+ CompletableFuture<Boolean> success = client.writeActionGroupMembers(actionGroup, members,
+ P4RuntimeClient.WriteOperationType.INSERT,
+ bmv2DefaultPipeconf);
+ assert (success.get());
+
+ success = client.writeActionGroup(actionGroup, P4RuntimeClient.WriteOperationType.INSERT, bmv2DefaultPipeconf);
+ assert (success.get());
+
+ CompletableFuture<Collection<PiActionGroup>> piGroups = client.dumpGroups(actionProfileId, bmv2DefaultPipeconf);
+
+ log.info("Number of groups: {}", piGroups.get().size());
+ piGroups.get().forEach(piGroup -> {
+ log.info("Group {}", piGroup);
+ log.info("------");
+ piGroup.members().forEach(piMem -> {
+ log.info(" {}", piMem);
+ });
+ });
+ }
+
+ @Test
+ @Ignore
public void testTofino() throws Exception {
createClient();
setPipelineConfig(bmv2DefaultPipeconf, null);
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionGroup.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionGroup.java
index f023e05..1de4d61 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionGroup.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionGroup.java
@@ -47,11 +47,15 @@
private final PiActionGroupId id;
private final Type type;
private final ImmutableSet<PiActionGroupMember> members;
+ private final PiActionProfileId piActionProfileId;
- private PiActionGroup(PiActionGroupId id, Type type, ImmutableSet<PiActionGroupMember> members) {
+ private PiActionGroup(PiActionGroupId id, Type type,
+ ImmutableSet<PiActionGroupMember> members,
+ PiActionProfileId piActionProfileId) {
this.id = id;
this.type = type;
this.members = members;
+ this.piActionProfileId = piActionProfileId;
}
/**
@@ -81,18 +85,28 @@
return members;
}
+ /**
+ * Gets identifier of the action profile.
+ *
+ * @return action profile id
+ */
+ public PiActionProfileId actionProfileId() {
+ return piActionProfileId;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (o == null || !(o instanceof PiActionGroup)) {
return false;
}
PiActionGroup that = (PiActionGroup) o;
- return id == that.id &&
+ return Objects.equal(id, that.id) &&
Objects.equal(type, that.type) &&
- Objects.equal(members, that.members);
+ Objects.equal(members, that.members) &&
+ Objects.equal(piActionProfileId, that.piActionProfileId);
}
@Override
@@ -106,6 +120,7 @@
.add("groupId", id)
.add("type", type)
.add("members", members)
+ .add("piActionProfileId", piActionProfileId)
.toString();
}
@@ -126,6 +141,7 @@
private PiActionGroupId id;
private Type type;
private Map<PiActionGroupMemberId, PiActionGroupMember> members = Maps.newHashMap();
+ private PiActionProfileId piActionProfileId;
private Builder() {
// hides constructor.
@@ -176,6 +192,17 @@
}
/**
+ * Sets the identifier of the action profile.
+ *
+ * @param piActionProfileId the identifier of the action profile
+ * @return this
+ */
+ public Builder withActionProfileId(PiActionProfileId piActionProfileId) {
+ this.piActionProfileId = piActionProfileId;
+ return this;
+ }
+
+ /**
* Creates a new action group.
*
* @return action group
@@ -183,8 +210,11 @@
public PiActionGroup build() {
checkNotNull(id);
checkNotNull(type);
- checkArgument(members.size() > 0, "Members cannot be empty");
- return new PiActionGroup(id, type, ImmutableSet.copyOf(members.values()));
+ checkArgument(!members.isEmpty(), "Members cannot be empty");
+ checkNotNull(piActionProfileId);
+ return new PiActionGroup(id, type,
+ ImmutableSet.copyOf(members.values()),
+ piActionProfileId);
}
}
}
diff --git a/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileId.java b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileId.java
new file mode 100644
index 0000000..e0158c9
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/pi/runtime/PiActionProfileId.java
@@ -0,0 +1,41 @@
+/*
+ * 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.onlab.util.Identifier;
+
+/**
+ * Identifier of an action profile of a protocol-independent pipeline.
+ */
+@Beta
+public final class PiActionProfileId extends Identifier<String> {
+
+ private PiActionProfileId(String actionProfileName) {
+ super(actionProfileName);
+ }
+
+ /**
+ * Returns action profile id with given action profile name.
+ *
+ * @param actionProfileName action profile name
+ * @return action profile id
+ */
+ public static PiActionProfileId of(String actionProfileName) {
+ return new PiActionProfileId(actionProfileName);
+ }
+}
diff --git a/core/api/src/test/java/org/onosproject/net/pi/runtime/PiActionGroupTest.java b/core/api/src/test/java/org/onosproject/net/pi/runtime/PiActionGroupTest.java
index e9b736b..0da15e4 100644
--- a/core/api/src/test/java/org/onosproject/net/pi/runtime/PiActionGroupTest.java
+++ b/core/api/src/test/java/org/onosproject/net/pi/runtime/PiActionGroupTest.java
@@ -28,6 +28,7 @@
import static org.hamcrest.Matchers.notNullValue;
import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
+import static org.onosproject.net.pi.runtime.PiConstantsTest.ACTION_PROF_ID;
import static org.onosproject.net.pi.runtime.PiConstantsTest.DST_ADDR;
import static org.onosproject.net.pi.runtime.PiConstantsTest.MOD_NW_DST;
@@ -51,12 +52,14 @@
.addMember(piActionGroupMember)
.withId(piActionGroupId)
.withType(PiActionGroup.Type.SELECT)
+ .withActionProfileId(ACTION_PROF_ID)
.build();
PiActionGroup sameAsPiActionGroup1 = PiActionGroup.builder()
.addMember(piActionGroupMember)
.withId(piActionGroupId)
.withType(PiActionGroup.Type.SELECT)
+ .withActionProfileId(ACTION_PROF_ID)
.build();
PiActionGroupId piActionGroupId2 = PiActionGroupId.of(20);
@@ -64,6 +67,7 @@
.addMember(piActionGroupMember)
.withId(piActionGroupId2)
.withType(PiActionGroup.Type.SELECT)
+ .withActionProfileId(ACTION_PROF_ID)
.build();
/**
diff --git a/core/api/src/test/java/org/onosproject/net/pi/runtime/PiConstantsTest.java b/core/api/src/test/java/org/onosproject/net/pi/runtime/PiConstantsTest.java
index b2bda37..86f713d 100644
--- a/core/api/src/test/java/org/onosproject/net/pi/runtime/PiConstantsTest.java
+++ b/core/api/src/test/java/org/onosproject/net/pi/runtime/PiConstantsTest.java
@@ -38,4 +38,7 @@
public static final String EGRESS_PORT = "egress_port";
public static final String INGRESS_PORT = "ingress_port";
+
+ public static final PiActionProfileId ACTION_PROF_ID =
+ PiActionProfileId.of("Test action profile");
}
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslator.java b/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslator.java
index dc6d1c5..fbfd9b7 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslator.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslator.java
@@ -131,8 +131,8 @@
Collection<PiFieldMatch> fieldMatches = buildFieldMatches(interpreter, rule.selector(), table);
/* Translate treatment */
- PiAction piAction = buildAction(rule.treatment(), interpreter, piTableId);
- piAction = typeCheckAction(piAction, table);
+ PiTableAction piTableAction = buildAction(rule.treatment(), interpreter, piTableId);
+ piTableAction = typeCheckAction(piTableAction, table);
PiTableEntry.Builder tableEntryBuilder = PiTableEntry.builder();
@@ -154,7 +154,7 @@
.withMatchKey(PiMatchKey.builder()
.addFieldMatches(fieldMatches)
.build())
- .withAction(piAction);
+ .withAction(piTableAction);
if (!rule.isPermanent()) {
if (table.supportsAging()) {
@@ -172,7 +172,7 @@
/**
* Builds a PI action out of the given treatment, optionally using the given interpreter.
*/
- private static PiAction buildAction(TrafficTreatment treatment, PiPipelineInterpreter interpreter,
+ private static PiTableAction buildAction(TrafficTreatment treatment, PiPipelineInterpreter interpreter,
PiTableId tableId)
throws PiFlowRuleTranslationException {
@@ -208,22 +208,28 @@
+ "protocol-independent instruction were provided.");
}
- if (piTableAction.type() != PiTableAction.Type.ACTION) {
- // TODO: implement handling of other table action types, e.g. action profiles.
- throw new PiFlowRuleTranslationException(format(
- "PiTableAction type %s is not supported yet.", piTableAction.type()));
- }
-
- return (PiAction) piTableAction;
+ return piTableAction;
}
/**
- * Checks that the given PI action is suitable for the given table model and returns a new action instance with
- * parameters well-sized, according to the table model. If not suitable, throws an exception explaining why.
+ * Checks that the given PI table action is suitable for the given table
+ * model and returns a new action instance with parameters well-sized,
+ * according to the table model. If not suitable, throws an exception explaining why.
*/
- private static PiAction typeCheckAction(PiAction piAction, PiTableModel table)
+ private static PiTableAction typeCheckAction(PiTableAction piTableAction, PiTableModel table)
throws PiFlowRuleTranslationException {
+ switch (piTableAction.type()) {
+ case ACTION:
+ return checkPiAction((PiAction) piTableAction, table);
+ default:
+ // FIXME: should we check? how?
+ return piTableAction;
+ }
+ }
+
+ private static PiTableAction checkPiAction(PiAction piAction, PiTableModel table)
+ throws PiFlowRuleTranslationException {
// Table supports this action?
PiActionModel actionModel = table.action(piAction.id().name()).orElseThrow(
() -> new PiFlowRuleTranslationException(format("Not such action '%s' for table '%s'",
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
index 6413037..cc227ba 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
@@ -212,6 +212,7 @@
import org.onosproject.net.pi.runtime.PiActionParamId;
import org.onosproject.net.pi.runtime.PiExactFieldMatch;
import org.onosproject.net.pi.runtime.PiFieldMatch;
+import org.onosproject.net.pi.runtime.PiActionProfileId;
import org.onosproject.net.pi.runtime.PiHeaderFieldId;
import org.onosproject.net.pi.runtime.PiLpmFieldMatch;
import org.onosproject.net.pi.runtime.PiMatchKey;
@@ -388,7 +389,6 @@
DefaultFlowRule.class,
TableId.class,
IndexTableId.class,
- PiTableId.class,
FlowRule.FlowRemoveReason.class,
DefaultPacketRequest.class,
PacketPriority.class,
@@ -620,6 +620,7 @@
PiTableId.class,
PiTernaryFieldMatch.class,
PiValidFieldMatch.class,
+ PiActionProfileId.class,
// Other
PiCriterion.class,
PiInstruction.class
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java
index 41fe160..448da71 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2DefaultPipeconfFactory.java
@@ -55,7 +55,6 @@
final URL jsonUrl = Bmv2DefaultPipeconfFactory.class.getResource(JSON_PATH);
final URL p4InfoUrl = Bmv2DefaultPipeconfFactory.class.getResource(P4INFO_PATH);
-
return DefaultPiPipeconf.builder()
.withId(new PiPipeconfId(PIPECONF_ID))
.withPipelineModel(Bmv2PipelineModelParser.parse(jsonUrl))
diff --git a/drivers/p4runtime/BUCK b/drivers/p4runtime/BUCK
index 57079be..5c50f12 100644
--- a/drivers/p4runtime/BUCK
+++ b/drivers/p4runtime/BUCK
@@ -5,14 +5,22 @@
'//protocols/p4runtime/api:onos-protocols-p4runtime-api',
'//incubator/grpc-dependencies:grpc-core-repkg-' + GRPC_VER,
'//lib:grpc-netty-' + GRPC_VER,
+ '//core/store/serializers:onos-core-serializers',
+ '//lib:KRYO',
]
BUNDLES = [
':onos-drivers-p4runtime',
]
-osgi_jar(
+TEST_DEPS = [
+ '//lib:TEST_ADAPTERS',
+ '//core/api:onos-api-tests',
+]
+
+osgi_jar_with_tests (
deps = COMPILE_DEPS,
+ test_deps = TEST_DEPS,
)
onos_app (
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4Interpreter.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4Interpreter.java
index e2fe315..d069e2a 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4Interpreter.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/DefaultP4Interpreter.java
@@ -30,6 +30,7 @@
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.flow.instructions.PiInstruction;
import org.onosproject.net.packet.DefaultInboundPacket;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.OutboundPacket;
@@ -167,7 +168,7 @@
@Override
public PiAction mapTreatment(TrafficTreatment treatment, PiTableId piTableId) throws PiInterpreterException {
-
+ initTargetSpecificAttributes();
if (treatment.allInstructions().size() == 0) {
// No instructions means drop for us.
return actionWithName(DROP);
@@ -181,17 +182,10 @@
switch (instruction.type()) {
case OUTPUT:
Instructions.OutputInstruction outInstruction = (Instructions.OutputInstruction) instruction;
- PortNumber port = outInstruction.port();
- if (!port.isLogical()) {
- return PiAction.builder()
- .withId(PiActionId.of(SET_EGRESS_PORT))
- .withParameter(new PiActionParam(PiActionParamId.of(PORT), copyFrom(port.toLong())))
- .build();
- } else if (port.equals(CONTROLLER)) {
- return actionWithName(SEND_TO_CPU);
- } else {
- throw new PiInterpreterException(format("Egress on logical port '%s' not supported", port));
- }
+ return outputPiAction(outInstruction);
+ case PROTOCOL_INDEPENDENT:
+ PiInstruction piInstruction = (PiInstruction) instruction;
+ return (PiAction) piInstruction.action();
case NOACTION:
return actionWithName(DROP);
default:
@@ -199,6 +193,25 @@
}
}
+ private PiAction outputPiAction(Instructions.OutputInstruction outInstruction) throws PiInterpreterException {
+ PortNumber port = outInstruction.port();
+ if (!port.isLogical()) {
+ try {
+ return PiAction.builder()
+ .withId(PiActionId.of(SET_EGRESS_PORT))
+ .withParameter(new PiActionParam(PiActionParamId.of(PORT),
+ fit(copyFrom(port.toLong()), portFieldBitWidth)))
+ .build();
+ } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
+ throw new PiInterpreterException(e.getMessage());
+ }
+ } else if (port.equals(CONTROLLER)) {
+ return actionWithName(SEND_TO_CPU);
+ } else {
+ throw new PiInterpreterException(format("Egress on logical port '%s' not supported", port));
+ }
+ }
+
@Override
public Optional<PiCounterId> mapTableCounter(PiTableId piTableId) {
return Optional.ofNullable(TABLE_COUNTER_MAP.get(piTableId));
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 15a40ca..e108123 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,71 +16,272 @@
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.driver.AbstractHandlerBehaviour;
+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.GroupDescription;
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.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;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
-public class P4RuntimeGroupProgrammable extends AbstractHandlerBehaviour implements GroupProgrammable {
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the group programmable behaviour for P4Runtime.
+ */
+public class P4RuntimeGroupProgrammable extends AbstractP4RuntimeHandlerBehaviour implements GroupProgrammable {
+ private static final String ACT_GRP_MEMS = "action group members";
+ private static final String DELETE = "delete";
+ 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");
/*
- Work in progress.
+ * 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).
*/
- private Device device;
-
+ // TODO: make this attribute configurable by child drivers (e.g. BMv2 or Tofino)
/*
- 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).
+ When updating an existing rule, if true, we issue a DELETE operation before inserting the new one, otherwise we
+ issue a MODIFY operation. This is useful fore devices that do not support MODIFY operations for table entries.
*/
+ private boolean deleteBeforeUpdate = true;
+
+ // TODO: can remove this check as soon as the multi-apply-per-same-flow rule bug is fixed.
+ /*
+ If true, we ignore re-installing rules that are already known in the ENTRY_STORE, i.e. same match key and action.
+ */
+ private boolean checkStoreBeforeUpdate = true;
+
+ // Needed to synchronize operations over the same group.
+ private static final Map<P4RuntimeGroupReference, Lock> GROUP_LOCKS = Maps.newConcurrentMap();
+
+ // 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.
+ return;
+ }
+ Device device = handler().get(DeviceService.class).getDevice(deviceId);
for (GroupOperation groupOp : groupOps.operations()) {
+ processGroupOp(device, groupOp);
+ }
+ }
+
+ private void processGroupOp(Device device, GroupOperation groupOp) {
+ GroupId groupId = groupOp.groupId();
+ 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());
+ return;
+ }
+
+ piActionGroupBuilder.addMembers(members);
+ PiActionGroup piActionGroup = piActionGroupBuilder.build();
+
+ 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;
switch (groupOp.opType()) {
case ADD:
- addGroup(deviceId, groupOp);
+ case MODIFY:
+ success = writeGroupToDevice(oldGroupWrapper, piActionGroup, members);
+ if (success) {
+ GROUP_STORE.put(groupRef, newGroupWrapper);
+ }
+ break;
+ case DELETE:
+ success = deleteGroupFromDevice(piActionGroup, members);
+ if (success) {
+ GROUP_STORE.remove(groupRef);
+ }
break;
default:
throw new UnsupportedOperationException();
}
+ } finally {
+ lock.unlock();
}
}
- 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
+ /**
+ * 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
+ * @return true if install success; false otherwise
+ */
+ private boolean writeGroupToDevice(P4RuntimeGroupWrapper oldGroupWrapper,
+ PiActionGroup piActionGroup,
+ Collection<PiActionGroupMember> members) {
+ boolean success = true;
+ CompletableFuture<Boolean> writeSuccess;
+ if (checkStoreBeforeUpdate && oldGroupWrapper != null &&
+ oldGroupWrapper.piActionGroup().equals(piActionGroup)) {
+ // Action group already exists, ignore it
+ return true;
}
+ if (deleteBeforeUpdate && oldGroupWrapper != null) {
+ success = deleteGroupFromDevice(oldGroupWrapper.piActionGroup(),
+ oldGroupWrapper.piActionGroup().members());
+ }
+ writeSuccess = client.writeActionGroupMembers(piActionGroup,
+ members,
+ P4RuntimeClient.WriteOperationType.INSERT,
+ pipeconf);
+ success = success && completeSuccess(writeSuccess, ACT_GRP_MEMS, INSERT);
+
+ writeSuccess = client.writeActionGroup(piActionGroup,
+ P4RuntimeClient.WriteOperationType.INSERT,
+ pipeconf);
+ success = success && completeSuccess(writeSuccess, ACT_GRP, INSERT);
+ return success;
+ }
+
+ private boolean deleteGroupFromDevice(PiActionGroup piActionGroup,
+ Collection<PiActionGroupMember> members) {
+ boolean success;
+ CompletableFuture<Boolean> writeSuccess;
+ writeSuccess = client.writeActionGroup(piActionGroup,
+ P4RuntimeClient.WriteOperationType.DELETE,
+ pipeconf);
+ success = completeSuccess(writeSuccess, ACT_GRP, DELETE);
+ writeSuccess = client.writeActionGroupMembers(piActionGroup,
+ members,
+ P4RuntimeClient.WriteOperationType.DELETE,
+ pipeconf);
+ success = success && completeSuccess(writeSuccess, ACT_GRP_MEMS, DELETE);
+ return success;
+ }
+
+ private boolean completeSuccess(CompletableFuture<Boolean> completableFuture,
+ String topic, String action) {
+ try {
+ return completableFuture.get();
+ } catch (InterruptedException | ExecutionException e) {
+ log.warn("Can't {} {} due to {}", action, topic, e.getMessage());
+ return false;
+ }
+ }
+
+ /**
+ * 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 : groupOp.buckets().buckets()) {
+ for (GroupBucket bucket : group.buckets().buckets()) {
/*
Problem:
In P4Runtime action group members, i.e. action buckets, are associated to a numeric ID chosen
@@ -95,40 +296,46 @@
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();
+ ByteBuffer bb = ByteBuffer.allocate(4)
+ .putShort((short) (piActionGroupId.id() & GROUP_ID_MASK))
+ .putShort((short) bucketIdx);
+ bb.rewind();
+ int memberId = bb.getInt();
- // Need an interpreter to map the bucket treatment to a PI action
+ 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 (!device.is(PiPipelineInterpreter.class)) {
- // log error
- }
+ 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;
+ }
- 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
+ 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()
@@ -137,15 +344,97 @@
.withWeight(bucket.weight())
.build();
- piActionGroupBuilder.addMember(member);
+ membersBuilder.add(member);
+ }
+ return membersBuilder.build();
+ }
- // Use P4RuntimeClient to install member;
- // TODO: implement P4RuntimeClient method.
+ @Override
+ public Collection<Group> getGroups() {
+ if (!init()) {
+ return Collections.emptySet();
}
- PiActionGroup piActionGroup = piActionGroupBuilder.build();
+ Collection<Group> result = Sets.newHashSet();
+ Collection<PiActionProfileId> piActionProfileIds = Sets.newHashSet();
- // Use P4RuntimeClient to insert group.
- // TODO: implement P4RuntimeClient method.
+ // Collection action profile Ids
+ // TODO: find better way to get all action profile ids....
+ GROUP_STORE.forEach((groupRef, wrapper) -> piActionProfileIds.add(groupRef.actionProfileId()));
+
+ AtomicBoolean success = new AtomicBoolean(true);
+ piActionProfileIds.forEach(actionProfileId -> {
+ Collection<PiActionGroup> piActionGroups = Sets.newHashSet();
+ try {
+ Collection<PiActionGroup> groupsFromDevice =
+ client.dumpGroups(actionProfileId, pipeconf).get();
+ if (groupsFromDevice == null) {
+ // Got error
+ success.set(false);
+ } else {
+ piActionGroups.addAll(groupsFromDevice);
+ }
+ } catch (ExecutionException | InterruptedException e) {
+ log.error("Exception while dumping groups for action profile {}: {}",
+ actionProfileId.id(), deviceId, e);
+ success.set(false);
+ }
+
+ piActionGroups.forEach(piActionGroup -> {
+ PiActionGroupId actionGroupId = piActionGroup.id();
+ P4RuntimeGroupReference groupRef =
+ new P4RuntimeGroupReference(deviceId, actionProfileId, actionGroupId);
+ P4RuntimeGroupWrapper wrapper = GROUP_STORE.get(groupRef);
+
+ if (wrapper == null) {
+ // group exists in client, but can't find in ONOS
+ log.warn("Can't find action profile group {} from local store.",
+ groupRef);
+ return;
+ }
+ if (!wrapper.piActionGroup().equals(piActionGroup)) {
+ log.warn("Group from device is different to group from local store.");
+ return;
+ }
+ result.add(wrapper.group());
+
+ });
+ });
+
+ if (!success.get()) {
+ // Got error while dump groups from device.
+ return Collections.emptySet();
+ } else {
+ return result;
+ }
+ }
+
+ /**
+ * 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
new file mode 100644
index 0000000..c334218
--- /dev/null
+++ b/drivers/p4runtime/src/test/java/org/onosproject/drivers/p4runtime/P4runtimeGroupProgrammableTest.java
@@ -0,0 +1,291 @@
+/*
+ * 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
new file mode 120000
index 0000000..8f71cbe
--- /dev/null
+++ b/drivers/p4runtime/src/test/resources/default.p4info
@@ -0,0 +1 @@
+../../../../../tools/test/p4src/p4-16/p4c-out/default.p4info
\ No newline at end of file
diff --git a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java
index 0bd19e5..3b7f3d3 100644
--- a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java
+++ b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeClient.java
@@ -18,9 +18,12 @@
import com.google.common.annotations.Beta;
import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiActionProfileId;
import org.onosproject.net.pi.runtime.PiCounterCellData;
import org.onosproject.net.pi.runtime.PiCounterCellId;
import org.onosproject.net.pi.runtime.PiCounterId;
+import org.onosproject.net.pi.runtime.PiActionGroup;
+import org.onosproject.net.pi.runtime.PiActionGroupMember;
import org.onosproject.net.pi.runtime.PiPacketOperation;
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.runtime.PiTableId;
@@ -115,6 +118,42 @@
PiPipeconf pipeconf);
/**
+ * Performs the given write operation for the given action group members and pipeconf.
+ *
+ * @param group action group
+ * @param members the collection of action group members
+ * @param opType write operation type
+ * @param pipeconf the pipeconf currently deployed on the device
+ * @return true if the operation was successful, false otherwise
+ */
+ CompletableFuture<Boolean> writeActionGroupMembers(PiActionGroup group,
+ Collection<PiActionGroupMember> members,
+ WriteOperationType opType,
+ PiPipeconf pipeconf);
+
+ /**
+ * Performs the given write operation for the given action group and pipeconf.
+ *
+ * @param group the action group
+ * @param opType write operation type
+ * @param pipeconf the pipeconf currently deployed on the device
+ * @return true if the operation was successful, false otherwise
+ */
+ CompletableFuture<Boolean> writeActionGroup(PiActionGroup group,
+ WriteOperationType opType,
+ PiPipeconf pipeconf);
+
+ /**
+ * Dumps all groups currently installed for the given action profile.
+ *
+ * @param actionProfileId the action profile id
+ * @param pipeconf the pipeconf currently deployed on the device
+ * @return completable future of a collection of groups
+ */
+ CompletableFuture<Collection<PiActionGroup>> dumpGroups(PiActionProfileId actionProfileId,
+ PiPipeconf pipeconf);
+
+ /**
* Shutdown the client by terminating any active RPC such as the stream channel.
*/
void shutdown();
diff --git a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeGroupReference.java b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeGroupReference.java
new file mode 100644
index 0000000..543ae4d
--- /dev/null
+++ b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeGroupReference.java
@@ -0,0 +1,103 @@
+/*
+ * 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.p4runtime.api;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.pi.runtime.PiActionProfileId;
+import org.onosproject.net.pi.runtime.PiActionGroupId;
+
+/**
+ * Class containing the reference for a group in P4Runtime.
+ */
+@Beta
+public final class P4RuntimeGroupReference {
+ private final DeviceId deviceId;
+ private final PiActionProfileId piActionProfileId;
+ private final PiActionGroupId groupId;
+
+ /**
+ * Creates P4 runtime group reference.
+ *
+ * @param deviceId the device id of group
+ * @param piActionProfileId the action profile id
+ * @param groupId the group Id of group
+ */
+ public P4RuntimeGroupReference(DeviceId deviceId, PiActionProfileId piActionProfileId,
+ PiActionGroupId groupId) {
+ this.deviceId = deviceId;
+ this.piActionProfileId = piActionProfileId;
+ this.groupId = groupId;
+ }
+
+ /**
+ * Gets device id of this group.
+ *
+ * @return the device id
+ */
+ public DeviceId deviceId() {
+ return deviceId;
+ }
+
+ /**
+ * Gets action profile id of this group.
+ *
+ * @return the action profile id
+ */
+ public PiActionProfileId actionProfileId() {
+ return piActionProfileId;
+ }
+
+ /**
+ * Gets group id of this group.
+ *
+ * @return group id
+ */
+ public PiActionGroupId groupId() {
+ return groupId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ P4RuntimeGroupReference that = (P4RuntimeGroupReference) o;
+ return Objects.equal(deviceId, that.deviceId) &&
+ Objects.equal(piActionProfileId, that.piActionProfileId) &&
+ Objects.equal(groupId, that.groupId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(deviceId, piActionProfileId, groupId);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("deviceId", deviceId)
+ .add("piActionProfileId", piActionProfileId)
+ .add("groupId", groupId)
+ .toString();
+ }
+}
diff --git a/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeGroupWrapper.java b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeGroupWrapper.java
new file mode 100644
index 0000000..8cb4b83
--- /dev/null
+++ b/protocols/p4runtime/api/src/main/java/org/onosproject/p4runtime/api/P4RuntimeGroupWrapper.java
@@ -0,0 +1,72 @@
+/*
+ * 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.p4runtime.api;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.group.Group;
+import org.onosproject.net.pi.runtime.PiActionGroup;
+
+/**
+ * A wrapper for a ONOS group installed on a P4Runtime device.
+ */
+@Beta
+public class P4RuntimeGroupWrapper {
+ private final PiActionGroup piActionGroup;
+ private final Group group;
+ private final long installMilliSeconds;
+
+ /**
+ * Creates new group wrapper.
+ *
+ * @param piActionGroup the Pi action group
+ * @param group the group
+ * @param installMilliSeconds the installation time
+ */
+ public P4RuntimeGroupWrapper(PiActionGroup piActionGroup, Group group,
+ long installMilliSeconds) {
+ this.piActionGroup = piActionGroup;
+ this.group = group;
+ this.installMilliSeconds = installMilliSeconds;
+ }
+
+ /**
+ * Gets PI action group from this wrapper.
+ *
+ * @return the PI action group
+ */
+ public PiActionGroup piActionGroup() {
+ return piActionGroup;
+ }
+
+ /**
+ * Gets group from this wrapper.
+ *
+ * @return the group
+ */
+ public Group group() {
+ return group;
+ }
+
+ /**
+ * Gets installation time of this wrapper.
+ *
+ * @return the installation time
+ */
+ public long installMilliSeconds() {
+ return installMilliSeconds;
+ }
+}
diff --git a/protocols/p4runtime/ctl/BUCK b/protocols/p4runtime/ctl/BUCK
index 899a1ff..cb22402 100644
--- a/protocols/p4runtime/ctl/BUCK
+++ b/protocols/p4runtime/ctl/BUCK
@@ -13,8 +13,9 @@
TEST_DEPS = [
'//lib:TEST',
+ '//lib:GRPC_TEST_1.3',
'//lib:minimal-json',
- '//incubator/bmv2/model:onos-incubator-bmv2-model',
+ '//lib:grpc-protobuf-lite-' + GRPC_VER,
]
osgi_jar_with_tests(
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileGroupEncoder.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileGroupEncoder.java
new file mode 100644
index 0000000..472bf8e
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileGroupEncoder.java
@@ -0,0 +1,144 @@
+/*
+ * 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.p4runtime.ctl;
+
+import com.google.common.collect.Maps;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiActionProfileId;
+import org.onosproject.net.pi.runtime.PiActionGroup;
+import org.onosproject.net.pi.runtime.PiActionGroupId;
+import p4.P4RuntimeOuterClass.ActionProfileGroup;
+import p4.P4RuntimeOuterClass.ActionProfileGroup.Member;
+import p4.P4RuntimeOuterClass.ActionProfileMember;
+import p4.config.P4InfoOuterClass;
+
+import java.util.Collection;
+import java.util.Map;
+
+import static java.lang.String.format;
+
+/**
+ * Encoder/Decoder for action profile group.
+ */
+public final class ActionProfileGroupEncoder {
+ private ActionProfileGroupEncoder() {
+ // hide default constructor
+ }
+
+ /**
+ * Encode a PI action group to a action profile group.
+ *
+ * @param piActionGroup the action profile group
+ * @param pipeconf the pipeconf
+ * @return a action profile group encoded from PI action group
+ * @throws P4InfoBrowser.NotFoundException if can't find action profile from P4Info browser
+ * @throws EncodeException if can't find P4Info from pipeconf
+ */
+ static ActionProfileGroup encode(PiActionGroup piActionGroup, PiPipeconf pipeconf)
+ throws P4InfoBrowser.NotFoundException, EncodeException {
+ P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+
+ if (browser == null) {
+ throw new EncodeException(format("Can't get P4 info browser from pipeconf %s", pipeconf));
+ }
+
+ PiActionProfileId piActionProfileId = piActionGroup.actionProfileId();
+ int actionProfileId;
+ P4InfoOuterClass.ActionProfile actionProfile =
+ browser.actionProfiles().getByName(piActionProfileId.id());
+ actionProfileId = actionProfile.getPreamble().getId();
+ ActionProfileGroup.Builder actionProfileGroupBuilder =
+ ActionProfileGroup.newBuilder()
+ .setGroupId(piActionGroup.id().id())
+ .setActionProfileId(actionProfileId);
+
+ switch (piActionGroup.type()) {
+ case SELECT:
+ actionProfileGroupBuilder.setType(ActionProfileGroup.Type.SELECT);
+ break;
+ default:
+ throw new EncodeException(format("Unsupported pi action group type %s",
+ piActionGroup.type()));
+ }
+
+ piActionGroup.members().forEach(m -> {
+ // TODO: currently we don't set "watch" field of member
+ Member member = Member.newBuilder()
+ .setMemberId(m.id().id())
+ .setWeight(m.weight())
+ .build();
+ actionProfileGroupBuilder.addMembers(member);
+ });
+
+ return actionProfileGroupBuilder.build();
+ }
+
+ /**
+ * Decode an action profile group with members information to a PI action group.
+ *
+ * @param actionProfileGroup the action profile group
+ * @param members members of the action profile group
+ * @param pipeconf the pipeconf
+ * @return decoded PI action group
+ * @throws P4InfoBrowser.NotFoundException if can't find action profile from P4Info browser
+ * @throws EncodeException if can't find P4Info from pipeconf
+ */
+ static PiActionGroup decode(ActionProfileGroup actionProfileGroup,
+ Collection<ActionProfileMember> members,
+ PiPipeconf pipeconf)
+ throws P4InfoBrowser.NotFoundException, EncodeException {
+ P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+ if (browser == null) {
+ throw new EncodeException(format("Can't get P4 info browser from pipeconf %s", pipeconf));
+ }
+ PiActionGroup.Builder piActionGroupBuilder = PiActionGroup.builder();
+
+ P4InfoOuterClass.ActionProfile actionProfile = browser.actionProfiles()
+ .getById(actionProfileGroup.getActionProfileId());
+ PiActionProfileId piActionProfileId = PiActionProfileId.of(actionProfile.getPreamble().getName());
+ piActionGroupBuilder.withActionProfileId(piActionProfileId)
+ .withId(PiActionGroupId.of(actionProfileGroup.getGroupId()));
+
+ switch (actionProfileGroup.getType()) {
+ case SELECT:
+ piActionGroupBuilder.withType(PiActionGroup.Type.SELECT);
+ break;
+ default:
+ throw new EncodeException(format("Unsupported action profile type %s",
+ actionProfileGroup.getType()));
+ }
+
+ Map<Integer, Integer> memberWeights = Maps.newHashMap();
+ actionProfileGroup.getMembersList().forEach(member -> {
+ int weight = member.getWeight();
+ if (weight < 1) {
+ // FIXME: currently PI has a bug which will always return weight 0
+ // ONOS won't accept group member with weight 0
+ weight = 1;
+ }
+ memberWeights.put(member.getMemberId(), weight);
+ });
+
+ for (ActionProfileMember member : members) {
+ int weight = memberWeights.get(member.getMemberId());
+ piActionGroupBuilder
+ .addMember(ActionProfileMemberEncoder.decode(member, weight, pipeconf));
+ }
+
+ return piActionGroupBuilder.build();
+ }
+}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileMemberEncoder.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileMemberEncoder.java
new file mode 100644
index 0000000..2f08a59
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/ActionProfileMemberEncoder.java
@@ -0,0 +1,112 @@
+/*
+ * 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.p4runtime.ctl;
+
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiActionGroup;
+import org.onosproject.net.pi.runtime.PiActionGroupMember;
+import org.onosproject.net.pi.runtime.PiActionGroupMemberId;
+import p4.P4RuntimeOuterClass;
+import p4.P4RuntimeOuterClass.ActionProfileMember;
+import p4.config.P4InfoOuterClass;
+
+import static java.lang.String.format;
+import static org.onosproject.p4runtime.ctl.TableEntryEncoder.decodeActionMsg;
+import static org.onosproject.p4runtime.ctl.TableEntryEncoder.encodePiAction;
+
+/**
+ * Encoder/Decoder of action profile member.
+ */
+public final class ActionProfileMemberEncoder {
+ private ActionProfileMemberEncoder() {
+ // Hide default constructor
+ }
+
+ /**
+ * Encode a PiActionGroupMember to a ActionProfileMember.
+ *
+ * @param group the PI action group of members
+ * @param member the member to encode
+ * @param pipeconf the pipeconf
+ * @return encoded member
+ */
+ /**
+ * Encode a PiActionGroupMember to a ActionProfileMember.
+ *
+ * @param group the PI action group of members
+ * @param member the member to encode
+ * @param pipeconf the pipeconf, as encode spec
+ * @return encoded member
+ * @throws P4InfoBrowser.NotFoundException can't find action profile from P4Info browser
+ * @throws EncodeException can't find P4Info from pipeconf
+ */
+ static ActionProfileMember encode(PiActionGroup group,
+ PiActionGroupMember member,
+ PiPipeconf pipeconf)
+ throws P4InfoBrowser.NotFoundException, EncodeException {
+
+ P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+
+ if (browser == null) {
+ throw new EncodeException(format("Can't get P4 info browser from pipeconf %s", pipeconf));
+ }
+
+ ActionProfileMember.Builder actionProfileMemberBuilder =
+ ActionProfileMember.newBuilder();
+
+ // member id
+ actionProfileMemberBuilder.setMemberId(member.id().id());
+
+ // action profile id
+ P4InfoOuterClass.ActionProfile actionProfile =
+ browser.actionProfiles().getByName(group.actionProfileId().id());
+
+ int actionProfileId = actionProfile.getPreamble().getId();
+ actionProfileMemberBuilder.setActionProfileId(actionProfileId);
+
+ // Action
+ P4RuntimeOuterClass.Action action = encodePiAction(member.action(), browser);
+ actionProfileMemberBuilder.setAction(action);
+
+ return actionProfileMemberBuilder.build();
+ }
+
+ /**
+ * Decode an action profile member to PI action group member.
+ *
+ * @param member the action profile member
+ * @param weight the weight of the member
+ * @param pipeconf the pipeconf, as decode spec
+ * @return decoded PI action group member
+ * @throws P4InfoBrowser.NotFoundException can't find definition of action from P4 info
+ * @throws EncodeException can't get P4 info browser from pipeconf
+ */
+ static PiActionGroupMember decode(ActionProfileMember member,
+ int weight,
+ PiPipeconf pipeconf)
+ throws P4InfoBrowser.NotFoundException, EncodeException {
+ P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+
+ if (browser == null) {
+ throw new EncodeException(format("Can't get P4 info browser from pipeconf %s", pipeconf));
+ }
+ return PiActionGroupMember.builder().withId(PiActionGroupMemberId.of(member.getMemberId()))
+ .withWeight(weight)
+ .withAction(decodeActionMsg(member.getAction(), browser))
+ .build();
+ }
+}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
index a9adf55..7f22e79 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
@@ -17,7 +17,10 @@
package org.onosproject.p4runtime.ctl;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.protobuf.ByteString;
import io.grpc.Context;
@@ -26,13 +29,17 @@
import io.grpc.StatusRuntimeException;
import io.grpc.stub.StreamObserver;
import org.onlab.osgi.DefaultServiceDirectory;
+import org.onlab.util.Tools;
import org.onosproject.net.DeviceId;
import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.runtime.PiActionProfileId;
import org.onosproject.net.pi.runtime.PiCounterCellData;
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.PiIndirectCounterCellId;
+import org.onosproject.net.pi.runtime.PiActionGroup;
+import org.onosproject.net.pi.runtime.PiActionGroupMember;
import org.onosproject.net.pi.runtime.PiPacketOperation;
import org.onosproject.net.pi.runtime.PiPipeconfService;
import org.onosproject.net.pi.runtime.PiTableEntry;
@@ -41,6 +48,8 @@
import org.onosproject.p4runtime.api.P4RuntimeEvent;
import org.slf4j.Logger;
import p4.P4RuntimeGrpc;
+import p4.P4RuntimeOuterClass.ActionProfileGroup;
+import p4.P4RuntimeOuterClass.ActionProfileMember;
import p4.P4RuntimeOuterClass.Entity;
import p4.P4RuntimeOuterClass.ForwardingPipelineConfig;
import p4.P4RuntimeOuterClass.MasterArbitrationUpdate;
@@ -53,6 +62,7 @@
import p4.P4RuntimeOuterClass.TableEntry;
import p4.P4RuntimeOuterClass.Update;
import p4.P4RuntimeOuterClass.WriteRequest;
+import p4.config.P4InfoOuterClass;
import p4.config.P4InfoOuterClass.P4Info;
import p4.tmp.P4Config;
@@ -69,6 +79,8 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
@@ -78,6 +90,8 @@
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType;
import static org.slf4j.LoggerFactory.getLogger;
+import static p4.P4RuntimeOuterClass.Entity.EntityCase.ACTION_PROFILE_GROUP;
+import static p4.P4RuntimeOuterClass.Entity.EntityCase.ACTION_PROFILE_MEMBER;
import static p4.P4RuntimeOuterClass.Entity.EntityCase.TABLE_ENTRY;
import static p4.P4RuntimeOuterClass.PacketOut;
import static p4.P4RuntimeOuterClass.SetForwardingPipelineConfigRequest.Action.VERIFY_AND_COMMIT;
@@ -106,7 +120,14 @@
private final Lock writeLock = new ReentrantLock();
private final StreamObserver<StreamMessageRequest> streamRequestObserver;
-
+ /**
+ * Default constructor.
+ *
+ * @param deviceId the ONOS device id
+ * @param p4DeviceId the P4 device id
+ * @param channel gRPC channel
+ * @param controller runtime client controller
+ */
P4RuntimeClientImpl(DeviceId deviceId, long p4DeviceId, ManagedChannel channel,
P4RuntimeControllerImpl controller) {
this.deviceId = deviceId;
@@ -216,6 +237,30 @@
"readAllCounterCells-" + cellIds.hashCode());
}
+ @Override
+ public CompletableFuture<Boolean> writeActionGroupMembers(PiActionGroup group,
+ Collection<PiActionGroupMember> members,
+ WriteOperationType opType,
+ PiPipeconf pipeconf) {
+ return supplyInContext(() -> doWriteActionGroupMembers(group, members, opType, pipeconf),
+ "writeActionGroupMembers-" + opType.name());
+ }
+
+ @Override
+ public CompletableFuture<Boolean> writeActionGroup(PiActionGroup group,
+ WriteOperationType opType,
+ PiPipeconf pipeconf) {
+ return supplyInContext(() -> doWriteActionGroup(group, opType, pipeconf),
+ "writeActionGroup-" + opType.name());
+ }
+
+ @Override
+ public CompletableFuture<Collection<PiActionGroup>> dumpGroups(PiActionProfileId actionProfileId,
+ PiPipeconf pipeconf) {
+ return supplyInContext(() -> doDumpGroups(actionProfileId, pipeconf),
+ "dumpGroups-" + actionProfileId.id());
+ }
+
/* Blocking method implementations below */
private boolean doInitStreamChannel() {
@@ -464,6 +509,191 @@
return CounterEntryCodec.decodeCounterEntities(entities, counterIdMap, pipeconf);
}
+ private boolean doWriteActionGroupMembers(PiActionGroup group, Collection<PiActionGroupMember> members,
+ WriteOperationType opType, PiPipeconf pipeconf) {
+ WriteRequest.Builder writeRequestBuilder = WriteRequest.newBuilder();
+
+ Collection<ActionProfileMember> actionProfileMembers = Lists.newArrayList();
+ try {
+ for (PiActionGroupMember member : members) {
+ actionProfileMembers.add(
+ ActionProfileMemberEncoder.encode(group, member, pipeconf)
+ );
+ }
+ } catch (EncodeException | P4InfoBrowser.NotFoundException e) {
+ log.warn("Can't encode group member {} due to {}", members, e.getMessage());
+ return false;
+ }
+
+ Collection<Update> updateMsgs = actionProfileMembers.stream()
+ .map(actionProfileMember ->
+ Update.newBuilder()
+ .setEntity(Entity.newBuilder()
+ .setActionProfileMember(actionProfileMember)
+ .build())
+ .setType(UPDATE_TYPES.get(opType))
+ .build())
+ .collect(Collectors.toList());
+
+ if (updateMsgs.size() == 0) {
+ // Nothing to update
+ return true;
+ }
+
+ writeRequestBuilder
+ .setDeviceId(p4DeviceId)
+ .addAllUpdates(updateMsgs);
+ try {
+ blockingStub.write(writeRequestBuilder.build());
+ return true;
+ } catch (StatusRuntimeException e) {
+ log.warn("Unable to write table entries ({}): {}", opType, e.getMessage());
+ return false;
+ }
+ }
+
+ private Collection<PiActionGroup> doDumpGroups(PiActionProfileId piActionProfileId, PiPipeconf pipeconf) {
+ log.debug("Dumping groups from action profile {} from {} (pipeconf {})...",
+ piActionProfileId.id(), deviceId, pipeconf.id());
+ P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(pipeconf);
+ if (browser == null) {
+ log.warn("Unable to get a P4Info browser for pipeconf {}, skipping dump action profile {}",
+ pipeconf, piActionProfileId);
+ return Collections.emptySet();
+ }
+
+ int actionProfileId;
+ try {
+ P4InfoOuterClass.ActionProfile actionProfile =
+ browser.actionProfiles().getByName(piActionProfileId.id());
+ actionProfileId = actionProfile.getPreamble().getId();
+ } catch (P4InfoBrowser.NotFoundException e) {
+ log.warn("Can't find action profile {} from p4info", piActionProfileId);
+ return Collections.emptySet();
+ }
+
+ ActionProfileGroup actionProfileGroup =
+ ActionProfileGroup.newBuilder()
+ .setActionProfileId(actionProfileId)
+ .build();
+
+ ReadRequest requestMsg = ReadRequest.newBuilder()
+ .setDeviceId(p4DeviceId)
+ .addEntities(Entity.newBuilder()
+ .setActionProfileGroup(actionProfileGroup)
+ .build())
+ .build();
+
+ Iterator<ReadResponse> responses;
+ try {
+ responses = blockingStub.read(requestMsg);
+ } catch (StatusRuntimeException e) {
+ log.warn("Unable to read action profile {} due to {}", piActionProfileId, e.getMessage());
+ return Collections.emptySet();
+ }
+
+ List<ActionProfileGroup> actionProfileGroups =
+ Tools.stream(() -> responses)
+ .map(ReadResponse::getEntitiesList)
+ .flatMap(List::stream)
+ .filter(entity -> entity.getEntityCase() == ACTION_PROFILE_GROUP)
+ .map(Entity::getActionProfileGroup)
+ .collect(Collectors.toList());
+
+ log.debug("Retrieved {} groups from action profile {} on {}...",
+ actionProfileGroups.size(), piActionProfileId.id(), deviceId);
+
+ // group id -> members
+ Multimap<Integer, ActionProfileMember> actionProfileMemberMap = HashMultimap.create();
+ AtomicLong memberCount = new AtomicLong(0);
+ AtomicBoolean success = new AtomicBoolean(true);
+ actionProfileGroups.forEach(actProfGrp -> {
+ actProfGrp.getMembersList().forEach(member -> {
+ ActionProfileMember actProfMember =
+ ActionProfileMember.newBuilder()
+ .setActionProfileId(actProfGrp.getActionProfileId())
+ .setMemberId(member.getMemberId())
+ .build();
+ Entity entity = Entity.newBuilder()
+ .setActionProfileMember(actProfMember)
+ .build();
+
+ ReadRequest reqMsg = ReadRequest.newBuilder().setDeviceId(p4DeviceId)
+ .addEntities(entity)
+ .build();
+
+ Iterator<ReadResponse> resps;
+ try {
+ resps = blockingStub.read(reqMsg);
+ } catch (StatusRuntimeException e) {
+ log.warn("Unable to read member {} from action profile {} due to {}",
+ member, piActionProfileId, e.getMessage());
+ success.set(false);
+ return;
+ }
+ Tools.stream(() -> resps)
+ .map(ReadResponse::getEntitiesList)
+ .flatMap(List::stream)
+ .filter(e -> e.getEntityCase() == ACTION_PROFILE_MEMBER)
+ .map(Entity::getActionProfileMember)
+ .forEach(m -> {
+ actionProfileMemberMap.put(actProfGrp.getGroupId(), m);
+ memberCount.incrementAndGet();
+ });
+ });
+ });
+
+ if (!success.get()) {
+ // Can't read members
+ return Collections.emptySet();
+ }
+ log.info("Retrieved {} group members from action profile {} on {}...",
+ memberCount.get(), piActionProfileId.id(), deviceId);
+
+ Collection<PiActionGroup> piActionGroups = Sets.newHashSet();
+
+ for (ActionProfileGroup apg : actionProfileGroups) {
+ try {
+ Collection<ActionProfileMember> members = actionProfileMemberMap.get(apg.getGroupId());
+ PiActionGroup decodedGroup =
+ ActionProfileGroupEncoder.decode(apg, members, pipeconf);
+ piActionGroups.add(decodedGroup);
+ } catch (EncodeException | P4InfoBrowser.NotFoundException e) {
+ log.warn("Can't decode group {} due to {}", apg, e.getMessage());
+ return Collections.emptySet();
+ }
+ }
+
+ return piActionGroups;
+ }
+
+ private boolean doWriteActionGroup(PiActionGroup group, WriteOperationType opType, PiPipeconf pipeconf) {
+ WriteRequest.Builder writeRequestBuilder = WriteRequest.newBuilder();
+ ActionProfileGroup actionProfileGroup;
+ try {
+ actionProfileGroup = ActionProfileGroupEncoder.encode(group, pipeconf);
+ } catch (EncodeException | P4InfoBrowser.NotFoundException e) {
+ log.warn("Can't encode group {} due to {}", e.getMessage());
+ return false;
+ }
+ Update updateMessage = Update.newBuilder()
+ .setEntity(Entity.newBuilder()
+ .setActionProfileGroup(actionProfileGroup)
+ .build())
+ .setType(UPDATE_TYPES.get(opType))
+ .build();
+ writeRequestBuilder
+ .setDeviceId(p4DeviceId)
+ .addUpdates(updateMessage);
+ try {
+ blockingStub.write(writeRequestBuilder.build());
+ return true;
+ } catch (StatusRuntimeException e) {
+ log.warn("Unable to write table entries ({}): {}", opType, e.getMessage());
+ return false;
+ }
+ }
+
/**
* Returns the internal P4 device ID associated with this client.
*
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java
index e26341b..383b857 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeControllerImpl.java
@@ -186,7 +186,7 @@
}
}
- void postEvent(P4RuntimeEvent event) {
+ public void postEvent(P4RuntimeEvent event) {
post(event);
}
}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeUtils.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeUtils.java
new file mode 100644
index 0000000..411e1fb
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeUtils.java
@@ -0,0 +1,51 @@
+/*
+ * 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.p4runtime.ctl;
+
+import com.google.protobuf.ByteString;
+
+import static java.lang.String.format;
+
+/**
+ * Utilities for P4 runtime control.
+ */
+public final class P4RuntimeUtils {
+
+ private P4RuntimeUtils() {
+ // Hide default construction
+ }
+
+ static void assertSize(String entityDescr, ByteString value, int bitWidth)
+ throws EncodeException {
+
+ int byteWidth = (int) Math.ceil((float) bitWidth / 8);
+ if (value.size() != byteWidth) {
+ throw new EncodeException(format("Wrong size for %s, expected %d bytes, but found %d",
+ entityDescr, byteWidth, value.size()));
+ }
+ }
+
+ static void assertPrefixLen(String entityDescr, int prefixLength, int bitWidth)
+ throws EncodeException {
+
+ if (prefixLength > bitWidth) {
+ throw new EncodeException(format(
+ "wrong prefix length for %s, field size is %d bits, but found one is %d",
+ entityDescr, bitWidth, prefixLength));
+ }
+ }
+}
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java
index 9ffc18f..8278b3e 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/TableEntryEncoder.java
@@ -17,10 +17,13 @@
package org.onosproject.p4runtime.ctl;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
import com.google.protobuf.ByteString;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.runtime.PiAction;
+import org.onosproject.net.pi.runtime.PiActionGroupId;
+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;
@@ -36,25 +39,26 @@
import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
import org.onosproject.net.pi.runtime.PiValidFieldMatch;
import org.slf4j.Logger;
-import p4.P4RuntimeOuterClass.Action;
import p4.P4RuntimeOuterClass.FieldMatch;
import p4.P4RuntimeOuterClass.TableAction;
import p4.P4RuntimeOuterClass.TableEntry;
+import p4.P4RuntimeOuterClass.Action;
import p4.config.P4InfoOuterClass;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import static java.lang.String.format;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
+import static org.onosproject.p4runtime.ctl.P4RuntimeUtils.assertPrefixLen;
+import static org.onosproject.p4runtime.ctl.P4RuntimeUtils.assertSize;
import static org.slf4j.LoggerFactory.getLogger;
/**
- * Encoder of table entries, from ONOS Pi* format, to P4Runtime protobuf messages, and vice versa.
+ * Encoder/Decoder of table entries, from ONOS Pi* format, to P4Runtime protobuf messages, and vice versa.
*/
final class TableEntryEncoder {
-
-
private static final Logger log = getLogger(TableEntryEncoder.class);
private static final String HEADER_PREFIX = "hdr.";
@@ -422,7 +426,7 @@
}
}
- private static TableAction encodePiTableAction(PiTableAction piTableAction, P4InfoBrowser browser)
+ static TableAction encodePiTableAction(PiTableAction piTableAction, P4InfoBrowser browser)
throws P4InfoBrowser.NotFoundException, EncodeException {
TableAction.Builder tableActionMsgBuilder = TableAction.newBuilder();
@@ -430,24 +434,17 @@
switch (piTableAction.type()) {
case ACTION:
PiAction piAction = (PiAction) piTableAction;
- int actionId = browser.actions().getByName(piAction.id().name()).getPreamble().getId();
-
- Action.Builder actionMsgBuilder = Action.newBuilder().setActionId(actionId);
-
- for (PiActionParam p : piAction.parameters()) {
- P4InfoOuterClass.Action.Param paramInfo = browser.actionParams(actionId).getByName(p.id().name());
- ByteString paramValue = ByteString.copyFrom(p.value().asReadOnlyBuffer());
- assertSize(format("param '%s' of action '%s'", p.id(), piAction.id()),
- paramValue, paramInfo.getBitwidth());
- actionMsgBuilder.addParams(Action.Param.newBuilder()
- .setParamId(paramInfo.getId())
- .setValue(paramValue)
- .build());
- }
-
- tableActionMsgBuilder.setAction(actionMsgBuilder.build());
+ Action theAction = encodePiAction(piAction, browser);
+ tableActionMsgBuilder.setAction(theAction);
break;
-
+ case ACTION_GROUP_ID:
+ PiActionGroupId actionGroupId = (PiActionGroupId) piTableAction;
+ tableActionMsgBuilder.setActionProfileGroupId(actionGroupId.id());
+ break;
+ case GROUP_MEMBER_ID:
+ PiActionGroupMemberId actionGroupMemberId = (PiActionGroupMemberId) piTableAction;
+ tableActionMsgBuilder.setActionProfileMemberId(actionGroupMemberId.id());
+ break;
default:
throw new EncodeException(
format("Building of table action type %s not implemented", piTableAction.type()));
@@ -456,50 +453,56 @@
return tableActionMsgBuilder.build();
}
- private static PiTableAction decodeTableActionMsg(TableAction tableActionMsg, P4InfoBrowser browser)
+ static PiTableAction decodeTableActionMsg(TableAction tableActionMsg, P4InfoBrowser browser)
throws P4InfoBrowser.NotFoundException, EncodeException {
-
TableAction.TypeCase typeCase = tableActionMsg.getTypeCase();
-
switch (typeCase) {
case ACTION:
- PiAction.Builder piActionBuilder = PiAction.builder();
Action actionMsg = tableActionMsg.getAction();
- // Action ID.
- int actionId = actionMsg.getActionId();
- String actionName = browser.actions().getById(actionId).getPreamble().getName();
- piActionBuilder.withId(PiActionId.of(actionName));
- // Params.
- for (Action.Param paramMsg : actionMsg.getParamsList()) {
- String paramName = browser.actionParams(actionId).getById(paramMsg.getParamId()).getName();
- ImmutableByteSequence paramValue = copyFrom(paramMsg.getValue().asReadOnlyByteBuffer());
- piActionBuilder.withParameter(new PiActionParam(PiActionParamId.of(paramName), paramValue));
- }
- return piActionBuilder.build();
-
+ return decodeActionMsg(actionMsg, browser);
default:
throw new EncodeException(
format("Decoding of table action type %s not implemented", typeCase.name()));
}
}
- private static void assertSize(String entityDescr, ByteString value, int bitWidth)
- throws EncodeException {
+ static Action encodePiAction(PiAction piAction, P4InfoBrowser browser)
+ throws P4InfoBrowser.NotFoundException, EncodeException {
- int byteWidth = (int) Math.ceil((float) bitWidth / 8);
- if (value.size() != byteWidth) {
- throw new EncodeException(format("Wrong size for %s, expected %d bytes, but found %d",
- entityDescr, byteWidth, value.size()));
+ int actionId = browser.actions().getByName(piAction.id().name()).getPreamble().getId();
+
+ Action.Builder actionMsgBuilder =
+ Action.newBuilder().setActionId(actionId);
+
+ for (PiActionParam p : piAction.parameters()) {
+ P4InfoOuterClass.Action.Param paramInfo = browser.actionParams(actionId).getByName(p.id().name());
+ ByteString paramValue = ByteString.copyFrom(p.value().asReadOnlyBuffer());
+ assertSize(format("param '%s' of action '%s'", p.id(), piAction.id()),
+ paramValue, paramInfo.getBitwidth());
+ actionMsgBuilder.addParams(Action.Param.newBuilder()
+ .setParamId(paramInfo.getId())
+ .setValue(paramValue)
+ .build());
}
+
+ return actionMsgBuilder.build();
}
- private static void assertPrefixLen(String entityDescr, int prefixLength, int bitWidth)
- throws EncodeException {
+ static PiAction decodeActionMsg(Action action, P4InfoBrowser browser)
+ throws P4InfoBrowser.NotFoundException {
+ P4InfoBrowser.EntityBrowser<P4InfoOuterClass.Action.Param> paramInfo =
+ browser.actionParams(action.getActionId());
+ String actionName = browser.actions()
+ .getById(action.getActionId())
+ .getPreamble().getName();
+ PiActionId id = PiActionId.of(actionName);
+ List<PiActionParam> params = Lists.newArrayList();
- if (prefixLength > bitWidth) {
- throw new EncodeException(format(
- "wrong prefix length for %s, field size is %d bits, but found one is %d",
- entityDescr, bitWidth, prefixLength));
+ for (Action.Param p : action.getParamsList()) {
+ String paramName = paramInfo.getById(p.getParamId()).getName();
+ ImmutableByteSequence value = ImmutableByteSequence.copyFrom(p.getValue().toByteArray());
+ params.add(new PiActionParam(PiActionParamId.of(paramName), value));
}
+ return PiAction.builder().withId(id).withParameters(params).build();
}
}
diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/MockP4RuntimeServer.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/MockP4RuntimeServer.java
new file mode 100644
index 0000000..4773458
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/MockP4RuntimeServer.java
@@ -0,0 +1,114 @@
+/*
+ * 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.p4runtime.ctl;
+
+import com.google.common.collect.Lists;
+import io.grpc.stub.StreamObserver;
+import p4.P4RuntimeGrpc;
+import p4.P4RuntimeOuterClass;
+import p4.P4RuntimeOuterClass.GetForwardingPipelineConfigRequest;
+import p4.P4RuntimeOuterClass.GetForwardingPipelineConfigResponse;
+import p4.P4RuntimeOuterClass.ReadRequest;
+import p4.P4RuntimeOuterClass.ReadResponse;
+import p4.P4RuntimeOuterClass.SetForwardingPipelineConfigRequest;
+import p4.P4RuntimeOuterClass.SetForwardingPipelineConfigResponse;
+import p4.P4RuntimeOuterClass.StreamMessageResponse;
+import p4.P4RuntimeOuterClass.WriteRequest;
+import p4.P4RuntimeOuterClass.WriteResponse;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class MockP4RuntimeServer extends P4RuntimeGrpc.P4RuntimeImplBase {
+ private CompletableFuture<Void> completeLock;
+ private AtomicLong counter;
+
+ // Requests
+ private List<WriteRequest> writeReqs;
+ private List<ReadRequest> readReqs;
+ private List<ReadResponse> readResps;
+
+ /**
+ * Expect N times request sent by client.
+ *
+ * @param times the number of request will sent by client.
+ * @return a completable future object, wll complete after client send N times requests.
+ */
+ public CompletableFuture<Void> expectRequests(long times) {
+ counter = new AtomicLong(times);
+ completeLock = new CompletableFuture<>();
+ readReqs = Lists.newArrayList();
+ writeReqs = Lists.newArrayList();
+ return completeLock;
+ }
+
+ private void complete() {
+ if (counter.decrementAndGet() == 0) {
+ completeLock.complete(null);
+ }
+ }
+
+ public void willReturnReadResult(Collection<ReadResponse> readResps) {
+ this.readResps = Lists.newArrayList(readResps);
+ }
+
+ public List<WriteRequest> getWriteReqs() {
+ return writeReqs;
+ }
+
+ public List<ReadRequest> getReadReqs() {
+ return readReqs;
+ }
+
+ @Override
+ public void write(WriteRequest request, StreamObserver<WriteResponse> responseObserver) {
+ writeReqs.add(request);
+ complete();
+ }
+
+ @Override
+ public void read(ReadRequest request, StreamObserver<ReadResponse> responseObserver) {
+ readReqs.add(request);
+ if (readResps != null && !readResps.isEmpty()) {
+ ReadResponse readResp = readResps.remove(0); // get first response
+ responseObserver.onNext(readResp);
+ responseObserver.onCompleted();
+ }
+ complete();
+ }
+
+ @Override
+ public void setForwardingPipelineConfig(SetForwardingPipelineConfigRequest request,
+ StreamObserver<SetForwardingPipelineConfigResponse> responseObserver) {
+ throw new UnsupportedOperationException("Not implement yet");
+ }
+
+ @Override
+ public void getForwardingPipelineConfig(GetForwardingPipelineConfigRequest request,
+ StreamObserver<GetForwardingPipelineConfigResponse> responseObserver) {
+ throw new UnsupportedOperationException("Not implement yet");
+ }
+
+ @Override
+ public StreamObserver<P4RuntimeOuterClass.StreamMessageRequest>
+ streamChannel(StreamObserver<StreamMessageResponse> responseObserver) {
+ // TODO: not implement yet
+ return null;
+ }
+}
diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/P4RuntimeGroupTest.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/P4RuntimeGroupTest.java
new file mode 100644
index 0000000..8932a16
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/P4RuntimeGroupTest.java
@@ -0,0 +1,279 @@
+/*
+ * 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.p4runtime.ctl;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.protobuf.ByteString;
+import io.grpc.ManagedChannel;
+import io.grpc.Server;
+import io.grpc.inprocess.InProcessChannelBuilder;
+import io.grpc.inprocess.InProcessServerBuilder;
+import io.grpc.internal.AbstractServerImplBuilder;
+import org.easymock.EasyMock;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onlab.util.ImmutableByteSequence;
+import org.onosproject.net.DeviceId;
+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.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.PiActionGroupId;
+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 p4.P4RuntimeOuterClass.ActionProfileGroup;
+import p4.P4RuntimeOuterClass.ActionProfileMember;
+import p4.P4RuntimeOuterClass.Entity;
+import p4.P4RuntimeOuterClass.Update;
+import p4.P4RuntimeOuterClass.WriteRequest;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
+import static org.onosproject.net.pi.runtime.PiActionGroup.Type.SELECT;
+import static org.onosproject.p4runtime.api.P4RuntimeClient.WriteOperationType.INSERT;
+import static p4.P4RuntimeOuterClass.*;
+
+/**
+ * Tests for P4 Runtime Action Profile Group support.
+ */
+public class P4RuntimeGroupTest {
+ private static final String PIPECONF_ID = "p4runtime-mock-pipeconf";
+ private static final String P4INFO_PATH = "/default.p4info";
+ private static final PiPipeconf PIPECONF = buildPipeconf();
+ private static final int P4_INFO_ACT_PROF_ID = 285227860;
+ private static final PiActionProfileId ACT_PROF_ID = PiActionProfileId.of("ecmp_selector");
+ private static final PiActionGroupId GROUP_ID = PiActionGroupId.of(1);
+ private static final int DEFAULT_MEMBER_WEIGHT = 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 int BASE_MEM_ID = 65535;
+ private static final List<Integer> MEMBER_IDS = ImmutableList.of(65536, 65537, 65538);
+ private static final Collection<PiActionGroupMember> GROUP_MEMBERS =
+ ImmutableSet.of(
+ outputMember((short) 1),
+ outputMember((short) 2),
+ outputMember((short) 3)
+ );
+ private static final PiActionGroup GROUP = PiActionGroup.builder()
+ .withId(GROUP_ID)
+ .addMembers(GROUP_MEMBERS)
+ .withActionProfileId(ACT_PROF_ID)
+ .withType(SELECT)
+ .build();
+ private static final DeviceId DEVICE_ID = DeviceId.deviceId("device:p4runtime:1");
+ private static final int P4_DEVICE_ID = 1;
+ private static final int SET_EGRESS_PORT_ID = 16794308;
+ private static final String GRPC_SERVER_NAME = "P4RuntimeGroupTest";
+ private static final long DEFAULT_TIMEOUT_TIME = 5;
+
+ private P4RuntimeClientImpl client;
+ private P4RuntimeControllerImpl controller;
+ private static MockP4RuntimeServer p4RuntimeServerImpl = new MockP4RuntimeServer();
+ private static Server grpcServer;
+ private static ManagedChannel grpcChannel;
+
+ private static PiActionGroupMember outputMember(short 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();
+ }
+
+ private static PiPipeconf buildPipeconf() {
+ final URL p4InfoUrl = P4RuntimeGroupTest.class.getResource(P4INFO_PATH);
+ return DefaultPiPipeconf.builder()
+ .withId(new PiPipeconfId(PIPECONF_ID))
+ .withPipelineModel(EasyMock.niceMock(PiPipelineModel.class))
+ .addExtension(P4_INFO_TEXT, p4InfoUrl)
+ .build();
+ }
+
+ @BeforeClass
+ public static void globalSetup() throws IOException {
+ AbstractServerImplBuilder builder = InProcessServerBuilder
+ .forName(GRPC_SERVER_NAME).directExecutor();
+ builder.addService(p4RuntimeServerImpl);
+ grpcServer = builder.build().start();
+ grpcChannel = InProcessChannelBuilder.forName(GRPC_SERVER_NAME)
+ .directExecutor()
+ .usePlaintext(true)
+ .build();
+ }
+
+ @AfterClass
+ public static void globalTeerDown() {
+ grpcServer.shutdown();
+ grpcChannel.shutdown();
+ }
+
+
+ @Before
+ public void setup() {
+ controller = niceMock(P4RuntimeControllerImpl.class);
+ client = new P4RuntimeClientImpl(DEVICE_ID, P4_DEVICE_ID,
+ grpcChannel,
+ controller);
+ }
+
+ @Test
+ public void testInsertPiActionGroup() throws Exception {
+ CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
+ client.writeActionGroup(GROUP, INSERT, PIPECONF);
+ complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
+ WriteRequest result = p4RuntimeServerImpl.getWriteReqs().get(0);
+ assertEquals(1, result.getDeviceId());
+ assertEquals(1, result.getUpdatesCount());
+
+ Update update = result.getUpdatesList().get(0);
+ assertEquals(Update.Type.INSERT, update.getType());
+
+ Entity entity = update.getEntity();
+ ActionProfileGroup actionProfileGroup = entity.getActionProfileGroup();
+ assertNotNull(actionProfileGroup);
+
+ assertEquals(P4_INFO_ACT_PROF_ID, actionProfileGroup.getActionProfileId());
+ assertEquals(3, actionProfileGroup.getMembersCount());
+ List<ActionProfileGroup.Member> members = actionProfileGroup.getMembersList();
+
+ for (ActionProfileGroup.Member member : members) {
+ // XXX: We can't guarantee the order of member, just make sure we
+ // have these member ids
+ assertTrue(MEMBER_IDS.contains(member.getMemberId()));
+ assertEquals(DEFAULT_MEMBER_WEIGHT, member.getWeight());
+ }
+ }
+
+ @Test
+ public void testInsertPiActionMembers() throws Exception {
+ CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
+ client.writeActionGroupMembers(GROUP, GROUP_MEMBERS, INSERT, PIPECONF);
+ complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
+ WriteRequest result = p4RuntimeServerImpl.getWriteReqs().get(0);
+ assertEquals(1, result.getDeviceId());
+ assertEquals(3, result.getUpdatesCount());
+
+ List<Update> updates = result.getUpdatesList();
+ for (Update update : updates) {
+ assertEquals(Update.Type.INSERT, update.getType());
+ Entity entity = update.getEntity();
+ ActionProfileMember member = entity.getActionProfileMember();
+ assertNotNull(member);
+ assertEquals(P4_INFO_ACT_PROF_ID, member.getActionProfileId());
+ assertTrue(MEMBER_IDS.contains(member.getMemberId()));
+ Action action = member.getAction();
+ assertEquals(SET_EGRESS_PORT_ID, action.getActionId());
+ assertEquals(1, action.getParamsCount());
+ Action.Param param = action.getParamsList().get(0);
+ assertEquals(1, param.getParamId());
+ byte outPort = (byte) (member.getMemberId() - BASE_MEM_ID);
+ ByteString bs = ByteString.copyFrom(new byte[]{0, outPort});
+ assertEquals(bs, param.getValue());
+ }
+ }
+
+ @Test
+ public void testReadGroups() throws Exception {
+ ActionProfileGroup.Builder group = ActionProfileGroup.newBuilder()
+ .setGroupId(GROUP_ID.id())
+ .setType(ActionProfileGroup.Type.SELECT)
+ .setActionProfileId(P4_INFO_ACT_PROF_ID);
+
+ List<ActionProfileMember> members = Lists.newArrayList();
+
+ MEMBER_IDS.forEach(id -> {
+ ActionProfileGroup.Member member = ActionProfileGroup.Member.newBuilder()
+ .setMemberId(id)
+ .setWeight(DEFAULT_MEMBER_WEIGHT)
+ .build();
+ group.addMembers(member);
+
+ byte outPort = (byte) (id - BASE_MEM_ID);
+ ByteString bs = ByteString.copyFrom(new byte[]{0, outPort});
+ Action.Param param = Action.Param.newBuilder()
+ .setParamId(1)
+ .setValue(bs)
+ .build();
+
+ Action action = Action.newBuilder()
+ .setActionId(SET_EGRESS_PORT_ID)
+ .addParams(param)
+ .build();
+
+
+ ActionProfileMember actProfMember =
+ ActionProfileMember.newBuilder()
+ .setMemberId(id)
+ .setAction(action)
+ .build();
+ members.add(actProfMember);
+ });
+
+ List<ReadResponse> responses = Lists.newArrayList();
+ responses.add(ReadResponse.newBuilder()
+ .addEntities(Entity.newBuilder().setActionProfileGroup(group))
+ .build()
+ );
+
+ members.forEach(m -> {
+ responses.add(ReadResponse.newBuilder()
+ .addEntities(Entity.newBuilder().setActionProfileMember(m))
+ .build());
+ });
+
+ p4RuntimeServerImpl.willReturnReadResult(responses);
+ CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(4);
+ CompletableFuture<Collection<PiActionGroup>> groupsComplete = client.dumpGroups(ACT_PROF_ID, PIPECONF);
+ complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
+
+ Collection<PiActionGroup> groups = groupsComplete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
+ assertEquals(1, groups.size());
+ PiActionGroup piActionGroup = groups.iterator().next();
+ assertEquals(ACT_PROF_ID, piActionGroup.actionProfileId());
+ assertEquals(GROUP_ID, piActionGroup.id());
+ assertEquals(SELECT, piActionGroup.type());
+ assertEquals(3, piActionGroup.members().size());
+ assertTrue(GROUP_MEMBERS.containsAll(piActionGroup.members()));
+ assertTrue(piActionGroup.members().containsAll(GROUP_MEMBERS));
+ }
+}
diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java
index 792e838..b3e9a1e 100644
--- a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java
@@ -18,12 +18,13 @@
import com.google.common.collect.Lists;
import com.google.common.testing.EqualsTester;
+import org.easymock.EasyMock;
import org.junit.Test;
import org.onlab.util.ImmutableByteSequence;
-import org.onosproject.bmv2.model.Bmv2PipelineModelParser;
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.PiPipelineModel;
import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionId;
import org.onosproject.net.pi.runtime.PiActionParam;
@@ -33,7 +34,6 @@
import org.onosproject.net.pi.runtime.PiTableEntry;
import org.onosproject.net.pi.runtime.PiTableId;
import org.onosproject.net.pi.runtime.PiTernaryFieldMatch;
-import org.slf4j.Logger;
import p4.P4RuntimeOuterClass.Action;
import p4.P4RuntimeOuterClass.TableEntry;
@@ -47,19 +47,14 @@
import static org.onlab.util.ImmutableByteSequence.copyFrom;
import static org.onlab.util.ImmutableByteSequence.fit;
import static org.onlab.util.ImmutableByteSequence.ofOnes;
-import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
import static org.onosproject.p4runtime.ctl.TableEntryEncoder.decode;
import static org.onosproject.p4runtime.ctl.TableEntryEncoder.encode;
-import static org.slf4j.LoggerFactory.getLogger;
-//import org.onosproject.driver.pipeline.DefaultSingleTablePipeline;
-//import org.onosproject.drivers.bmv2.Bmv2DefaultInterpreter;
-
+/**
+ * Test for P4 runtime table entry encoder.
+ */
public class TableEntryEncoderTest {
-
- private final Logger log = getLogger(getClass());
-
private static final String TABLE_0 = "table0";
private static final String SET_EGRESS_PORT = "set_egress_port";
private static final String PORT = "port";
@@ -72,14 +67,11 @@
private final Random rand = new Random();
private final URL p4InfoUrl = this.getClass().getResource("/default.p4info");
- private final URL jsonUrl = this.getClass().getResource("/default.json");
private final PiPipeconf defaultPipeconf = DefaultPiPipeconf.builder()
.withId(new PiPipeconfId("mock"))
- .withPipelineModel(Bmv2PipelineModelParser.parse(jsonUrl))
-// .addBehaviour(PiPipelineInterpreter.class, Bmv2DefaultInterpreter.class)
+ .withPipelineModel(EasyMock.niceMock(PiPipelineModel.class))
.addExtension(P4_INFO_TEXT, p4InfoUrl)
- .addExtension(BMV2_JSON, jsonUrl)
.build();
private final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(defaultPipeconf);
diff --git a/protocols/p4runtime/ctl/src/test/resources/default.json b/protocols/p4runtime/ctl/src/test/resources/default.json
deleted file mode 100644
index 3a46dcc..0000000
--- a/protocols/p4runtime/ctl/src/test/resources/default.json
+++ /dev/null
@@ -1,2697 +0,0 @@
-{
- "program" : "default.p4",
- "__meta__" : {
- "version" : [2, 7],
- "compiler" : "https://github.com/p4lang/p4c"
- },
- "header_types" : [
- {
- "name" : "scalars_0",
- "id" : 0,
- "fields" : [
- ["tmp", 32, false],
- ["tmp_0", 32, false]
- ]
- },
- {
- "name" : "standard_metadata",
- "id" : 1,
- "fields" : [
- ["ingress_port", 9, false],
- ["egress_spec", 9, false],
- ["egress_port", 9, false],
- ["clone_spec", 32, false],
- ["instance_type", 32, false],
- ["drop", 1, false],
- ["recirculate_port", 16, false],
- ["packet_length", 32, false],
- ["enq_timestamp", 32, false],
- ["enq_qdepth", 19, false],
- ["deq_timedelta", 32, false],
- ["deq_qdepth", 19, false],
- ["ingress_global_timestamp", 48, false],
- ["lf_field_list", 32, false],
- ["mcast_grp", 16, false],
- ["resubmit_flag", 1, false],
- ["egress_rid", 16, false],
- ["_padding", 5, false]
- ]
- },
- {
- "name" : "ethernet_t",
- "id" : 2,
- "fields" : [
- ["dstAddr", 48, false],
- ["srcAddr", 48, false],
- ["etherType", 16, false]
- ]
- },
- {
- "name" : "ipv4_t",
- "id" : 3,
- "fields" : [
- ["version", 4, false],
- ["ihl", 4, false],
- ["diffserv", 8, false],
- ["totalLen", 16, false],
- ["identification", 16, false],
- ["flags", 3, false],
- ["fragOffset", 13, false],
- ["ttl", 8, false],
- ["protocol", 8, false],
- ["hdrChecksum", 16, false],
- ["srcAddr", 32, false],
- ["dstAddr", 32, false]
- ]
- },
- {
- "name" : "tcp_t",
- "id" : 4,
- "fields" : [
- ["srcPort", 16, false],
- ["dstPort", 16, false],
- ["seqNo", 32, false],
- ["ackNo", 32, false],
- ["dataOffset", 4, false],
- ["res", 3, false],
- ["ecn", 3, false],
- ["ctrl", 6, false],
- ["window", 16, false],
- ["checksum", 16, false],
- ["urgentPtr", 16, false]
- ]
- },
- {
- "name" : "udp_t",
- "id" : 5,
- "fields" : [
- ["srcPort", 16, false],
- ["dstPort", 16, false],
- ["length_", 16, false],
- ["checksum", 16, false]
- ]
- },
- {
- "name" : "ecmp_metadata_t",
- "id" : 6,
- "fields" : [
- ["groupId", 16, false],
- ["selector", 16, false]
- ]
- },
- {
- "name" : "wcmp_meta_t",
- "id" : 7,
- "fields" : [
- ["groupId", 16, false],
- ["numBits", 8, false],
- ["selector", 64, false]
- ]
- },
- {
- "name" : "intrinsic_metadata_t",
- "id" : 8,
- "fields" : [
- ["ingress_global_timestamp", 32, false],
- ["lf_field_list", 32, false],
- ["mcast_grp", 16, false],
- ["egress_rid", 16, false]
- ]
- }
- ],
- "headers" : [
- {
- "name" : "standard_metadata_3",
- "id" : 0,
- "header_type" : "standard_metadata",
- "metadata" : true,
- "pi_omit" : true
- },
- {
- "name" : "standard_metadata_4",
- "id" : 1,
- "header_type" : "standard_metadata",
- "metadata" : true,
- "pi_omit" : true
- },
- {
- "name" : "standard_metadata_5",
- "id" : 2,
- "header_type" : "standard_metadata",
- "metadata" : true,
- "pi_omit" : true
- },
- {
- "name" : "scalars",
- "id" : 3,
- "header_type" : "scalars_0",
- "metadata" : true,
- "pi_omit" : true
- },
- {
- "name" : "standard_metadata",
- "id" : 4,
- "header_type" : "standard_metadata",
- "metadata" : true,
- "pi_omit" : true
- },
- {
- "name" : "ethernet",
- "id" : 5,
- "header_type" : "ethernet_t",
- "metadata" : false,
- "pi_omit" : true
- },
- {
- "name" : "ipv4",
- "id" : 6,
- "header_type" : "ipv4_t",
- "metadata" : false,
- "pi_omit" : true
- },
- {
- "name" : "tcp",
- "id" : 7,
- "header_type" : "tcp_t",
- "metadata" : false,
- "pi_omit" : true
- },
- {
- "name" : "udp",
- "id" : 8,
- "header_type" : "udp_t",
- "metadata" : false,
- "pi_omit" : true
- },
- {
- "name" : "ecmp_metadata",
- "id" : 9,
- "header_type" : "ecmp_metadata_t",
- "metadata" : true,
- "pi_omit" : true
- },
- {
- "name" : "wcmp_meta",
- "id" : 10,
- "header_type" : "wcmp_meta_t",
- "metadata" : true,
- "pi_omit" : true
- },
- {
- "name" : "intrinsic_metadata",
- "id" : 11,
- "header_type" : "intrinsic_metadata_t",
- "metadata" : true,
- "pi_omit" : true
- }
- ],
- "header_stacks" : [],
- "header_union_types" : [],
- "header_unions" : [],
- "header_union_stacks" : [],
- "field_lists" : [],
- "errors" : [
- ["NoError", 1],
- ["PacketTooShort", 2],
- ["NoMatch", 3],
- ["StackOutOfBounds", 4],
- ["HeaderTooShort", 5],
- ["ParserTimeout", 6]
- ],
- "enums" : [],
- "parsers" : [
- {
- "name" : "parser",
- "id" : 0,
- "init_state" : "start",
- "parse_states" : [
- {
- "name" : "parse_ipv4",
- "id" : 0,
- "parser_ops" : [
- {
- "parameters" : [
- {
- "type" : "regular",
- "value" : "ipv4"
- }
- ],
- "op" : "extract"
- }
- ],
- "transitions" : [
- {
- "value" : "0x06",
- "mask" : null,
- "next_state" : "parse_tcp"
- },
- {
- "value" : "0x11",
- "mask" : null,
- "next_state" : "parse_udp"
- },
- {
- "value" : "default",
- "mask" : null,
- "next_state" : null
- }
- ],
- "transition_key" : [
- {
- "type" : "field",
- "value" : ["ipv4", "protocol"]
- }
- ]
- },
- {
- "name" : "parse_tcp",
- "id" : 1,
- "parser_ops" : [
- {
- "parameters" : [
- {
- "type" : "regular",
- "value" : "tcp"
- }
- ],
- "op" : "extract"
- }
- ],
- "transitions" : [
- {
- "value" : "default",
- "mask" : null,
- "next_state" : null
- }
- ],
- "transition_key" : []
- },
- {
- "name" : "parse_udp",
- "id" : 2,
- "parser_ops" : [
- {
- "parameters" : [
- {
- "type" : "regular",
- "value" : "udp"
- }
- ],
- "op" : "extract"
- }
- ],
- "transitions" : [
- {
- "value" : "default",
- "mask" : null,
- "next_state" : null
- }
- ],
- "transition_key" : []
- },
- {
- "name" : "start",
- "id" : 3,
- "parser_ops" : [
- {
- "parameters" : [
- {
- "type" : "regular",
- "value" : "ethernet"
- }
- ],
- "op" : "extract"
- }
- ],
- "transitions" : [
- {
- "value" : "0x0800",
- "mask" : null,
- "next_state" : "parse_ipv4"
- },
- {
- "value" : "default",
- "mask" : null,
- "next_state" : null
- }
- ],
- "transition_key" : [
- {
- "type" : "field",
- "value" : ["ethernet", "etherType"]
- }
- ]
- }
- ]
- }
- ],
- "deparsers" : [
- {
- "name" : "deparser",
- "id" : 0,
- "source_info" : {
- "filename" : "include/parsers.p4",
- "line" : 43,
- "column" : 8,
- "source_fragment" : "DeparserImpl"
- },
- "order" : ["ethernet", "ipv4", "udp", "tcp"]
- }
- ],
- "meter_arrays" : [],
- "counter_arrays" : [
- {
- "name" : "table0_counter",
- "id" : 0,
- "is_direct" : true,
- "binding" : "table0"
- },
- {
- "name" : "port_counters_control.egress_port_counter",
- "id" : 1,
- "source_info" : {
- "filename" : "include/port_counters.p4",
- "line" : 6,
- "column" : 38,
- "source_fragment" : "egress_port_counter"
- },
- "size" : 254,
- "is_direct" : false
- },
- {
- "name" : "port_counters_control.ingress_port_counter",
- "id" : 2,
- "source_info" : {
- "filename" : "include/port_counters.p4",
- "line" : 7,
- "column" : 38,
- "source_fragment" : "ingress_port_counter"
- },
- "size" : 254,
- "is_direct" : false
- }
- ],
- "register_arrays" : [],
- "calculations" : [],
- "learn_lists" : [],
- "actions" : [
- {
- "name" : "set_egress_port",
- "id" : 0,
- "runtime_data" : [
- {
- "name" : "port",
- "bitwidth" : 9
- }
- ],
- "primitives" : [
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "ingress_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "egress_spec"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_spec"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "egress_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "clone_spec"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "clone_spec"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "instance_type"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "instance_type"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "drop"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "drop"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "recirculate_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "recirculate_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "packet_length"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "packet_length"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "enq_timestamp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "enq_timestamp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "enq_qdepth"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "enq_qdepth"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "deq_timedelta"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "deq_timedelta"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "deq_qdepth"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "deq_qdepth"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "ingress_global_timestamp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_global_timestamp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "lf_field_list"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "lf_field_list"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "mcast_grp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "mcast_grp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "resubmit_flag"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "resubmit_flag"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "egress_rid"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_rid"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "egress_spec"]
- },
- {
- "type" : "runtime_data",
- "value" : 0
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 9,
- "column" : 4,
- "source_fragment" : "standard_metadata.egress_spec = port"
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "ingress_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_spec"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "egress_spec"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "egress_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "clone_spec"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "clone_spec"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "instance_type"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "instance_type"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "drop"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "drop"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "recirculate_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "recirculate_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "packet_length"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "packet_length"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "enq_timestamp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "enq_timestamp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "enq_qdepth"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "enq_qdepth"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "deq_timedelta"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "deq_timedelta"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "deq_qdepth"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "deq_qdepth"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_global_timestamp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "ingress_global_timestamp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "lf_field_list"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "lf_field_list"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "mcast_grp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "mcast_grp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "resubmit_flag"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "resubmit_flag"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_rid"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_3", "egress_rid"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 8,
- "column" : 49,
- "source_fragment" : "standard_metadata, Port port) { ..."
- }
- }
- ]
- },
- {
- "name" : "send_to_cpu",
- "id" : 1,
- "runtime_data" : [],
- "primitives" : [
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "ingress_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "egress_spec"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_spec"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "egress_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "clone_spec"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "clone_spec"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "instance_type"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "instance_type"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "drop"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "drop"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "recirculate_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "recirculate_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "packet_length"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "packet_length"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "enq_timestamp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "enq_timestamp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "enq_qdepth"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "enq_qdepth"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "deq_timedelta"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "deq_timedelta"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "deq_qdepth"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "deq_qdepth"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "ingress_global_timestamp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_global_timestamp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "lf_field_list"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "lf_field_list"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "mcast_grp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "mcast_grp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "resubmit_flag"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "resubmit_flag"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "egress_rid"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_rid"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "egress_spec"]
- },
- {
- "type" : "hexstr",
- "value" : "0x00ff"
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 5,
- "column" : 4,
- "source_fragment" : "standard_metadata.egress_spec = 9w255"
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "ingress_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_spec"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "egress_spec"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "egress_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "clone_spec"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "clone_spec"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "instance_type"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "instance_type"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "drop"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "drop"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "recirculate_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "recirculate_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "packet_length"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "packet_length"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "enq_timestamp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "enq_timestamp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "enq_qdepth"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "enq_qdepth"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "deq_timedelta"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "deq_timedelta"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "deq_qdepth"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "deq_qdepth"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_global_timestamp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "ingress_global_timestamp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "lf_field_list"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "lf_field_list"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "mcast_grp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "mcast_grp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "resubmit_flag"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "resubmit_flag"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_rid"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_4", "egress_rid"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 4,
- "column" : 45,
- "source_fragment" : "standard_metadata) { ..."
- }
- }
- ]
- },
- {
- "name" : "drop",
- "id" : 2,
- "runtime_data" : [],
- "primitives" : [
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "ingress_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "egress_spec"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_spec"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "egress_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "clone_spec"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "clone_spec"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "instance_type"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "instance_type"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "drop"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "drop"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "recirculate_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "recirculate_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "packet_length"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "packet_length"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "enq_timestamp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "enq_timestamp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "enq_qdepth"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "enq_qdepth"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "deq_timedelta"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "deq_timedelta"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "deq_qdepth"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "deq_qdepth"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "ingress_global_timestamp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_global_timestamp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "lf_field_list"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "lf_field_list"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "mcast_grp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "mcast_grp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "resubmit_flag"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "resubmit_flag"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "egress_rid"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_rid"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "egress_spec"]
- },
- {
- "type" : "hexstr",
- "value" : "0x01ff"
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 13,
- "column" : 4,
- "source_fragment" : "standard_metadata.egress_spec = 9w511"
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "ingress_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_spec"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "egress_spec"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "egress_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "clone_spec"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "clone_spec"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "instance_type"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "instance_type"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "drop"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "drop"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "recirculate_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "recirculate_port"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "packet_length"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "packet_length"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "enq_timestamp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "enq_timestamp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "enq_qdepth"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "enq_qdepth"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "deq_timedelta"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "deq_timedelta"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "deq_qdepth"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "deq_qdepth"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_global_timestamp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "ingress_global_timestamp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "lf_field_list"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "lf_field_list"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "mcast_grp"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "mcast_grp"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "resubmit_flag"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "resubmit_flag"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_rid"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata_5", "egress_rid"]
- }
- ],
- "source_info" : {
- "filename" : "include/actions.p4",
- "line" : 12,
- "column" : 38,
- "source_fragment" : "standard_metadata) { ..."
- }
- }
- ]
- },
- {
- "name" : "NoAction",
- "id" : 3,
- "runtime_data" : [],
- "primitives" : []
- },
- {
- "name" : "act",
- "id" : 4,
- "runtime_data" : [],
- "primitives" : [
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["scalars", "tmp"]
- },
- {
- "type" : "expression",
- "value" : {
- "type" : "expression",
- "value" : {
- "op" : "&",
- "left" : {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_port"]
- },
- "right" : {
- "type" : "hexstr",
- "value" : "0xffffffff"
- }
- }
- }
- }
- ]
- },
- {
- "op" : "count",
- "parameters" : [
- {
- "type" : "counter_array",
- "value" : "port_counters_control.ingress_port_counter"
- },
- {
- "type" : "field",
- "value" : ["scalars", "tmp"]
- }
- ],
- "source_info" : {
- "filename" : "include/port_counters.p4",
- "line" : 11,
- "column" : 12,
- "source_fragment" : "ingress_port_counter.count((bit<32>)standard_metadata.ingress_port)"
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["scalars", "tmp_0"]
- },
- {
- "type" : "expression",
- "value" : {
- "type" : "expression",
- "value" : {
- "op" : "&",
- "left" : {
- "type" : "field",
- "value" : ["standard_metadata", "egress_spec"]
- },
- "right" : {
- "type" : "hexstr",
- "value" : "0xffffffff"
- }
- }
- }
- }
- ]
- },
- {
- "op" : "count",
- "parameters" : [
- {
- "type" : "counter_array",
- "value" : "port_counters_control.egress_port_counter"
- },
- {
- "type" : "field",
- "value" : ["scalars", "tmp_0"]
- }
- ],
- "source_info" : {
- "filename" : "include/port_counters.p4",
- "line" : 12,
- "column" : 12,
- "source_fragment" : "egress_port_counter.count((bit<32>)standard_metadata.egress_spec)"
- }
- }
- ]
- }
- ],
- "pipelines" : [
- {
- "name" : "ingress",
- "id" : 0,
- "source_info" : {
- "filename" : "default.p4",
- "line" : 10,
- "column" : 8,
- "source_fragment" : "ingress"
- },
- "init_table" : "table0",
- "tables" : [
- {
- "name" : "table0",
- "id" : 0,
- "source_info" : {
- "filename" : "default.p4",
- "line" : 13,
- "column" : 10,
- "source_fragment" : "table0"
- },
- "key" : [
- {
- "match_type" : "ternary",
- "target" : ["standard_metadata", "ingress_port"],
- "mask" : null
- },
- {
- "match_type" : "ternary",
- "target" : ["ethernet", "dstAddr"],
- "mask" : null
- },
- {
- "match_type" : "ternary",
- "target" : ["ethernet", "srcAddr"],
- "mask" : null
- },
- {
- "match_type" : "ternary",
- "target" : ["ethernet", "etherType"],
- "mask" : null
- }
- ],
- "match_type" : "ternary",
- "type" : "simple",
- "max_size" : 1024,
- "support_timeout" : false,
- "direct_meters" : null,
- "action_ids" : [0, 1, 2, 3],
- "actions" : ["set_egress_port", "send_to_cpu", "drop", "NoAction"],
- "base_default_next" : "node_3",
- "next_tables" : {
- "set_egress_port" : "node_3",
- "send_to_cpu" : "node_3",
- "drop" : "node_3",
- "NoAction" : "node_3"
- },
- "default_entry" : {
- "action_id" : 3,
- "action_const" : false,
- "action_data" : [],
- "action_entry_const" : false
- }
- },
- {
- "name" : "tbl_act",
- "id" : 1,
- "key" : [],
- "match_type" : "exact",
- "type" : "simple",
- "max_size" : 1024,
- "with_counters" : false,
- "support_timeout" : false,
- "direct_meters" : null,
- "action_ids" : [4],
- "actions" : ["act"],
- "base_default_next" : null,
- "next_tables" : {
- "act" : null
- },
- "default_entry" : {
- "action_id" : 4,
- "action_const" : true,
- "action_data" : [],
- "action_entry_const" : true
- }
- }
- ],
- "action_profiles" : [],
- "conditionals" : [
- {
- "name" : "node_3",
- "id" : 0,
- "source_info" : {
- "filename" : "include/port_counters.p4",
- "line" : 10,
- "column" : 12,
- "source_fragment" : "standard_metadata.egress_spec < 254"
- },
- "expression" : {
- "type" : "expression",
- "value" : {
- "op" : "<",
- "left" : {
- "type" : "field",
- "value" : ["standard_metadata", "egress_spec"]
- },
- "right" : {
- "type" : "hexstr",
- "value" : "0x00fe"
- }
- }
- },
- "false_next" : null,
- "true_next" : "tbl_act"
- }
- ]
- },
- {
- "name" : "egress",
- "id" : 1,
- "source_info" : {
- "filename" : "default.p4",
- "line" : 36,
- "column" : 8,
- "source_fragment" : "egress"
- },
- "init_table" : null,
- "tables" : [],
- "action_profiles" : [],
- "conditionals" : []
- }
- ],
- "checksums" : [],
- "force_arith" : [],
- "extern_instances" : [],
- "field_aliases" : [
- [
- "queueing_metadata.enq_timestamp",
- ["standard_metadata", "enq_timestamp"]
- ],
- [
- "queueing_metadata.enq_qdepth",
- ["standard_metadata", "enq_qdepth"]
- ],
- [
- "queueing_metadata.deq_timedelta",
- ["standard_metadata", "deq_timedelta"]
- ],
- [
- "queueing_metadata.deq_qdepth",
- ["standard_metadata", "deq_qdepth"]
- ],
- [
- "intrinsic_metadata.ingress_global_timestamp",
- ["standard_metadata", "ingress_global_timestamp"]
- ],
- [
- "intrinsic_metadata.lf_field_list",
- ["standard_metadata", "lf_field_list"]
- ],
- [
- "intrinsic_metadata.mcast_grp",
- ["standard_metadata", "mcast_grp"]
- ],
- [
- "intrinsic_metadata.resubmit_flag",
- ["standard_metadata", "resubmit_flag"]
- ],
- [
- "intrinsic_metadata.egress_rid",
- ["standard_metadata", "egress_rid"]
- ]
- ]
-}
\ No newline at end of file
diff --git a/protocols/p4runtime/ctl/src/test/resources/default.p4info b/protocols/p4runtime/ctl/src/test/resources/default.p4info
deleted file mode 100644
index b224b87..0000000
--- a/protocols/p4runtime/ctl/src/test/resources/default.p4info
+++ /dev/null
@@ -1,147 +0,0 @@
-tables {
- preamble {
- id: 33617813
- name: "table0"
- alias: "table0"
- }
- match_fields {
- id: 1
- name: "standard_metadata.ingress_port"
- bitwidth: 9
- match_type: TERNARY
- }
- match_fields {
- id: 2
- name: "hdr.ethernet.dstAddr"
- bitwidth: 48
- match_type: TERNARY
- }
- match_fields {
- id: 3
- name: "hdr.ethernet.srcAddr"
- bitwidth: 48
- match_type: TERNARY
- }
- match_fields {
- id: 4
- name: "hdr.ethernet.etherType"
- bitwidth: 16
- match_type: TERNARY
- }
- action_refs {
- id: 16794308
- }
- action_refs {
- id: 16829080
- }
- action_refs {
- id: 16793508
- }
- action_refs {
- id: 16800567
- annotations: "@defaultonly()"
- }
- direct_resource_ids: 301990488
- size: 1024
- with_entry_timeout: true
-}
-actions {
- preamble {
- id: 16794308
- name: "set_egress_port"
- alias: "set_egress_port"
- }
- params {
- id: 1
- name: "port"
- bitwidth: 9
- }
-}
-actions {
- preamble {
- id: 16829080
- name: "send_to_cpu"
- alias: "send_to_cpu"
- }
-}
-actions {
- preamble {
- id: 16793508
- name: "drop"
- alias: "drop"
- }
-}
-actions {
- preamble {
- id: 16800567
- name: "NoAction"
- alias: "NoAction"
- }
-}
-counters {
- preamble {
- id: 302025528
- name: "port_counters_control.egress_port_counter"
- alias: "egress_port_counter"
- }
- spec {
- unit: PACKETS
- }
- size: 254
-}
-counters {
- preamble {
- id: 301999025
- name: "port_counters_control.ingress_port_counter"
- alias: "ingress_port_counter"
- }
- spec {
- unit: PACKETS
- }
- size: 254
-}
-direct_counters {
- preamble {
- id: 301990488
- name: "table0_counter"
- alias: "table0_counter"
- }
- spec {
- unit: PACKETS
- }
- direct_table_id: 33617813
-}
-controller_packet_metadata {
- preamble {
- id: 2868941301
- name: "packet_in"
- annotations: "@controller_header(\"packet_in\")"
- }
- metadata {
- id: 1
- name: "ingress_port"
- bitwidth: 9
- }
- metadata {
- id: 2
- name: "other1"
- bitwidth: 32
- }
-}
-controller_packet_metadata {
- preamble {
- id: 2868916615
- name: "packet_out"
- annotations: "@controller_header(\"packet_out\")"
- }
- metadata {
- id: 1
- name: "egress_port"
- bitwidth: 9
- }
- metadata {
- id: 2
- name: "other2"
- bitwidth: 32
- }
-}
diff --git a/protocols/p4runtime/ctl/src/test/resources/default.p4info b/protocols/p4runtime/ctl/src/test/resources/default.p4info
new file mode 120000
index 0000000..4dda381
--- /dev/null
+++ b/protocols/p4runtime/ctl/src/test/resources/default.p4info
@@ -0,0 +1 @@
+../../../../../../tools/test/p4src/p4-16/p4c-out/default.p4info
\ No newline at end of file