P4 tutorial exercise 2
Change-Id: I91f8a9287cdfd57a4a9c03b91fdc0de57b8d4f2c
diff --git a/apps/p4-tutorial/README.md b/apps/p4-tutorial/README.md
index 1aa4f9b..1d11e17 100644
--- a/apps/p4-tutorial/README.md
+++ b/apps/p4-tutorial/README.md
@@ -57,26 +57,33 @@
### MyTunnel Pipeconf
-The `mytunnel.p4` program is provided to ONOS as part of a "pipeconf", along
-with the Java implementations of some ONOS driver behaviors necessary to
-control this pipeline.
+The `mytunnel.p4` program is provided to ONOS as part of a "pipeconf".
-The following Java classes are provided:
-
-* [PipeconfFactory.java](./pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipeconfFactory.java):
+The main class used to implement the pipeconf is
+[PipeconfFactory.java](./pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipeconfFactory.java).
This class is declared as an OSGi component which is "activated" once the
-pipeconf application is loaded in ONOS. The main purpose of this class is to
+pipeconf app is loaded in ONOS. The main purpose of this class is to
instantiate the Pipeconf object and register that with the corresponding service
in ONOS. This is where we associate ONOS driver behaviors with the pipeconf, and
-also define the necessary pipeconf extensions to be able to program and control
-a BMv2 switch via P4Runtime, namelly the BMv2 JSON configuration and the P4Info
-file.
+also define the necessary pipeconf extensions to be able to deploy the P4
+program to a device.
+
+This pipeconf contains:
+
+* [mytunnel.json](/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.json):
+The BMv2 JSON configuration used to execute the P4 program. This is an output of
+the P4 compiler for BMv2.
+
+* [mytunnel.p4info](/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4info):
+P4Info file obtained from the P4 compiler.
* [PipelineInterpreterImple.java](./pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java):
Implementation of the `PipelineInterpreter` ONOS driver behavior. The main
purpose of this class is to provide a mapping between ONOS constructs and P4
program-specific ones, for example methods to map ONOS well-known header fields
-and actions to those defined in the P4 program.
+and actions to those defined in the P4 program. For a more detailed explanation
+of each method, check the
+[PipelineInterpreter interface](./core/api/src/main/java/org/onosproject/net/pi/model/PiPipelineInterpreter.java).
* [PortStatisticsDiscoveryImpl.java](./pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java):
Implementation of the `PortStatisticsDiscovery` ONOS driver behavior. As the
@@ -87,14 +94,10 @@
### MyTunnel App
-This application is used to provide connectivity between each pair of hosts via
+This app is used to provide connectivity between each pair of hosts via
the MyTunnel protocol. The implementation can be found
-[here](./mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/MyTunnelApp.java).
-
-The application works by registering an host listener with the ONOS Host
-Service. Every time a new host is discovered, the application creates two
-unidirectional tunnels between that host and any other host previously
-discovered.
+[here](./mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/MyTunnelApp.java),
+and it will be discussed in more details on Exercise 2.
## Tutorial exercises
@@ -103,7 +106,7 @@
[Click here to go to this exercise instructions](./exercise-1.md)
This exercise shows how to start ONOS and Mininet with BMv2, it also
-demonstrates connectivity between hosts using the pipeline-agnostic application
+demonstrates connectivity between hosts using the pipeline-agnostic app
Reactive Forwarding, in combination with other well known ONOS services such as
Proxy ARP, Host Location Provider, and LLDP Link Discovery.
@@ -112,4 +115,4 @@
[Click here to go to this exercise instructions](./exercise-2.md)
Similar to exercise 1, but here connectivity between hosts is demonstrated using
-pipeline-specific application "MyTunnel".
+pipeline-specific app "MyTunnel".
diff --git a/apps/p4-tutorial/exercise-2.md b/apps/p4-tutorial/exercise-2.md
index 0976af0..401079e 100644
--- a/apps/p4-tutorial/exercise-2.md
+++ b/apps/p4-tutorial/exercise-2.md
@@ -1,3 +1,247 @@
-Exercise 2:
-
-The goal of exercise 2 is to showcase how a pipeline aware application can be used with P4 devices...
+# Exercise 2 (ONOS+P4 Tutorial)
+
+The goal of this exercise is to demonstrate how ONOS apps can be used to
+control any P4-defined pipeline, even those implementing custom non-standard
+protocols.
+
+## Overview
+
+Similarly to exercise 1, in this example we want to provide connectivity between
+hosts of a network when using switches programmed with the `mytunnel.p4`
+program. Differently from exercise 1, forwarding between hosts will be provided
+by the MyTunnel app, instead of Reactive Forwarding. The MyTunnel app provides
+connectivity by programming the dataplane to forward packets via the MyTunnel
+protocol.
+
+Before starting, we suggest to open the onos/apps/p4-tutorial directory in your
+editor of choice for an easier access to the different files of this exercise.
+For example, if using atom:
+
+```
+$ atom $ONOS_ROOT/apps/p4-tutorial/
+```
+
+## Protocol overview
+
+The MyTunnel protocol works by encapsulating IPv4 frames into a MyTunnel header
+defined as following:
+
+```
+header my_tunnel_t {
+ bit<16> proto_id; /* EtherType of the original
+ unencapsulated Ethernet frame */
+ bit<32> tun_id; /* Arbitrary tunnel identifier uniquelly
+ representing the egress endpoint of the tunnel */
+}
+```
+
+A switch implementing the MyTunnel protocol can forward packets using three
+different forwarding behaviors:
+
+1. **Ingress**: for IPv4 packets received at a edge switch, i.e. the first node
+in the tunnel path, the MyTunnel header is applied with an arbitrary tunnel
+identifier decided by the control plane.
+
+2. **Transit**: for packets with the MyTunnel header processed by an
+intermediate node in the tunnel path, the switch simply forwards the packet by
+looking at the tunnel ID field.
+
+3. **Egress**: for packets with the MyTunnel header processed by the last node
+in the path, the switch removes the MyTunnel header before forwarding the packet
+to the output port.
+
+## MyTunnel pipeline overview
+
+The three forwarding behaviors described before can be achieved by inserting
+entries in two different tables of `mytunnel.p4`, namely `t_tunnel_ingress` and
+`t_tunnel_fwd`.
+
+* `t_tunnel_ingress`: this table is used to implement the ingress behavior. It
+matches on the IPv4 destination address (longest-prefix match), and provides
+the `my_tunnel_ingress` action, which encapsulates the packet in the MyTunnel
+header with a given tunnel ID (action parameter).
+
+* `t_tunnel_fwd`: this table is used to implement both the transit and egress
+behaviors. It matches on the tunnel ID, and allows two different actions,
+`set_out_port` and `my_tunnel_egress`. `set_out_port` is used to set the
+output port where the packet should be transmitted, without further
+modifications. With `my_tunnel_egress`, the packet is stripped of the MyTunnel
+header before setting the output port.
+
+## MyTunnel app overview
+
+To begin, open
+[MyTunnelApp.java](./mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/MyTunnelApp.java)
+in your editor of choice, and familiarize with the app implementation.
+
+The file is located here:
+
+```
+$ONOS_ROOT/apps/mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/MyTunnelApp.java
+```
+
+The MyTunnel app works by registering an event listener with the ONOS Host
+Service (`class InternalHostListener` at line 308). This listener is used to
+notify the MyTunnel app every time a new host is discovered. Host discovery is
+performed by the Proxy-ARP app. Each time an ARP request is received (via
+packet-in), ONOS learns the location of the sender of the ARP request, before
+generating an ARP reply or forwarding the requests to other hosts. When learning
+the location of a new host, ONOS informs all apps that have registered a
+listener with an `HOST_ADDED` event.
+
+Once an `HOST_ADDED` event is notified to the MyTunnel app, this creates two
+unidirectional tunnels between that host and any other host previously
+discovered. For each tunnel, the app computes the shortest path between the two
+hosts (method `provisionTunnel` at line 128), and for each switch in the path it
+installs flow rules for the `t_tunnel_ingress` table (method
+`insertTunnelIngressRule` at line 182), and/or the `t_tunnel_fwd` table (method
+`insertTunnelForwardRule` at line 219), depending on the position of the switch
+in the path, the app will install rule to perform the ingress, transit, or
+egress behaviors.
+
+## Exercise steps
+
+1. **Complete the implementation of the MyTunnel app**:
+
+ 1. Open [MyTunnelApp.java](./mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/MyTunnelApp.java) in your editor of choice.
+
+ 2. Look for the `insertTunnelForwardRule` method (line 219).
+
+ 3. Complete the implementation of this method (There's a `TODO EXERCISE`
+ comment at line 251).
+
+ **Spoiler alert:** There is a reference solution in the same directory
+ as MyTunnelApp.java. Feel free to compare your implementation to the
+ reference.
+
+2. **Start ONOS with and all the apps**.
+
+ 1. On a first terminal window, start ONOS:
+
+ ```
+ $ cd $ONOS_ROOT
+ $ ONOS_APPS=proxyarp,hostprovider,lldpprovider ok clean
+ ```
+
+ 2. On a second terminal window to **access the ONOS CLI**:
+
+ ```
+ $ onos localhost
+ ```
+
+ 2. **Acticate the BMv2 drivers, pipeconf, and MyTunnel app**:
+
+ ```
+ onos> app activate org.onosproject.drivers.bmv2
+ onos> app activate org.onosproject.p4tutorial.pipeconf
+ onos> app activate org.onosproject.p4tutorial.pipeconf
+ ```
+
+ **Hint:** To avoid accessing the CLI to start all applications, you can
+ modify the value of the `ONOS_APPS` variable when starting ONOS. For
+ example:
+
+ ```
+ $ cd $ONOS_ROOT
+ $ ONOS_APPS=proxyarp,hostprovider,lldpprovider,drivers.bmv2,p4tutorial.pipeconf,p4tutorial.pipeconf ok clean
+ ```
+
+ 3. **Check that all apps have been activated successfully**:
+
+ ```
+ onos> apps -s -a
+ ```
+
+ You should see an output like this:
+
+ ```
+ * 5 org.onosproject.hostprovider 1.14.0.SNAPSHOT Host Location Provider
+ * 6 org.onosproject.lldpprovider 1.14.0.SNAPSHOT LLDP Link Provider
+ * 16 org.onosproject.proxyarp 1.14.0.SNAPSHOT Proxy ARP/NDP
+ * 20 org.onosproject.drivers 1.14.0.SNAPSHOT Default Drivers
+ * 42 org.onosproject.protocols.grpc 1.14.0.SNAPSHOT gRPC Protocol Subsystem
+ * 43 org.onosproject.protocols.p4runtime 1.14.0.SNAPSHOT P4Runtime Protocol Subsystem
+ * 44 org.onosproject.p4runtime 1.14.0.SNAPSHOT P4Runtime Provider
+ * 50 org.onosproject.generaldeviceprovider 1.14.0.SNAPSHOT General Device Provider
+ * 51 org.onosproject.drivers.p4runtime 1.14.0.SNAPSHOT P4Runtime Drivers
+ * 52 org.onosproject.p4tutorial.pipeconf 1.14.0.SNAPSHOT P4 Tutorial Pipeconf
+ * 79 org.onosproject.pipelines.basic 1.14.0.SNAPSHOT Basic Pipelines
+ * 90 org.onosproject.protocols.gnmi 1.14.0.SNAPSHOT gNMI Protocol Subsystem
+ * 91 org.onosproject.drivers.gnmi 1.14.0.SNAPSHOT gNMI Drivers
+ * 160 org.onosproject.drivers.bmv2 1.14.0.SNAPSHOT BMv2 Drivers
+ ```
+
+ 4. (optional) **Change flow rule polling interval**. Run the following
+ command in the ONOS CLI:
+
+ ```
+ onos> cfg set org.onosproject.net.flow.impl.FlowRuleManager fallbackFlowPollFrequency 5
+ ```
+
+3. **Run Mininet to set up a tree topology of BMv2 devices**, on a new terminal
+window type:
+
+ ```
+ $ sudo -E mn --custom $BMV2_MN_PY --switch onosbmv2,pipeconf=p4-tutorial-pipeconf --topo tree,3 --controller remote,ip=127.0.0.1
+ ```
+
+4. **Check that all devices, link, and hosts have been discovered correctly in ONOS**.
+
+ 1. To check the devices, on the ONOS CLI, type:
+
+ ```
+ onos> devices -s
+ ```
+
+ The `-s` argument provides a more compact output.
+
+ You should see 7 devices in total. Please note the driver that has been
+ assigned to this device `bmv2:p4-tutorial-pipeconf`. It means that the
+ device is being controlled using the driver behaviors provided the BMv2
+ device driver (which uses P4Runtime) and the pipeconf.
+
+ 2. Check the links:
+
+ ```
+ onos> links
+ ```
+
+ The `-s` argument provides a more compact output.
+
+ You should see 12 links (the topology has 6 bidirectional links in total).
+
+ 3. Check the hosts:
+
+ ```
+ onos> hosts -s
+ ```
+
+ You should see 0 hosts, as we have not injected any ARP packet yet.
+
+5. **Ping hosts**
+
+ 1. On the Mininet CLI, type:
+
+ ```
+ mininet> h1 ping h7
+ ```
+
+ If the implementation of MyTunnelApp.java has been completed correctly,
+ ping should work. If not, check the reference solution in the same
+ directory as MyTunnelApp.java.
+
+ 2. Check the ONOS log, you should see messages from the MyTunnel app setting
+ up the tunnel.
+
+6. **Look around**.
+
+ 1. Repeat step 3.v and 3.vi from exercise one to check the
+flow rules in ONOS and on BMv2.
+
+ 2. Check the hosts in ONOS:
+
+ ```
+ onos> hosts -s
+ ```
+
+ You should see 2 hosts, h1 and h7.
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 c5fac98..5acc434 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
@@ -79,7 +79,7 @@
private static final Logger log = getLogger(MyTunnelApp.class);
//--------------------------------------------------------------------------
- // ONOS services needed by this application.
+ // ONOS core services needed by this application.
//--------------------------------------------------------------------------
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)