Modified ECMP demo app for Tofino
Change-Id: Ie3b7d33a95563e8392b1775cc7b3033bb4b4466a
diff --git a/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java b/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java
index f77763e..04cfc7a 100644
--- a/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java
+++ b/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java
@@ -89,6 +89,7 @@
private static final int NUM_LEAFS = 2;
private static final int NUM_SPINES = 2;
+ protected static final int HASHED_LINKS = 2;
private static final int FLOW_PRIORITY = 100;
private static final int CLEANUP_SLEEP = 2000;
@@ -416,7 +417,7 @@
newFlowRules.addAll(generateSpineRules(deviceId, hosts, topo));
}
} catch (FlowRuleGeneratorException e) {
- log.warn("Exception while executing flow rule generator: {}", e.toString());
+ log.warn("Exception while executing flow rule generator: {}", e.getMessage());
return;
}
diff --git a/apps/pi-demo/ecmp/src/main/java/org/onosproject/pi/demo/app/ecmp/EcmpFabricApp.java b/apps/pi-demo/ecmp/src/main/java/org/onosproject/pi/demo/app/ecmp/EcmpFabricApp.java
index 3aabca8..4cac11b 100644
--- a/apps/pi-demo/ecmp/src/main/java/org/onosproject/pi/demo/app/ecmp/EcmpFabricApp.java
+++ b/apps/pi-demo/ecmp/src/main/java/org/onosproject/pi/demo/app/ecmp/EcmpFabricApp.java
@@ -21,35 +21,35 @@
import org.apache.commons.lang3.tuple.Pair;
import org.apache.felix.scr.annotations.Component;
import org.onlab.util.ImmutableByteSequence;
+import org.onosproject.bmv2.model.Bmv2PipelineModelParser;
import org.onosproject.driver.pipeline.DefaultSingleTablePipeline;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.Path;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
import org.onosproject.net.behaviour.Pipeliner;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.PiCriterion;
+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.runtime.PiAction;
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.PiHeaderFieldId;
import org.onosproject.net.pi.runtime.PiTableAction;
-import org.onosproject.pi.demo.app.common.AbstractUpgradableFabricApp;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.Host;
-import org.onosproject.net.Path;
-import org.onosproject.net.Port;
-import org.onosproject.net.PortNumber;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.FlowRule;
-import org.onosproject.net.flow.TrafficTreatment;
-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.topology.DefaultTopologyVertex;
import org.onosproject.net.topology.Topology;
import org.onosproject.net.topology.TopologyGraph;
-import org.onosproject.bmv2.model.Bmv2PipelineModelParser;
+import org.onosproject.pi.demo.app.common.AbstractUpgradableFabricApp;
import java.net.URL;
import java.util.Collection;
@@ -59,6 +59,7 @@
import java.util.Set;
import java.util.stream.Collectors;
+import static java.lang.String.format;
import static java.util.stream.Collectors.toSet;
import static org.onlab.packet.EthType.EtherType.IPV4;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
@@ -74,8 +75,8 @@
private static final String APP_NAME = "org.onosproject.pi-ecmp-fabric";
private static final String PIPECONF_ID = "pi-demo-ecmp";
- private static final URL P4INFO_URL = EcmpFabricApp.class.getResource("/ecmp.p4info");
- private static final URL JSON_URL = EcmpFabricApp.class.getResource("/ecmp.json");
+ private static final URL P4INFO_URL = EcmpFabricApp.class.getResource("/ecmp_14.p4info");
+ private static final URL JSON_URL = EcmpFabricApp.class.getResource("/ecmp_14.json");
private static final PiPipeconf ECMP_PIPECONF = DefaultPiPipeconf.builder()
.withId(new PiPipeconfId(PIPECONF_ID))
@@ -220,15 +221,19 @@
}
private Pair<PiTableAction, List<FlowRule>> provisionEcmpPiTableAction(DeviceId deviceId,
- Set<PortNumber> fabricPorts)
+ Set<PortNumber> fabricPorts)
throws FlowRuleGeneratorException {
// Install ECMP group table entries that map from hash values to actual fabric ports...
int groupId = groupIdOf(deviceId, fabricPorts);
- int groupSize = fabricPorts.size();
+ if (fabricPorts.size() != HASHED_LINKS) {
+ throw new FlowRuleGeneratorException(format(
+ "Invalid number of fabric ports for %s, expected %d but found %d",
+ deviceId, HASHED_LINKS, fabricPorts.size()));
+ }
Iterator<PortNumber> portIterator = fabricPorts.iterator();
List<FlowRule> rules = Lists.newArrayList();
- for (short i = 0; i < groupSize; i++) {
+ for (short i = 0; i < HASHED_LINKS; i++) {
FlowRule rule = flowRuleBuilder(deviceId, EcmpInterpreter.ECMP_GROUP_TABLE)
.withSelector(
buildEcmpTrafficSelector(groupId, i))
@@ -240,19 +245,17 @@
rules.add(rule);
}
- PiTableAction piTableAction = buildEcmpPiTableAction(groupId, groupSize);
+ PiTableAction piTableAction = buildEcmpPiTableAction(groupId);
return Pair.of(piTableAction, rules);
}
- private PiTableAction buildEcmpPiTableAction(int groupId, int groupSize) {
+ private PiTableAction buildEcmpPiTableAction(int groupId) {
return PiAction.builder()
.withId(PiActionId.of(ECMP_GROUP_ACTION_NAME))
.withParameter(new PiActionParam(PiActionParamId.of(GROUP_ID),
ImmutableByteSequence.copyFrom(groupId)))
- .withParameter(new PiActionParam(PiActionParamId.of(GROUP_SIZE),
- ImmutableByteSequence.copyFrom(groupSize)))
.build();
}
diff --git a/apps/pi-demo/ecmp/src/main/java/org/onosproject/pi/demo/app/ecmp/EcmpInterpreter.java b/apps/pi-demo/ecmp/src/main/java/org/onosproject/pi/demo/app/ecmp/EcmpInterpreter.java
index d58ff16..94896aa 100644
--- a/apps/pi-demo/ecmp/src/main/java/org/onosproject/pi/demo/app/ecmp/EcmpInterpreter.java
+++ b/apps/pi-demo/ecmp/src/main/java/org/onosproject/pi/demo/app/ecmp/EcmpInterpreter.java
@@ -60,21 +60,25 @@
*/
public class EcmpInterpreter extends AbstractHandlerBehaviour implements PiPipelineInterpreter {
+ // standard_metadata for Bmv2, ig_intr_md for Tofino
+ // TODO: extract header name from model (first column of table0)
+ private static final String STD_METADATA_HEADER_NAME = "ig_intr_md";
+
protected static final String ECMP_METADATA_HEADER_NAME = "ecmp_metadata_t";
protected static final String ECMP_GROUP_ACTION_NAME = "ecmp_group";
protected static final String GROUP_ID = "group_id";
protected static final String SELECTOR = "selector";
- protected static final String GROUP_SIZE = "groupSize";
protected static final String ECMP_GROUP_TABLE = "ecmp_group_table";
protected static final String TABLE0 = "table0";
private static final String SEND_TO_CPU = "send_to_cpu";
private static final String PORT = "port";
- private static final String DROP = "drop";
+ private static final String DROP = "_drop";
private static final String SET_EGRESS_PORT = "set_egress_port";
private static final String EGRESS_PORT = "egress_port";
+ private static final String INGRESS_PORT = "ingress_port";
private static final int PORT_NUMBER_BIT_WIDTH = 9;
- private static final PiHeaderFieldId IN_PORT_ID = PiHeaderFieldId.of("standard_metadata", "ingress_port");
+ private static final PiHeaderFieldId IN_PORT_ID = PiHeaderFieldId.of(STD_METADATA_HEADER_NAME, "ingress_port");
private static final PiHeaderFieldId ETH_DST_ID = PiHeaderFieldId.of("ethernet", "dstAddr");
private static final PiHeaderFieldId ETH_SRC_ID = PiHeaderFieldId.of("ethernet", "srcAddr");
private static final PiHeaderFieldId ETH_TYPE_ID = PiHeaderFieldId.of("ethernet", "etherType");
@@ -91,8 +95,6 @@
0, PiTableId.of(TABLE0),
1, PiTableId.of(ECMP_GROUP_TABLE));
- public static final String INGRESS_PORT = "ingress_port";
-
@Override
public Optional<Integer> mapPiTableId(PiTableId piTableId) {
return Optional.ofNullable(TABLE_MAP.inverse().get(piTableId));
@@ -117,7 +119,7 @@
Instructions.OutputInstruction outInstruction = (Instructions.OutputInstruction) instruction;
PortNumber port = outInstruction.port();
if (!port.isLogical()) {
- PiAction.builder()
+ return PiAction.builder()
.withId(PiActionId.of(SET_EGRESS_PORT))
.withParameter(new PiActionParam(PiActionParamId.of(PORT),
ImmutableByteSequence.copyFrom(port.toLong())))
@@ -176,7 +178,7 @@
throw new PiInterpreterException("Logical port not supported: " +
outInst.port());
} else if (outInst.port().equals(FLOOD)) {
- //Since ecmp.p4 does not support flood for each port of the device
+ // Since ecmp.p4 does not support flood for each port of the device
// create a packet operation to send the packet out of that specific port
for (Port port : handler().get(DeviceService.class).getPorts(packet.sendThrough())) {
builder.add(createPiPacketOperation(packet.data(), port.number().toLong()));
@@ -206,7 +208,7 @@
try {
portValue = ImmutableByteSequence.fit(portValue, PORT_NUMBER_BIT_WIDTH);
} catch (ImmutableByteSequence.ByteSequenceTrimException e) {
- throw new PiInterpreterException("Port number too big: {}" +
+ throw new PiInterpreterException("Port number too big:" +
portNumber + " causes " + e.getMessage());
}
return PiPacketMetadata.builder()
@@ -230,10 +232,10 @@
if (packetMetadata.isPresent()) {
- //Obtaining the ingress port as an immutable byte sequence
+ // Obtaining the ingress port as an immutable byte sequence.
ImmutableByteSequence portByteSequence = packetMetadata.get().value();
- //Converting immutableByteSequence to short
+ // Converting immutableByteSequence to short.
short s = portByteSequence.asReadOnlyBuffer().getShort();
ConnectPoint receivedFrom = new ConnectPoint(deviceId, PortNumber.portNumber(s));
diff --git a/apps/pi-demo/ecmp/src/main/resources/ecmp.json b/apps/pi-demo/ecmp/src/main/resources/ecmp_14.json
similarity index 100%
rename from apps/pi-demo/ecmp/src/main/resources/ecmp.json
rename to apps/pi-demo/ecmp/src/main/resources/ecmp_14.json
diff --git a/apps/pi-demo/ecmp/src/main/resources/ecmp.p4info b/apps/pi-demo/ecmp/src/main/resources/ecmp_14.p4info
similarity index 100%
rename from apps/pi-demo/ecmp/src/main/resources/ecmp.p4info
rename to apps/pi-demo/ecmp/src/main/resources/ecmp_14.p4info
diff --git a/apps/pi-demo/ecmp/src/main/resources/ecmp_16.json b/apps/pi-demo/ecmp/src/main/resources/ecmp_16.json
new file mode 120000
index 0000000..5b1b6d9
--- /dev/null
+++ b/apps/pi-demo/ecmp/src/main/resources/ecmp_16.json
@@ -0,0 +1 @@
+../../../../../../tools/test/p4src/p4-14/p4c-out/ecmp.json
\ No newline at end of file
diff --git a/apps/pi-demo/ecmp/src/main/resources/ecmp_16.p4info b/apps/pi-demo/ecmp/src/main/resources/ecmp_16.p4info
new file mode 120000
index 0000000..7fe1b6c
--- /dev/null
+++ b/apps/pi-demo/ecmp/src/main/resources/ecmp_16.p4info
@@ -0,0 +1 @@
+../../../../../../tools/test/p4src/p4-14/p4c-out/ecmp.p4info
\ No newline at end of file
diff --git a/core/net/src/test/java/org/onosproject/net/pi/impl/MockInterpreter.java b/core/net/src/test/java/org/onosproject/net/pi/impl/MockInterpreter.java
index 2dff2f1..794e7f8 100644
--- a/core/net/src/test/java/org/onosproject/net/pi/impl/MockInterpreter.java
+++ b/core/net/src/test/java/org/onosproject/net/pi/impl/MockInterpreter.java
@@ -50,7 +50,7 @@
static final String TABLE0 = "table0";
static final String SEND_TO_CPU = "send_to_cpu";
static final String PORT = "port";
- static final String DROP = "drop";
+ static final String DROP = "_drop";
static final String SET_EGRESS_PORT = "set_egress_port";
static final PiHeaderFieldId IN_PORT_ID = PiHeaderFieldId.of("standard_metadata", "ingress_port");