MyTunnel P4 tutorial app and pipeconf
Change-Id: I0549276fc7f6c8d0d244d6c52b1b9e85b9c3e13c
diff --git a/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipeconfFactory.java b/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipeconfFactory.java
index 5d37bd1..47fad41 100644
--- a/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipeconfFactory.java
+++ b/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipeconfFactory.java
@@ -45,8 +45,8 @@
public final class PipeconfFactory {
public static final PiPipeconfId PIPECONF_ID = new PiPipeconfId("p4-tutorial-pipeconf");
- private static final URL P4INFO_URL = PipeconfFactory.class.getResource("/main.p4info");
- private static final URL BMV2_JSON_URL = PipeconfFactory.class.getResource("/main.json");
+ private static final URL P4INFO_URL = PipeconfFactory.class.getResource("/mytunnel.p4info");
+ private static final URL BMV2_JSON_URL = PipeconfFactory.class.getResource("/mytunnel.json");
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private PiPipeconfService piPipeconfService;
@@ -75,7 +75,7 @@
.withPipelineModel(pipelineModel)
.addBehaviour(PiPipelineInterpreter.class, PipelineInterpreterImpl.class)
.addBehaviour(PortStatisticsDiscovery.class, PortStatisticsDiscoveryImpl.class)
- // Since main.p4 defines only 1 table, we re-use the existing single-table pipeliner.
+ // Since mytunnel.p4 defines only 1 table, we re-use the existing single-table pipeliner.
.addBehaviour(Pipeliner.class, DefaultSingleTablePipeline.class)
.addExtension(P4_INFO_TEXT, P4INFO_URL)
.addExtension(BMV2_JSON, BMV2_JSON_URL)
diff --git a/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java b/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java
index a34cada..58afa10 100644
--- a/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java
+++ b/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java
@@ -19,10 +19,12 @@
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Ethernet;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
@@ -30,7 +32,7 @@
import org.onosproject.net.flow.TrafficTreatment;
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.Instructions.OutputInstruction;
import org.onosproject.net.packet.DefaultInboundPacket;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.OutboundPacket;
@@ -51,7 +53,6 @@
import java.util.Optional;
import static java.lang.String.format;
-import static java.util.stream.Collectors.toList;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
import static org.onosproject.net.PortNumber.CONTROLLER;
import static org.onosproject.net.PortNumber.FLOOD;
@@ -59,34 +60,48 @@
import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_OUT;
/**
- * Implementation of a PI interpreter for the main.p4 program.
+ * Implementation of a pipeline interpreter for the mytunnel.p4 program.
*/
-public final class PipelineInterpreterImpl extends AbstractHandlerBehaviour implements PiPipelineInterpreter {
+public final class PipelineInterpreterImpl
+ extends AbstractHandlerBehaviour
+ implements PiPipelineInterpreter {
- private static final String DOT = ".";
+ private static final String DOT = ".";
private static final String HDR = "hdr";
- private static final String TABLE0 = "table0";
- private static final String IP_PROTO_FILTER_TABLE = "ip_proto_filter_table";
- 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 SET_EGRESS_PORT = "set_egress_port";
+ private static final String C_INGRESS = "c_ingress";
+ private static final String T_L2_FWD = "t_l2_fwd";
private static final String EGRESS_PORT = "egress_port";
private static final String INGRESS_PORT = "ingress_port";
private static final String ETHERNET = "ethernet";
private static final String STANDARD_METADATA = "standard_metadata";
private static final int PORT_FIELD_BITWIDTH = 9;
- private static final PiMatchFieldId INGRESS_PORT_ID = PiMatchFieldId.of(STANDARD_METADATA + DOT + "ingress_port");
- private static final PiMatchFieldId ETH_DST_ID = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + "dst_addr");
- private static final PiMatchFieldId ETH_SRC_ID = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + "src_addr");
- private static final PiMatchFieldId ETH_TYPE_ID = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + "ether_type");
- private static final PiTableId TABLE0_ID = PiTableId.of(TABLE0);
- private static final PiTableId IP_PROTO_FILTER_TABLE_ID = PiTableId.of(IP_PROTO_FILTER_TABLE);
+ private static final PiMatchFieldId INGRESS_PORT_ID =
+ PiMatchFieldId.of(STANDARD_METADATA + DOT + "ingress_port");
+ private static final PiMatchFieldId ETH_DST_ID =
+ PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + "dst_addr");
+ private static final PiMatchFieldId ETH_SRC_ID =
+ PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + "src_addr");
+ private static final PiMatchFieldId ETH_TYPE_ID =
+ PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + "ether_type");
- private static final BiMap<Integer, PiTableId> TABLE_MAP = ImmutableBiMap.of(
- 0, TABLE0_ID,
- 1, IP_PROTO_FILTER_TABLE_ID);
+ private static final PiTableId TABLE_L2_FWD_ID =
+ PiTableId.of(C_INGRESS + DOT + T_L2_FWD);
+
+ private static final PiActionId ACT_ID_NOP =
+ PiActionId.of("NoAction");
+ private static final PiActionId ACT_ID_SEND_TO_CPU =
+ PiActionId.of(C_INGRESS + DOT + "send_to_cpu");
+ private static final PiActionId ACT_ID_SET_EGRESS_PORT =
+ PiActionId.of(C_INGRESS + DOT + "set_egress_port");
+
+ private static final PiActionParamId ACT_PARAM_ID_PORT =
+ PiActionParamId.of("port");
+
+ private static final BiMap<Integer, PiTableId> TABLE_MAP =
+ new ImmutableBiMap.Builder<Integer, PiTableId>()
+ .put(0, TABLE_L2_FWD_ID)
+ .build();
private static final BiMap<Criterion.Type, PiMatchFieldId> CRITERION_MAP =
new ImmutableBiMap.Builder<Criterion.Type, PiMatchFieldId>()
@@ -97,129 +112,6 @@
.build();
@Override
- public PiAction mapTreatment(TrafficTreatment treatment, PiTableId piTableId)
- throws PiInterpreterException {
-
- if (treatment.allInstructions().size() == 0) {
- // No instructions means drop for us.
- return PiAction.builder()
- .withId(PiActionId.of(DROP))
- .build();
- } else if (treatment.allInstructions().size() > 1) {
- // We understand treatments with only 1 instruction.
- throw new PiInterpreterException("Treatment has multiple instructions");
- }
-
- // Get the first and only instruction.
- Instruction instruction = treatment.allInstructions().get(0);
-
- switch (instruction.type()) {
- case OUTPUT:
- // We understand only instructions of type 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 PiAction.builder()
- .withId(PiActionId.of(SEND_TO_CPU))
- .build();
- } else {
- throw new PiInterpreterException(format("Output on logical port '%s' not supported", port));
- }
- default:
- throw new PiInterpreterException(format("Instruction of type '%s' not supported", instruction.type()));
- }
- }
-
- @Override
- public Collection<PiPacketOperation> mapOutboundPacket(OutboundPacket packet)
- throws PiInterpreterException {
-
- TrafficTreatment treatment = packet.treatment();
-
- // We support only packet-out with OUTPUT instructions.
- List<Instructions.OutputInstruction> outInstructions = treatment.allInstructions().stream()
- .filter(i -> i.type().equals(OUTPUT))
- .map(i -> (Instructions.OutputInstruction) i)
- .collect(toList());
-
- if (treatment.allInstructions().size() != outInstructions.size()) {
- // There are other instructions that are not of type OUTPUT.
- throw new PiInterpreterException("Treatment not supported: " + treatment);
- }
-
- ImmutableList.Builder<PiPacketOperation> builder = ImmutableList.builder();
-
- for (Instructions.OutputInstruction outInst : outInstructions) {
- if (outInst.port().isLogical() && !outInst.port().equals(FLOOD)) {
- throw new PiInterpreterException(format("Output on logical port '%s' not supported", outInst.port()));
- } else if (outInst.port().equals(FLOOD)) {
- // Since main.p4 does not support flooding, we create a packet operation for each switch port.
- DeviceService deviceService = handler().get(DeviceService.class);
- for (Port port : deviceService.getPorts(packet.sendThrough())) {
- builder.add(createPiPacketOperation(packet.data(), port.number().toLong()));
- }
- } else {
- builder.add(createPiPacketOperation(packet.data(), outInst.port().toLong()));
- }
- }
- return builder.build();
- }
-
- @Override
- public InboundPacket mapInboundPacket(PiPacketOperation packetIn)
- throws PiInterpreterException {
- // We assume that the packet is ethernet, which is fine since default.p4 can deparse only ethernet packets.
- Ethernet ethPkt;
- try {
- ethPkt = Ethernet.deserializer().deserialize(packetIn.data().asArray(), 0, packetIn.data().size());
- } catch (DeserializationException dex) {
- throw new PiInterpreterException(dex.getMessage());
- }
-
- // Returns the ingress port packet metadata.
- Optional<PiControlMetadata> packetMetadata = packetIn.metadatas().stream()
- .filter(metadata -> metadata.id().toString().equals(INGRESS_PORT))
- .findFirst();
-
- if (packetMetadata.isPresent()) {
- ImmutableByteSequence portByteSequence = packetMetadata.get().value();
- short s = portByteSequence.asReadOnlyBuffer().getShort();
- ConnectPoint receivedFrom = new ConnectPoint(packetIn.deviceId(), PortNumber.portNumber(s));
- return new DefaultInboundPacket(receivedFrom, ethPkt, packetIn.data().asReadOnlyBuffer());
- } else {
- throw new PiInterpreterException(format(
- "Missing metadata '%s' in packet-in received from '%s': %s",
- INGRESS_PORT, packetIn.deviceId(), packetIn));
- }
- }
-
- private PiPacketOperation createPiPacketOperation(ByteBuffer data, long portNumber) throws PiInterpreterException {
- PiControlMetadata metadata = createControlMetadata(portNumber);
- return PiPacketOperation.builder()
- .forDevice(this.data().deviceId())
- .withType(PACKET_OUT)
- .withData(copyFrom(data))
- .withMetadatas(ImmutableList.of(metadata))
- .build();
- }
-
- private PiControlMetadata createControlMetadata(long portNumber) throws PiInterpreterException {
- try {
- return PiControlMetadata.builder()
- .withId(PiControlMetadataId.of(EGRESS_PORT))
- .withValue(copyFrom(portNumber).fit(PORT_FIELD_BITWIDTH))
- .build();
- } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
- throw new PiInterpreterException(format("Port number %d too big, %s", portNumber, e.getMessage()));
- }
- }
-
- @Override
public Optional<PiMatchFieldId> mapCriterionType(Criterion.Type type) {
return Optional.ofNullable(CRITERION_MAP.get(type));
}
@@ -238,4 +130,139 @@
public Optional<Integer> mapPiTableId(PiTableId piTableId) {
return Optional.ofNullable(TABLE_MAP.inverse().get(piTableId));
}
+
+ @Override
+ public PiAction mapTreatment(TrafficTreatment treatment, PiTableId piTableId)
+ throws PiInterpreterException {
+
+ if (piTableId != TABLE_L2_FWD_ID) {
+ throw new PiInterpreterException(
+ "Can map treatments only for 't_l2_fwd' table");
+ }
+
+ if (treatment.allInstructions().size() == 0) {
+ // 0 instructions means "NoAction"
+ return PiAction.builder().withId(ACT_ID_NOP).build();
+ } else if (treatment.allInstructions().size() > 1) {
+ // We understand treatments with only 1 instruction.
+ throw new PiInterpreterException("Treatment has multiple instructions");
+ }
+
+ // Get the first and only instruction.
+ Instruction instruction = treatment.allInstructions().get(0);
+
+ if (instruction.type() != OUTPUT) {
+ // We can map only instructions of type OUTPUT.
+ throw new PiInterpreterException(format(
+ "Instruction of type '%s' not supported", instruction.type()));
+ }
+
+ OutputInstruction outInstruction = (OutputInstruction) instruction;
+ PortNumber port = outInstruction.port();
+ if (!port.isLogical()) {
+ return PiAction.builder()
+ .withId(ACT_ID_SET_EGRESS_PORT)
+ .withParameter(new PiActionParam(
+ ACT_PARAM_ID_PORT, copyFrom(port.toLong())))
+ .build();
+ } else if (port.equals(CONTROLLER)) {
+ return PiAction.builder()
+ .withId(ACT_ID_SEND_TO_CPU)
+ .build();
+ } else {
+ throw new PiInterpreterException(format(
+ "Output on logical port '%s' not supported", port));
+ }
+ }
+
+ @Override
+ public Collection<PiPacketOperation> mapOutboundPacket(OutboundPacket packet)
+ throws PiInterpreterException {
+
+ TrafficTreatment treatment = packet.treatment();
+
+ // We support only packet-out with OUTPUT instructions.
+ if (treatment.allInstructions().size() != 1 &&
+ treatment.allInstructions().get(0).type() != OUTPUT) {
+ throw new PiInterpreterException(
+ "Treatment not supported: " + treatment.toString());
+ }
+
+ Instruction instruction = treatment.allInstructions().get(0);
+ PortNumber port = ((OutputInstruction) instruction).port();
+ List<PiPacketOperation> piPacketOps = Lists.newArrayList();
+
+ if (!port.isLogical()) {
+ piPacketOps.add(createPiPacketOp(packet.data(), port.toLong()));
+ } else if (port.equals(FLOOD)) {
+ // Since mytunnel.p4 does not support flooding, we create a packet
+ // operation for each switch port.
+ DeviceService deviceService = handler().get(DeviceService.class);
+ DeviceId deviceId = packet.sendThrough();
+ for (Port p : deviceService.getPorts(deviceId)) {
+ piPacketOps.add(createPiPacketOp(packet.data(), p.number().toLong()));
+ }
+ } else {
+ throw new PiInterpreterException(format(
+ "Output on logical port '%s' not supported", port));
+ }
+
+ return piPacketOps;
+ }
+
+ @Override
+ public InboundPacket mapInboundPacket(PiPacketOperation packetIn)
+ throws PiInterpreterException {
+ // We assume that the packet is ethernet, which is fine since mytunnel.p4
+ // can deparse only ethernet packets.
+ Ethernet ethPkt;
+
+ try {
+ ethPkt = Ethernet.deserializer().deserialize(
+ packetIn.data().asArray(), 0, packetIn.data().size());
+ } catch (DeserializationException dex) {
+ throw new PiInterpreterException(dex.getMessage());
+ }
+
+ // Returns the ingress port packet metadata.
+ Optional<PiControlMetadata> packetMetadata = packetIn.metadatas().stream()
+ .filter(metadata -> metadata.id().toString().equals(INGRESS_PORT))
+ .findFirst();
+
+ if (packetMetadata.isPresent()) {
+ short s = packetMetadata.get().value().asReadOnlyBuffer().getShort();
+ ConnectPoint receivedFrom = new ConnectPoint(
+ packetIn.deviceId(), PortNumber.portNumber(s));
+ return new DefaultInboundPacket(
+ receivedFrom, ethPkt, packetIn.data().asReadOnlyBuffer());
+ } else {
+ throw new PiInterpreterException(format(
+ "Missing metadata '%s' in packet-in received from '%s': %s",
+ INGRESS_PORT, packetIn.deviceId(), packetIn));
+ }
+ }
+
+ private PiPacketOperation createPiPacketOp(ByteBuffer data, long portNumber)
+ throws PiInterpreterException {
+ PiControlMetadata metadata = createControlMetadata(portNumber);
+ return PiPacketOperation.builder()
+ .forDevice(this.data().deviceId())
+ .withType(PACKET_OUT)
+ .withData(copyFrom(data))
+ .withMetadatas(ImmutableList.of(metadata))
+ .build();
+ }
+
+ private PiControlMetadata createControlMetadata(long portNumber)
+ throws PiInterpreterException {
+ try {
+ return PiControlMetadata.builder()
+ .withId(PiControlMetadataId.of(EGRESS_PORT))
+ .withValue(copyFrom(portNumber).fit(PORT_FIELD_BITWIDTH))
+ .build();
+ } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
+ throw new PiInterpreterException(format(
+ "Port number %d too big, %s", portNumber, e.getMessage()));
+ }
+ }
}
diff --git a/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PortStatisticsDiscoveryImpl.java b/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PortStatisticsDiscoveryImpl.java
index 1f204e2..f5fd70c 100644
--- a/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PortStatisticsDiscoveryImpl.java
+++ b/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PortStatisticsDiscoveryImpl.java
@@ -44,15 +44,15 @@
import static org.onosproject.net.pi.model.PiCounterType.INDIRECT;
/**
- * Implementation of the PortStatisticsDiscovery behaviour for the main.p4 program. This behaviour works by using a
+ * Implementation of the PortStatisticsDiscovery behaviour for the mytunnel.p4 program. This behaviour works by using a
* P4Runtime client to read the values of the ingress/egress port counters defined in the P4 program.
*/
public final class PortStatisticsDiscoveryImpl extends AbstractHandlerBehaviour implements PortStatisticsDiscovery {
private static final Logger log = LoggerFactory.getLogger(PortStatisticsDiscoveryImpl.class);
- private static final PiCounterId INGRESS_COUNTER_ID = PiCounterId.of("igr_port_counter");
- private static final PiCounterId EGRESS_COUNTER_ID = PiCounterId.of("egr_port_counter");
+ private static final PiCounterId INGRESS_COUNTER_ID = PiCounterId.of("c_ingress.rx_port_counter");
+ private static final PiCounterId EGRESS_COUNTER_ID = PiCounterId.of("c_ingress.tx_port_counter");
@Override
public Collection<PortStatistics> discoverPortStatistics() {
diff --git a/apps/p4-tutorial/pipeconf/src/main/resources/Makefile b/apps/p4-tutorial/pipeconf/src/main/resources/Makefile
index 9a6a8d0..adfd7ed 100644
--- a/apps/p4-tutorial/pipeconf/src/main/resources/Makefile
+++ b/apps/p4-tutorial/pipeconf/src/main/resources/Makefile
@@ -1,6 +1,4 @@
-all: main
+all: mytunnel
-main: main.p4
- p4c-bm2-ss -o main.json --p4runtime-file main.p4info --p4runtime-format text main.p4
- # Fix for BMv2/p4c bug...
- sed -i -e 's/"value" : "0xff"/"value" : "0x00ff"/g' main.json
\ No newline at end of file
+mytunnel: mytunnel.p4
+ p4c-bm2-ss -o mytunnel.json --p4runtime-file mytunnel.p4info --p4runtime-format text mytunnel.p4
diff --git a/apps/p4-tutorial/pipeconf/src/main/resources/main.json b/apps/p4-tutorial/pipeconf/src/main/resources/main.json
deleted file mode 100644
index 3d059bb..0000000
--- a/apps/p4-tutorial/pipeconf/src/main/resources/main.json
+++ /dev/null
@@ -1,931 +0,0 @@
-{
- "program" : "main.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" : "ethernet_t",
- "id" : 1,
- "fields" : [
- ["dst_addr", 48, false],
- ["src_addr", 48, false],
- ["ether_type", 16, false]
- ]
- },
- {
- "name" : "ipv4_t",
- "id" : 2,
- "fields" : [
- ["version", 4, false],
- ["ihl", 4, false],
- ["diffserv", 8, false],
- ["len", 16, false],
- ["identification", 16, false],
- ["flags", 3, false],
- ["frag_offset", 13, false],
- ["ttl", 8, false],
- ["protocol", 8, false],
- ["hdr_checksum", 16, false],
- ["src_addr", 32, false],
- ["dst_addr", 32, false]
- ]
- },
- {
- "name" : "packet_out_header_t",
- "id" : 3,
- "fields" : [
- ["egress_port", 9, false],
- ["_padding", 7, false]
- ]
- },
- {
- "name" : "packet_in_header_t",
- "id" : 4,
- "fields" : [
- ["ingress_port", 9, false],
- ["_padding_0", 7, false]
- ]
- },
- {
- "name" : "standard_metadata",
- "id" : 5,
- "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_1", 5, false]
- ]
- }
- ],
- "headers" : [
- {
- "name" : "scalars",
- "id" : 0,
- "header_type" : "scalars_0",
- "metadata" : true,
- "pi_omit" : true
- },
- {
- "name" : "standard_metadata",
- "id" : 1,
- "header_type" : "standard_metadata",
- "metadata" : true,
- "pi_omit" : true
- },
- {
- "name" : "ethernet",
- "id" : 2,
- "header_type" : "ethernet_t",
- "metadata" : false,
- "pi_omit" : true
- },
- {
- "name" : "ipv4",
- "id" : 3,
- "header_type" : "ipv4_t",
- "metadata" : false,
- "pi_omit" : true
- },
- {
- "name" : "packet_out",
- "id" : 4,
- "header_type" : "packet_out_header_t",
- "metadata" : false,
- "pi_omit" : true
- },
- {
- "name" : "packet_in",
- "id" : 5,
- "header_type" : "packet_in_header_t",
- "metadata" : false,
- "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" : "start",
- "id" : 0,
- "parser_ops" : [],
- "transitions" : [
- {
- "value" : "0x00ff",
- "mask" : null,
- "next_state" : "parse_packet_out"
- },
- {
- "value" : "default",
- "mask" : null,
- "next_state" : "parse_ethernet"
- }
- ],
- "transition_key" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_port"]
- }
- ]
- },
- {
- "name" : "parse_packet_out",
- "id" : 1,
- "parser_ops" : [
- {
- "parameters" : [
- {
- "type" : "regular",
- "value" : "packet_out"
- }
- ],
- "op" : "extract"
- }
- ],
- "transitions" : [
- {
- "value" : "default",
- "mask" : null,
- "next_state" : "parse_ethernet"
- }
- ],
- "transition_key" : []
- },
- {
- "name" : "parse_ethernet",
- "id" : 2,
- "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", "ether_type"]
- }
- ]
- },
- {
- "name" : "parse_ipv4",
- "id" : 3,
- "parser_ops" : [
- {
- "parameters" : [
- {
- "type" : "regular",
- "value" : "ipv4"
- }
- ],
- "op" : "extract"
- }
- ],
- "transitions" : [
- {
- "value" : "default",
- "mask" : null,
- "next_state" : null
- }
- ],
- "transition_key" : []
- }
- ]
- }
- ],
- "deparsers" : [
- {
- "name" : "deparser",
- "id" : 0,
- "source_info" : {
- "filename" : "main.p4",
- "line" : 264,
- "column" : 8,
- "source_fragment" : "DeparserImpl"
- },
- "order" : ["packet_in", "ethernet", "ipv4"]
- }
- ],
- "meter_arrays" : [],
- "counter_arrays" : [
- {
- "name" : "egr_port_counter",
- "id" : 0,
- "source_info" : {
- "filename" : "main.p4",
- "line" : 181,
- "column" : 38,
- "source_fragment" : "egr_port_counter"
- },
- "size" : 511,
- "is_direct" : false
- },
- {
- "name" : "igr_port_counter",
- "id" : 1,
- "source_info" : {
- "filename" : "main.p4",
- "line" : 182,
- "column" : 38,
- "source_fragment" : "igr_port_counter"
- },
- "size" : 511,
- "is_direct" : false
- }
- ],
- "register_arrays" : [],
- "calculations" : [],
- "learn_lists" : [],
- "actions" : [
- {
- "name" : "NoAction",
- "id" : 0,
- "runtime_data" : [],
- "primitives" : []
- },
- {
- "name" : "send_to_cpu",
- "id" : 1,
- "runtime_data" : [],
- "primitives" : [
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_spec"]
- },
- {
- "type" : "hexstr",
- "value" : "0x00ff"
- }
- ],
- "source_info" : {
- "filename" : "main.p4",
- "line" : 24,
- "column" : 24,
- "source_fragment" : "255; ..."
- }
- },
- {
- "op" : "add_header",
- "parameters" : [
- {
- "type" : "header",
- "value" : "packet_in"
- }
- ],
- "source_info" : {
- "filename" : "main.p4",
- "line" : 137,
- "column" : 8,
- "source_fragment" : "hdr.packet_in.setValid()"
- }
- },
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["packet_in", "ingress_port"]
- },
- {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_port"]
- }
- ],
- "source_info" : {
- "filename" : "main.p4",
- "line" : 138,
- "column" : 8,
- "source_fragment" : "hdr.packet_in.ingress_port = standard_metadata.ingress_port"
- }
- }
- ]
- },
- {
- "name" : "set_egress_port",
- "id" : 2,
- "runtime_data" : [
- {
- "name" : "port",
- "bitwidth" : 9
- }
- ],
- "primitives" : [
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_spec"]
- },
- {
- "type" : "runtime_data",
- "value" : 0
- }
- ],
- "source_info" : {
- "filename" : "main.p4",
- "line" : 142,
- "column" : 8,
- "source_fragment" : "standard_metadata.egress_spec = port"
- }
- }
- ]
- },
- {
- "name" : "_drop",
- "id" : 3,
- "runtime_data" : [],
- "primitives" : [
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_spec"]
- },
- {
- "type" : "hexstr",
- "value" : "0x01ff"
- }
- ],
- "source_info" : {
- "filename" : "main.p4",
- "line" : 25,
- "column" : 25,
- "source_fragment" : "511; ..."
- }
- }
- ]
- },
- {
- "name" : "_drop",
- "id" : 4,
- "runtime_data" : [],
- "primitives" : [
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_spec"]
- },
- {
- "type" : "hexstr",
- "value" : "0x01ff"
- }
- ],
- "source_info" : {
- "filename" : "main.p4",
- "line" : 25,
- "column" : 25,
- "source_fragment" : "511; ..."
- }
- }
- ]
- },
- {
- "name" : "act",
- "id" : 5,
- "runtime_data" : [],
- "primitives" : [
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["standard_metadata", "egress_spec"]
- },
- {
- "type" : "field",
- "value" : ["packet_out", "egress_port"]
- }
- ],
- "source_info" : {
- "filename" : "main.p4",
- "line" : 195,
- "column" : 12,
- "source_fragment" : "standard_metadata.egress_spec = hdr.packet_out.egress_port"
- }
- },
- {
- "op" : "remove_header",
- "parameters" : [
- {
- "type" : "header",
- "value" : "packet_out"
- }
- ],
- "source_info" : {
- "filename" : "main.p4",
- "line" : 196,
- "column" : 12,
- "source_fragment" : "hdr.packet_out.setInvalid()"
- }
- }
- ]
- },
- {
- "name" : "act_0",
- "id" : 6,
- "runtime_data" : [],
- "primitives" : [
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["scalars", "tmp"]
- },
- {
- "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" : "egr_port_counter"
- },
- {
- "type" : "field",
- "value" : ["scalars", "tmp"]
- }
- ],
- "source_info" : {
- "filename" : "main.p4",
- "line" : 218,
- "column" : 12,
- "source_fragment" : "egr_port_counter.count((bit<32>) standard_metadata.egress_spec)"
- }
- }
- ]
- },
- {
- "name" : "act_1",
- "id" : 7,
- "runtime_data" : [],
- "primitives" : [
- {
- "op" : "assign",
- "parameters" : [
- {
- "type" : "field",
- "value" : ["scalars", "tmp_0"]
- },
- {
- "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" : "igr_port_counter"
- },
- {
- "type" : "field",
- "value" : ["scalars", "tmp_0"]
- }
- ],
- "source_info" : {
- "filename" : "main.p4",
- "line" : 221,
- "column" : 12,
- "source_fragment" : "igr_port_counter.count((bit<32>) standard_metadata.ingress_port)"
- }
- }
- ]
- }
- ],
- "pipelines" : [
- {
- "name" : "ingress",
- "id" : 0,
- "source_info" : {
- "filename" : "main.p4",
- "line" : 126,
- "column" : 8,
- "source_fragment" : "IngressImpl"
- },
- "init_table" : "node_2",
- "tables" : [
- {
- "name" : "tbl_act",
- "id" : 0,
- "key" : [],
- "match_type" : "exact",
- "type" : "simple",
- "max_size" : 1024,
- "with_counters" : false,
- "support_timeout" : false,
- "direct_meters" : null,
- "action_ids" : [5],
- "actions" : ["act"],
- "base_default_next" : "node_7",
- "next_tables" : {
- "act" : "node_7"
- },
- "default_entry" : {
- "action_id" : 5,
- "action_const" : true,
- "action_data" : [],
- "action_entry_const" : true
- }
- },
- {
- "name" : "table0",
- "id" : 1,
- "source_info" : {
- "filename" : "main.p4",
- "line" : 149,
- "column" : 10,
- "source_fragment" : "table0"
- },
- "key" : [
- {
- "match_type" : "ternary",
- "target" : ["standard_metadata", "ingress_port"],
- "mask" : null
- },
- {
- "match_type" : "ternary",
- "target" : ["ethernet", "dst_addr"],
- "mask" : null
- },
- {
- "match_type" : "ternary",
- "target" : ["ethernet", "src_addr"],
- "mask" : null
- },
- {
- "match_type" : "ternary",
- "target" : ["ethernet", "ether_type"],
- "mask" : null
- }
- ],
- "match_type" : "ternary",
- "type" : "simple",
- "max_size" : 1024,
- "with_counters" : false,
- "support_timeout" : false,
- "direct_meters" : null,
- "action_ids" : [2, 1, 3],
- "actions" : ["set_egress_port", "send_to_cpu", "_drop"],
- "base_default_next" : "node_7",
- "next_tables" : {
- "set_egress_port" : "node_5",
- "send_to_cpu" : "node_7",
- "_drop" : "node_7"
- },
- "default_entry" : {
- "action_id" : 3,
- "action_const" : false,
- "action_data" : [],
- "action_entry_const" : false
- }
- },
- {
- "name" : "ip_proto_filter_table",
- "id" : 2,
- "source_info" : {
- "filename" : "main.p4",
- "line" : 164,
- "column" : 10,
- "source_fragment" : "ip_proto_filter_table"
- },
- "key" : [
- {
- "match_type" : "ternary",
- "target" : ["ipv4", "src_addr"],
- "mask" : null
- },
- {
- "match_type" : "exact",
- "target" : ["ipv4", "protocol"],
- "mask" : null
- }
- ],
- "match_type" : "ternary",
- "type" : "simple",
- "max_size" : 1024,
- "with_counters" : false,
- "support_timeout" : false,
- "direct_meters" : null,
- "action_ids" : [4, 0],
- "actions" : ["_drop", "NoAction"],
- "base_default_next" : "node_7",
- "next_tables" : {
- "_drop" : "node_7",
- "NoAction" : "node_7"
- },
- "default_entry" : {
- "action_id" : 0,
- "action_const" : false,
- "action_data" : [],
- "action_entry_const" : false
- }
- },
- {
- "name" : "tbl_act_0",
- "id" : 3,
- "key" : [],
- "match_type" : "exact",
- "type" : "simple",
- "max_size" : 1024,
- "with_counters" : false,
- "support_timeout" : false,
- "direct_meters" : null,
- "action_ids" : [6],
- "actions" : ["act_0"],
- "base_default_next" : "node_9",
- "next_tables" : {
- "act_0" : "node_9"
- },
- "default_entry" : {
- "action_id" : 6,
- "action_const" : true,
- "action_data" : [],
- "action_entry_const" : true
- }
- },
- {
- "name" : "tbl_act_1",
- "id" : 4,
- "key" : [],
- "match_type" : "exact",
- "type" : "simple",
- "max_size" : 1024,
- "with_counters" : false,
- "support_timeout" : false,
- "direct_meters" : null,
- "action_ids" : [7],
- "actions" : ["act_1"],
- "base_default_next" : null,
- "next_tables" : {
- "act_1" : null
- },
- "default_entry" : {
- "action_id" : 7,
- "action_const" : true,
- "action_data" : [],
- "action_entry_const" : true
- }
- }
- ],
- "action_profiles" : [],
- "conditionals" : [
- {
- "name" : "node_2",
- "id" : 0,
- "source_info" : {
- "filename" : "main.p4",
- "line" : 188,
- "column" : 12,
- "source_fragment" : "standard_metadata.ingress_port == CPU_PORT"
- },
- "expression" : {
- "type" : "expression",
- "value" : {
- "op" : "==",
- "left" : {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_port"]
- },
- "right" : {
- "type" : "hexstr",
- "value" : "0x00ff"
- }
- }
- },
- "true_next" : "tbl_act",
- "false_next" : "table0"
- },
- {
- "name" : "node_5",
- "id" : 1,
- "source_info" : {
- "filename" : "main.p4",
- "line" : 205,
- "column" : 24,
- "source_fragment" : "hdr.ipv4.isValid()"
- },
- "expression" : {
- "type" : "expression",
- "value" : {
- "op" : "==",
- "left" : {
- "type" : "field",
- "value" : ["ipv4", "$valid$"]
- },
- "right" : {
- "type" : "hexstr",
- "value" : "0x01"
- }
- }
- },
- "true_next" : "ip_proto_filter_table",
- "false_next" : "node_7"
- },
- {
- "name" : "node_7",
- "id" : 2,
- "source_info" : {
- "filename" : "main.p4",
- "line" : 217,
- "column" : 12,
- "source_fragment" : "standard_metadata.egress_spec < 511"
- },
- "expression" : {
- "type" : "expression",
- "value" : {
- "op" : "<",
- "left" : {
- "type" : "field",
- "value" : ["standard_metadata", "egress_spec"]
- },
- "right" : {
- "type" : "hexstr",
- "value" : "0x01ff"
- }
- }
- },
- "true_next" : "tbl_act_0",
- "false_next" : "node_9"
- },
- {
- "name" : "node_9",
- "id" : 3,
- "source_info" : {
- "filename" : "main.p4",
- "line" : 220,
- "column" : 12,
- "source_fragment" : "standard_metadata.ingress_port < 511"
- },
- "expression" : {
- "type" : "expression",
- "value" : {
- "op" : "<",
- "left" : {
- "type" : "field",
- "value" : ["standard_metadata", "ingress_port"]
- },
- "right" : {
- "type" : "hexstr",
- "value" : "0x01ff"
- }
- }
- },
- "false_next" : null,
- "true_next" : "tbl_act_1"
- }
- ]
- },
- {
- "name" : "egress",
- "id" : 1,
- "source_info" : {
- "filename" : "main.p4",
- "line" : 230,
- "column" : 8,
- "source_fragment" : "EgressImpl"
- },
- "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/apps/p4-tutorial/pipeconf/src/main/resources/main.p4 b/apps/p4-tutorial/pipeconf/src/main/resources/main.p4
deleted file mode 100644
index 9f0b809..0000000
--- a/apps/p4-tutorial/pipeconf/src/main/resources/main.p4
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright 2017-present Open Networking Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <core.p4>
-#include <v1model.p4>
-
-#define ETH_TYPE_IPV4 0x0800
-#define MAX_PORTS 511
-
-typedef bit<9> port_t;
-const port_t CPU_PORT = 255;
-const port_t DROP_PORT = 511;
-
-//------------------------------------------------------------------------------
-// HEADERS
-//------------------------------------------------------------------------------
-
-header ethernet_t {
- bit<48> dst_addr;
- bit<48> src_addr;
- bit<16> ether_type;
-}
-
-header ipv4_t {
- bit<4> version;
- bit<4> ihl;
- bit<8> diffserv;
- bit<16> len;
- bit<16> identification;
- bit<3> flags;
- bit<13> frag_offset;
- bit<8> ttl;
- bit<8> protocol;
- bit<16> hdr_checksum;
- bit<32> src_addr;
- bit<32> dst_addr;
-}
-
-/*
-Packet-in header. Prepended to packets sent to the controller and used to carry
-the original ingress port where the packet was received.
- */
-@controller_header("packet_in")
-header packet_in_header_t {
- bit<9> ingress_port;
-}
-
-/*
-Packet-out header. Prepended to packets received by the controller and used to
-tell the switch on which physical port this packet should be forwarded.
- */
-@controller_header("packet_out")
-header packet_out_header_t {
- bit<9> egress_port;
-}
-
-/*
-For convenience we collect all headers under the same struct.
- */
-struct headers_t {
- ethernet_t ethernet;
- ipv4_t ipv4;
- packet_out_header_t packet_out;
- packet_in_header_t packet_in;
-}
-
-/*
-Metadata can be used to carry information from one table to another.
- */
-struct metadata_t {
- /* Empty. We don't use it in this program. */
-}
-
-//------------------------------------------------------------------------------
-// PARSER
-//------------------------------------------------------------------------------
-
-parser ParserImpl(packet_in packet,
- out headers_t hdr,
- inout metadata_t meta,
- inout standard_metadata_t standard_metadata) {
-
- state start {
- transition select(standard_metadata.ingress_port) {
- CPU_PORT: parse_packet_out;
- default: parse_ethernet;
- }
- }
-
- state parse_packet_out {
- packet.extract(hdr.packet_out);
- transition parse_ethernet;
- }
-
- state parse_ethernet {
- packet.extract(hdr.ethernet);
- transition select(hdr.ethernet.ether_type) {
- ETH_TYPE_IPV4: parse_ipv4;
- default: accept;
- }
- }
-
- state parse_ipv4 {
- packet.extract(hdr.ipv4);
- transition accept;
- }
-}
-
-//------------------------------------------------------------------------------
-// INGRESS PIPELINE
-//------------------------------------------------------------------------------
-
-control IngressImpl(inout headers_t hdr,
- inout metadata_t meta,
- inout standard_metadata_t standard_metadata) {
-
- action send_to_cpu() {
- standard_metadata.egress_spec = CPU_PORT;
- /*
- Packets sent to the controller needs to be prepended with the packet-in
- header. By setting it valid we make sure it will be deparsed before the
- ethernet header (see DeparserImpl).
- */
- hdr.packet_in.setValid();
- hdr.packet_in.ingress_port = standard_metadata.ingress_port;
- }
-
- action set_egress_port(port_t port) {
- standard_metadata.egress_spec = port;
- }
-
- action _drop() {
- standard_metadata.egress_spec = DROP_PORT;
- }
-
- table table0 {
- key = {
- standard_metadata.ingress_port : ternary;
- hdr.ethernet.dst_addr : ternary;
- hdr.ethernet.src_addr : ternary;
- hdr.ethernet.ether_type : ternary;
- }
- actions = {
- set_egress_port();
- send_to_cpu();
- _drop();
- }
- default_action = _drop();
- }
-
- table ip_proto_filter_table {
- key = {
- hdr.ipv4.src_addr : ternary;
- hdr.ipv4.protocol : exact;
- }
- actions = {
- _drop();
- }
- }
-
- /*
- Port counters.
- We use these counter instances to count packets/bytes received/sent on each
- port. BMv2 always counts both packets and bytes, even if the counter is
- instantiated as "packets". For each counter we instantiate a number of cells
- equal to MAX_PORTS.
- */
- counter(MAX_PORTS, CounterType.packets) egr_port_counter;
- counter(MAX_PORTS, CounterType.packets) igr_port_counter;
-
- /*
- We define here the processing to be executed by this ingress pipeline.
- */
- apply {
- if (standard_metadata.ingress_port == CPU_PORT) {
- /*
- Packet received from CPU_PORT, this is a packet-out sent by the
- controller. Skip pipeline processing, set the egress port as
- requested by the controller (packet_out header) and remove the
- packet_out header.
- */
- standard_metadata.egress_spec = hdr.packet_out.egress_port;
- hdr.packet_out.setInvalid();
- } else {
- /*
- Packet received from switch port. Apply table0, if action is
- set_egress_port and packet is IPv4, then apply
- ip_proto_filter_table.
- */
- switch(table0.apply().action_run) {
- set_egress_port: {
- if (hdr.ipv4.isValid()) {
- ip_proto_filter_table.apply();
- }
- }
- }
- }
-
- /*
- For each port counter, we update the cell at index = ingress/egress
- port. We avoid counting packets sent/received on CPU_PORT or dropped
- (DROP_PORT).
- */
- if (standard_metadata.egress_spec < MAX_PORTS) {
- egr_port_counter.count((bit<32>) standard_metadata.egress_spec);
- }
- if (standard_metadata.ingress_port < MAX_PORTS) {
- igr_port_counter.count((bit<32>) standard_metadata.ingress_port);
- }
- }
-}
-
-//------------------------------------------------------------------------------
-// EGRESS PIPELINE
-//------------------------------------------------------------------------------
-
-control EgressImpl(inout headers_t hdr,
- inout metadata_t meta,
- inout standard_metadata_t standard_metadata) {
- apply {
- /*
- Nothing to do on the egress pipeline.
- */
- }
-}
-
-//------------------------------------------------------------------------------
-// CHECKSUM HANDLING
-//------------------------------------------------------------------------------
-
-control VerifyChecksumImpl(in headers_t hdr, inout metadata_t meta) {
- apply {
- /*
- Nothing to do here, we assume checksum is always correct.
- */
- }
-}
-
-control ComputeChecksumImpl(inout headers_t hdr, inout metadata_t meta) {
- apply {
- /*
- Nothing to do here, as we do not modify packet headers.
- */
- }
-}
-
-//------------------------------------------------------------------------------
-// DEPARSER
-//------------------------------------------------------------------------------
-
-control DeparserImpl(packet_out packet, in headers_t hdr) {
- apply {
- /*
- Deparse headers in order. Only valid headers are emitted.
- */
- packet.emit(hdr.packet_in);
- packet.emit(hdr.ethernet);
- packet.emit(hdr.ipv4);
- }
-}
-
-//------------------------------------------------------------------------------
-// SWITCH INSTANTIATION
-//------------------------------------------------------------------------------
-
-V1Switch(ParserImpl(),
- VerifyChecksumImpl(),
- IngressImpl(),
- EgressImpl(),
- ComputeChecksumImpl(),
- DeparserImpl()) main;
diff --git a/apps/p4-tutorial/pipeconf/src/main/resources/main.p4info b/apps/p4-tutorial/pipeconf/src/main/resources/main.p4info
deleted file mode 100644
index c4882d2..0000000
--- a/apps/p4-tutorial/pipeconf/src/main/resources/main.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.dst_addr"
- bitwidth: 48
- match_type: TERNARY
- }
- match_fields {
- id: 3
- name: "hdr.ethernet.src_addr"
- bitwidth: 48
- match_type: TERNARY
- }
- match_fields {
- id: 4
- name: "hdr.ethernet.ether_type"
- bitwidth: 16
- match_type: TERNARY
- }
- action_refs {
- id: 16794308
- }
- action_refs {
- id: 16829080
- }
- action_refs {
- id: 16784184
- }
- size: 1024
-}
-tables {
- preamble {
- id: 33573361
- name: "ip_proto_filter_table"
- alias: "ip_proto_filter_table"
- }
- match_fields {
- id: 1
- name: "hdr.ipv4.src_addr"
- bitwidth: 32
- match_type: TERNARY
- }
- match_fields {
- id: 2
- name: "hdr.ipv4.protocol"
- bitwidth: 8
- match_type: EXACT
- }
- action_refs {
- id: 16784184
- }
- action_refs {
- id: 16800567
- annotations: "@defaultonly()"
- }
- size: 1024
-}
-actions {
- preamble {
- id: 16800567
- name: "NoAction"
- alias: "NoAction"
- }
-}
-actions {
- preamble {
- id: 16829080
- name: "send_to_cpu"
- alias: "send_to_cpu"
- }
-}
-actions {
- preamble {
- id: 16794308
- name: "set_egress_port"
- alias: "set_egress_port"
- }
- params {
- id: 1
- name: "port"
- bitwidth: 9
- }
-}
-actions {
- preamble {
- id: 16784184
- name: "_drop"
- alias: "_drop"
- }
-}
-counters {
- preamble {
- id: 302012419
- name: "egr_port_counter"
- alias: "egr_port_counter"
- }
- spec {
- unit: PACKETS
- }
- size: 511
-}
-counters {
- preamble {
- id: 302054463
- name: "igr_port_counter"
- alias: "igr_port_counter"
- }
- spec {
- unit: PACKETS
- }
- size: 511
-}
-controller_packet_metadata {
- preamble {
- id: 2868941301
- name: "packet_in"
- annotations: "@controller_header(\"packet_in\")"
- }
- metadata {
- id: 1
- name: "ingress_port"
- bitwidth: 9
- }
-}
-controller_packet_metadata {
- preamble {
- id: 2868916615
- name: "packet_out"
- annotations: "@controller_header(\"packet_out\")"
- }
- metadata {
- id: 1
- name: "egress_port"
- bitwidth: 9
- }
-}
diff --git a/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.json b/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.json
new file mode 100644
index 0000000..d7b8e81
--- /dev/null
+++ b/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.json
@@ -0,0 +1,1552 @@
+{
+ "program" : "mytunnel.p4",
+ "__meta__" : {
+ "version" : [2, 7],
+ "compiler" : "https://github.com/p4lang/p4c"
+ },
+ "header_types" : [
+ {
+ "name" : "scalars_0",
+ "id" : 0,
+ "fields" : [
+ ["tmp", 32, false],
+ ["tmp_1", 32, false],
+ ["tmp_0", 1, false],
+ ["hasReturned_0", 1, false],
+ ["_padding_2", 6, false]
+ ]
+ },
+ {
+ "name" : "ethernet_t",
+ "id" : 1,
+ "fields" : [
+ ["dst_addr", 48, false],
+ ["src_addr", 48, false],
+ ["ether_type", 16, false]
+ ]
+ },
+ {
+ "name" : "my_tunnel_t",
+ "id" : 2,
+ "fields" : [
+ ["proto_id", 16, false],
+ ["tun_id", 32, false]
+ ]
+ },
+ {
+ "name" : "ipv4_t",
+ "id" : 3,
+ "fields" : [
+ ["version", 4, false],
+ ["ihl", 4, false],
+ ["diffserv", 8, false],
+ ["len", 16, false],
+ ["identification", 16, false],
+ ["flags", 3, false],
+ ["frag_offset", 13, false],
+ ["ttl", 8, false],
+ ["protocol", 8, false],
+ ["hdr_checksum", 16, false],
+ ["src_addr", 32, false],
+ ["dst_addr", 32, false]
+ ]
+ },
+ {
+ "name" : "packet_out_header_t",
+ "id" : 4,
+ "fields" : [
+ ["egress_port", 9, false],
+ ["_padding", 7, false]
+ ]
+ },
+ {
+ "name" : "packet_in_header_t",
+ "id" : 5,
+ "fields" : [
+ ["ingress_port", 9, false],
+ ["_padding_0", 7, false]
+ ]
+ },
+ {
+ "name" : "standard_metadata",
+ "id" : 6,
+ "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],
+ ["egress_global_timestamp", 48, false],
+ ["lf_field_list", 32, false],
+ ["mcast_grp", 16, false],
+ ["resubmit_flag", 32, false],
+ ["egress_rid", 16, false],
+ ["checksum_error", 1, false],
+ ["recirculate_flag", 32, false],
+ ["_padding_1", 5, false]
+ ]
+ }
+ ],
+ "headers" : [
+ {
+ "name" : "scalars",
+ "id" : 0,
+ "header_type" : "scalars_0",
+ "metadata" : true,
+ "pi_omit" : true
+ },
+ {
+ "name" : "standard_metadata",
+ "id" : 1,
+ "header_type" : "standard_metadata",
+ "metadata" : true,
+ "pi_omit" : true
+ },
+ {
+ "name" : "ethernet",
+ "id" : 2,
+ "header_type" : "ethernet_t",
+ "metadata" : false,
+ "pi_omit" : true
+ },
+ {
+ "name" : "my_tunnel",
+ "id" : 3,
+ "header_type" : "my_tunnel_t",
+ "metadata" : false,
+ "pi_omit" : true
+ },
+ {
+ "name" : "ipv4",
+ "id" : 4,
+ "header_type" : "ipv4_t",
+ "metadata" : false,
+ "pi_omit" : true
+ },
+ {
+ "name" : "packet_out",
+ "id" : 5,
+ "header_type" : "packet_out_header_t",
+ "metadata" : false,
+ "pi_omit" : true
+ },
+ {
+ "name" : "packet_in",
+ "id" : 6,
+ "header_type" : "packet_in_header_t",
+ "metadata" : false,
+ "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" : "start",
+ "id" : 0,
+ "parser_ops" : [],
+ "transitions" : [
+ {
+ "type" : "hexstr",
+ "value" : "0x00ff",
+ "mask" : null,
+ "next_state" : "parse_packet_out"
+ },
+ {
+ "value" : "default",
+ "mask" : null,
+ "next_state" : "parse_ethernet"
+ }
+ ],
+ "transition_key" : [
+ {
+ "type" : "field",
+ "value" : ["standard_metadata", "ingress_port"]
+ }
+ ]
+ },
+ {
+ "name" : "parse_packet_out",
+ "id" : 1,
+ "parser_ops" : [
+ {
+ "parameters" : [
+ {
+ "type" : "regular",
+ "value" : "packet_out"
+ }
+ ],
+ "op" : "extract"
+ }
+ ],
+ "transitions" : [
+ {
+ "value" : "default",
+ "mask" : null,
+ "next_state" : "parse_ethernet"
+ }
+ ],
+ "transition_key" : []
+ },
+ {
+ "name" : "parse_ethernet",
+ "id" : 2,
+ "parser_ops" : [
+ {
+ "parameters" : [
+ {
+ "type" : "regular",
+ "value" : "ethernet"
+ }
+ ],
+ "op" : "extract"
+ }
+ ],
+ "transitions" : [
+ {
+ "type" : "hexstr",
+ "value" : "0x1212",
+ "mask" : null,
+ "next_state" : "parse_my_tunnel"
+ },
+ {
+ "type" : "hexstr",
+ "value" : "0x0800",
+ "mask" : null,
+ "next_state" : "parse_ipv4"
+ },
+ {
+ "value" : "default",
+ "mask" : null,
+ "next_state" : null
+ }
+ ],
+ "transition_key" : [
+ {
+ "type" : "field",
+ "value" : ["ethernet", "ether_type"]
+ }
+ ]
+ },
+ {
+ "name" : "parse_my_tunnel",
+ "id" : 3,
+ "parser_ops" : [
+ {
+ "parameters" : [
+ {
+ "type" : "regular",
+ "value" : "my_tunnel"
+ }
+ ],
+ "op" : "extract"
+ }
+ ],
+ "transitions" : [
+ {
+ "type" : "hexstr",
+ "value" : "0x0800",
+ "mask" : null,
+ "next_state" : "parse_ipv4"
+ },
+ {
+ "value" : "default",
+ "mask" : null,
+ "next_state" : null
+ }
+ ],
+ "transition_key" : [
+ {
+ "type" : "field",
+ "value" : ["my_tunnel", "proto_id"]
+ }
+ ]
+ },
+ {
+ "name" : "parse_ipv4",
+ "id" : 4,
+ "parser_ops" : [
+ {
+ "parameters" : [
+ {
+ "type" : "regular",
+ "value" : "ipv4"
+ }
+ ],
+ "op" : "extract"
+ }
+ ],
+ "transitions" : [
+ {
+ "value" : "default",
+ "mask" : null,
+ "next_state" : null
+ }
+ ],
+ "transition_key" : []
+ }
+ ]
+ }
+ ],
+ "parse_vsets" : [],
+ "deparsers" : [
+ {
+ "name" : "deparser",
+ "id" : 0,
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 286,
+ "column" : 8,
+ "source_fragment" : "c_deparser"
+ },
+ "order" : ["packet_in", "ethernet", "my_tunnel", "ipv4"]
+ }
+ ],
+ "meter_arrays" : [],
+ "counter_arrays" : [
+ {
+ "name" : "c_ingress.tx_port_counter",
+ "id" : 0,
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 140,
+ "column" : 48,
+ "source_fragment" : "tx_port_counter"
+ },
+ "size" : 255,
+ "is_direct" : false
+ },
+ {
+ "name" : "c_ingress.rx_port_counter",
+ "id" : 1,
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 141,
+ "column" : 48,
+ "source_fragment" : "rx_port_counter"
+ },
+ "size" : 255,
+ "is_direct" : false
+ },
+ {
+ "name" : "c_ingress.l2_fwd_counter",
+ "id" : 2,
+ "is_direct" : true,
+ "binding" : "c_ingress.t_l2_fwd"
+ }
+ ],
+ "register_arrays" : [],
+ "calculations" : [],
+ "learn_lists" : [],
+ "actions" : [
+ {
+ "name" : "NoAction",
+ "id" : 0,
+ "runtime_data" : [],
+ "primitives" : []
+ },
+ {
+ "name" : "c_ingress.send_to_cpu",
+ "id" : 1,
+ "runtime_data" : [],
+ "primitives" : [
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["standard_metadata", "egress_spec"]
+ },
+ {
+ "type" : "hexstr",
+ "value" : "0x00ff"
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 26,
+ "column" : 24,
+ "source_fragment" : "255; ..."
+ }
+ },
+ {
+ "op" : "add_header",
+ "parameters" : [
+ {
+ "type" : "header",
+ "value" : "packet_in"
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 148,
+ "column" : 8,
+ "source_fragment" : "hdr.packet_in.setValid()"
+ }
+ },
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["packet_in", "ingress_port"]
+ },
+ {
+ "type" : "field",
+ "value" : ["standard_metadata", "ingress_port"]
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 149,
+ "column" : 8,
+ "source_fragment" : "hdr.packet_in.ingress_port = standard_metadata.ingress_port"
+ }
+ }
+ ]
+ },
+ {
+ "name" : "c_ingress.set_out_port",
+ "id" : 2,
+ "runtime_data" : [
+ {
+ "name" : "port",
+ "bitwidth" : 9
+ }
+ ],
+ "primitives" : [
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["standard_metadata", "egress_spec"]
+ },
+ {
+ "type" : "runtime_data",
+ "value" : 0
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 153,
+ "column" : 8,
+ "source_fragment" : "standard_metadata.egress_spec = port"
+ }
+ }
+ ]
+ },
+ {
+ "name" : "c_ingress.set_out_port",
+ "id" : 3,
+ "runtime_data" : [
+ {
+ "name" : "port",
+ "bitwidth" : 9
+ }
+ ],
+ "primitives" : [
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["standard_metadata", "egress_spec"]
+ },
+ {
+ "type" : "runtime_data",
+ "value" : 0
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 153,
+ "column" : 8,
+ "source_fragment" : "standard_metadata.egress_spec = port"
+ }
+ }
+ ]
+ },
+ {
+ "name" : "c_ingress._drop",
+ "id" : 4,
+ "runtime_data" : [],
+ "primitives" : [
+ {
+ "op" : "drop",
+ "parameters" : [],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 157,
+ "column" : 8,
+ "source_fragment" : "mark_to_drop()"
+ }
+ }
+ ]
+ },
+ {
+ "name" : "c_ingress._drop",
+ "id" : 5,
+ "runtime_data" : [],
+ "primitives" : [
+ {
+ "op" : "drop",
+ "parameters" : [],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 157,
+ "column" : 8,
+ "source_fragment" : "mark_to_drop()"
+ }
+ }
+ ]
+ },
+ {
+ "name" : "c_ingress._drop",
+ "id" : 6,
+ "runtime_data" : [],
+ "primitives" : [
+ {
+ "op" : "drop",
+ "parameters" : [],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 157,
+ "column" : 8,
+ "source_fragment" : "mark_to_drop()"
+ }
+ }
+ ]
+ },
+ {
+ "name" : "c_ingress.my_tunnel_ingress",
+ "id" : 7,
+ "runtime_data" : [
+ {
+ "name" : "tun_id",
+ "bitwidth" : 32
+ }
+ ],
+ "primitives" : [
+ {
+ "op" : "add_header",
+ "parameters" : [
+ {
+ "type" : "header",
+ "value" : "my_tunnel"
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 161,
+ "column" : 8,
+ "source_fragment" : "hdr.my_tunnel.setValid()"
+ }
+ },
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["my_tunnel", "tun_id"]
+ },
+ {
+ "type" : "runtime_data",
+ "value" : 0
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 162,
+ "column" : 8,
+ "source_fragment" : "hdr.my_tunnel.tun_id = tun_id"
+ }
+ },
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["my_tunnel", "proto_id"]
+ },
+ {
+ "type" : "field",
+ "value" : ["ethernet", "ether_type"]
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 163,
+ "column" : 8,
+ "source_fragment" : "hdr.my_tunnel.proto_id = hdr.ethernet.ether_type"
+ }
+ },
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["ethernet", "ether_type"]
+ },
+ {
+ "type" : "hexstr",
+ "value" : "0x1212"
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 22,
+ "column" : 34,
+ "source_fragment" : "0x1212; ..."
+ }
+ }
+ ]
+ },
+ {
+ "name" : "c_ingress.my_tunnel_egress",
+ "id" : 8,
+ "runtime_data" : [
+ {
+ "name" : "port",
+ "bitwidth" : 9
+ }
+ ],
+ "primitives" : [
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["standard_metadata", "egress_spec"]
+ },
+ {
+ "type" : "runtime_data",
+ "value" : 0
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 168,
+ "column" : 8,
+ "source_fragment" : "standard_metadata.egress_spec = port"
+ }
+ },
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["ethernet", "ether_type"]
+ },
+ {
+ "type" : "field",
+ "value" : ["my_tunnel", "proto_id"]
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 169,
+ "column" : 8,
+ "source_fragment" : "hdr.ethernet.ether_type = hdr.my_tunnel.proto_id"
+ }
+ },
+ {
+ "op" : "remove_header",
+ "parameters" : [
+ {
+ "type" : "header",
+ "value" : "my_tunnel"
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 170,
+ "column" : 8,
+ "source_fragment" : "hdr.my_tunnel.setInvalid()"
+ }
+ }
+ ]
+ },
+ {
+ "name" : "act",
+ "id" : 9,
+ "runtime_data" : [],
+ "primitives" : [
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["standard_metadata", "egress_spec"]
+ },
+ {
+ "type" : "field",
+ "value" : ["packet_out", "egress_port"]
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 222,
+ "column" : 12,
+ "source_fragment" : "standard_metadata.egress_spec = hdr.packet_out.egress_port"
+ }
+ },
+ {
+ "op" : "remove_header",
+ "parameters" : [
+ {
+ "type" : "header",
+ "value" : "packet_out"
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 223,
+ "column" : 12,
+ "source_fragment" : "hdr.packet_out.setInvalid()"
+ }
+ }
+ ]
+ },
+ {
+ "name" : "act_0",
+ "id" : 10,
+ "runtime_data" : [],
+ "primitives" : [
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["scalars", "tmp_0"]
+ },
+ {
+ "type" : "expression",
+ "value" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "b2d",
+ "left" : null,
+ "right" : {
+ "type" : "bool",
+ "value" : true
+ }
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name" : "act_1",
+ "id" : 11,
+ "runtime_data" : [],
+ "primitives" : [
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["scalars", "tmp_0"]
+ },
+ {
+ "type" : "expression",
+ "value" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "b2d",
+ "left" : null,
+ "right" : {
+ "type" : "bool",
+ "value" : false
+ }
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name" : "act_2",
+ "id" : 12,
+ "runtime_data" : [],
+ "primitives" : [
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["scalars", "hasReturned_0"]
+ },
+ {
+ "type" : "expression",
+ "value" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "b2d",
+ "left" : null,
+ "right" : {
+ "type" : "bool",
+ "value" : true
+ }
+ }
+ }
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 230,
+ "column" : 16,
+ "source_fragment" : "return"
+ }
+ }
+ ]
+ },
+ {
+ "name" : "act_3",
+ "id" : 13,
+ "runtime_data" : [],
+ "primitives" : [
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["scalars", "hasReturned_0"]
+ },
+ {
+ "type" : "expression",
+ "value" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "b2d",
+ "left" : null,
+ "right" : {
+ "type" : "bool",
+ "value" : false
+ }
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name" : "act_4",
+ "id" : 14,
+ "runtime_data" : [],
+ "primitives" : [
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["scalars", "tmp"]
+ },
+ {
+ "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" : "c_ingress.tx_port_counter"
+ },
+ {
+ "type" : "field",
+ "value" : ["scalars", "tmp"]
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 246,
+ "column" : 12,
+ "source_fragment" : "tx_port_counter.count((bit<32>) standard_metadata.egress_spec)"
+ }
+ }
+ ]
+ },
+ {
+ "name" : "act_5",
+ "id" : 15,
+ "runtime_data" : [],
+ "primitives" : [
+ {
+ "op" : "assign",
+ "parameters" : [
+ {
+ "type" : "field",
+ "value" : ["scalars", "tmp_1"]
+ },
+ {
+ "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" : "c_ingress.rx_port_counter"
+ },
+ {
+ "type" : "field",
+ "value" : ["scalars", "tmp_1"]
+ }
+ ],
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 249,
+ "column" : 12,
+ "source_fragment" : "rx_port_counter.count((bit<32>) standard_metadata.ingress_port)"
+ }
+ }
+ ]
+ }
+ ],
+ "pipelines" : [
+ {
+ "name" : "ingress",
+ "id" : 0,
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 134,
+ "column" : 8,
+ "source_fragment" : "c_ingress"
+ },
+ "init_table" : "tbl_act",
+ "tables" : [
+ {
+ "name" : "tbl_act",
+ "id" : 0,
+ "key" : [],
+ "match_type" : "exact",
+ "type" : "simple",
+ "max_size" : 1024,
+ "with_counters" : false,
+ "support_timeout" : false,
+ "direct_meters" : null,
+ "action_ids" : [13],
+ "actions" : ["act_3"],
+ "base_default_next" : "node_3",
+ "next_tables" : {
+ "act_3" : "node_3"
+ },
+ "default_entry" : {
+ "action_id" : 13,
+ "action_const" : true,
+ "action_data" : [],
+ "action_entry_const" : true
+ }
+ },
+ {
+ "name" : "tbl_act_0",
+ "id" : 1,
+ "key" : [],
+ "match_type" : "exact",
+ "type" : "simple",
+ "max_size" : 1024,
+ "with_counters" : false,
+ "support_timeout" : false,
+ "direct_meters" : null,
+ "action_ids" : [9],
+ "actions" : ["act"],
+ "base_default_next" : "node_15",
+ "next_tables" : {
+ "act" : "node_15"
+ },
+ "default_entry" : {
+ "action_id" : 9,
+ "action_const" : true,
+ "action_data" : [],
+ "action_entry_const" : true
+ }
+ },
+ {
+ "name" : "c_ingress.t_l2_fwd",
+ "id" : 2,
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 175,
+ "column" : 10,
+ "source_fragment" : "t_l2_fwd"
+ },
+ "key" : [
+ {
+ "match_type" : "ternary",
+ "name" : "standard_metadata.ingress_port",
+ "target" : ["standard_metadata", "ingress_port"],
+ "mask" : null
+ },
+ {
+ "match_type" : "ternary",
+ "name" : "hdr.ethernet.dst_addr",
+ "target" : ["ethernet", "dst_addr"],
+ "mask" : null
+ },
+ {
+ "match_type" : "ternary",
+ "name" : "hdr.ethernet.src_addr",
+ "target" : ["ethernet", "src_addr"],
+ "mask" : null
+ },
+ {
+ "match_type" : "ternary",
+ "name" : "hdr.ethernet.ether_type",
+ "target" : ["ethernet", "ether_type"],
+ "mask" : null
+ }
+ ],
+ "match_type" : "ternary",
+ "type" : "simple",
+ "max_size" : 1024,
+ "with_counters" : true,
+ "support_timeout" : false,
+ "direct_meters" : null,
+ "action_ids" : [2, 1, 4, 0],
+ "actions" : ["c_ingress.set_out_port", "c_ingress.send_to_cpu", "c_ingress._drop", "NoAction"],
+ "base_default_next" : null,
+ "next_tables" : {
+ "__HIT__" : "tbl_act_1",
+ "__MISS__" : "tbl_act_2"
+ },
+ "default_entry" : {
+ "action_id" : 0,
+ "action_const" : false,
+ "action_data" : [],
+ "action_entry_const" : false
+ }
+ },
+ {
+ "name" : "tbl_act_1",
+ "id" : 3,
+ "key" : [],
+ "match_type" : "exact",
+ "type" : "simple",
+ "max_size" : 1024,
+ "with_counters" : false,
+ "support_timeout" : false,
+ "direct_meters" : null,
+ "action_ids" : [10],
+ "actions" : ["act_0"],
+ "base_default_next" : "node_8",
+ "next_tables" : {
+ "act_0" : "node_8"
+ },
+ "default_entry" : {
+ "action_id" : 10,
+ "action_const" : true,
+ "action_data" : [],
+ "action_entry_const" : true
+ }
+ },
+ {
+ "name" : "tbl_act_2",
+ "id" : 4,
+ "key" : [],
+ "match_type" : "exact",
+ "type" : "simple",
+ "max_size" : 1024,
+ "with_counters" : false,
+ "support_timeout" : false,
+ "direct_meters" : null,
+ "action_ids" : [11],
+ "actions" : ["act_1"],
+ "base_default_next" : "node_8",
+ "next_tables" : {
+ "act_1" : "node_8"
+ },
+ "default_entry" : {
+ "action_id" : 11,
+ "action_const" : true,
+ "action_data" : [],
+ "action_entry_const" : true
+ }
+ },
+ {
+ "name" : "tbl_act_3",
+ "id" : 5,
+ "key" : [],
+ "match_type" : "exact",
+ "type" : "simple",
+ "max_size" : 1024,
+ "with_counters" : false,
+ "support_timeout" : false,
+ "direct_meters" : null,
+ "action_ids" : [12],
+ "actions" : ["act_2"],
+ "base_default_next" : "node_10",
+ "next_tables" : {
+ "act_2" : "node_10"
+ },
+ "default_entry" : {
+ "action_id" : 12,
+ "action_const" : true,
+ "action_data" : [],
+ "action_entry_const" : true
+ }
+ },
+ {
+ "name" : "c_ingress.t_tunnel_ingress",
+ "id" : 6,
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 192,
+ "column" : 10,
+ "source_fragment" : "t_tunnel_ingress"
+ },
+ "key" : [
+ {
+ "match_type" : "lpm",
+ "name" : "hdr.ipv4.dst_addr",
+ "target" : ["ipv4", "dst_addr"],
+ "mask" : null
+ }
+ ],
+ "match_type" : "lpm",
+ "type" : "simple",
+ "max_size" : 1024,
+ "with_counters" : false,
+ "support_timeout" : false,
+ "direct_meters" : null,
+ "action_ids" : [7, 5],
+ "actions" : ["c_ingress.my_tunnel_ingress", "c_ingress._drop"],
+ "base_default_next" : "node_13",
+ "next_tables" : {
+ "c_ingress.my_tunnel_ingress" : "node_13",
+ "c_ingress._drop" : "node_13"
+ },
+ "default_entry" : {
+ "action_id" : 5,
+ "action_const" : false,
+ "action_data" : [],
+ "action_entry_const" : false
+ }
+ },
+ {
+ "name" : "c_ingress.t_tunnel_fwd",
+ "id" : 7,
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 203,
+ "column" : 10,
+ "source_fragment" : "t_tunnel_fwd"
+ },
+ "key" : [
+ {
+ "match_type" : "exact",
+ "name" : "hdr.my_tunnel.tun_id",
+ "target" : ["my_tunnel", "tun_id"],
+ "mask" : null
+ }
+ ],
+ "match_type" : "exact",
+ "type" : "simple",
+ "max_size" : 1024,
+ "with_counters" : false,
+ "support_timeout" : false,
+ "direct_meters" : null,
+ "action_ids" : [3, 8, 6],
+ "actions" : ["c_ingress.set_out_port", "c_ingress.my_tunnel_egress", "c_ingress._drop"],
+ "base_default_next" : "node_15",
+ "next_tables" : {
+ "c_ingress.set_out_port" : "node_15",
+ "c_ingress.my_tunnel_egress" : "node_15",
+ "c_ingress._drop" : "node_15"
+ },
+ "default_entry" : {
+ "action_id" : 6,
+ "action_const" : false,
+ "action_data" : [],
+ "action_entry_const" : false
+ }
+ },
+ {
+ "name" : "tbl_act_4",
+ "id" : 8,
+ "key" : [],
+ "match_type" : "exact",
+ "type" : "simple",
+ "max_size" : 1024,
+ "with_counters" : false,
+ "support_timeout" : false,
+ "direct_meters" : null,
+ "action_ids" : [14],
+ "actions" : ["act_4"],
+ "base_default_next" : "node_18",
+ "next_tables" : {
+ "act_4" : "node_18"
+ },
+ "default_entry" : {
+ "action_id" : 14,
+ "action_const" : true,
+ "action_data" : [],
+ "action_entry_const" : true
+ }
+ },
+ {
+ "name" : "tbl_act_5",
+ "id" : 9,
+ "key" : [],
+ "match_type" : "exact",
+ "type" : "simple",
+ "max_size" : 1024,
+ "with_counters" : false,
+ "support_timeout" : false,
+ "direct_meters" : null,
+ "action_ids" : [15],
+ "actions" : ["act_5"],
+ "base_default_next" : null,
+ "next_tables" : {
+ "act_5" : null
+ },
+ "default_entry" : {
+ "action_id" : 15,
+ "action_const" : true,
+ "action_data" : [],
+ "action_entry_const" : true
+ }
+ }
+ ],
+ "action_profiles" : [],
+ "conditionals" : [
+ {
+ "name" : "node_3",
+ "id" : 0,
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 217,
+ "column" : 12,
+ "source_fragment" : "standard_metadata.ingress_port == CPU_PORT"
+ },
+ "expression" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "==",
+ "left" : {
+ "type" : "field",
+ "value" : ["standard_metadata", "ingress_port"]
+ },
+ "right" : {
+ "type" : "hexstr",
+ "value" : "0x00ff"
+ }
+ }
+ },
+ "true_next" : "tbl_act_0",
+ "false_next" : "c_ingress.t_l2_fwd"
+ },
+ {
+ "name" : "node_8",
+ "id" : 1,
+ "expression" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "d2b",
+ "left" : null,
+ "right" : {
+ "type" : "field",
+ "value" : ["scalars", "tmp_0"]
+ }
+ }
+ },
+ "true_next" : "tbl_act_3",
+ "false_next" : "node_10"
+ },
+ {
+ "name" : "node_10",
+ "id" : 2,
+ "expression" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "not",
+ "left" : null,
+ "right" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "d2b",
+ "left" : null,
+ "right" : {
+ "type" : "field",
+ "value" : ["scalars", "hasReturned_0"]
+ }
+ }
+ }
+ }
+ },
+ "true_next" : "node_11",
+ "false_next" : "node_15"
+ },
+ {
+ "name" : "node_11",
+ "id" : 3,
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 233,
+ "column" : 16,
+ "source_fragment" : "hdr.ipv4.isValid() && !hdr.my_tunnel.isValid()"
+ },
+ "expression" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "and",
+ "left" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "d2b",
+ "left" : null,
+ "right" : {
+ "type" : "field",
+ "value" : ["ipv4", "$valid$"]
+ }
+ }
+ },
+ "right" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "not",
+ "left" : null,
+ "right" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "d2b",
+ "left" : null,
+ "right" : {
+ "type" : "field",
+ "value" : ["my_tunnel", "$valid$"]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "true_next" : "c_ingress.t_tunnel_ingress",
+ "false_next" : "node_13"
+ },
+ {
+ "name" : "node_13",
+ "id" : 4,
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 238,
+ "column" : 16,
+ "source_fragment" : "hdr.my_tunnel.isValid()"
+ },
+ "expression" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "d2b",
+ "left" : null,
+ "right" : {
+ "type" : "field",
+ "value" : ["my_tunnel", "$valid$"]
+ }
+ }
+ },
+ "true_next" : "c_ingress.t_tunnel_fwd",
+ "false_next" : "node_15"
+ },
+ {
+ "name" : "node_15",
+ "id" : 5,
+ "expression" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "not",
+ "left" : null,
+ "right" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "d2b",
+ "left" : null,
+ "right" : {
+ "type" : "field",
+ "value" : ["scalars", "hasReturned_0"]
+ }
+ }
+ }
+ }
+ },
+ "false_next" : null,
+ "true_next" : "node_16"
+ },
+ {
+ "name" : "node_16",
+ "id" : 6,
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 245,
+ "column" : 12,
+ "source_fragment" : "standard_metadata.egress_spec < 255"
+ },
+ "expression" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "<",
+ "left" : {
+ "type" : "field",
+ "value" : ["standard_metadata", "egress_spec"]
+ },
+ "right" : {
+ "type" : "hexstr",
+ "value" : "0x00ff"
+ }
+ }
+ },
+ "true_next" : "tbl_act_4",
+ "false_next" : "node_18"
+ },
+ {
+ "name" : "node_18",
+ "id" : 7,
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 248,
+ "column" : 12,
+ "source_fragment" : "standard_metadata.ingress_port < 255"
+ },
+ "expression" : {
+ "type" : "expression",
+ "value" : {
+ "op" : "<",
+ "left" : {
+ "type" : "field",
+ "value" : ["standard_metadata", "ingress_port"]
+ },
+ "right" : {
+ "type" : "hexstr",
+ "value" : "0x00ff"
+ }
+ }
+ },
+ "false_next" : null,
+ "true_next" : "tbl_act_5"
+ }
+ ]
+ },
+ {
+ "name" : "egress",
+ "id" : 1,
+ "source_info" : {
+ "filename" : "mytunnel.p4",
+ "line" : 258,
+ "column" : 8,
+ "source_fragment" : "c_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.egress_global_timestamp",
+ ["standard_metadata", "egress_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"]
+ ],
+ [
+ "intrinsic_metadata.recirculate_flag",
+ ["standard_metadata", "recirculate_flag"]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4 b/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4
new file mode 100644
index 0000000..7d73489
--- /dev/null
+++ b/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4
@@ -0,0 +1,306 @@
+/*
+ * 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.
+ */
+
+#include <core.p4>
+#include <v1model.p4>
+
+#define MAX_PORTS 255
+
+const bit<16> ETH_TYPE_MYTUNNEL = 0x1212;
+const bit<16> ETH_TYPE_IPV4 = 0x800;
+
+typedef bit<9> port_t;
+const port_t CPU_PORT = 255;
+
+//------------------------------------------------------------------------------
+// HEADERS
+//------------------------------------------------------------------------------
+
+header ethernet_t {
+ bit<48> dst_addr;
+ bit<48> src_addr;
+ bit<16> ether_type;
+}
+
+header my_tunnel_t {
+ bit<16> proto_id;
+ bit<32> tun_id;
+}
+
+header ipv4_t {
+ bit<4> version;
+ bit<4> ihl;
+ bit<8> diffserv;
+ bit<16> len;
+ bit<16> identification;
+ bit<3> flags;
+ bit<13> frag_offset;
+ bit<8> ttl;
+ bit<8> protocol;
+ bit<16> hdr_checksum;
+ bit<32> src_addr;
+ bit<32> dst_addr;
+}
+
+// Packet-in header. Prepended to packets sent to the controller and used to
+// carry the original ingress port where the packet was received.
+@controller_header("packet_in")
+header packet_in_header_t {
+ bit<9> ingress_port;
+}
+
+// Packet-out header. Prepended to packets received by the controller and used
+// to tell the switch on which port this packet should be forwarded.
+@controller_header("packet_out")
+header packet_out_header_t {
+ bit<9> egress_port;
+}
+
+// For convenience we collect all headers under the same struct.
+struct headers_t {
+ ethernet_t ethernet;
+ my_tunnel_t my_tunnel;
+ ipv4_t ipv4;
+ packet_out_header_t packet_out;
+ packet_in_header_t packet_in;
+}
+
+// Metadata can be used to carry information from one table to another.
+struct metadata_t {
+ // Empty. We don't use it in this program.
+}
+
+//------------------------------------------------------------------------------
+// PARSER
+//------------------------------------------------------------------------------
+
+parser c_parser(packet_in packet,
+ out headers_t hdr,
+ inout metadata_t meta,
+ inout standard_metadata_t standard_metadata) {
+
+ state start {
+ transition select(standard_metadata.ingress_port) {
+ CPU_PORT: parse_packet_out;
+ default: parse_ethernet;
+ }
+ }
+
+ state parse_packet_out {
+ packet.extract(hdr.packet_out);
+ transition parse_ethernet;
+ }
+
+ state parse_ethernet {
+ packet.extract(hdr.ethernet);
+ transition select(hdr.ethernet.ether_type) {
+ ETH_TYPE_MYTUNNEL: parse_my_tunnel;
+ ETH_TYPE_IPV4: parse_ipv4;
+ default: accept;
+ }
+ }
+
+ state parse_my_tunnel {
+ packet.extract(hdr.my_tunnel);
+ transition select(hdr.my_tunnel.proto_id) {
+ ETH_TYPE_IPV4: parse_ipv4;
+ default: accept;
+ }
+ }
+
+ state parse_ipv4 {
+ packet.extract(hdr.ipv4);
+ transition accept;
+ }
+}
+
+//------------------------------------------------------------------------------
+// INGRESS PIPELINE
+//------------------------------------------------------------------------------
+
+control c_ingress(inout headers_t hdr,
+ inout metadata_t meta,
+ inout standard_metadata_t standard_metadata) {
+
+ // We use these counters to count packets/bytes received/sent on each port.
+ // For each counter we instantiate a number of cells equal to MAX_PORTS.
+ counter(MAX_PORTS, CounterType.packets_and_bytes) tx_port_counter;
+ counter(MAX_PORTS, CounterType.packets_and_bytes) rx_port_counter;
+
+ action send_to_cpu() {
+ standard_metadata.egress_spec = CPU_PORT;
+ // Packets sent to the controller needs to be prepended with the
+ // packet-in header. By setting it valid we make sure it will be
+ // deparsed on the wire (see c_deparser).
+ hdr.packet_in.setValid();
+ hdr.packet_in.ingress_port = standard_metadata.ingress_port;
+ }
+
+ action set_out_port(port_t port) {
+ standard_metadata.egress_spec = port;
+ }
+
+ action _drop() {
+ mark_to_drop();
+ }
+
+ action my_tunnel_ingress(bit<32> tun_id) {
+ hdr.my_tunnel.setValid();
+ hdr.my_tunnel.tun_id = tun_id;
+ hdr.my_tunnel.proto_id = hdr.ethernet.ether_type;
+ hdr.ethernet.ether_type = ETH_TYPE_MYTUNNEL;
+ }
+
+ action my_tunnel_egress(bit<9> port) {
+ standard_metadata.egress_spec = port;
+ hdr.ethernet.ether_type = hdr.my_tunnel.proto_id;
+ hdr.my_tunnel.setInvalid();
+ }
+
+ direct_counter(CounterType.packets_and_bytes) l2_fwd_counter;
+
+ table t_l2_fwd {
+ key = {
+ standard_metadata.ingress_port : ternary;
+ hdr.ethernet.dst_addr : ternary;
+ hdr.ethernet.src_addr : ternary;
+ hdr.ethernet.ether_type : ternary;
+ }
+ actions = {
+ set_out_port();
+ send_to_cpu();
+ _drop();
+ NoAction;
+ }
+ default_action = NoAction();
+ counters = l2_fwd_counter;
+ }
+
+ table t_tunnel_ingress {
+ key = {
+ hdr.ipv4.dst_addr: lpm;
+ }
+ actions = {
+ my_tunnel_ingress;
+ _drop();
+ }
+ default_action = _drop();
+ }
+
+ table t_tunnel_fwd {
+ key = {
+ hdr.my_tunnel.tun_id: exact;
+ }
+ actions = {
+ set_out_port;
+ my_tunnel_egress;
+ _drop();
+ }
+ default_action = _drop();
+ }
+
+ // Define processing applied by this control block.
+ apply {
+ if (standard_metadata.ingress_port == CPU_PORT) {
+ // Packet received from CPU_PORT, this is a packet-out sent by the
+ // controller. Skip table processing, set the egress port as
+ // requested by the controller (packet_out header) and remove the
+ // packet_out header.
+ standard_metadata.egress_spec = hdr.packet_out.egress_port;
+ hdr.packet_out.setInvalid();
+ } else {
+ // Packet received from data plane port.
+ if (t_l2_fwd.apply().hit) {
+ // Packet hit an entry in t_l2_fwd table. A forwarding action
+ // has already been taken. No need to apply other tables, exit
+ // this control block.
+ return;
+ }
+
+ if (hdr.ipv4.isValid() && !hdr.my_tunnel.isValid()) {
+ // Process only non-tunneled IPv4 packets.
+ t_tunnel_ingress.apply();
+ }
+
+ if (hdr.my_tunnel.isValid()) {
+ // Process all tunneled packets.
+ t_tunnel_fwd.apply();
+ }
+ }
+
+ // Update port counters at index = ingress or egress port.
+ if (standard_metadata.egress_spec < MAX_PORTS) {
+ tx_port_counter.count((bit<32>) standard_metadata.egress_spec);
+ }
+ if (standard_metadata.ingress_port < MAX_PORTS) {
+ rx_port_counter.count((bit<32>) standard_metadata.ingress_port);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// EGRESS PIPELINE
+//------------------------------------------------------------------------------
+
+control c_egress(inout headers_t hdr,
+ inout metadata_t meta,
+ inout standard_metadata_t standard_metadata) {
+ apply {
+ // Nothing to do on the egress pipeline.
+ }
+}
+
+//------------------------------------------------------------------------------
+// CHECKSUM HANDLING
+//------------------------------------------------------------------------------
+
+control c_verify_checksum(inout headers_t hdr, inout metadata_t meta) {
+ apply {
+ // Nothing to do here, we assume checksum is always correct.
+ }
+}
+
+control c_compute_checksum(inout headers_t hdr, inout metadata_t meta) {
+ apply {
+ // No need to compute checksum as we do not modify packet headers.
+ }
+}
+
+//------------------------------------------------------------------------------
+// DEPARSER
+//------------------------------------------------------------------------------
+
+control c_deparser(packet_out packet, in headers_t hdr) {
+ apply {
+ // Emit headers on the wire in the following order.
+ // Only valid headers are emitted.
+ packet.emit(hdr.packet_in);
+ packet.emit(hdr.ethernet);
+ packet.emit(hdr.my_tunnel);
+ packet.emit(hdr.ipv4);
+ }
+}
+
+//------------------------------------------------------------------------------
+// SWITCH INSTANTIATION
+//------------------------------------------------------------------------------
+
+V1Switch(c_parser(),
+ c_verify_checksum(),
+ c_ingress(),
+ c_egress(),
+ c_compute_checksum(),
+ c_deparser()) main;
diff --git a/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4info b/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4info
new file mode 100644
index 0000000..e8685f1
--- /dev/null
+++ b/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4info
@@ -0,0 +1,202 @@
+tables {
+ preamble {
+ id: 33606914
+ name: "c_ingress.t_l2_fwd"
+ alias: "t_l2_fwd"
+ }
+ match_fields {
+ id: 1
+ name: "standard_metadata.ingress_port"
+ bitwidth: 9
+ match_type: TERNARY
+ }
+ match_fields {
+ id: 2
+ name: "hdr.ethernet.dst_addr"
+ bitwidth: 48
+ match_type: TERNARY
+ }
+ match_fields {
+ id: 3
+ name: "hdr.ethernet.src_addr"
+ bitwidth: 48
+ match_type: TERNARY
+ }
+ match_fields {
+ id: 4
+ name: "hdr.ethernet.ether_type"
+ bitwidth: 16
+ match_type: TERNARY
+ }
+ action_refs {
+ id: 16831479
+ }
+ action_refs {
+ id: 16822540
+ }
+ action_refs {
+ id: 16808599
+ }
+ action_refs {
+ id: 16800567
+ }
+ direct_resource_ids: 302001589
+ size: 1024
+}
+tables {
+ preamble {
+ id: 33565612
+ name: "c_ingress.t_tunnel_ingress"
+ alias: "t_tunnel_ingress"
+ }
+ match_fields {
+ id: 1
+ name: "hdr.ipv4.dst_addr"
+ bitwidth: 32
+ match_type: LPM
+ }
+ action_refs {
+ id: 16835665
+ }
+ action_refs {
+ id: 16808599
+ }
+ size: 1024
+}
+tables {
+ preamble {
+ id: 33556067
+ name: "c_ingress.t_tunnel_fwd"
+ alias: "t_tunnel_fwd"
+ }
+ match_fields {
+ id: 1
+ name: "hdr.my_tunnel.tun_id"
+ bitwidth: 32
+ match_type: EXACT
+ }
+ action_refs {
+ id: 16831479
+ }
+ action_refs {
+ id: 16800149
+ }
+ action_refs {
+ id: 16808599
+ }
+ size: 1024
+}
+actions {
+ preamble {
+ id: 16800567
+ name: "NoAction"
+ alias: "NoAction"
+ }
+}
+actions {
+ preamble {
+ id: 16822540
+ name: "c_ingress.send_to_cpu"
+ alias: "send_to_cpu"
+ }
+}
+actions {
+ preamble {
+ id: 16831479
+ name: "c_ingress.set_out_port"
+ alias: "set_out_port"
+ }
+ params {
+ id: 1
+ name: "port"
+ bitwidth: 9
+ }
+}
+actions {
+ preamble {
+ id: 16808599
+ name: "c_ingress._drop"
+ alias: "_drop"
+ }
+}
+actions {
+ preamble {
+ id: 16835665
+ name: "c_ingress.my_tunnel_ingress"
+ alias: "my_tunnel_ingress"
+ }
+ params {
+ id: 1
+ name: "tun_id"
+ bitwidth: 32
+ }
+}
+actions {
+ preamble {
+ id: 16800149
+ name: "c_ingress.my_tunnel_egress"
+ alias: "my_tunnel_egress"
+ }
+ params {
+ id: 1
+ name: "port"
+ bitwidth: 9
+ }
+}
+counters {
+ preamble {
+ id: 302003196
+ name: "c_ingress.tx_port_counter"
+ alias: "tx_port_counter"
+ }
+ spec {
+ unit: BOTH
+ }
+ size: 255
+}
+counters {
+ preamble {
+ id: 302045227
+ name: "c_ingress.rx_port_counter"
+ alias: "rx_port_counter"
+ }
+ spec {
+ unit: BOTH
+ }
+ size: 255
+}
+direct_counters {
+ preamble {
+ id: 302001589
+ name: "c_ingress.l2_fwd_counter"
+ alias: "l2_fwd_counter"
+ }
+ spec {
+ unit: BOTH
+ }
+ direct_table_id: 33606914
+}
+controller_packet_metadata {
+ preamble {
+ id: 2868941301
+ name: "packet_in"
+ annotations: "@controller_header(\"packet_in\")"
+ }
+ metadata {
+ id: 1
+ name: "ingress_port"
+ bitwidth: 9
+ }
+}
+controller_packet_metadata {
+ preamble {
+ id: 2868916615
+ name: "packet_out"
+ annotations: "@controller_header(\"packet_out\")"
+ }
+ metadata {
+ id: 1
+ name: "egress_port"
+ bitwidth: 9
+ }
+}