mirror of
https://github.com/opennetworkinglab/onos.git
synced 2026-05-05 20:26:16 +02:00
MyTunnel P4 tutorial app and pipeconf
Change-Id: I0549276fc7f6c8d0d244d6c52b1b9e85b9c3e13c
This commit is contained in:
parent
181f3f46cc
commit
700648c993
@ -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',
|
||||
]
|
||||
)
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
apps/p4-tutorial/mytunnel/BUCK
Normal file
24
apps/p4-tutorial/mytunnel/BUCK
Normal file
@ -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',
|
||||
]
|
||||
)
|
||||
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright 2017-present Open Networking Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.onosproject.p4tutorial.mytunnel;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.felix.scr.annotations.Activate;
|
||||
import org.apache.felix.scr.annotations.Component;
|
||||
import org.apache.felix.scr.annotations.Deactivate;
|
||||
import org.apache.felix.scr.annotations.Reference;
|
||||
import org.apache.felix.scr.annotations.ReferenceCardinality;
|
||||
import org.onlab.packet.IpAddress;
|
||||
import org.onosproject.core.ApplicationId;
|
||||
import org.onosproject.core.CoreService;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.Host;
|
||||
import org.onosproject.net.Link;
|
||||
import org.onosproject.net.Path;
|
||||
import org.onosproject.net.PortNumber;
|
||||
import org.onosproject.net.flow.DefaultFlowRule;
|
||||
import org.onosproject.net.flow.DefaultTrafficSelector;
|
||||
import org.onosproject.net.flow.DefaultTrafficTreatment;
|
||||
import org.onosproject.net.flow.FlowRule;
|
||||
import org.onosproject.net.flow.FlowRuleService;
|
||||
import org.onosproject.net.flow.criteria.PiCriterion;
|
||||
import org.onosproject.net.host.HostEvent;
|
||||
import org.onosproject.net.host.HostListener;
|
||||
import org.onosproject.net.host.HostService;
|
||||
import org.onosproject.net.pi.model.PiActionId;
|
||||
import org.onosproject.net.pi.model.PiActionParamId;
|
||||
import org.onosproject.net.pi.model.PiMatchFieldId;
|
||||
import org.onosproject.net.pi.model.PiTableId;
|
||||
import org.onosproject.net.pi.runtime.PiAction;
|
||||
import org.onosproject.net.pi.runtime.PiActionParam;
|
||||
import org.onosproject.net.topology.Topology;
|
||||
import org.onosproject.net.topology.TopologyService;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.onlab.util.ImmutableByteSequence.copyFrom;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
/**
|
||||
* MyTunnel application which provides forwarding between each pair of hosts via
|
||||
* MyTunnel protocol as defined in mytunnel.p4.
|
||||
* <p>
|
||||
* The app works by listening for host events. Each time a new host is
|
||||
* discovered, it provisions a tunnel between that host and all the others.
|
||||
*/
|
||||
@Component(immediate = true)
|
||||
public class MyTunnelApp {
|
||||
|
||||
private static final String APP_NAME = "org.onosproject.p4tutorial.mytunnel";
|
||||
|
||||
// Default priority used for flow rules installed by this app.
|
||||
private static final int FLOW_RULE_PRIORITY = 100;
|
||||
|
||||
private final HostListener hostListener = new InternalHostListener();
|
||||
private ApplicationId appId;
|
||||
private AtomicInteger nextTunnelId = new AtomicInteger();
|
||||
|
||||
private static final Logger log = getLogger(MyTunnelApp.class);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// P4 program entity names. Values derived from mytunnel.p4info
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Match field IDs.
|
||||
private static final PiMatchFieldId MF_ID_MY_TUNNEL_DST_ID =
|
||||
PiMatchFieldId.of("hdr.my_tunnel.tun_id");
|
||||
private static final PiMatchFieldId MF_ID_IP_DST =
|
||||
PiMatchFieldId.of("hdr.ipv4.dst_addr");
|
||||
// Table IDs.
|
||||
private static final PiTableId TBL_ID_TUNNEL_FWD =
|
||||
PiTableId.of("c_ingress.t_tunnel_fwd");
|
||||
private static final PiTableId TBL_ID_TUNNEL_INGRESS =
|
||||
PiTableId.of("c_ingress.t_tunnel_ingress");
|
||||
// Action IDs.
|
||||
private static final PiActionId ACT_ID_MY_TUNNEL_INGRESS =
|
||||
PiActionId.of("c_ingress.my_tunnel_ingress");
|
||||
private static final PiActionId ACT_ID_SET_OUT_PORT =
|
||||
PiActionId.of("c_ingress.set_out_port");
|
||||
private static final PiActionId ACT_ID_MY_TUNNEL_EGRESS =
|
||||
PiActionId.of("c_ingress.my_tunnel_egress");
|
||||
|
||||
// Action params ID.
|
||||
private static final PiActionParamId ACT_PARAM_ID_TUN_ID =
|
||||
PiActionParamId.of("tun_id");
|
||||
private static final PiActionParamId ACT_PARAM_ID_PORT =
|
||||
PiActionParamId.of("port");
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// ONOS services needed by this application.
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
private FlowRuleService flowRuleService;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
private CoreService coreService;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
private TopologyService topologyService;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
private HostService hostService;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
@Activate
|
||||
public void activate() {
|
||||
// Register app and event listeners.
|
||||
log.info("Starting...");
|
||||
appId = coreService.registerApplication(APP_NAME);
|
||||
hostService.addListener(hostListener);
|
||||
log.info("STARTED", appId.id());
|
||||
}
|
||||
|
||||
@Deactivate
|
||||
public void deactivate() {
|
||||
// Remove listeners and clean-up flow rules.
|
||||
log.info("Stopping...");
|
||||
hostService.removeListener(hostListener);
|
||||
flowRuleService.removeFlowRulesById(appId);
|
||||
log.info("STOPPED");
|
||||
}
|
||||
|
||||
/**
|
||||
* Provisions a tunnel between the given source and destination host with
|
||||
* the given tunnel ID. The tunnel is established using a randomly picked
|
||||
* shortest path based on the given topology snapshot.
|
||||
*
|
||||
* @param tunId tunnel ID
|
||||
* @param srcHost tunnel source host
|
||||
* @param dstHost tunnel destination host
|
||||
* @param topo topology snapshot
|
||||
*/
|
||||
private void provisionTunnel(int tunId, Host srcHost, Host dstHost, Topology topo) {
|
||||
|
||||
// Get all shortest paths between switches connected to source and
|
||||
// destination hosts.
|
||||
DeviceId srcSwitch = srcHost.location().deviceId();
|
||||
DeviceId dstSwitch = dstHost.location().deviceId();
|
||||
|
||||
List<Link> pathLinks;
|
||||
if (srcSwitch.equals(dstSwitch)) {
|
||||
// Source and dest hosts are connected to the same switch.
|
||||
pathLinks = Collections.emptyList();
|
||||
} else {
|
||||
// Compute shortest path.
|
||||
Set<Path> allPaths = topologyService.getPaths(topo, srcSwitch, dstSwitch);
|
||||
if (allPaths.size() == 0) {
|
||||
log.warn("No paths between {} and {}", srcHost.id(), dstHost.id());
|
||||
return;
|
||||
}
|
||||
// If many shortest paths are available, pick a random one.
|
||||
pathLinks = pickRandomPath(allPaths).links();
|
||||
}
|
||||
|
||||
// Tunnel ingress rules.
|
||||
for (IpAddress dstIpAddr : dstHost.ipAddresses()) {
|
||||
// In ONOS discovered hosts can have multiple IP addresses.
|
||||
// Insert tunnel ingress rule for each IP address.
|
||||
// Next switches will forward based only on tunnel ID.
|
||||
insertIngressRule(srcSwitch, dstIpAddr, tunId);
|
||||
}
|
||||
|
||||
// Insert tunnel forward rules on all switches in the path, excluded the
|
||||
// last one.
|
||||
for (Link link : pathLinks) {
|
||||
DeviceId sw = link.src().deviceId();
|
||||
PortNumber port = link.src().port();
|
||||
insertForwardRule(sw, port, tunId, false);
|
||||
}
|
||||
|
||||
// Tunnel egress rule.
|
||||
PortNumber egressSwitchPort = dstHost.location().port();
|
||||
insertForwardRule(dstSwitch, egressSwitchPort, tunId, true);
|
||||
|
||||
log.info("** Completed provisioning of tunnel {} (srcHost={} dstHost={})",
|
||||
tunId, srcHost.id(), dstHost.id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and insert a flow rule to perform the tunnel INGRESS function
|
||||
* for the given switch, destination IP address and tunnel ID.
|
||||
*
|
||||
* @param switchId switch ID
|
||||
* @param dstIpAddr IP address to forward inside the tunnel
|
||||
* @param tunId tunnel ID
|
||||
*/
|
||||
private void insertIngressRule(DeviceId switchId,
|
||||
IpAddress dstIpAddr,
|
||||
int tunId) {
|
||||
|
||||
log.info("Inserting INGRESS rule: switchId={}, dstIpAddr={}, tunId={}",
|
||||
switchId, dstIpAddr, tunId);
|
||||
|
||||
PiCriterion match = PiCriterion.builder()
|
||||
.matchLpm(MF_ID_IP_DST, dstIpAddr.toOctets(), 32)
|
||||
.build();
|
||||
|
||||
PiAction action = PiAction.builder()
|
||||
.withId(ACT_ID_MY_TUNNEL_INGRESS)
|
||||
.withParameter(new PiActionParam(
|
||||
ACT_PARAM_ID_TUN_ID, copyFrom(tunId)))
|
||||
.build();
|
||||
|
||||
insertPiFlowRule(switchId, TBL_ID_TUNNEL_INGRESS, match, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and insert a flow rule to perform the tunnel FORWARD/EGRESS
|
||||
* function for the given switch, output port address and tunnel ID.
|
||||
*
|
||||
* @param switchId switch ID
|
||||
* @param outPort output port where to forward tunneled packets
|
||||
* @param tunId tunnel ID
|
||||
* @param isEgress if true, perform tunnel egress action, otherwise forward
|
||||
* packet as is to port
|
||||
*/
|
||||
private void insertForwardRule(DeviceId switchId,
|
||||
PortNumber outPort,
|
||||
int tunId,
|
||||
boolean isEgress) {
|
||||
|
||||
log.info("Inserting {} rule: switchId={}, outPort={}, tunId={}",
|
||||
isEgress ? "EGRESS" : "FORWARD", switchId, outPort, tunId);
|
||||
|
||||
PiCriterion match = PiCriterion.builder()
|
||||
.matchExact(MF_ID_MY_TUNNEL_DST_ID, tunId)
|
||||
.build();
|
||||
|
||||
PiActionId actionId = isEgress ? ACT_ID_MY_TUNNEL_EGRESS : ACT_ID_SET_OUT_PORT;
|
||||
|
||||
PiAction action = PiAction.builder()
|
||||
.withId(actionId)
|
||||
.withParameter(new PiActionParam(
|
||||
ACT_PARAM_ID_PORT, copyFrom((short) outPort.toLong())))
|
||||
.build();
|
||||
|
||||
insertPiFlowRule(switchId, TBL_ID_TUNNEL_FWD, match, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a flow rule in the system that using a PI criterion and action.
|
||||
*
|
||||
* @param switchId switch ID
|
||||
* @param tableId table ID
|
||||
* @param piCriterion PI criterion
|
||||
* @param piAction PI action
|
||||
*/
|
||||
private void insertPiFlowRule(DeviceId switchId, PiTableId tableId,
|
||||
PiCriterion piCriterion, PiAction piAction) {
|
||||
FlowRule rule = DefaultFlowRule.builder()
|
||||
.forDevice(switchId)
|
||||
.forTable(tableId)
|
||||
.fromApp(appId)
|
||||
.withPriority(FLOW_RULE_PRIORITY)
|
||||
.makePermanent()
|
||||
.withSelector(DefaultTrafficSelector.builder()
|
||||
.matchPi(piCriterion).build())
|
||||
.withTreatment(DefaultTrafficTreatment.builder()
|
||||
.piTableAction(piAction).build())
|
||||
.build();
|
||||
flowRuleService.applyFlowRules(rule);
|
||||
}
|
||||
|
||||
private int getNewTunnelId() {
|
||||
return nextTunnelId.incrementAndGet();
|
||||
}
|
||||
|
||||
private Path pickRandomPath(Set<Path> paths) {
|
||||
int item = new Random().nextInt(paths.size());
|
||||
List<Path> pathList = Lists.newArrayList(paths);
|
||||
return pathList.get(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* A listener of host events that provisions two tunnels for each pair of
|
||||
* hosts when a new host is discovered.
|
||||
*/
|
||||
private class InternalHostListener implements HostListener {
|
||||
|
||||
@Override
|
||||
public void event(HostEvent event) {
|
||||
if (event.type() != HostEvent.Type.HOST_ADDED) {
|
||||
// Ignore other host events.
|
||||
return;
|
||||
}
|
||||
synchronized (this) {
|
||||
// Synchronizing here is an overkill, but safer for demo purposes.
|
||||
Host host = event.subject();
|
||||
Topology topo = topologyService.currentTopology();
|
||||
for (Host otherHost : hostService.getHosts()) {
|
||||
if (!host.equals(otherHost)) {
|
||||
provisionTunnel(getNewTunnelId(), host, otherHost, topo);
|
||||
provisionTunnel(getNewTunnelId(), otherHost, host, topo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -16,4 +16,4 @@
|
||||
/**
|
||||
* P4 tutorial application classes.
|
||||
*/
|
||||
package org.onosproject.p4tutorial.icmpdropper;
|
||||
package org.onosproject.p4tutorial.mytunnel;
|
||||
@ -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)
|
||||
|
||||
@ -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<Integer, PiTableId> TABLE_MAP = ImmutableBiMap.of(
|
||||
0, TABLE0_ID,
|
||||
1, IP_PROTO_FILTER_TABLE_ID);
|
||||
private static final PiTableId TABLE_L2_FWD_ID =
|
||||
PiTableId.of(C_INGRESS + DOT + T_L2_FWD);
|
||||
|
||||
private static final PiActionId ACT_ID_NOP =
|
||||
PiActionId.of("NoAction");
|
||||
private static final PiActionId ACT_ID_SEND_TO_CPU =
|
||||
PiActionId.of(C_INGRESS + DOT + "send_to_cpu");
|
||||
private static final PiActionId ACT_ID_SET_EGRESS_PORT =
|
||||
PiActionId.of(C_INGRESS + DOT + "set_egress_port");
|
||||
|
||||
private static final PiActionParamId ACT_PARAM_ID_PORT =
|
||||
PiActionParamId.of("port");
|
||||
|
||||
private static final BiMap<Integer, PiTableId> TABLE_MAP =
|
||||
new ImmutableBiMap.Builder<Integer, PiTableId>()
|
||||
.put(0, TABLE_L2_FWD_ID)
|
||||
.build();
|
||||
|
||||
private static final BiMap<Criterion.Type, PiMatchFieldId> CRITERION_MAP =
|
||||
new ImmutableBiMap.Builder<Criterion.Type, PiMatchFieldId>()
|
||||
@ -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<PiPacketOperation> mapOutboundPacket(OutboundPacket packet)
|
||||
throws PiInterpreterException {
|
||||
|
||||
TrafficTreatment treatment = packet.treatment();
|
||||
|
||||
// We support only packet-out with OUTPUT instructions.
|
||||
List<Instructions.OutputInstruction> outInstructions = treatment.allInstructions().stream()
|
||||
.filter(i -> i.type().equals(OUTPUT))
|
||||
.map(i -> (Instructions.OutputInstruction) i)
|
||||
.collect(toList());
|
||||
|
||||
if (treatment.allInstructions().size() != outInstructions.size()) {
|
||||
// There are other instructions that are not of type OUTPUT.
|
||||
throw new PiInterpreterException("Treatment not supported: " + treatment);
|
||||
}
|
||||
|
||||
ImmutableList.Builder<PiPacketOperation> builder = ImmutableList.builder();
|
||||
|
||||
for (Instructions.OutputInstruction outInst : outInstructions) {
|
||||
if (outInst.port().isLogical() && !outInst.port().equals(FLOOD)) {
|
||||
throw new PiInterpreterException(format("Output on logical port '%s' not supported", outInst.port()));
|
||||
} else if (outInst.port().equals(FLOOD)) {
|
||||
// Since main.p4 does not support flooding, we create a packet operation for each switch port.
|
||||
DeviceService deviceService = handler().get(DeviceService.class);
|
||||
for (Port port : deviceService.getPorts(packet.sendThrough())) {
|
||||
builder.add(createPiPacketOperation(packet.data(), port.number().toLong()));
|
||||
}
|
||||
} else {
|
||||
builder.add(createPiPacketOperation(packet.data(), outInst.port().toLong()));
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InboundPacket mapInboundPacket(PiPacketOperation packetIn)
|
||||
throws PiInterpreterException {
|
||||
// We assume that the packet is ethernet, which is fine since default.p4 can deparse only ethernet packets.
|
||||
Ethernet ethPkt;
|
||||
try {
|
||||
ethPkt = Ethernet.deserializer().deserialize(packetIn.data().asArray(), 0, packetIn.data().size());
|
||||
} catch (DeserializationException dex) {
|
||||
throw new PiInterpreterException(dex.getMessage());
|
||||
}
|
||||
|
||||
// Returns the ingress port packet metadata.
|
||||
Optional<PiControlMetadata> packetMetadata = packetIn.metadatas().stream()
|
||||
.filter(metadata -> metadata.id().toString().equals(INGRESS_PORT))
|
||||
.findFirst();
|
||||
|
||||
if (packetMetadata.isPresent()) {
|
||||
ImmutableByteSequence portByteSequence = packetMetadata.get().value();
|
||||
short s = portByteSequence.asReadOnlyBuffer().getShort();
|
||||
ConnectPoint receivedFrom = new ConnectPoint(packetIn.deviceId(), PortNumber.portNumber(s));
|
||||
return new DefaultInboundPacket(receivedFrom, ethPkt, packetIn.data().asReadOnlyBuffer());
|
||||
} else {
|
||||
throw new PiInterpreterException(format(
|
||||
"Missing metadata '%s' in packet-in received from '%s': %s",
|
||||
INGRESS_PORT, packetIn.deviceId(), packetIn));
|
||||
}
|
||||
}
|
||||
|
||||
private PiPacketOperation createPiPacketOperation(ByteBuffer data, long portNumber) throws PiInterpreterException {
|
||||
PiControlMetadata metadata = createControlMetadata(portNumber);
|
||||
return PiPacketOperation.builder()
|
||||
.forDevice(this.data().deviceId())
|
||||
.withType(PACKET_OUT)
|
||||
.withData(copyFrom(data))
|
||||
.withMetadatas(ImmutableList.of(metadata))
|
||||
.build();
|
||||
}
|
||||
|
||||
private PiControlMetadata createControlMetadata(long portNumber) throws PiInterpreterException {
|
||||
try {
|
||||
return PiControlMetadata.builder()
|
||||
.withId(PiControlMetadataId.of(EGRESS_PORT))
|
||||
.withValue(copyFrom(portNumber).fit(PORT_FIELD_BITWIDTH))
|
||||
.build();
|
||||
} catch (ImmutableByteSequence.ByteSequenceTrimException e) {
|
||||
throw new PiInterpreterException(format("Port number %d too big, %s", portNumber, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<PiMatchFieldId> mapCriterionType(Criterion.Type type) {
|
||||
return Optional.ofNullable(CRITERION_MAP.get(type));
|
||||
@ -238,4 +130,139 @@ public final class PipelineInterpreterImpl extends AbstractHandlerBehaviour impl
|
||||
public Optional<Integer> mapPiTableId(PiTableId piTableId) {
|
||||
return Optional.ofNullable(TABLE_MAP.inverse().get(piTableId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PiAction mapTreatment(TrafficTreatment treatment, PiTableId piTableId)
|
||||
throws PiInterpreterException {
|
||||
|
||||
if (piTableId != TABLE_L2_FWD_ID) {
|
||||
throw new PiInterpreterException(
|
||||
"Can map treatments only for 't_l2_fwd' table");
|
||||
}
|
||||
|
||||
if (treatment.allInstructions().size() == 0) {
|
||||
// 0 instructions means "NoAction"
|
||||
return PiAction.builder().withId(ACT_ID_NOP).build();
|
||||
} else if (treatment.allInstructions().size() > 1) {
|
||||
// We understand treatments with only 1 instruction.
|
||||
throw new PiInterpreterException("Treatment has multiple instructions");
|
||||
}
|
||||
|
||||
// Get the first and only instruction.
|
||||
Instruction instruction = treatment.allInstructions().get(0);
|
||||
|
||||
if (instruction.type() != OUTPUT) {
|
||||
// We can map only instructions of type OUTPUT.
|
||||
throw new PiInterpreterException(format(
|
||||
"Instruction of type '%s' not supported", instruction.type()));
|
||||
}
|
||||
|
||||
OutputInstruction outInstruction = (OutputInstruction) instruction;
|
||||
PortNumber port = outInstruction.port();
|
||||
if (!port.isLogical()) {
|
||||
return PiAction.builder()
|
||||
.withId(ACT_ID_SET_EGRESS_PORT)
|
||||
.withParameter(new PiActionParam(
|
||||
ACT_PARAM_ID_PORT, copyFrom(port.toLong())))
|
||||
.build();
|
||||
} else if (port.equals(CONTROLLER)) {
|
||||
return PiAction.builder()
|
||||
.withId(ACT_ID_SEND_TO_CPU)
|
||||
.build();
|
||||
} else {
|
||||
throw new PiInterpreterException(format(
|
||||
"Output on logical port '%s' not supported", port));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PiPacketOperation> mapOutboundPacket(OutboundPacket packet)
|
||||
throws PiInterpreterException {
|
||||
|
||||
TrafficTreatment treatment = packet.treatment();
|
||||
|
||||
// We support only packet-out with OUTPUT instructions.
|
||||
if (treatment.allInstructions().size() != 1 &&
|
||||
treatment.allInstructions().get(0).type() != OUTPUT) {
|
||||
throw new PiInterpreterException(
|
||||
"Treatment not supported: " + treatment.toString());
|
||||
}
|
||||
|
||||
Instruction instruction = treatment.allInstructions().get(0);
|
||||
PortNumber port = ((OutputInstruction) instruction).port();
|
||||
List<PiPacketOperation> piPacketOps = Lists.newArrayList();
|
||||
|
||||
if (!port.isLogical()) {
|
||||
piPacketOps.add(createPiPacketOp(packet.data(), port.toLong()));
|
||||
} else if (port.equals(FLOOD)) {
|
||||
// Since mytunnel.p4 does not support flooding, we create a packet
|
||||
// operation for each switch port.
|
||||
DeviceService deviceService = handler().get(DeviceService.class);
|
||||
DeviceId deviceId = packet.sendThrough();
|
||||
for (Port p : deviceService.getPorts(deviceId)) {
|
||||
piPacketOps.add(createPiPacketOp(packet.data(), p.number().toLong()));
|
||||
}
|
||||
} else {
|
||||
throw new PiInterpreterException(format(
|
||||
"Output on logical port '%s' not supported", port));
|
||||
}
|
||||
|
||||
return piPacketOps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InboundPacket mapInboundPacket(PiPacketOperation packetIn)
|
||||
throws PiInterpreterException {
|
||||
// We assume that the packet is ethernet, which is fine since mytunnel.p4
|
||||
// can deparse only ethernet packets.
|
||||
Ethernet ethPkt;
|
||||
|
||||
try {
|
||||
ethPkt = Ethernet.deserializer().deserialize(
|
||||
packetIn.data().asArray(), 0, packetIn.data().size());
|
||||
} catch (DeserializationException dex) {
|
||||
throw new PiInterpreterException(dex.getMessage());
|
||||
}
|
||||
|
||||
// Returns the ingress port packet metadata.
|
||||
Optional<PiControlMetadata> packetMetadata = packetIn.metadatas().stream()
|
||||
.filter(metadata -> metadata.id().toString().equals(INGRESS_PORT))
|
||||
.findFirst();
|
||||
|
||||
if (packetMetadata.isPresent()) {
|
||||
short s = packetMetadata.get().value().asReadOnlyBuffer().getShort();
|
||||
ConnectPoint receivedFrom = new ConnectPoint(
|
||||
packetIn.deviceId(), PortNumber.portNumber(s));
|
||||
return new DefaultInboundPacket(
|
||||
receivedFrom, ethPkt, packetIn.data().asReadOnlyBuffer());
|
||||
} else {
|
||||
throw new PiInterpreterException(format(
|
||||
"Missing metadata '%s' in packet-in received from '%s': %s",
|
||||
INGRESS_PORT, packetIn.deviceId(), packetIn));
|
||||
}
|
||||
}
|
||||
|
||||
private PiPacketOperation createPiPacketOp(ByteBuffer data, long portNumber)
|
||||
throws PiInterpreterException {
|
||||
PiControlMetadata metadata = createControlMetadata(portNumber);
|
||||
return PiPacketOperation.builder()
|
||||
.forDevice(this.data().deviceId())
|
||||
.withType(PACKET_OUT)
|
||||
.withData(copyFrom(data))
|
||||
.withMetadatas(ImmutableList.of(metadata))
|
||||
.build();
|
||||
}
|
||||
|
||||
private PiControlMetadata createControlMetadata(long portNumber)
|
||||
throws PiInterpreterException {
|
||||
try {
|
||||
return PiControlMetadata.builder()
|
||||
.withId(PiControlMetadataId.of(EGRESS_PORT))
|
||||
.withValue(copyFrom(portNumber).fit(PORT_FIELD_BITWIDTH))
|
||||
.build();
|
||||
} catch (ImmutableByteSequence.ByteSequenceTrimException e) {
|
||||
throw new PiInterpreterException(format(
|
||||
"Port number %d too big, %s", portNumber, e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<PortStatistics> discoverPortStatistics() {
|
||||
|
||||
@ -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
|
||||
mytunnel: mytunnel.p4
|
||||
p4c-bm2-ss -o mytunnel.json --p4runtime-file mytunnel.p4info --p4runtime-format text mytunnel.p4
|
||||
|
||||
@ -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"]
|
||||
]
|
||||
]
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
1552
apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.json
Normal file
1552
apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -17,12 +17,13 @@
|
||||
#include <core.p4>
|
||||
#include <v1model.p4>
|
||||
|
||||
#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;
|
||||
202
apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4info
Normal file
202
apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4info
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
@ -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',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user