From 700648c99327938868bbc9145352a2bb20ee7645 Mon Sep 17 00:00:00 2001 From: Carmelo Cascone Date: Wed, 11 Apr 2018 12:02:16 -0700 Subject: [PATCH] MyTunnel P4 tutorial app and pipeconf Change-Id: I0549276fc7f6c8d0d244d6c52b1b9e85b9c3e13c --- apps/p4-tutorial/icmpdropper/BUCK | 25 - .../p4tutorial/icmpdropper/IcmpDropper.java | 167 -- apps/p4-tutorial/mytunnel/BUCK | 24 + .../p4tutorial/mytunnel/MyTunnelApp.java | 323 ++++ .../p4tutorial/mytunnel}/package-info.java | 2 +- .../p4tutorial/pipeconf/PipeconfFactory.java | 6 +- .../pipeconf/PipelineInterpreterImpl.java | 313 ++-- .../pipeconf/PortStatisticsDiscoveryImpl.java | 6 +- .../pipeconf/src/main/resources/Makefile | 8 +- .../pipeconf/src/main/resources/main.json | 931 ---------- .../pipeconf/src/main/resources/main.p4info | 147 -- .../pipeconf/src/main/resources/mytunnel.json | 1552 +++++++++++++++++ .../main/resources/{main.p4 => mytunnel.p4} | 208 ++- .../src/main/resources/mytunnel.p4info | 202 +++ modules.defs | 2 +- 15 files changed, 2397 insertions(+), 1519 deletions(-) delete mode 100644 apps/p4-tutorial/icmpdropper/BUCK delete mode 100644 apps/p4-tutorial/icmpdropper/src/main/java/org/onosproject/p4tutorial/icmpdropper/IcmpDropper.java create mode 100644 apps/p4-tutorial/mytunnel/BUCK create mode 100644 apps/p4-tutorial/mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/MyTunnelApp.java rename apps/p4-tutorial/{icmpdropper/src/main/java/org/onosproject/p4tutorial/icmpdropper => mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel}/package-info.java (93%) delete mode 100644 apps/p4-tutorial/pipeconf/src/main/resources/main.json delete mode 100644 apps/p4-tutorial/pipeconf/src/main/resources/main.p4info create mode 100644 apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.json rename apps/p4-tutorial/pipeconf/src/main/resources/{main.p4 => mytunnel.p4} (51%) create mode 100644 apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4info diff --git a/apps/p4-tutorial/icmpdropper/BUCK b/apps/p4-tutorial/icmpdropper/BUCK deleted file mode 100644 index 026827df26..0000000000 --- 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 ce1c682632..0000000000 --- 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 0000000000..5ada8fc4fb --- /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 0000000000..eb91243421 --- /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. + *

