Various improvements to P4 tutorial
- Added steps to exercise 2 to use wireshark to capture MyTunnel packets
- Various formatting fix/improvements
- Fixed markdown link to use relative paths
- Fixed bm-cli command not to use sudo (not needed)
Change-Id: I514da99a6cfadd048294c610ba201503c0339e89
(cherry picked from commit 19ea89f8540eef0e41fdf7b4fd9a2a1950f2ade9)
diff --git a/apps/p4-tutorial/README.md b/apps/p4-tutorial/README.md
index 17f6711..2fed6af 100644
--- a/apps/p4-tutorial/README.md
+++ b/apps/p4-tutorial/README.md
@@ -1,9 +1,8 @@
# ONOS+P4 Tutorial
-This directory contains source code and instructions to run the ONOS+P4
-tutorial exercises. Goal of the exercises is to learn how to use ONOS to control
-P4-capable devices via P4Runtime, and how to write ONOS apps to control custom
-data plane capabilities implemented in P4.
+Welcome to the ONOS+P4 tutorial! The goal of this tutorial is to learn how to
+use ONOS to control P4-capable devices via P4Runtime, and how to write ONOS apps
+to control custom data plane capabilities implemented in P4.
For help, please write to the mailing list
[brigade-p4@onosproject.org](mailto:brigade-p4@onosproject.org) or check the
@@ -24,7 +23,7 @@
* <https://docs.oracle.com/cd/E26217_01/E26796/html/qs-import-vm.html>
For more information on the content of the VM and minimum system requirements,
-[click here](/tools/dev/p4vm/README.md).
+[click here](../../tools/dev/p4vm/README.md).
### VM credentials
@@ -35,14 +34,26 @@
## Overview
+Before starting, we suggest to open the `$ONOS_ROOT/apps/p4-tutorial` directory
+in your editor of choice for easier access to the different files used in the
+exercise. For example, if using the Atom editor:
+
+```
+$ atom $ONOS_ROOT/apps/p4-tutorial/
+```
+
### mytunnel.p4
These exercises are based on a simple P4 program called
-[mytunnel.p4](./pipeconf/src/main/resources/mytunnel.p4) designed for this
+[mytunnel.p4](pipeconf/src/main/resources/mytunnel.p4) designed for this
tutorial.
-To start, have a look a the P4 program. Even if this is the first time you
-see P4 code, the program has been commented to provide an understanding of the
+```
+$ atom $ONOS_ROOT/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4
+```
+
+To start, have a look a the P4 program. Even if this is the first time you see
+P4 code, the program has been commented to provide an understanding of the
pipeline behavior to anyone with basic programming and networking background.
While checking the P4 program, try answering the following questions:
@@ -59,39 +70,45 @@
* What happens if a matching entry is not found in table `t_l2_fwd`? What's the
next table applied to the packet?
-[Click here to see the solution to these questions](./questions.md)
+The answer to these questions is provided in the `questions.md` file in this
+directory.
### MyTunnel Pipeconf
The `mytunnel.p4` program is provided to ONOS as part of a "pipeconf".
The main class used to implement the pipeconf is
-[PipeconfFactory.java](./pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipeconfFactory.java).
+[PipeconfFactory.java](pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipeconfFactory.java).
+
+```
+$ atom $ONOS_ROOT/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipeconfFactory.java
+```
+
This class is declared as an OSGi runtime component which is "activated" once
the 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 deploy the P4
-program to a device.
+in ONOS. This is where we associate ONOS driver behaviors with the pipeconf
+(look for the `buildPipeconf()` method), and 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):
+* [mytunnel.json](pipeconf/src/main/resources/mytunnel.json):
The JSON configuration used to execute the P4 program on BMv2. This is an output
of the P4 compiler for BMv2.
-* [mytunnel.p4info](/apps/p4-tutorial/pipeconf/src/main/resources/mytunnel.p4info):
+* [mytunnel.p4info](pipeconf/src/main/resources/mytunnel.p4info):
P4Info file obtained from the P4 compiler.
-* [PipelineInterpreterImpl.java](./pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java):
+* [PipelineInterpreterImpl.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 packet forwarding/manipulation 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).
+[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):
+* [PortStatisticsDiscoveryImpl.java](pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java):
Implementation of the `PortStatisticsDiscovery` ONOS driver behavior. As the
name suggests, this behavior is used to report statistics on the switch ports to
ONOS, e.g. number of packets/bytes received and transmitted for each port. This
@@ -103,14 +120,14 @@
This app is used to provide connectivity between each pair of hosts via the
MyTunnel protocol, a non-standard tunneling protocol created for this exercise.
The implementation of this app can be found
-[here](./mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/MyTunnelApp.java),
+[here](mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/MyTunnelApp.java),
and it will be discussed in more details on Exercise 2.
## Tutorial exercises
### Exercise 1
-[Click here to go to this exercise instructions](./exercise-1.md)
+[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 app
@@ -119,7 +136,7 @@
### Exercise 2
-[Click here to go to this exercise instructions](./exercise-2.md)
+[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 app "MyTunnel".
+a pipeline-specific app "MyTunnel".
diff --git a/apps/p4-tutorial/exercise-1.md b/apps/p4-tutorial/exercise-1.md
index 631ea1f..3db67c0 100644
--- a/apps/p4-tutorial/exercise-1.md
+++ b/apps/p4-tutorial/exercise-1.md
@@ -144,7 +144,7 @@
startup process**, to view them (on a separate terminal window):
```
- $ ls /tmp
+ $ ls /tmp/bmv2-*
```
3. You will **find ONOS netcfg JSON files in this folder** for each BMv2
@@ -236,10 +236,10 @@
These flow rules appear to be installed on table "0". This is a logical
table number mapped by the pipeconf's interpreter to the P4 table named
- `t_l2_fwd` in [mytunnel.p4 (line 191)](./pipeconf/src/main/resources/mytunnel.p4#L191).
+ `t_l2_fwd` in [mytunnel.p4 (line 191)](pipeconf/src/main/resources/mytunnel.p4#L191).
This mapping is defined in
- [PipelineInterpreterImpl.java (line 103)](./pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java#L103)
+ [PipelineInterpreterImpl.java (line 103)](pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java#L103)
6. **Compare ONOS flow rules to the table entries installed on the BMv2
switch**.
@@ -327,15 +327,18 @@
5. Congratulations, you completed the first exercise of the ONOS+P4 tutorial!
- To kill ONOS, press `ctrl-c` in the ONOS log terminal window. To kill
- Mininet, press `ctrl-d` in the Mininet CLI or type `exit`.
-
## Bonus exercise
-As a bonus exercise, you can re-run Mininet with a larger topology to see how
-Exercise 1 works with a more complex topology.
+As a bonus exercise, you can re-run Mininet with more switches and hosts to see
+how Exercise 1 works with a more complex topology.
-1. Rerun the steps in Exercise 1, replacing step 3.i. with the following:
+1. Quit the current Mininet topology. In the Mininet CLI type:
+
+ ```
+ mininet> exit
+ ```
+
+2. Start a new Mininet topology with the following command:
```
$ sudo -E mn --custom $BMV2_MN_PY --switch onosbmv2,pipeconf=p4-tutorial-pipeconf --topo tree,3 --controller remote,ip=127.0.0.1
@@ -349,10 +352,10 @@
correctly on the switch (showing state `PENDING_ADD` when using ONOS command
`flows`). In this case, ONOS provides an automatic reconciliation mechanism
that tries to re-install the failed entries. To force ONOS to perform this
- process more often, **make sure to apply step 2.v before starting Mininet**.
+ process more often, **make sure to apply step 2.v**.
-2. After you activate the Reactive Forwarding app as in step 4.ii.,
- you can ping all hosts in the network using the following Mininet command:
+3. If the Reactive Forwarding app is still running (see step 4.ii),
+ you can ping all hosts in the network using the following Mininet command:
```
mininet> pingall
@@ -361,7 +364,7 @@
If everything went well, ping should work for every host pair in the
network.
-3. You can visualize the topology using the ONOS web UI.
+4. You can visualize the topology using the ONOS web UI.
Open a browser from within the tutorial VM (e.g. Firefox) to
<http://127.0.0.1:8181/onos/ui/>. When asked, use the username `onos`
@@ -370,3 +373,8 @@
While here, feel free to interact with and discover the ONOS UI. For more
information on how to use the ONOS web UI please refer to this guide:
<https://wiki.onosproject.org/x/OYMg>
+
+ To show or hide hosts, press the `H` key on your keyboard.
+
+5. Once done, to kill ONOS, press `ctrl-c` in the ONOS log terminal window. To
+ quit Mininet, press `ctrl-d` in the Mininet CLI or type `exit`.
diff --git a/apps/p4-tutorial/exercise-2.md b/apps/p4-tutorial/exercise-2.md
index 2c48a1f..c798f35 100644
--- a/apps/p4-tutorial/exercise-2.md
+++ b/apps/p4-tutorial/exercise-2.md
@@ -6,15 +6,15 @@
## 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
+Similarly to exercise 1, here 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 data plane to forward packets using 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
+Before starting, we suggest to open the `$ONOS_ROOT/apps/p4-tutorial` directory in
+your editor of choice for easier access to the different files of this
exercise. For example, if using the Atom editor:
```
@@ -38,17 +38,17 @@
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.
+1. **Ingress**: for IPv4 packets received at an 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. When operating in this mode, the switch
-simply forwards the packet by looking at the tunnel ID field.
+ intermediate node in the tunnel path. When operating in this mode, the switch
+ forwards the packet by simply 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.
+ in the path, the switch removes the MyTunnel header before forwarding the
+ packet to the output port.
## MyTunnel pipeline overview
@@ -70,8 +70,7 @@
## MyTunnel app overview
-To begin, open
-[MyTunnelApp.java](./mytunnel/src/main/java/org/onosproject/p4tutorial/mytunnel/MyTunnelApp.java)
+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.
For example, if using the Atom editor:
@@ -83,14 +82,14 @@
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 means of two ONOS core services: Host Location Provider and
-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
+performed using two ONOS core services: Host Location Provider and 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
+Once a `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
@@ -104,7 +103,7 @@
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.
+ 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).
@@ -112,10 +111,18 @@
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
+ as `MyTunnelApp.java`. Feel free to compare your implementation to the
reference one.
-2. **Start ONOS with and all the apps**.
+2. **Start ONOS with all the apps required**.
+
+ 0. If ONOS is still running from the previous exercise, stop it by pressing
+ `ctrl-c` in the ONOS log terminal window.
+
+ This is required since we need to re-build ONOS to reflect the
+ `MyTunnelApp.java` changes you just implemented. There is a way to build
+ just the app and upload that to ONOS at runtime, but this functionality
+ is not covered in this tutorial.
1. On a first terminal window, start ONOS:
@@ -124,13 +131,21 @@
$ ONOS_APPS=proxyarp,hostprovider,lldpprovider ok clean
```
- 2. On a second terminal window to **access the ONOS CLI**:
+ This command will automatically trigger a new build before starting ONOS.
+
+ **Important!** Remember to save your changes to `MytunnelApp.java`
+ before building and starting ONOS.
+
+ 2. On a second terminal window, use the ONOS CLI to activate the MyTunnel
+ pipeconf and app.
+
+ To access the ONOS CLI:
```
$ onos localhost
```
- 2. **Activate the BMv2 drivers, pipeconf, and MyTunnel app**:
+ **Activate the BMv2 drivers, pipeconf, and MyTunnel app**:
```
onos> app activate org.onosproject.drivers.bmv2
@@ -174,14 +189,14 @@
```
4. (optional) **Change flow rule polling interval**. Run the following
- command in the ONOS CLI:
+ 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:
+3. **Run Mininet to set up a tree topology of BMv2 switches**, 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
@@ -199,8 +214,8 @@
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.
+ device is being controlled using the "behaviors" provided by the BMv2
+ driver (which uses P4Runtime) plus the pipeconf ones.
2. Check the links:
@@ -226,20 +241,80 @@
mininet> h1 ping h7
```
- If the implementation of MyTunnelApp.java has been completed correctly,
+ If the implementation of `MyTunnelApp.java` has been completed correctly,
ping should work. If not, check the ONOS log for possible errors in the
MyTunnel app. As a last resort, please check the reference solution in
- the same directory as MyTunnelApp.java and compare that to yours.
+ the same directory as `MyTunnelApp.java` and compare that to yours.
-6. **Look around**.
+ There are 7 hosts, in the network from `h1` to `h8`. You should be able to
+ get ping working between all pairs of hosts.
+
+6. **Look around**:
1. Repeat step 3.v and 3.vi from exercise one to check the
-flow rules in ONOS and on BMv2.
+ flow rules in ONOS and on BMv2.
- 2. Check the hosts in ONOS:
+ 2. Verify that hosts have been discovered by ONOS:
```
onos> hosts -s
```
- You should see 2 hosts, h1 and h7.
+ You should see all the hosts that you pinged so far.
+
+7. **Use Wireshark to dump packets with MyTunnel header**:
+
+ 1. Using the ONOS web UI, find the port number of any switch that forwards
+ packets with the MyTunnel header applied. This will be a port of any
+ link connecting two switches.
+
+ * Open the ONOS UI at <http://127.0.0.1:8181/onos/ui/>. To log in, use
+ username `onos` and password `rocks`.
+
+ * To show/hide switch names, press the `L` key on your keyboard.
+
+ * To see the switch port number for a particular link, position the
+ mouse over the link, you should see two numbers at the two link
+ endpoints. This will be your port number.
+
+ * For example, an internal-facing port carrying packets with the
+ MyTunnel header applied is port `3` of device `s3`.
+
+ 2. Open Wireshark using the icon located in the desktop, or by typing
+ `sudo wireshark` in a terminal window.
+
+ 3. Start packet capture on the switch port you identified. Mininet uses the
+ naming `[switch_name]-eth[port_number]` for the emulated switch ports.
+ For example, for port `3` of switch `s3`, the interface name will be
+ `s3-eth3`.
+
+ 4. Start a ping in Mininet between any two hosts which path uses the
+ identified link/port.
+
+ * In the ONOS UI, to show/hide hosts, press the `H` key on your keyboard.
+
+ * For example, the path between `h1` (10.0.0.1) and `h4` (10.0.0.4)
+ uses port `3` of switch `s3`.
+
+ * Start ping in Mininet:
+
+ ```
+ mininet> h1 ping h4
+ ```
+
+ 5. Analyze the captured packets in Wireshark.
+
+ * Packets with protocol `LLDP` and `0x8942` (EtherType) are generated by
+ ONOS using P4Runtime "packet-out" and are used for link discovery.
+
+ * Packets with EtherType `0x1212` are ping packets encapsulated with the
+ MyTunnel header! Indeed, since this is not a standard protocol,
+ Wireshark doesn't know how to parse the Ethernet payload and shows
+ them as general Ethernet packets.
+
+8. **Congratulations, you have completed the exercise!**
+
+ Hopefully, it should be a bit more clear by now how to use P4 to implement
+ custom header processing (like the `MyTunnel` header), and how to write ONOS
+ apps that control the match-action tables of switches to forward packets
+ across the network using such non-standard headers (like MyTunnelApp).
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 4a92716..4b9848c 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
@@ -255,9 +255,9 @@
* 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.
+ * Hint: the code will be similar to the case when isEgress is true.
*/
- action = null;
+ action = null; // Replace null with your solution.
}
log.info("Inserting {} rule on switch {}: table={}, match={}, action={}",
diff --git a/tools/dev/p4vm/bm-commands.sh b/tools/dev/p4vm/bm-commands.sh
index 599f5c0..ba69f77 100644
--- a/tools/dev/p4vm/bm-commands.sh
+++ b/tools/dev/p4vm/bm-commands.sh
@@ -7,7 +7,7 @@
fi
tport=$(head -n 1 /tmp/bmv2-$1-thrift-port)
echo "Starting CLI for BMv2 instance $1 (Thrift port $tport)..."
- sudo bm_CLI --thrift-port ${tport} --pre SimplePreLAG ${@:2}
+ bm_CLI --thrift-port ${tport} --pre SimplePreLAG ${@:2}
}
bm-dbg () {