MyTunnel exercise with solution for P4 tutorial
Change-Id: Ifddfa27d6df6545bbd529239ca400967fb623a29
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
index eb91243..c5fac98 100644
--- 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
@@ -55,7 +55,6 @@
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
-import static org.onlab.util.ImmutableByteSequence.copyFrom;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -80,34 +79,6 @@
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.
//--------------------------------------------------------------------------
@@ -181,20 +152,20 @@
// 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);
+ insertTunnelIngressRule(srcSwitch, dstIpAddr, tunId);
}
- // Insert tunnel forward rules on all switches in the path, excluded the
+ // Insert tunnel transit 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);
+ insertTunnelForwardRule(sw, port, tunId, false);
}
// Tunnel egress rule.
PortNumber egressSwitchPort = dstHost.location().port();
- insertForwardRule(dstSwitch, egressSwitchPort, tunId, true);
+ insertTunnelForwardRule(dstSwitch, egressSwitchPort, tunId, true);
log.info("** Completed provisioning of tunnel {} (srcHost={} dstHost={})",
tunId, srcHost.id(), dstHost.id());
@@ -208,24 +179,31 @@
* @param dstIpAddr IP address to forward inside the tunnel
* @param tunId tunnel ID
*/
- private void insertIngressRule(DeviceId switchId,
- IpAddress dstIpAddr,
- int tunId) {
+ private void insertTunnelIngressRule(DeviceId switchId,
+ IpAddress dstIpAddr,
+ int tunId) {
- log.info("Inserting INGRESS rule: switchId={}, dstIpAddr={}, tunId={}",
- switchId, dstIpAddr, tunId);
+ PiTableId tunnelIngressTableId = PiTableId.of("c_ingress.t_tunnel_ingress");
+
+ // Longest prefix match on IPv4 dest address.
+ PiMatchFieldId ipDestMatchFieldId = PiMatchFieldId.of("hdr.ipv4.dst_addr");
PiCriterion match = PiCriterion.builder()
- .matchLpm(MF_ID_IP_DST, dstIpAddr.toOctets(), 32)
+ .matchLpm(ipDestMatchFieldId, dstIpAddr.toOctets(), 32)
.build();
+ PiActionParam tunIdParam = new PiActionParam(PiActionParamId.of("tun_id"), tunId);
+
+ PiActionId ingressActionId = PiActionId.of("c_ingress.my_tunnel_ingress");
PiAction action = PiAction.builder()
- .withId(ACT_ID_MY_TUNNEL_INGRESS)
- .withParameter(new PiActionParam(
- ACT_PARAM_ID_TUN_ID, copyFrom(tunId)))
+ .withId(ingressActionId)
+ .withParameter(tunIdParam)
.build();
- insertPiFlowRule(switchId, TBL_ID_TUNNEL_INGRESS, match, action);
+ log.info("Inserting INGRESS rule on switch {}: table={}, match={}, action={}",
+ switchId, tunnelIngressTableId, match, action);
+
+ insertPiFlowRule(switchId, tunnelIngressTableId, match, action);
}
/**
@@ -234,31 +212,59 @@
*
* @param switchId switch ID
* @param outPort output port where to forward tunneled packets
- * @param tunId tunnel ID
+ * @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) {
+ private void insertTunnelForwardRule(DeviceId switchId,
+ PortNumber outPort,
+ int tunId,
+ boolean isEgress) {
- log.info("Inserting {} rule: switchId={}, outPort={}, tunId={}",
- isEgress ? "EGRESS" : "FORWARD", switchId, outPort, tunId);
+ PiTableId tunnelForwardTableId = PiTableId.of("c_ingress.t_tunnel_fwd");
+ // Exact match on tun_id
+ PiMatchFieldId tunIdMatchFieldId = PiMatchFieldId.of("hdr.my_tunnel.tun_id");
PiCriterion match = PiCriterion.builder()
- .matchExact(MF_ID_MY_TUNNEL_DST_ID, tunId)
+ .matchExact(tunIdMatchFieldId, tunId)
.build();
- PiActionId actionId = isEgress ? ACT_ID_MY_TUNNEL_EGRESS : ACT_ID_SET_OUT_PORT;
+ // Action depend on isEgress parameter.
+ // if true, perform tunnel egress action on the given outPort, otherwise
+ // simply forward packet as is (set_out_port action).
+ PiActionParamId portParamId = PiActionParamId.of("port");
+ PiActionParam portParam = new PiActionParam(portParamId, (short) outPort.toLong());
- PiAction action = PiAction.builder()
- .withId(actionId)
- .withParameter(new PiActionParam(
- ACT_PARAM_ID_PORT, copyFrom((short) outPort.toLong())))
- .build();
+ final PiAction action;
+ if (isEgress) {
+ // Tunnel egress action.
+ // Remove MyTunnel header and forward to outPort.
+ PiActionId egressActionId = PiActionId.of("c_ingress.my_tunnel_egress");
+ action = PiAction.builder()
+ .withId(egressActionId)
+ .withParameter(portParam)
+ .build();
+ } else {
+ // Tunnel transit action.
+ // Forward the packet as is to outPort.
+ /*
+ * TODO EXERCISE: create action object for the transit case.
+ * Look at the t_tunnel_fwd table in the P4 program. Which of the 3
+ * actions can be used to simply set the output port? Get the full
+ * action name from the P4Info file, and use that when creating the
+ * PiActionId object. When creating the PiAction object, remember to
+ * add all action parameters as defined in the P4 program.
+ *
+ * Hint: the code will be similar to the case when isEgress = false.
+ */
+ action = null;
+ }
- insertPiFlowRule(switchId, TBL_ID_TUNNEL_FWD, match, action);
+ log.info("Inserting {} rule on switch {}: table={}, match={}, action={}",
+ isEgress ? "EGRESS" : "TRANSIT",
+ switchId, tunnelForwardTableId, match, action);
+
+ insertPiFlowRule(switchId, tunnelForwardTableId, match, action);
}
/**