+ * 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 pathLinks; + if (srcSwitch.equals(dstSwitch)) { + // Source and dest hosts are connected to the same switch. + pathLinks = Collections.emptyList(); + } else { + // Compute shortest path. + Set 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 paths) { + int item = new Random().nextInt(paths.size()); + List 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 93% 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 5ea11801f5..f107c31d2e 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 5d37bd1663..47fad41054 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 @@ import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT 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 @@ public final class PipeconfFactory { .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 a34cada6a2..58afa10d7d 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 @@ package org.onosproject.p4tutorial.pipeconf; 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.driver.AbstractHandlerBehaviour; 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.List; 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.flow.instructions.Instruction.Type.OUTPUT; 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 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 TABLE_MAP = + new ImmutableBiMap.Builder() + .put(0, TABLE_L2_FWD_ID) + .build(); private static final BiMap CRITERION_MAP = new ImmutableBiMap.Builder() @@ -96,129 +111,6 @@ public final class PipelineInterpreterImpl extends AbstractHandlerBehaviour impl .put(Criterion.Type.ETH_TYPE, ETH_TYPE_ID) .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 mapOutboundPacket(OutboundPacket packet) - throws PiInterpreterException { - - TrafficTreatment treatment = packet.treatment(); - - // We support only packet-out with OUTPUT instructions. - List 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 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 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 mapCriterionType(Criterion.Type type) { return Optional.ofNullable(CRITERION_MAP.get(type)); @@ -238,4 +130,139 @@ public final class PipelineInterpreterImpl extends AbstractHandlerBehaviour impl public Optional 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 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 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 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 1f204e286d..f5fd70ccbe 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 java.util.stream.Collectors; 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 discoverPortStatistics() { diff --git a/apps/p4-tutorial/pipeconf/src/main/resources/Makefile b/apps/p4-tutorial/pipeconf/src/main/resources/Makefile index 9a6a8d01c7..adfd7edb19 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 3d059bb978..0000000000 --- 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.p4info b/apps/p4-tutorial/pipeconf/src/main/resources/main.p4info deleted file mode 100644 index c4882d2586..0000000000 --- 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 0000000000..d7b8e81d27 --- /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/main.p4 b/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4 similarity index 51% rename from apps/p4-tutorial/pipeconf/src/main/resources/main.p4 rename to apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4 index 9f0b809c42..7d73489081 100644 --- a/apps/p4-tutorial/pipeconf/src/main/resources/main.p4 +++ b/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4 @@ -17,12 +17,13 @@ #include #include -#define ETH_TYPE_IPV4 0x0800 -#define MAX_PORTS 511 +#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; -const port_t DROP_PORT = 511; //------------------------------------------------------------------------------ // HEADERS @@ -34,6 +35,11 @@ header ethernet_t { 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; @@ -49,46 +55,39 @@ header ipv4_t { 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. - */ +// 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. - */ +// 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. - */ +// 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. - */ +// Metadata can be used to carry information from one table to another. struct metadata_t { - /* Empty. We don't use it in this program. */ + // Empty. We don't use it in this program. } //------------------------------------------------------------------------------ // PARSER //------------------------------------------------------------------------------ -parser ParserImpl(packet_in packet, +parser c_parser(packet_in packet, out headers_t hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { @@ -108,6 +107,15 @@ parser ParserImpl(packet_in packet, 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; } @@ -123,30 +131,48 @@ parser ParserImpl(packet_in packet, // INGRESS PIPELINE //------------------------------------------------------------------------------ -control IngressImpl(inout headers_t hdr, +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 before the - ethernet header (see DeparserImpl). - */ + // 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_egress_port(port_t port) { + action set_out_port(port_t port) { standard_metadata.egress_spec = port; } action _drop() { - standard_metadata.egress_spec = DROP_PORT; + mark_to_drop(); } - table table0 { + 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; @@ -154,71 +180,73 @@ control IngressImpl(inout headers_t hdr, hdr.ethernet.ether_type : ternary; } actions = { - set_egress_port(); + 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 ip_proto_filter_table { + table t_tunnel_fwd { key = { - hdr.ipv4.src_addr : ternary; - hdr.ipv4.protocol : exact; + hdr.my_tunnel.tun_id: exact; } actions = { + set_out_port; + my_tunnel_egress; _drop(); } + default_action = _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. - */ + // 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 pipeline processing, set the egress port as - requested by the controller (packet_out header) and remove the - packet_out header. - */ + // 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 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(); - } - } + // 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(); } } - /* - 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). - */ + // Update port counters at index = ingress or egress port. if (standard_metadata.egress_spec < MAX_PORTS) { - egr_port_counter.count((bit<32>) standard_metadata.egress_spec); + tx_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); + rx_port_counter.count((bit<32>) standard_metadata.ingress_port); } } } @@ -227,13 +255,11 @@ control IngressImpl(inout headers_t hdr, // EGRESS PIPELINE //------------------------------------------------------------------------------ -control EgressImpl(inout headers_t hdr, - inout metadata_t meta, - inout standard_metadata_t standard_metadata) { +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. - */ + // Nothing to do on the egress pipeline. } } @@ -241,19 +267,15 @@ control EgressImpl(inout headers_t hdr, // CHECKSUM HANDLING //------------------------------------------------------------------------------ -control VerifyChecksumImpl(in headers_t hdr, inout metadata_t meta) { +control c_verify_checksum(inout headers_t hdr, inout metadata_t meta) { apply { - /* - Nothing to do here, we assume checksum is always correct. - */ + // Nothing to do here, we assume checksum is always correct. } } -control ComputeChecksumImpl(inout headers_t hdr, inout metadata_t meta) { +control c_compute_checksum(inout headers_t hdr, inout metadata_t meta) { apply { - /* - Nothing to do here, as we do not modify packet headers. - */ + // No need to compute checksum as we do not modify packet headers. } } @@ -261,13 +283,13 @@ control ComputeChecksumImpl(inout headers_t hdr, inout metadata_t meta) { // DEPARSER //------------------------------------------------------------------------------ -control DeparserImpl(packet_out packet, in headers_t hdr) { +control c_deparser(packet_out packet, in headers_t hdr) { apply { - /* - Deparse headers in order. Only valid headers are emitted. - */ + // 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); } } @@ -276,9 +298,9 @@ control DeparserImpl(packet_out packet, in headers_t hdr) { // SWITCH INSTANTIATION //------------------------------------------------------------------------------ -V1Switch(ParserImpl(), - VerifyChecksumImpl(), - IngressImpl(), - EgressImpl(), - ComputeChecksumImpl(), - DeparserImpl()) main; +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 0000000000..e8685f14b1 --- /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 5d422a22ab..13f485af66 100644 --- a/modules.defs +++ b/modules.defs @@ -233,7 +233,7 @@ ONOS_APPS = [ '//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',