MyTunnel P4 tutorial app and pipeconf
Change-Id: I0549276fc7f6c8d0d244d6c52b1b9e85b9c3e13c
diff --git a/apps/p4-tutorial/icmpdropper/BUCK b/apps/p4-tutorial/icmpdropper/BUCK
deleted file mode 100644
index 026827d..0000000
--- a/apps/p4-tutorial/icmpdropper/BUCK
+++ /dev/null
@@ -1,25 +0,0 @@
-COMPILE_DEPS = [
- '//lib:CORE_DEPS',
- '//apps/p4-tutorial/pipeconf:onos-apps-p4-tutorial-pipeconf',
-]
-
-osgi_jar (
- deps = COMPILE_DEPS,
-)
-
-BUNDLES = [
- '//apps/p4-tutorial/icmpdropper:onos-apps-p4-tutorial-icmpdropper',
-]
-
-onos_app (
- app_name = 'org.onosproject.p4tutorial.icmpdropper',
- title = 'ICMP Dropper (P4 Tutorial)',
- category = 'Security',
- url = 'http://onosproject.org',
- description = 'Inhibits forwarding of ICMP packets for PI-enabled devices using the ' +
- 'p4-tutorial-pipeconf.',
- included_bundles = BUNDLES,
- required_apps = [
- 'org.onosproject.p4tutorial.pipeconf',
- ]
-)
diff --git a/apps/p4-tutorial/icmpdropper/src/main/java/org/onosproject/p4tutorial/icmpdropper/IcmpDropper.java b/apps/p4-tutorial/icmpdropper/src/main/java/org/onosproject/p4tutorial/icmpdropper/IcmpDropper.java
deleted file mode 100644
index ce1c682..0000000
--- a/apps/p4-tutorial/icmpdropper/src/main/java/org/onosproject/p4tutorial/icmpdropper/IcmpDropper.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2017-present Open Networking Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.onosproject.p4tutorial.icmpdropper;
-
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.onosproject.app.ApplicationAdminService;
-import org.onosproject.core.ApplicationId;
-import org.onosproject.core.CoreService;
-import org.onosproject.net.Device;
-import org.onosproject.net.DeviceId;
-import org.onosproject.net.device.DeviceEvent;
-import org.onosproject.net.device.DeviceListener;
-import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.flow.DefaultFlowRule;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.FlowRule;
-import org.onosproject.net.flow.FlowRuleService;
-import org.onosproject.net.flow.criteria.PiCriterion;
-import org.onosproject.net.behaviour.PiPipelineProgrammable;
-import org.onosproject.net.pi.runtime.PiAction;
-import org.onosproject.net.pi.model.PiActionId;
-import org.onosproject.net.pi.model.PiMatchFieldId;
-import org.onosproject.net.pi.service.PiPipeconfService;
-import org.onosproject.net.pi.model.PiTableId;
-import org.onosproject.p4tutorial.pipeconf.PipeconfFactory;
-import org.slf4j.Logger;
-
-import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
-import static org.slf4j.LoggerFactory.getLogger;
-
-/**
- * Simple application that drops all ICMP packets.
- */
-@Component(immediate = true)
-public class IcmpDropper {
-
- private static final Logger log = getLogger(IcmpDropper.class);
-
- private static final String APP_NAME = "org.onosproject.p4tutorial.icmpdropper";
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- private DeviceService deviceService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- private FlowRuleService flowRuleService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- private ApplicationAdminService appService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- private CoreService coreService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- private PiPipeconfService piPipeconfService;
-
- private final DeviceListener deviceListener = new InternalDeviceListener();
-
- private ApplicationId appId;
-
- @Activate
- public void activate() {
- log.info("Starting...");
-
- appId = coreService.registerApplication(APP_NAME);
- // Register listener for handling new devices.
- deviceService.addListener(deviceListener);
- // Install rules to existing devices.
- deviceService.getDevices()
- .forEach(device -> installDropRule(device.id()));
-
- log.info("STARTED", appId.id());
- }
-
- @Deactivate
- public void deactivate() {
- log.info("Stopping...");
-
- deviceService.removeListener(deviceListener);
- flowRuleService.removeFlowRulesById(appId);
-
- log.info("STOPPED");
- }
-
- private boolean checkPipeconf(Device device) {
- if (!device.is(PiPipelineProgrammable.class)) {
- // Device is not PI-pipeline programmable. Ignore.
- return false;
- }
- if (!piPipeconfService.ofDevice(device.id()).isPresent() ||
- !piPipeconfService.ofDevice(device.id()).get().equals(PipeconfFactory.PIPECONF_ID)) {
- log.warn("Device {} has pipeconf {} instead of {}, can't install flow rule for this device",
- device.id(), piPipeconfService.ofDevice(device.id()).get(), PipeconfFactory.PIPECONF_ID);
- return false;
- }
-
- return true;
- }
-
- private void installDropRule(DeviceId deviceId) {
- PiMatchFieldId ipv4ProtoFieldId = PiMatchFieldId.of("hdr.ipv4.protocol");
- PiActionId dropActionId = PiActionId.of("_drop");
-
- PiCriterion piCriterion = PiCriterion.builder()
- .matchExact(ipv4ProtoFieldId, (byte) 0x01)
- .build();
- PiAction dropAction = PiAction.builder()
- .withId(dropActionId)
- .build();
-
- FlowRule flowRule = DefaultFlowRule.builder()
- .forDevice(deviceId)
- .forTable(PiTableId.of("ip_proto_filter_table"))
- .fromApp(appId)
- .makePermanent()
- .withPriority(1000)
- .withSelector(DefaultTrafficSelector.builder()
- .matchPi(piCriterion)
- .build())
- .withTreatment(
- DefaultTrafficTreatment.builder()
- .piTableAction(dropAction)
- .build())
- .build();
-
- log.warn("Installing ICMP drop rule to {}", deviceId);
-
- flowRuleService.applyFlowRules(flowRule);
- }
-
- /**
- * A listener of device events that installs a rule to drop packet for each new device.
- */
- private class InternalDeviceListener implements DeviceListener {
- @Override
- public void event(DeviceEvent event) {
- Device device = event.subject();
- if (checkPipeconf(device)) {
- installDropRule(device.id());
- }
- }
-
- @Override
- public boolean isRelevant(DeviceEvent event) {
- // Reacts only to new devices.
- return event.type() == DEVICE_ADDED;
- }
- }
-}
diff --git a/apps/p4-tutorial/mytunnel/BUCK b/apps/p4-tutorial/mytunnel/BUCK
new file mode 100644
index 0000000..5ada8fc
--- /dev/null
+++ b/apps/p4-tutorial/mytunnel/BUCK
@@ -0,0 +1,24 @@
+COMPILE_DEPS = [
+ '//lib:CORE_DEPS',
+ '//apps/p4-tutorial/pipeconf:onos-apps-p4-tutorial-pipeconf',
+]
+
+osgi_jar (
+ deps = COMPILE_DEPS,
+)
+
+BUNDLES = [
+ '//apps/p4-tutorial/mytunnel:onos-apps-p4-tutorial-mytunnel',
+]
+
+onos_app (
+ app_name = 'org.onosproject.p4tutorial.mytunnel',
+ title = 'MyTunnel Demo App',
+ category = 'Steering',
+ url = 'http://onosproject.org',
+ description = 'Provides forwarding between each pair of hosts via MyTunnel protocol',
+ included_bundles = BUNDLES,
+ required_apps = [
+ 'org.onosproject.p4tutorial.pipeconf',
+ ]
+)
diff --git a/apps/p4-tutorial/mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/MyTunnelApp.java b/apps/p4-tutorial/mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/MyTunnelApp.java
new file mode 100644
index 0000000..eb91243
--- /dev/null
+++ b/apps/p4-tutorial/mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/MyTunnelApp.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.p4tutorial.mytunnel;
+
+import com.google.common.collect.Lists;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.IpAddress;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.Link;
+import org.onosproject.net.Path;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultFlowRule;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.criteria.PiCriterion;
+import org.onosproject.net.host.HostEvent;
+import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.pi.model.PiActionId;
+import org.onosproject.net.pi.model.PiActionParamId;
+import org.onosproject.net.pi.model.PiMatchFieldId;
+import org.onosproject.net.pi.model.PiTableId;
+import org.onosproject.net.pi.runtime.PiAction;
+import org.onosproject.net.pi.runtime.PiActionParam;
+import org.onosproject.net.topology.Topology;
+import org.onosproject.net.topology.TopologyService;
+import org.slf4j.Logger;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.onlab.util.ImmutableByteSequence.copyFrom;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * MyTunnel application which provides forwarding between each pair of hosts via
+ * MyTunnel protocol as defined in mytunnel.p4.
+ * <p>
+ * The app works by listening for host events. Each time a new host is
+ * discovered, it provisions a tunnel between that host and all the others.
+ */
+@Component(immediate = true)
+public class MyTunnelApp {
+
+ private static final String APP_NAME = "org.onosproject.p4tutorial.mytunnel";
+
+ // Default priority used for flow rules installed by this app.
+ private static final int FLOW_RULE_PRIORITY = 100;
+
+ private final HostListener hostListener = new InternalHostListener();
+ private ApplicationId appId;
+ private AtomicInteger nextTunnelId = new AtomicInteger();
+
+ private static final Logger log = getLogger(MyTunnelApp.class);
+
+ //--------------------------------------------------------------------------
+ // P4 program entity names. Values derived from mytunnel.p4info
+ //--------------------------------------------------------------------------
+
+ // Match field IDs.
+ private static final PiMatchFieldId MF_ID_MY_TUNNEL_DST_ID =
+ PiMatchFieldId.of("hdr.my_tunnel.tun_id");
+ private static final PiMatchFieldId MF_ID_IP_DST =
+ PiMatchFieldId.of("hdr.ipv4.dst_addr");
+ // Table IDs.
+ private static final PiTableId TBL_ID_TUNNEL_FWD =
+ PiTableId.of("c_ingress.t_tunnel_fwd");
+ private static final PiTableId TBL_ID_TUNNEL_INGRESS =
+ PiTableId.of("c_ingress.t_tunnel_ingress");
+ // Action IDs.
+ private static final PiActionId ACT_ID_MY_TUNNEL_INGRESS =
+ PiActionId.of("c_ingress.my_tunnel_ingress");
+ private static final PiActionId ACT_ID_SET_OUT_PORT =
+ PiActionId.of("c_ingress.set_out_port");
+ private static final PiActionId ACT_ID_MY_TUNNEL_EGRESS =
+ PiActionId.of("c_ingress.my_tunnel_egress");
+
+ // Action params ID.
+ private static final PiActionParamId ACT_PARAM_ID_TUN_ID =
+ PiActionParamId.of("tun_id");
+ private static final PiActionParamId ACT_PARAM_ID_PORT =
+ PiActionParamId.of("port");
+
+ //--------------------------------------------------------------------------
+ // ONOS services needed by this application.
+ //--------------------------------------------------------------------------
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ private FlowRuleService flowRuleService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ private CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ private TopologyService topologyService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ private HostService hostService;
+
+ //--------------------------------------------------------------------------
+ //--------------------------------------------------------------------------
+
+ @Activate
+ public void activate() {
+ // Register app and event listeners.
+ log.info("Starting...");
+ appId = coreService.registerApplication(APP_NAME);
+ hostService.addListener(hostListener);
+ log.info("STARTED", appId.id());
+ }
+
+ @Deactivate
+ public void deactivate() {
+ // Remove listeners and clean-up flow rules.
+ log.info("Stopping...");
+ hostService.removeListener(hostListener);
+ flowRuleService.removeFlowRulesById(appId);
+ log.info("STOPPED");
+ }
+
+ /**
+ * Provisions a tunnel between the given source and destination host with
+ * the given tunnel ID. The tunnel is established using a randomly picked
+ * shortest path based on the given topology snapshot.
+ *
+ * @param tunId tunnel ID
+ * @param srcHost tunnel source host
+ * @param dstHost tunnel destination host
+ * @param topo topology snapshot
+ */
+ private void provisionTunnel(int tunId, Host srcHost, Host dstHost, Topology topo) {
+
+ // Get all shortest paths between switches connected to source and
+ // destination hosts.
+ DeviceId srcSwitch = srcHost.location().deviceId();
+ DeviceId dstSwitch = dstHost.location().deviceId();
+
+ List<Link> pathLinks;
+ if (srcSwitch.equals(dstSwitch)) {
+ // Source and dest hosts are connected to the same switch.
+ pathLinks = Collections.emptyList();
+ } else {
+ // Compute shortest path.
+ Set<Path> allPaths = topologyService.getPaths(topo, srcSwitch, dstSwitch);
+ if (allPaths.size() == 0) {
+ log.warn("No paths between {} and {}", srcHost.id(), dstHost.id());
+ return;
+ }
+ // If many shortest paths are available, pick a random one.
+ pathLinks = pickRandomPath(allPaths).links();
+ }
+
+ // Tunnel ingress rules.
+ for (IpAddress dstIpAddr : dstHost.ipAddresses()) {
+ // In ONOS discovered hosts can have multiple IP addresses.
+ // Insert tunnel ingress rule for each IP address.
+ // Next switches will forward based only on tunnel ID.
+ insertIngressRule(srcSwitch, dstIpAddr, tunId);
+ }
+
+ // Insert tunnel forward rules on all switches in the path, excluded the
+ // last one.
+ for (Link link : pathLinks) {
+ DeviceId sw = link.src().deviceId();
+ PortNumber port = link.src().port();
+ insertForwardRule(sw, port, tunId, false);
+ }
+
+ // Tunnel egress rule.
+ PortNumber egressSwitchPort = dstHost.location().port();
+ insertForwardRule(dstSwitch, egressSwitchPort, tunId, true);
+
+ log.info("** Completed provisioning of tunnel {} (srcHost={} dstHost={})",
+ tunId, srcHost.id(), dstHost.id());
+ }
+
+ /**
+ * Generates and insert a flow rule to perform the tunnel INGRESS function
+ * for the given switch, destination IP address and tunnel ID.
+ *
+ * @param switchId switch ID
+ * @param dstIpAddr IP address to forward inside the tunnel
+ * @param tunId tunnel ID
+ */
+ private void insertIngressRule(DeviceId switchId,
+ IpAddress dstIpAddr,
+ int tunId) {
+
+ log.info("Inserting INGRESS rule: switchId={}, dstIpAddr={}, tunId={}",
+ switchId, dstIpAddr, tunId);
+
+ PiCriterion match = PiCriterion.builder()
+ .matchLpm(MF_ID_IP_DST, dstIpAddr.toOctets(), 32)
+ .build();
+
+ PiAction action = PiAction.builder()
+ .withId(ACT_ID_MY_TUNNEL_INGRESS)
+ .withParameter(new PiActionParam(
+ ACT_PARAM_ID_TUN_ID, copyFrom(tunId)))
+ .build();
+
+ insertPiFlowRule(switchId, TBL_ID_TUNNEL_INGRESS, match, action);
+ }
+
+ /**
+ * Generates and insert a flow rule to perform the tunnel FORWARD/EGRESS
+ * function for the given switch, output port address and tunnel ID.
+ *
+ * @param switchId switch ID
+ * @param outPort output port where to forward tunneled packets
+ * @param tunId tunnel ID
+ * @param isEgress if true, perform tunnel egress action, otherwise forward
+ * packet as is to port
+ */
+ private void insertForwardRule(DeviceId switchId,
+ PortNumber outPort,
+ int tunId,
+ boolean isEgress) {
+
+ log.info("Inserting {} rule: switchId={}, outPort={}, tunId={}",
+ isEgress ? "EGRESS" : "FORWARD", switchId, outPort, tunId);
+
+ PiCriterion match = PiCriterion.builder()
+ .matchExact(MF_ID_MY_TUNNEL_DST_ID, tunId)
+ .build();
+
+ PiActionId actionId = isEgress ? ACT_ID_MY_TUNNEL_EGRESS : ACT_ID_SET_OUT_PORT;
+
+ PiAction action = PiAction.builder()
+ .withId(actionId)
+ .withParameter(new PiActionParam(
+ ACT_PARAM_ID_PORT, copyFrom((short) outPort.toLong())))
+ .build();
+
+ insertPiFlowRule(switchId, TBL_ID_TUNNEL_FWD, match, action);
+ }
+
+ /**
+ * Inserts a flow rule in the system that using a PI criterion and action.
+ *
+ * @param switchId switch ID
+ * @param tableId table ID
+ * @param piCriterion PI criterion
+ * @param piAction PI action
+ */
+ private void insertPiFlowRule(DeviceId switchId, PiTableId tableId,
+ PiCriterion piCriterion, PiAction piAction) {
+ FlowRule rule = DefaultFlowRule.builder()
+ .forDevice(switchId)
+ .forTable(tableId)
+ .fromApp(appId)
+ .withPriority(FLOW_RULE_PRIORITY)
+ .makePermanent()
+ .withSelector(DefaultTrafficSelector.builder()
+ .matchPi(piCriterion).build())
+ .withTreatment(DefaultTrafficTreatment.builder()
+ .piTableAction(piAction).build())
+ .build();
+ flowRuleService.applyFlowRules(rule);
+ }
+
+ private int getNewTunnelId() {
+ return nextTunnelId.incrementAndGet();
+ }
+
+ private Path pickRandomPath(Set<Path> paths) {
+ int item = new Random().nextInt(paths.size());
+ List<Path> pathList = Lists.newArrayList(paths);
+ return pathList.get(item);
+ }
+
+ /**
+ * A listener of host events that provisions two tunnels for each pair of
+ * hosts when a new host is discovered.
+ */
+ private class InternalHostListener implements HostListener {
+
+ @Override
+ public void event(HostEvent event) {
+ if (event.type() != HostEvent.Type.HOST_ADDED) {
+ // Ignore other host events.
+ return;
+ }
+ synchronized (this) {
+ // Synchronizing here is an overkill, but safer for demo purposes.
+ Host host = event.subject();
+ Topology topo = topologyService.currentTopology();
+ for (Host otherHost : hostService.getHosts()) {
+ if (!host.equals(otherHost)) {
+ provisionTunnel(getNewTunnelId(), host, otherHost, topo);
+ provisionTunnel(getNewTunnelId(), otherHost, host, topo);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/apps/p4-tutorial/icmpdropper/src/main/java/org/onosproject/p4tutorial/icmpdropper/package-info.java b/apps/p4-tutorial/mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/package-info.java
similarity index 92%
rename from apps/p4-tutorial/icmpdropper/src/main/java/org/onosproject/p4tutorial/icmpdropper/package-info.java
rename to apps/p4-tutorial/mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/package-info.java
index 5ea1180..f107c31 100644
--- a/apps/p4-tutorial/icmpdropper/src/main/java/org/onosproject/p4tutorial/icmpdropper/package-info.java
+++ b/apps/p4-tutorial/mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/package-info.java
@@ -16,4 +16,4 @@
/**
* P4 tutorial application classes.
*/
-package org.onosproject.p4tutorial.icmpdropper;
\ No newline at end of file
+package org.onosproject.p4tutorial.mytunnel;
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
+ }
+}
diff --git a/modules.defs b/modules.defs
index 5d422a2..13f485a 100644
--- a/modules.defs
+++ b/modules.defs
@@ -233,7 +233,7 @@
'//incubator/protobuf/services/nb:onos-incubator-protobuf-services-nb-oar',
'//apps/openstacknetworkingui:onos-apps-openstacknetworkingui-oar',
'//apps/p4-tutorial/pipeconf:onos-apps-p4-tutorial-pipeconf-oar',
- '//apps/p4-tutorial/icmpdropper:onos-apps-p4-tutorial-icmpdropper-oar',
+ '//apps/p4-tutorial/mytunnel:onos-apps-p4-tutorial-mytunnel-oar',
'//apps/cfm:onos-apps-cfm-oar',
'//apps/routeradvertisement:onos-apps-routeradvertisement-oar',
'//apps/powermanagement:onos-apps-powermanagement-oar',