The goal of this exercise is to write a P4 program that implements the PacketIn
and PacketOut
mechanisms, along with an idle timeout mechanism for table entries. The control plane uses P4Runtime to configure and manage the data plane. The P4 program flowcache.p4
contains one ingress table (flow_cache
) and two counters (ingressPktOutCounter
, egressPktInCounter
).
The action flow_unknown
in the flow_cache
table triggers the generation of a PacketIn when no flow rules match the packet. The PacketIn is then forwarded to the controller via P4Runtime. Upon receiving these packets, the controller adds an entry to the flow table with action cached_action
. While the controller computes and installs the flow rule, PacketOut messages are sent via P4Runtime to the data plane in order to forward the packets to their destination.
Once a flow entry is installed and no packets match it, the idle timeout start. Once a flow entry is installed and no packets match it, the idle timeout starts. When the timer expires, an IdleTimeoutNotification message is sent to the controller.
The Counters ingressPktOutCounter
and egressPktInCounter
are used to verify whether PacketIn
and PacketOut
messages are sent or received.
You will use the starter program, mycontroller.py
, and a few helper
libraries in the p4runtime_lib
directory to create the table entries
necessary to forward traffic between hosts.
Spoiler alert: There is a reference solution in the
solution
sub-directory. Feel free to compare your implementation to the reference.
The starter code for this assignment is in files called flowcache.p4
and mycontroller.py
. Your job will be to finalize the P4 program to properly implement the PacketIn
and PacketOut
idle timeout mechanismes.
Let's first compile the new P4 program, start the network, and use mycontroller.py
to install the flowcache pipeline in the data plane.
-
In your shell, run:
make
This will:
- compile
flowcache.p4
, - start a Mininet instance with three switches (
s1
,s2
,s3
) configured in a triangle, each connected to one host (h1
,h2
,h3
), and - assign IPs of
10.0.1.1
,10.0.2.2
,10.0.3.3
to the respective hosts.
- compile
-
You should now see a Mininet command prompt. Start a ping between h1 and h2:
mininet> h1 ping h2
Because there are no rules on the switches, you should not receive any replies yet. You should leave the ping running in this shell.
-
Open another shell and run the starter code:
cd ~/tutorials/exercises/flowcache ./mycontroller.py
This will install the
flowcache.p4
program on the switches, and it will wait for notifications from the data plane. -
Press
Ctrl-C
to the second shell to stopmycontroller.py
Each switch currently has no flow rules. So, as soon as a packet is received, it will be sent to the control plane within a PacketIn. Your job is to write the functions that handle PacketIn, PacketOut, and idle timeout mechanisms. Then, you can verify that PacketIn and PacketOut are working by reading the counters.
If you see the following error message when running mycontroller.py
, then
the gRPC server is not running on one or more switches.
p4@p4:~/tutorials/exercises/flowcache$ ./mycontroller.py
...
grpc._channel._Rendezvous: <_Rendezvous of RPC that terminated with (StatusCode.UNAVAILABLE, Connect Failed)>
You can check to see which of gRPC ports are listening on the machine by running:
sudo netstat -lpnt
The easiest solution is to enter Ctrl-D
or exit
in the mininet>
prompt,
and re-run make
.
A P4 program defines a packet-processing pipeline, but the rules
within each table are inserted by the control plane. In this case,
mycontroller.py
implements our control plane, instead of installing static
table entries like we have in the previous exercises.
Important: A P4 program also defines the interface between the
switch pipeline and control plane. This interface is defined in the
flow_cache.p4info
file. The table entries that you build in mycontroller.py
refer to specific tables, keys, and actions by name, and we use a P4Info helper
to convert the names into the IDs that are required for P4Runtime. Any changes
in the P4 program that add or rename tables, keys, or actions will need to be
reflected in your table entries.
You MUST NOT associate the CPU port number with an interface,
i.e. it would cause problems if you added a command line option
-i 510@veth16
to the example command line above. The CPU port is
special in that effectively one end is connected to the BMv2 switch
on the CPU port, and the other end is always connected to the
P4Runtime API server code that runs within the simple_switch_grpc
process.
All packets sent by your P4 code to the CPU port go to this P4Runtime
API server, are sent via a PacketIn
message from the server to your
controller (which is a P4Runtime API client) over the P4Runtime API
gRPC connection, and become PacketIn
messages to your controller
program. The controller metadata header, if you have one, must be the
first header when the packet is sent to the CPU port by your P4
program.
All PacketOut
messages from your controller program go over the
P4Runtime API grPC connection to the P4Runtime API server code running
inside of the simple_switch_grpc
process, and are then sent into the
CPU port for your P4 program to process. The controller metadata
header, if any, will always be the first header of the packet as
seen by your P4 parser.
The mycontroller.py
file is a basic controller plane that does the following:
- Establishes a gRPC connection to the switches for the P4Runtime service.
- Pushes the P4 program to each switch.
- Receives
PacketIn
messages and generates flow rules to provide connectivity among all hosts. - Sends
PacketOut
messages to forward the packets to their destination while the corresponding flow rules are not yet installed. - Handles the
IdleTimeoutNotification
. - Reads
PacketIn
andPacketOut
ingress and egress counters periodically.
It also contains comments marked with TODO
which indicate the functionality
that you need to implement.
Your job will be to write functions that will handle the PacketIn
, PacketOut
and idle timeout mechanismes.
In this exercise, you will be interacting with some of the classes and methods in
the p4runtime_lib
directory. Here is a summary of each of the files in the directory:
helper.py
- Contains the
P4InfoHelper
class which is used to parse thep4info
files. - Provides translation methods from entity name to and from ID number.
- Builds P4 program-dependent sections of P4Runtime table entries.
- Contains the
switch.py
- Contains the
SwitchConnection
class which grabs the gRPC client stub, and establishes connections to the switches. - Provides helper methods that construct the P4Runtime protocol buffer messages and makes the P4Runtime gRPC service calls.
- Contains the
bmv2.py
- Contains
Bmv2SwitchConnection
which extendsSwitchConnections
and provides the BMv2-specific device payload to load the P4 program.
- Contains
convert.py
- Provides convenience methods to encode and decode from friendly strings and numbers to the byte strings required for the protocol buffer messages.
- Used by
helper.py
Follow the instructions from Step 1. If your Mininet network is still running, you will just need to run the following in your second shell:
./mycontroller.py
You should start to see ICMP replies in your Mininet prompt, and you should start to see the values for all counters start to increment.
You might notice that the rules that are printed by mycontroller.py
contain the entity
IDs rather than the table names. You can use the P4Info helper to translate these IDs
into entry names.
If you are interested, you can find the protocol buffer and gRPC definitions here:
If the Mininet shell crashes, it may leave a Mininet instance running in the background. Use the following command to clean up:
make clean
To run the reference solution, you should run the following command from the
~/tutorials/exercises/p4runtime
directory:
solution/mycontroller.py
Congratulations, your implementation works! Move onto the next assignment Explicit Congestion Notification
Documentation on the Usage of Gateway (gw) and ARP Commands in topology.json is here
The documentation for P4_16 and P4Runtime is available here
All excercises in this repository use the v1model architecture, the documentation for which is available at: