SIGCOMM 2019 Tutorial Edits (#272)
* Updated the utils/run_exercise.py to allow exercises to customize host configuration from the topology.json file. Now hosts and `ping` each other in the basic exercise. Other Linux utilities should work as well (e.g. iperf). ``` mininet> h1 ping h2 PING 10.0.2.2 (10.0.2.2) 56(84) bytes of data. 64 bytes from 10.0.2.2: icmp_seq=1 ttl=62 time=3.11 ms 64 bytes from 10.0.2.2: icmp_seq=2 ttl=62 time=2.34 ms 64 bytes from 10.0.2.2: icmp_seq=3 ttl=62 time=2.15 ms ^C --- 10.0.2.2 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2003ms rtt min/avg/max/mdev = 2.153/2.540/3.118/0.416 ms mininet> pingall *** Ping: testing ping reachability h1 -> h2 h3 h2 -> h1 h3 h3 -> h1 h2 *** Results: 0% dropped (6/6 received) ``` Only updated basic exercise, still need to update other exercises. Also, updated the root-bootstrap.sh because I was running into issues with latest version of vagrant. * Accidentially added the solution to the basic exercise in the previous commit. Undoing that here ... * Updated the topology.json file and table entries for the basic_tunnel exercise. * Updated P4Runtime exercise with new topology and table entries. * Fixed MAC addresses in P4Runtime exercise. It is working now. * Fixed MAC addresses in P4Runtime exercise starter code * Updated ECN exercise to use new topology.json file. Updated the table entries / MAC addresses as well. * Updated the topology.json file and table entries for the MRI exercise. * Updated source_routing exercise with new topology file and verified correct functionality. * Updated load_balance exercise with new topology. * Moved basic exercise triangle topology into a separate folder * Added new topology for the basic exercise: a single pod of a fat-tree. * Updated Makefiles and run_exercise.py to allow exercises to configure each switch with a different P4 program. This is mainly for the firewall exercise. * Updated Makefiles of project to work with new utils/Makefile * Updated load_balance and p4runtime exercise Makefiles * Initial commit of the firewall exercise, which is a simple stateful firewall that uses a bloom filter. Need to update README files * Initial commit of the path_monitor exercise. It is working but still need to update the README and figure out what we want the tutorial attendees to implement. * Updated README file in firewall exercise. Also removed the bits from the starter code that we want the tutorial attendees to implement * Renamed path_monitor exercise to link_monitor * Updated the README in the link_monitor exercise and removed the bits from the starter code that we want the tutorial attendees to implement. * Updated README for the firewall exercise * Adding pod-topo.png image to basic exercise * Added firewall-topo.png image to firewall exercise * Added link-monitor-topo.png to link_monitor exercise * Updated README files to point to topology images * Updated top-level README to point to new exercises. * Fixed link for VM dependencies script in README * Updated bmv2/pi/p4c commits * Updated README files for exercises to fix some typos and added a note about the V1Model architecture. * Added a note about food for thought in the link_monitor README * Updated the firewall.p4 program to use two register arrays rather than a single one. This is to make the design more portable to high line rate devices which can only support a single access to each register array. * Minor fix to firewall exercise to get rid of compiler warning. * Updated comment in firewall exercise. * Minor (typo) fixes in the firewall ReadMe * More info in firewall exercise ReadMe step 2 * Updated firewall.p4 to reuse direction variable * More testing steps, small fixes in firewall exercise Readme * Added food for thought to firewall Readme * Cosmetic fixes to firewall ReadMe * Made a few updates to the basic exercise README and added more details to the link_monitor exercise README. Also added a command to install grip when provisioning the VM. This could be useful for rendering the markdown README files offline. * Updated top level README so it can be merged into the master branch. * Moved cmd to install grip from root-bootstrap to user-bootstrap
15
README.md
@@ -21,6 +21,10 @@ you get started with P4 programming, organized into several modules:
|
|||||||
* [Calculator](./exercises/other/calc)
|
* [Calculator](./exercises/other/calc)
|
||||||
* [Load Balancing](./exercises/load_balance)
|
* [Load Balancing](./exercises/load_balance)
|
||||||
|
|
||||||
|
5. Stateful Packet Processing
|
||||||
|
* [Firewall](./exercises/firewall)
|
||||||
|
* [Link Monitoring](./exercises/link_monitor)
|
||||||
|
|
||||||
## Presentation
|
## Presentation
|
||||||
|
|
||||||
The slides are available [online](http://bit.ly/p4d2-2018-spring) and
|
The slides are available [online](http://bit.ly/p4d2-2018-spring) and
|
||||||
@@ -31,9 +35,10 @@ which contains various examples that you can refer to.
|
|||||||
|
|
||||||
## Obtaining required software
|
## Obtaining required software
|
||||||
|
|
||||||
If you are starting this tutorial at the Spring 2018 P4 Developer Day,
|
If you are starting this tutorial at one of the proctored tutorial events,
|
||||||
then we've already provided you with a virtual machine that has all of
|
then we've already provided you with a virtual machine that has all of
|
||||||
the required software installed.
|
the required software installed. Ask an instructor for a USB stick with
|
||||||
|
the VM image.
|
||||||
|
|
||||||
Otherwise, to complete the exercises, you will need to either build a
|
Otherwise, to complete the exercises, you will need to either build a
|
||||||
virtual machine or install several dependencies.
|
virtual machine or install several dependencies.
|
||||||
@@ -47,11 +52,11 @@ To build the virtual machine:
|
|||||||
- When the machine reboots, you should have a graphical desktop machine with the required
|
- When the machine reboots, you should have a graphical desktop machine with the required
|
||||||
software pre-installed.
|
software pre-installed.
|
||||||
|
|
||||||
*Note: Before running the `vagrant up` command, make sure you have enabled virtualization in your environment; otherwise you may get a "VT-x is disabled in the BIOS for both all CPU modes" error. Check [this](https://stackoverflow.com/questions/33304393/vt-x-is-disabled-in-the-bios-for-both-all-cpu-modes-verr-vmx-msr-all-vmx-disabl) for enabling it in virtualbox and/or BIOS for different system configurations.
|
*Note*: Before running the `vagrant up` command, make sure you have enabled virtualization in your environment; otherwise you may get a "VT-x is disabled in the BIOS for both all CPU modes" error. Check [this](https://stackoverflow.com/questions/33304393/vt-x-is-disabled-in-the-bios-for-both-all-cpu-modes-verr-vmx-msr-all-vmx-disabl) for enabling it in virtualbox and/or BIOS for different system configurations.
|
||||||
|
|
||||||
You will need the script to execute to completion before you can see the `p4` login on your virtual machine's GUI. In some cases, the `vagrant up` command brings up only the default `vagrant` login with the password `vagrant`. Dependencies may or may not have been installed for you to proceed with running P4 programs. Please refer the existing issues to help fix your problem or create a new one if your specific problem isn't addressed there.*
|
You will need the script to execute to completion before you can see the `p4` login on your virtual machine's GUI. In some cases, the `vagrant up` command brings up only the default `vagrant` login with the password `vagrant`. Dependencies may or may not have been installed for you to proceed with running P4 programs. Please refer the [existing issues](https://github.com/p4lang/tutorials/issues) to help fix your problem or create a new one if your specific problem isn't addressed there.
|
||||||
|
|
||||||
To install dependencies by hand, please reference the [vm](../vm) installation scripts.
|
To install dependencies by hand, please reference the [vm](./vm) installation scripts.
|
||||||
They contain the dependencies, versions, and installation procedure.
|
They contain the dependencies, versions, and installation procedure.
|
||||||
You should be able to run them directly on an Ubuntu 16.04 machine:
|
You should be able to run them directly on an Ubuntu 16.04 machine:
|
||||||
- `sudo ./root-bootstrap.sh`
|
- `sudo ./root-bootstrap.sh`
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
BMV2_SWITCH_EXE = simple_switch_grpc
|
BMV2_SWITCH_EXE = simple_switch_grpc
|
||||||
NO_P4 = true
|
TOPO = pod-topo/topology.json
|
||||||
P4C_ARGS = --p4runtime-files $(basename $@).p4.p4info.txt
|
|
||||||
|
|
||||||
include ../../utils/Makefile
|
include ../../utils/Makefile
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 138 B After Width: | Height: | Size: 97 B |
@@ -17,6 +17,17 @@ MAC address and output port for the next hop. We have already defined
|
|||||||
the control plane rules, so you only need to implement the data plane
|
the control plane rules, so you only need to implement the data plane
|
||||||
logic of your P4 program.
|
logic of your P4 program.
|
||||||
|
|
||||||
|
We will use the following topology for this exercise. It is a single
|
||||||
|
pod of a fat-tree topology and henceforth referred to as pod-topo:
|
||||||
|

|
||||||
|
|
||||||
|
Our P4 program will be written for the V1Model architecture implemented
|
||||||
|
on P4.org's bmv2 software switch. The architecture file for the V1Model
|
||||||
|
can be found at: /usr/local/share/p4c/p4include/v1model.p4. This file
|
||||||
|
desribes the interfaces of the P4 programmable elements in the architecture,
|
||||||
|
the supported externs, as well as the architecture's standard metadata
|
||||||
|
fields. We encourage you to take a look at it.
|
||||||
|
|
||||||
> **Spoiler alert:** There is a reference solution in the `solution`
|
> **Spoiler alert:** There is a reference solution in the `solution`
|
||||||
> sub-directory. Feel free to compare your implementation to the
|
> sub-directory. Feel free to compare your implementation to the
|
||||||
> reference.
|
> reference.
|
||||||
@@ -36,27 +47,18 @@ up a switch in Mininet to test its behavior.
|
|||||||
```
|
```
|
||||||
This will:
|
This will:
|
||||||
* compile `basic.p4`, and
|
* compile `basic.p4`, and
|
||||||
* start a Mininet instance with three switches (`s1`, `s2`, `s3`)
|
* start the pod-topo in Mininet and configure all switches with
|
||||||
configured in a triangle, each connected to one host (`h1`, `h2`,
|
the appropriate P4 program + table entries, and
|
||||||
and `h3`).
|
* configure all hosts with the commands listed in
|
||||||
* The hosts are assigned IPs of `10.0.1.1`, `10.0.2.2`, and `10.0.3.3`.
|
[pod-topo/topology.json](./pod-topo/topology.json)
|
||||||
|
|
||||||
2. You should now see a Mininet command prompt. Open two terminals
|
2. You should now see a Mininet command prompt. Try to ping between
|
||||||
for `h1` and `h2`, respectively:
|
hosts in the topology:
|
||||||
```bash
|
```bash
|
||||||
mininet> xterm h1 h2
|
mininet> h1 ping h2
|
||||||
|
mininet> pingall
|
||||||
```
|
```
|
||||||
3. Each host includes a small Python-based messaging client and
|
3. Type `exit` to leave each xterm and the Mininet command line.
|
||||||
server. In `h2`'s xterm, start the server:
|
|
||||||
```bash
|
|
||||||
./receive.py
|
|
||||||
```
|
|
||||||
4. In `h1`'s xterm, send a message to `h2`:
|
|
||||||
```bash
|
|
||||||
./send.py 10.0.2.2 "P4 is cool"
|
|
||||||
```
|
|
||||||
The message will not be received.
|
|
||||||
5. Type `exit` to leave each xterm and the Mininet command line.
|
|
||||||
Then, to stop mininet:
|
Then, to stop mininet:
|
||||||
```bash
|
```bash
|
||||||
make stop
|
make stop
|
||||||
@@ -66,7 +68,7 @@ server. In `h2`'s xterm, start the server:
|
|||||||
make clean
|
make clean
|
||||||
```
|
```
|
||||||
|
|
||||||
The message was not received because each switch is programmed
|
The ping failed because each switch is programmed
|
||||||
according to `basic.p4`, which drops all packets on arrival.
|
according to `basic.p4`, which drops all packets on arrival.
|
||||||
Your job is to extend this file so it forwards packets.
|
Your job is to extend this file so it forwards packets.
|
||||||
|
|
||||||
@@ -77,7 +79,7 @@ within each table are inserted by the control plane. When a rule
|
|||||||
matches a packet, its action is invoked with parameters supplied by
|
matches a packet, its action is invoked with parameters supplied by
|
||||||
the control plane as part of the rule.
|
the control plane as part of the rule.
|
||||||
|
|
||||||
In this exercise, we have already implemented the the control plane
|
In this exercise, we have already implemented the control plane
|
||||||
logic for you. As part of bringing up the Mininet instance, the
|
logic for you. As part of bringing up the Mininet instance, the
|
||||||
`make run` command will install packet-processing rules in the tables of
|
`make run` command will install packet-processing rules in the tables of
|
||||||
each switch. These are defined in the `sX-runtime.json` files, where
|
each switch. These are defined in the `sX-runtime.json` files, where
|
||||||
@@ -86,7 +88,7 @@ each switch. These are defined in the `sX-runtime.json` files, where
|
|||||||
**Important:** We use P4Runtime to install the control plane rules. The
|
**Important:** We use P4Runtime to install the control plane rules. The
|
||||||
content of files `sX-runtime.json` refer to specific names of tables, keys, and
|
content of files `sX-runtime.json` refer to specific names of tables, keys, and
|
||||||
actions, as defined in the P4Info file produced by the compiler (look for the
|
actions, as defined in the P4Info file produced by the compiler (look for the
|
||||||
file `build/basic.p4info` after executing `make run`). Any changes in the P4
|
file `build/basic.p4.p4info.txt` after executing `make run`). Any changes in the P4
|
||||||
program that add or rename tables, keys, or actions will need to be reflected in
|
program that add or rename tables, keys, or actions will need to be reflected in
|
||||||
these `sX-runtime.json` files.
|
these `sX-runtime.json` files.
|
||||||
|
|
||||||
@@ -120,20 +122,22 @@ A complete `basic.p4` will contain the following components:
|
|||||||
|
|
||||||
## Step 3: Run your solution
|
## Step 3: Run your solution
|
||||||
|
|
||||||
Follow the instructions from Step 1. This time, your message from
|
Follow the instructions from Step 1. This time, you should be able to
|
||||||
`h1` should be delivered to `h2`.
|
sucessfully ping between any two hosts in the topology.
|
||||||
|
|
||||||
### Food for thought
|
### Food for thought
|
||||||
|
|
||||||
The "test suite" for your solution---sending a message from `h1` to
|
The "test suite" for your solution---sending pings between hosts in the
|
||||||
`h2`---is not very robust. What else should you test to be confident
|
topology---is not very robust. What else should you test to be confident
|
||||||
of your implementation?
|
that you implementation is correct?
|
||||||
|
|
||||||
> Although the Python `scapy` library is outside the scope of this tutorial,
|
> Although the Python `scapy` library is outside the scope of this tutorial,
|
||||||
> it can be used to generate packets for testing. The `send.py` file shows how
|
> it can be used to generate packets for testing. The `send.py` file shows how
|
||||||
> to use it.
|
> to use it.
|
||||||
|
|
||||||
Other questions to consider:
|
Other questions to consider:
|
||||||
|
- How would you enhance your program to respond to ARP requests?
|
||||||
|
- How would you enhance your program to support traceroute?
|
||||||
- How would you enhance your program to support next hops?
|
- How would you enhance your program to support next hops?
|
||||||
- Is this program enough to replace a router? What's missing?
|
- Is this program enough to replace a router? What's missing?
|
||||||
|
|
||||||
@@ -152,7 +156,7 @@ messages to fix your `basic.p4` implementation.
|
|||||||
|
|
||||||
3. `basic.p4` might compile, and the control plane rules might be
|
3. `basic.p4` might compile, and the control plane rules might be
|
||||||
installed, but the switch might not process packets in the desired
|
installed, but the switch might not process packets in the desired
|
||||||
way. The `/tmp/p4s.<switch-name>.log` files contain detailed logs
|
way. The `logs/sX.log` files contain detailed logs
|
||||||
that describing how each switch processes each packet. The output is
|
that describing how each switch processes each packet. The output is
|
||||||
detailed and can help pinpoint logic errors in your implementation.
|
detailed and can help pinpoint logic errors in your implementation.
|
||||||
|
|
||||||
@@ -166,9 +170,3 @@ these instances:
|
|||||||
make stop
|
make stop
|
||||||
```
|
```
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
Congratulations, your implementation works! In the next exercise we
|
|
||||||
will build on top of this and add support for a basic tunneling
|
|
||||||
protocol: [basic_tunnel](../basic_tunnel)!
|
|
||||||
|
|
||||||
|
|||||||
BIN
exercises/basic/pod-topo/pod-topo.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
57
exercises/basic/pod-topo/s1-runtime.json
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"target": "bmv2",
|
||||||
|
"p4info": "build/basic.p4.p4info.txt",
|
||||||
|
"bmv2_json": "build/basic.json",
|
||||||
|
"table_entries": [
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyIngress.drop",
|
||||||
|
"action_params": { }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:11",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:22",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:03:00",
|
||||||
|
"port": 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:04:00",
|
||||||
|
"port": 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
57
exercises/basic/pod-topo/s2-runtime.json
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"target": "bmv2",
|
||||||
|
"p4info": "build/basic.p4.p4info.txt",
|
||||||
|
"bmv2_json": "build/basic.json",
|
||||||
|
"table_entries": [
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyIngress.drop",
|
||||||
|
"action_params": { }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:03:00",
|
||||||
|
"port": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:04:00",
|
||||||
|
"port": 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:03:33",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:04:44",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
57
exercises/basic/pod-topo/s3-runtime.json
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"target": "bmv2",
|
||||||
|
"p4info": "build/basic.p4.p4info.txt",
|
||||||
|
"bmv2_json": "build/basic.json",
|
||||||
|
"table_entries": [
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyIngress.drop",
|
||||||
|
"action_params": { }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
57
exercises/basic/pod-topo/s4-runtime.json
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"target": "bmv2",
|
||||||
|
"p4info": "build/basic.p4.p4info.txt",
|
||||||
|
"bmv2_json": "build/basic.json",
|
||||||
|
"table_entries": [
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyIngress.drop",
|
||||||
|
"action_params": { }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
26
exercises/basic/pod-topo/topology.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"hosts": {
|
||||||
|
"h1": {"ip": "10.0.1.1/24", "mac": "08:00:00:00:01:11",
|
||||||
|
"commands":["route add default gw 10.0.1.10 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.1.10 08:00:00:00:01:00"]},
|
||||||
|
"h2": {"ip": "10.0.2.2/24", "mac": "08:00:00:00:02:22",
|
||||||
|
"commands":["route add default gw 10.0.2.20 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.2.20 08:00:00:00:02:00"]},
|
||||||
|
"h3": {"ip": "10.0.3.3/24", "mac": "08:00:00:00:03:33",
|
||||||
|
"commands":["route add default gw 10.0.3.30 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.3.30 08:00:00:00:03:00"]},
|
||||||
|
"h4": {"ip": "10.0.4.4/24", "mac": "08:00:00:00:04:44",
|
||||||
|
"commands":["route add default gw 10.0.4.40 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.4.40 08:00:00:00:04:00"]}
|
||||||
|
},
|
||||||
|
"switches": {
|
||||||
|
"s1": { "runtime_json" : "pod-topo/s1-runtime.json" },
|
||||||
|
"s2": { "runtime_json" : "pod-topo/s2-runtime.json" },
|
||||||
|
"s3": { "runtime_json" : "pod-topo/s3-runtime.json" },
|
||||||
|
"s4": { "runtime_json" : "pod-topo/s4-runtime.json" }
|
||||||
|
},
|
||||||
|
"links": [
|
||||||
|
["h1", "s1-p1"], ["h2", "s1-p2"], ["s1-p3", "s3-p1"], ["s1-p4", "s4-p2"],
|
||||||
|
["h3", "s2-p1"], ["h4", "s2-p2"], ["s2-p3", "s4-p1"], ["s2-p4", "s3-p2"]
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"hosts": [
|
|
||||||
"h1",
|
|
||||||
"h2",
|
|
||||||
"h3"
|
|
||||||
],
|
|
||||||
"switches": {
|
|
||||||
"s1": { "runtime_json" : "s1-runtime.json" },
|
|
||||||
"s2": { "runtime_json" : "s2-runtime.json" },
|
|
||||||
"s3": { "runtime_json" : "s3-runtime.json" }
|
|
||||||
},
|
|
||||||
"links": [
|
|
||||||
["h1", "s1"], ["s1", "s2"], ["s1", "s3"],
|
|
||||||
["s3", "s2"], ["s2", "h2"], ["s3", "h3"]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:01:01",
|
"dstAddr": "08:00:00:00:01:11",
|
||||||
"port": 1
|
"port": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:02:02:00",
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
"port": 2
|
"port": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:03:03:00",
|
"dstAddr": "08:00:00:00:03:00",
|
||||||
"port": 3
|
"port": 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:01:02:00",
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
"port": 2
|
"port": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:02:02",
|
"dstAddr": "08:00:00:00:02:22",
|
||||||
"port": 1
|
"port": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:03:03:00",
|
"dstAddr": "08:00:00:00:03:00",
|
||||||
"port": 3
|
"port": 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:01:03:00",
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
"port": 2
|
"port": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:02:03:00",
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
"port": 3
|
"port": 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:03:03",
|
"dstAddr": "08:00:00:00:03:33",
|
||||||
"port": 1
|
"port": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
22
exercises/basic/triangle-topo/topology.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"hosts": {
|
||||||
|
"h1": {"ip": "10.0.1.1/24", "mac": "08:00:00:00:01:11",
|
||||||
|
"commands":["route add default gw 10.0.1.10 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.1.10 08:00:00:00:01:00"]},
|
||||||
|
"h2": {"ip": "10.0.2.2/24", "mac": "08:00:00:00:02:22",
|
||||||
|
"commands":["route add default gw 10.0.2.20 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.2.20 08:00:00:00:02:00"]},
|
||||||
|
"h3": {"ip": "10.0.3.3/24", "mac": "08:00:00:00:03:33",
|
||||||
|
"commands":["route add default gw 10.0.3.30 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.3.30 08:00:00:00:03:00"]}
|
||||||
|
},
|
||||||
|
"switches": {
|
||||||
|
"s1": { "runtime_json" : "triangle-topo/s1-runtime.json" },
|
||||||
|
"s2": { "runtime_json" : "triangle-topo/s2-runtime.json" },
|
||||||
|
"s3": { "runtime_json" : "triangle-topo/s3-runtime.json" }
|
||||||
|
},
|
||||||
|
"links": [
|
||||||
|
["h1", "s1-p1"], ["s1-p2", "s2-p2"], ["s1-p3", "s3-p2"],
|
||||||
|
["s3-p3", "s2-p3"], ["h2", "s2-p1"], ["h3", "s3-p1"]
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
BMV2_SWITCH_EXE = simple_switch_grpc
|
BMV2_SWITCH_EXE = simple_switch_grpc
|
||||||
NO_P4 = true
|
|
||||||
P4C_ARGS = --p4runtime-files $(basename $@).p4.p4info.txt
|
|
||||||
|
|
||||||
include ../../utils/Makefile
|
include ../../utils/Makefile
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 138 B After Width: | Height: | Size: 67 B |
@@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:01:01",
|
"dstAddr": "08:00:00:00:01:11",
|
||||||
"port": 1
|
"port": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:02:02:00",
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
"port": 2
|
"port": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:03:03:00",
|
"dstAddr": "08:00:00:00:03:00",
|
||||||
"port": 3
|
"port": 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:01:02:00",
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
"port": 2
|
"port": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:02:02",
|
"dstAddr": "08:00:00:00:02:22",
|
||||||
"port": 1
|
"port": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:03:02:00",
|
"dstAddr": "08:00:00:00:03:00",
|
||||||
"port": 3
|
"port": 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:01:03:00",
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
"port": 2
|
"port": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:02:03:00",
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
"port": 3
|
"port": 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:03:03",
|
"dstAddr": "08:00:00:00:03:33",
|
||||||
"port": 1
|
"port": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
{
|
{
|
||||||
"hosts": [
|
"hosts": {
|
||||||
"h1",
|
"h1": {"ip": "10.0.1.1/24", "mac": "08:00:00:00:01:11",
|
||||||
"h2",
|
"commands":["route add default gw 10.0.1.10 dev eth0",
|
||||||
"h3"
|
"arp -i eth0 -s 10.0.1.10 08:00:00:00:01:00"]},
|
||||||
],
|
"h2": {"ip": "10.0.2.2/24", "mac": "08:00:00:00:02:22",
|
||||||
|
"commands":["route add default gw 10.0.2.20 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.2.20 08:00:00:00:02:00"]},
|
||||||
|
"h3": {"ip": "10.0.3.3/24", "mac": "08:00:00:00:03:33",
|
||||||
|
"commands":["route add default gw 10.0.3.30 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.3.30 08:00:00:00:03:00"]}
|
||||||
|
},
|
||||||
"switches": {
|
"switches": {
|
||||||
"s1": { "runtime_json" : "s1-runtime.json" },
|
"s1": { "runtime_json" : "s1-runtime.json" },
|
||||||
"s2": { "runtime_json" : "s2-runtime.json" },
|
"s2": { "runtime_json" : "s2-runtime.json" },
|
||||||
"s3": { "runtime_json" : "s3-runtime.json" }
|
"s3": { "runtime_json" : "s3-runtime.json" }
|
||||||
},
|
},
|
||||||
"links": [
|
"links": [
|
||||||
["h1", "s1"], ["s1", "s2"], ["s1", "s3"],
|
["h1", "s1-p1"], ["s1-p2", "s2-p2"], ["s1-p3", "s3-p2"],
|
||||||
["s3", "s2"], ["s2", "h2"], ["s3", "h3"]
|
["s3-p3", "s2-p3"], ["h2", "s2-p1"], ["h3", "s3-p1"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
BMV2_SWITCH_EXE = simple_switch_grpc
|
BMV2_SWITCH_EXE = simple_switch_grpc
|
||||||
NO_P4 = true
|
|
||||||
P4C_ARGS = --p4runtime-files $(basename $@).p4.p4info.txt
|
|
||||||
|
|
||||||
include ../../utils/Makefile
|
include ../../utils/Makefile
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 138 B After Width: | Height: | Size: 67 B |
@@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:01:01",
|
"dstAddr": "08:00:00:00:01:01",
|
||||||
"port": 2
|
"port": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:01:0b",
|
"dstAddr": "08:00:00:00:01:11",
|
||||||
"port": 1
|
"port": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:02:03:00",
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
"port": 3
|
"port": 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:03:02:00",
|
"dstAddr": "08:00:00:00:03:00",
|
||||||
"port": 4
|
"port": 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:02:02",
|
"dstAddr": "08:00:00:00:02:02",
|
||||||
"port": 2
|
"port": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:02:16",
|
"dstAddr": "08:00:00:00:02:22",
|
||||||
"port": 1
|
"port": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:01:03:00",
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
"port": 3
|
"port": 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:03:03:00",
|
"dstAddr": "08:00:00:00:03:00",
|
||||||
"port": 4
|
"port": 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:03:03",
|
"dstAddr": "08:00:00:00:03:03",
|
||||||
"port": 1
|
"port": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:01:04:00",
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
"port": 2
|
"port": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:02:04:00",
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
"port": 3
|
"port": 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,28 @@
|
|||||||
{
|
{
|
||||||
"hosts": [
|
"hosts": {
|
||||||
"h1",
|
"h1": {"ip": "10.0.1.1/31", "mac": "08:00:00:00:01:01",
|
||||||
"h2",
|
"commands":["route add default gw 10.0.1.0 dev eth0",
|
||||||
"h3",
|
"arp -i eth0 -s 10.0.1.0 08:00:00:00:01:00"]},
|
||||||
"h11",
|
"h11": {"ip": "10.0.1.11/31", "mac": "08:00:00:00:01:11",
|
||||||
"h22"
|
"commands":["route add default gw 10.0.1.10 dev eth0",
|
||||||
],
|
"arp -i eth0 -s 10.0.1.10 08:00:00:00:01:00"]},
|
||||||
|
"h2": {"ip": "10.0.2.2/31", "mac": "08:00:00:00:02:02",
|
||||||
|
"commands":["route add default gw 10.0.2.3 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.2.3 08:00:00:00:02:00"]},
|
||||||
|
"h22": {"ip": "10.0.2.22/31", "mac": "08:00:00:00:02:22",
|
||||||
|
"commands":["route add default gw 10.0.2.23 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.2.23 08:00:00:00:02:00"]},
|
||||||
|
"h3": {"ip": "10.0.3.3/31", "mac": "08:00:00:00:03:03",
|
||||||
|
"commands":["route add default gw 10.0.3.2 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.3.2 08:00:00:00:03:00"]}
|
||||||
|
},
|
||||||
"switches": {
|
"switches": {
|
||||||
"s1": { "runtime_json" : "s1-runtime.json" },
|
"s1": { "runtime_json" : "s1-runtime.json" },
|
||||||
"s2": { "runtime_json" : "s2-runtime.json" },
|
"s2": { "runtime_json" : "s2-runtime.json" },
|
||||||
"s3": { "runtime_json" : "s3-runtime.json" }
|
"s3": { "runtime_json" : "s3-runtime.json" }
|
||||||
},
|
},
|
||||||
"links": [
|
"links": [
|
||||||
["h1", "s1"], ["h11", "s1"], ["s1", "s2", "0", 0.5], ["s1", "s3"],
|
["h1", "s1-p2"], ["h11", "s1-p1"], ["s1-p3", "s2-p3", "0", 0.5], ["s1-p4", "s3-p2"],
|
||||||
["s3", "s2"], ["s2", "h2"], ["s2", "h22"], ["s3", "h3"]
|
["s3-p3", "s2-p4"], ["h2", "s2-p2"], ["h22", "s2-p1"], ["h3", "s3-p1"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
5
exercises/firewall/Makefile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
BMV2_SWITCH_EXE = simple_switch_grpc
|
||||||
|
TOPO = pod-topo/topology.json
|
||||||
|
DEFAULT_PROG = basic.p4
|
||||||
|
|
||||||
|
include ../../utils/Makefile
|
||||||
|
After Width: | Height: | Size: 121 B |
215
exercises/firewall/README.md
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
# Implementing A Basic Stateful Firewall
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
The objective of this exercise is to write a P4 program that
|
||||||
|
implements a simple stateful firewall. To do this, we will use
|
||||||
|
a bloom filter. This exercise builds upon the basic exercise
|
||||||
|
so be sure to complete that one before trying this one.
|
||||||
|
|
||||||
|
We will use the pod-topology for this exercise, which consists of
|
||||||
|
four hosts connected to four switches, which are wired up as they
|
||||||
|
would be in a single pod of a fat tree topology.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Switch s1 will be configured with a P4 program that implements a
|
||||||
|
simple stateful firewall (`firewall.p4`), the rest of the switches will run the
|
||||||
|
basic IPv4 router program (`basic.p4`) from the previous exercise.
|
||||||
|
|
||||||
|
The firewall on s1 should have the following functionality:
|
||||||
|
* Hosts h1 and h2 are on the internal network and can always
|
||||||
|
connect to one another.
|
||||||
|
* Hosts h1 and h2 can freely connect to h3 and h4 on the
|
||||||
|
external network.
|
||||||
|
* Hosts h3 and h4 can only reply to connections once they have been
|
||||||
|
established from either h1 or h2, but cannot initiate new
|
||||||
|
connections to hosts on the internal network.
|
||||||
|
|
||||||
|
**Note**: This stateful firewall is implemented 100% in the dataplane
|
||||||
|
using a simple bloom filter. Thus there is some probability of
|
||||||
|
hash collisions that would let unwanted flows to pass through.
|
||||||
|
|
||||||
|
Our P4 program will be written for the V1Model architecture implemented
|
||||||
|
on P4.org's bmv2 software switch. The architecture file for the V1Model
|
||||||
|
can be found at: /usr/local/share/p4c/p4include/v1model.p4. This file
|
||||||
|
desribes the interfaces of the P4 programmable elements in the architecture,
|
||||||
|
the supported externs, as well as the architecture's standard metadata
|
||||||
|
fields. We encourage you to take a look at it.
|
||||||
|
|
||||||
|
> **Spoiler alert:** There is a reference solution in the `solution`
|
||||||
|
> sub-directory. Feel free to compare your implementation to the
|
||||||
|
> reference.
|
||||||
|
|
||||||
|
## Step 1: Run the (incomplete) starter code
|
||||||
|
|
||||||
|
The directory with this README also contains a skeleton P4 program,
|
||||||
|
`firewall.p4`. Your job will be to extend this skeleton program to
|
||||||
|
properly implement the firewall.
|
||||||
|
|
||||||
|
Before that, let's compile the incomplete `firewall.p4` and bring
|
||||||
|
up a switch in Mininet to test its behavior.
|
||||||
|
|
||||||
|
1. In your shell, run:
|
||||||
|
```bash
|
||||||
|
make run
|
||||||
|
```
|
||||||
|
This will:
|
||||||
|
* compile `firewall.p4`, and
|
||||||
|
* start the pod-topo in Mininet and configure all switches with
|
||||||
|
the appropriate P4 program + table entries, and
|
||||||
|
* configure all hosts with the commands listed in
|
||||||
|
[pod-topo/topology.json](./pod-topo/topology.json)
|
||||||
|
|
||||||
|
2. You should now see a Mininet command prompt. Try to run some iperf
|
||||||
|
TCP flows between the hosts. TCP flows within the internal
|
||||||
|
network should work:
|
||||||
|
```bash
|
||||||
|
mininet> iperf h1 h2
|
||||||
|
```
|
||||||
|
|
||||||
|
TCP flows from hosts in the internal network to the outside hosts
|
||||||
|
should also work:
|
||||||
|
```bash
|
||||||
|
mininet> iperf h1 h3
|
||||||
|
```
|
||||||
|
|
||||||
|
TCP flows from the outside hosts to hosts inside the
|
||||||
|
internal network should NOT work. However, since the firewall is not
|
||||||
|
implemented yet, the following should work:
|
||||||
|
```bash
|
||||||
|
mininet> iperf h3 h1
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Type `exit` to leave the Mininet command line.
|
||||||
|
Then, to stop mininet:
|
||||||
|
```bash
|
||||||
|
make stop
|
||||||
|
```
|
||||||
|
And to delete all pcaps, build files, and logs:
|
||||||
|
```bash
|
||||||
|
make clean
|
||||||
|
```
|
||||||
|
|
||||||
|
### A note about the control plane
|
||||||
|
|
||||||
|
A P4 program defines a packet-processing pipeline, but the rules
|
||||||
|
within each table are inserted by the control plane. When a rule
|
||||||
|
matches a packet, its action is invoked with parameters supplied by
|
||||||
|
the control plane as part of the rule.
|
||||||
|
|
||||||
|
In this exercise, we have already implemented the the control plane
|
||||||
|
logic for you. As part of bringing up the Mininet instance, the
|
||||||
|
`make` command will install packet-processing rules in the tables of
|
||||||
|
each switch. These are defined in the `sX-runtime.json` files, where
|
||||||
|
`X` corresponds to the switch number.
|
||||||
|
|
||||||
|
**Important:** We use P4Runtime to install the control plane rules. The
|
||||||
|
content of files `sX-runtime.json` refer to specific names of tables, keys, and
|
||||||
|
actions, as defined in the P4Info file produced by the compiler (look for the
|
||||||
|
file `build/firewall.p4.p4info.txt` after executing `make run`). Any changes in the P4
|
||||||
|
program that add or rename tables, keys, or actions will need to be reflected in
|
||||||
|
these `sX-runtime.json` files.
|
||||||
|
|
||||||
|
## Step 2: Implement Firewall
|
||||||
|
|
||||||
|
The `firewall.p4` file contains a skeleton P4 program with key pieces of
|
||||||
|
logic replaced by `TODO` comments. Your implementation should follow
|
||||||
|
the structure given in this file --- replace each `TODO` with logic
|
||||||
|
implementing the missing piece.
|
||||||
|
|
||||||
|
**High-level Approach:** We will use a bloom filter with two hash functions
|
||||||
|
to check if a packet coming into the internal network is a part of
|
||||||
|
an already established TCP connection. We will use two different register
|
||||||
|
arrays for the bloom filter, each to be updated by a hash function.
|
||||||
|
Using different register arrays makes our design amenable to high-speed
|
||||||
|
P4 targets that typically allow only one access to a register array per packet.
|
||||||
|
|
||||||
|
A complete `firewall.p4` will contain the following components:
|
||||||
|
|
||||||
|
1. Header type definitions for Ethernet (`ethernet_t`), IPv4 (`ipv4_t`) and TCP (`tcp_t`).
|
||||||
|
2. Parsers for Ethernet, IPv4 and TCP that populate `ethernet_t`, `ipv4_t` and `tcp_t` fields.
|
||||||
|
3. An action to drop a packet, using `mark_to_drop()`.
|
||||||
|
4. An action (called `compute_hashes`) to compute the bloom filter's two hashes using hash
|
||||||
|
algorithms `crc16` and `crc32`. The hashes will be computed on the packet 5-tuple consisting
|
||||||
|
of IPv4 source and destination addresses, source and destination port numbers and
|
||||||
|
the IPv4 protocol type.
|
||||||
|
5. An action (`ipv4_forward`) and a table (`ipv4_lpm`) that will perform basic
|
||||||
|
IPv4 forwarding (adopted from `basic.p4`).
|
||||||
|
6. An action (called `set_direction`) that will simply set a one-bit direction variable
|
||||||
|
as per the action's parameter.
|
||||||
|
7. A table (called `check_ports`) that will read the ingress and egress port of a packet
|
||||||
|
(after IPv4 forwarding) and invoke `set_direction`. The direction will be set to `1`,
|
||||||
|
if the packet is incoming into the internal network. Otherwise, the direction will be set to `0`.
|
||||||
|
To achieve this, the file `pod-topo/s1-runtime.json` contains the appropriate control plane
|
||||||
|
entries for the `check_ports` table.
|
||||||
|
8. A control that will:
|
||||||
|
1. First apply the table `ipv4_lpm` if the packet has a valid IPv4 header.
|
||||||
|
2. Then if the TCP header is valid, apply the `check_ports` table to determine the direction.
|
||||||
|
3. Apply the `compute_hashes` action to compute the two hash values which are the bit positions
|
||||||
|
in the two register arrays of the bloom filter (`reg_pos_one` and `reg_pos_two`).
|
||||||
|
When the direction is `1` i.e. the packet is incoming into the internal network,
|
||||||
|
`compute_hashes` will be invoked by swapping the source and destination IPv4 addresses
|
||||||
|
and the source and destination ports. This is to check against bloom filter's set bits
|
||||||
|
when the TCP connection was initially made from the internal network.
|
||||||
|
4. **TODO:** If the TCP packet is going out of the internal network and is a SYN packet,
|
||||||
|
set both the bloom filter arrays at the computed bit positions (`reg_pos_one` and `reg_pos_two`).
|
||||||
|
Else, if the TCP packet is entering the internal network,
|
||||||
|
read both the bloom filter arrays at the computed bit positions and drop the packet if
|
||||||
|
either is not set.
|
||||||
|
9. A deparser that emits the Ethernet, IPv4 and TCP headers in the right order.
|
||||||
|
10. A `package` instantiation supplied with the parser, control, and deparser.
|
||||||
|
> In general, a package also requires instances of checksum verification
|
||||||
|
> and recomputation controls. These are not necessary for this tutorial
|
||||||
|
> and are replaced with instantiations of empty controls.
|
||||||
|
|
||||||
|
|
||||||
|
## Step 3: Run your solution
|
||||||
|
|
||||||
|
Follow the instructions from Step 1. This time, the `iperf` flow between
|
||||||
|
h3 and h1 should be blocked by the firewall.
|
||||||
|
|
||||||
|
### Food for thought
|
||||||
|
|
||||||
|
You may have noticed that in this simple stateful firewall, we are adding
|
||||||
|
new TCP connections to the bloom filter (based on outgoing SYN packets).
|
||||||
|
However, we are not removing them in case of TCP connection teardown
|
||||||
|
(FIN packets). How would you implement the removal of TCP connections that are
|
||||||
|
no longer active?
|
||||||
|
|
||||||
|
Things to consider:
|
||||||
|
- Can we simply set the bloom filter array bits to `0` on
|
||||||
|
receiving a FIN packet? What happens when there is one hash collision in
|
||||||
|
the bloom filter arrays between two _active_ TCP connections?
|
||||||
|
- How can we modify our bloom filter structure so that the deletion
|
||||||
|
operation can be properly supported?
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
|
There are several problems that might manifest as you develop your program:
|
||||||
|
|
||||||
|
1. `firewall.p4` might fail to compile. In this case, `make run` will
|
||||||
|
report the error emitted from the compiler and halt.
|
||||||
|
|
||||||
|
2. `firewall.p4` might compile but fail to support the control plane
|
||||||
|
rules in the `s1-runtime.json` file that `make run` tries to install
|
||||||
|
using P4Runtime. In this case, `make run` will report errors if control
|
||||||
|
plane rules cannot be installed. Use these error messages to fix your
|
||||||
|
`firewall.p4` implementation.
|
||||||
|
|
||||||
|
3. `firewall.p4` might compile, and the control plane rules might be
|
||||||
|
installed, but the switch might not process packets in the desired
|
||||||
|
way. The `logs/sX.log` files contain detailed logs that describe
|
||||||
|
how each switch processes each packet. The output is detailed and can
|
||||||
|
help pinpoint logic errors in your implementation.
|
||||||
|
|
||||||
|
#### Cleaning up Mininet
|
||||||
|
|
||||||
|
In the latter two cases above, `make run` may leave a Mininet instance
|
||||||
|
running in the background. Use the following command to clean up
|
||||||
|
these instances:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make stop
|
||||||
|
```
|
||||||
|
|
||||||
176
exercises/firewall/basic.p4
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
/* -*- P4_16 -*- */
|
||||||
|
#include <core.p4>
|
||||||
|
#include <v1model.p4>
|
||||||
|
|
||||||
|
const bit<16> TYPE_IPV4 = 0x800;
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** H E A D E R S ***********************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
typedef bit<9> egressSpec_t;
|
||||||
|
typedef bit<48> macAddr_t;
|
||||||
|
typedef bit<32> ip4Addr_t;
|
||||||
|
|
||||||
|
header ethernet_t {
|
||||||
|
macAddr_t dstAddr;
|
||||||
|
macAddr_t srcAddr;
|
||||||
|
bit<16> etherType;
|
||||||
|
}
|
||||||
|
|
||||||
|
header ipv4_t {
|
||||||
|
bit<4> version;
|
||||||
|
bit<4> ihl;
|
||||||
|
bit<8> diffserv;
|
||||||
|
bit<16> totalLen;
|
||||||
|
bit<16> identification;
|
||||||
|
bit<3> flags;
|
||||||
|
bit<13> fragOffset;
|
||||||
|
bit<8> ttl;
|
||||||
|
bit<8> protocol;
|
||||||
|
bit<16> hdrChecksum;
|
||||||
|
ip4Addr_t srcAddr;
|
||||||
|
ip4Addr_t dstAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct metadata {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
|
|
||||||
|
struct headers {
|
||||||
|
ethernet_t ethernet;
|
||||||
|
ipv4_t ipv4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** P A R S E R ***********************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
parser MyParser(packet_in packet,
|
||||||
|
out headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
|
||||||
|
state start {
|
||||||
|
transition parse_ethernet;
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_ethernet {
|
||||||
|
packet.extract(hdr.ethernet);
|
||||||
|
transition select(hdr.ethernet.etherType) {
|
||||||
|
TYPE_IPV4: parse_ipv4;
|
||||||
|
default: accept;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_ipv4 {
|
||||||
|
packet.extract(hdr.ipv4);
|
||||||
|
transition accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************ C H E C K S U M V E R I F I C A T I O N *************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
|
||||||
|
apply { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************** I N G R E S S P R O C E S S I N G *******************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyIngress(inout headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
action drop() {
|
||||||
|
mark_to_drop(standard_metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
|
||||||
|
standard_metadata.egress_spec = port;
|
||||||
|
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
|
||||||
|
hdr.ethernet.dstAddr = dstAddr;
|
||||||
|
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
table ipv4_lpm {
|
||||||
|
key = {
|
||||||
|
hdr.ipv4.dstAddr: lpm;
|
||||||
|
}
|
||||||
|
actions = {
|
||||||
|
ipv4_forward;
|
||||||
|
drop;
|
||||||
|
NoAction;
|
||||||
|
}
|
||||||
|
size = 1024;
|
||||||
|
default_action = drop();
|
||||||
|
}
|
||||||
|
|
||||||
|
apply {
|
||||||
|
if (hdr.ipv4.isValid()) {
|
||||||
|
ipv4_lpm.apply();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************** E G R E S S P R O C E S S I N G *******************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyEgress(inout headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
apply { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************* C H E C K S U M C O M P U T A T I O N **************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
|
||||||
|
apply {
|
||||||
|
update_checksum(
|
||||||
|
hdr.ipv4.isValid(),
|
||||||
|
{ hdr.ipv4.version,
|
||||||
|
hdr.ipv4.ihl,
|
||||||
|
hdr.ipv4.diffserv,
|
||||||
|
hdr.ipv4.totalLen,
|
||||||
|
hdr.ipv4.identification,
|
||||||
|
hdr.ipv4.flags,
|
||||||
|
hdr.ipv4.fragOffset,
|
||||||
|
hdr.ipv4.ttl,
|
||||||
|
hdr.ipv4.protocol,
|
||||||
|
hdr.ipv4.srcAddr,
|
||||||
|
hdr.ipv4.dstAddr },
|
||||||
|
hdr.ipv4.hdrChecksum,
|
||||||
|
HashAlgorithm.csum16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** D E P A R S E R *******************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyDeparser(packet_out packet, in headers hdr) {
|
||||||
|
apply {
|
||||||
|
packet.emit(hdr.ethernet);
|
||||||
|
packet.emit(hdr.ipv4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** S W I T C H *******************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
V1Switch(
|
||||||
|
MyParser(),
|
||||||
|
MyVerifyChecksum(),
|
||||||
|
MyIngress(),
|
||||||
|
MyEgress(),
|
||||||
|
MyComputeChecksum(),
|
||||||
|
MyDeparser()
|
||||||
|
) main;
|
||||||
BIN
exercises/firewall/firewall-topo.png
Normal file
|
After Width: | Height: | Size: 171 KiB |
276
exercises/firewall/firewall.p4
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
/* -*- P4_16 -*- */
|
||||||
|
#include <core.p4>
|
||||||
|
#include <v1model.p4>
|
||||||
|
|
||||||
|
/* CONSTANTS */
|
||||||
|
|
||||||
|
const bit<16> TYPE_IPV4 = 0x800;
|
||||||
|
const bit<8> TYPE_TCP = 6;
|
||||||
|
|
||||||
|
#define BLOOM_FILTER_ENTRIES 4096
|
||||||
|
#define BLOOM_FILTER_BIT_WIDTH 1
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** H E A D E R S ***********************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
typedef bit<9> egressSpec_t;
|
||||||
|
typedef bit<48> macAddr_t;
|
||||||
|
typedef bit<32> ip4Addr_t;
|
||||||
|
|
||||||
|
header ethernet_t {
|
||||||
|
macAddr_t dstAddr;
|
||||||
|
macAddr_t srcAddr;
|
||||||
|
bit<16> etherType;
|
||||||
|
}
|
||||||
|
|
||||||
|
header ipv4_t {
|
||||||
|
bit<4> version;
|
||||||
|
bit<4> ihl;
|
||||||
|
bit<8> diffserv;
|
||||||
|
bit<16> totalLen;
|
||||||
|
bit<16> identification;
|
||||||
|
bit<3> flags;
|
||||||
|
bit<13> fragOffset;
|
||||||
|
bit<8> ttl;
|
||||||
|
bit<8> protocol;
|
||||||
|
bit<16> hdrChecksum;
|
||||||
|
ip4Addr_t srcAddr;
|
||||||
|
ip4Addr_t dstAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
header tcp_t{
|
||||||
|
bit<16> srcPort;
|
||||||
|
bit<16> dstPort;
|
||||||
|
bit<32> seqNo;
|
||||||
|
bit<32> ackNo;
|
||||||
|
bit<4> dataOffset;
|
||||||
|
bit<4> res;
|
||||||
|
bit<1> cwr;
|
||||||
|
bit<1> ece;
|
||||||
|
bit<1> urg;
|
||||||
|
bit<1> ack;
|
||||||
|
bit<1> psh;
|
||||||
|
bit<1> rst;
|
||||||
|
bit<1> syn;
|
||||||
|
bit<1> fin;
|
||||||
|
bit<16> window;
|
||||||
|
bit<16> checksum;
|
||||||
|
bit<16> urgentPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct metadata {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
|
|
||||||
|
struct headers {
|
||||||
|
ethernet_t ethernet;
|
||||||
|
ipv4_t ipv4;
|
||||||
|
tcp_t tcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** P A R S E R ***********************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
parser MyParser(packet_in packet,
|
||||||
|
out headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
|
||||||
|
state start {
|
||||||
|
transition parse_ethernet;
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_ethernet {
|
||||||
|
packet.extract(hdr.ethernet);
|
||||||
|
transition select(hdr.ethernet.etherType) {
|
||||||
|
TYPE_IPV4: parse_ipv4;
|
||||||
|
default: accept;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_ipv4 {
|
||||||
|
packet.extract(hdr.ipv4);
|
||||||
|
transition select(hdr.ipv4.protocol){
|
||||||
|
TYPE_TCP: tcp;
|
||||||
|
default: accept;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state tcp {
|
||||||
|
packet.extract(hdr.tcp);
|
||||||
|
transition accept;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************ C H E C K S U M V E R I F I C A T I O N *************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
|
||||||
|
apply { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************** I N G R E S S P R O C E S S I N G *******************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyIngress(inout headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
|
||||||
|
register<bit<BLOOM_FILTER_BIT_WIDTH>>(BLOOM_FILTER_ENTRIES) bloom_filter_1;
|
||||||
|
register<bit<BLOOM_FILTER_BIT_WIDTH>>(BLOOM_FILTER_ENTRIES) bloom_filter_2;
|
||||||
|
bit<32> reg_pos_one; bit<32> reg_pos_two;
|
||||||
|
bit<1> reg_val_one; bit<1> reg_val_two;
|
||||||
|
bit<1> direction;
|
||||||
|
|
||||||
|
action drop() {
|
||||||
|
mark_to_drop(standard_metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
action compute_hashes(ip4Addr_t ipAddr1, ip4Addr_t ipAddr2, bit<16> port1, bit<16> port2){
|
||||||
|
//Get register position
|
||||||
|
hash(reg_pos_one, HashAlgorithm.crc16, (bit<32>)0, {ipAddr1,
|
||||||
|
ipAddr2,
|
||||||
|
port1,
|
||||||
|
port2,
|
||||||
|
hdr.ipv4.protocol},
|
||||||
|
(bit<32>)BLOOM_FILTER_ENTRIES);
|
||||||
|
|
||||||
|
hash(reg_pos_two, HashAlgorithm.crc32, (bit<32>)0, {ipAddr1,
|
||||||
|
ipAddr2,
|
||||||
|
port1,
|
||||||
|
port2,
|
||||||
|
hdr.ipv4.protocol},
|
||||||
|
(bit<32>)BLOOM_FILTER_ENTRIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
|
||||||
|
standard_metadata.egress_spec = port;
|
||||||
|
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
|
||||||
|
hdr.ethernet.dstAddr = dstAddr;
|
||||||
|
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
table ipv4_lpm {
|
||||||
|
key = {
|
||||||
|
hdr.ipv4.dstAddr: lpm;
|
||||||
|
}
|
||||||
|
actions = {
|
||||||
|
ipv4_forward;
|
||||||
|
drop;
|
||||||
|
NoAction;
|
||||||
|
}
|
||||||
|
size = 1024;
|
||||||
|
default_action = drop();
|
||||||
|
}
|
||||||
|
|
||||||
|
action set_direction(bit<1> dir) {
|
||||||
|
direction = dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
table check_ports {
|
||||||
|
key = {
|
||||||
|
standard_metadata.ingress_port: exact;
|
||||||
|
standard_metadata.egress_spec: exact;
|
||||||
|
}
|
||||||
|
actions = {
|
||||||
|
set_direction;
|
||||||
|
NoAction;
|
||||||
|
}
|
||||||
|
size = 1024;
|
||||||
|
default_action = NoAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
apply {
|
||||||
|
if (hdr.ipv4.isValid()){
|
||||||
|
ipv4_lpm.apply();
|
||||||
|
if (hdr.tcp.isValid()){
|
||||||
|
direction = 0; // default
|
||||||
|
if (check_ports.apply().hit) {
|
||||||
|
// test and set the bloom filter
|
||||||
|
if (direction == 0) {
|
||||||
|
compute_hashes(hdr.ipv4.srcAddr, hdr.ipv4.dstAddr, hdr.tcp.srcPort, hdr.tcp.dstPort);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
compute_hashes(hdr.ipv4.dstAddr, hdr.ipv4.srcAddr, hdr.tcp.dstPort, hdr.tcp.srcPort);
|
||||||
|
}
|
||||||
|
// Packet comes from internal network
|
||||||
|
if (direction == 0){
|
||||||
|
// TODO: this packet is part of an outgoing TCP connection.
|
||||||
|
// We need to set the bloom filter if this is a SYN packet
|
||||||
|
// E.g. bloom_filter_1.write(<index>, <value>);
|
||||||
|
}
|
||||||
|
// Packet comes from outside
|
||||||
|
else if (direction == 1){
|
||||||
|
// TODO: this packet is part of an incomming TCP connection.
|
||||||
|
// We need to check if this packet is allowed to pass by reading the bloom filter
|
||||||
|
// E.g. bloom_filter_1.read(<value>, <index>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************** E G R E S S P R O C E S S I N G *******************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyEgress(inout headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
apply { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************* C H E C K S U M C O M P U T A T I O N **************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
|
||||||
|
apply {
|
||||||
|
update_checksum(
|
||||||
|
hdr.ipv4.isValid(),
|
||||||
|
{ hdr.ipv4.version,
|
||||||
|
hdr.ipv4.ihl,
|
||||||
|
hdr.ipv4.diffserv,
|
||||||
|
hdr.ipv4.totalLen,
|
||||||
|
hdr.ipv4.identification,
|
||||||
|
hdr.ipv4.flags,
|
||||||
|
hdr.ipv4.fragOffset,
|
||||||
|
hdr.ipv4.ttl,
|
||||||
|
hdr.ipv4.protocol,
|
||||||
|
hdr.ipv4.srcAddr,
|
||||||
|
hdr.ipv4.dstAddr },
|
||||||
|
hdr.ipv4.hdrChecksum,
|
||||||
|
HashAlgorithm.csum16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** D E P A R S E R *******************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyDeparser(packet_out packet, in headers hdr) {
|
||||||
|
apply {
|
||||||
|
packet.emit(hdr.ethernet);
|
||||||
|
packet.emit(hdr.ipv4);
|
||||||
|
packet.emit(hdr.tcp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** S W I T C H *******************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
V1Switch(
|
||||||
|
MyParser(),
|
||||||
|
MyVerifyChecksum(),
|
||||||
|
MyIngress(),
|
||||||
|
MyEgress(),
|
||||||
|
MyComputeChecksum(),
|
||||||
|
MyDeparser()
|
||||||
|
) main;
|
||||||
145
exercises/firewall/pod-topo/s1-runtime.json
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
{
|
||||||
|
"target": "bmv2",
|
||||||
|
"p4info": "build/firewall.p4.p4info.txt",
|
||||||
|
"bmv2_json": "build/firewall.json",
|
||||||
|
"table_entries": [
|
||||||
|
{
|
||||||
|
"table": "MyIngress.check_ports",
|
||||||
|
"match": {
|
||||||
|
"standard_metadata.ingress_port": 1,
|
||||||
|
"standard_metadata.egress_spec": 3
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.set_direction",
|
||||||
|
"action_params": {
|
||||||
|
"dir": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.check_ports",
|
||||||
|
"match": {
|
||||||
|
"standard_metadata.ingress_port": 1,
|
||||||
|
"standard_metadata.egress_spec": 4
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.set_direction",
|
||||||
|
"action_params": {
|
||||||
|
"dir": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.check_ports",
|
||||||
|
"match": {
|
||||||
|
"standard_metadata.ingress_port": 2,
|
||||||
|
"standard_metadata.egress_spec": 3
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.set_direction",
|
||||||
|
"action_params": {
|
||||||
|
"dir": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.check_ports",
|
||||||
|
"match": {
|
||||||
|
"standard_metadata.ingress_port": 2,
|
||||||
|
"standard_metadata.egress_spec": 4
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.set_direction",
|
||||||
|
"action_params": {
|
||||||
|
"dir": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.check_ports",
|
||||||
|
"match": {
|
||||||
|
"standard_metadata.ingress_port": 3,
|
||||||
|
"standard_metadata.egress_spec": 1
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.set_direction",
|
||||||
|
"action_params": {
|
||||||
|
"dir": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.check_ports",
|
||||||
|
"match": {
|
||||||
|
"standard_metadata.ingress_port": 3,
|
||||||
|
"standard_metadata.egress_spec": 2
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.set_direction",
|
||||||
|
"action_params": {
|
||||||
|
"dir": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.check_ports",
|
||||||
|
"match": {
|
||||||
|
"standard_metadata.ingress_port": 4,
|
||||||
|
"standard_metadata.egress_spec": 1
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.set_direction",
|
||||||
|
"action_params": {
|
||||||
|
"dir": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.check_ports",
|
||||||
|
"match": {
|
||||||
|
"standard_metadata.ingress_port": 4,
|
||||||
|
"standard_metadata.egress_spec": 2
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.set_direction",
|
||||||
|
"action_params": {
|
||||||
|
"dir": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyIngress.drop",
|
||||||
|
"action_params": { }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:11",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:22",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:03:00",
|
||||||
|
"port": 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:04:00",
|
||||||
|
"port": 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
57
exercises/firewall/pod-topo/s2-runtime.json
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"target": "bmv2",
|
||||||
|
"p4info": "build/basic.p4.p4info.txt",
|
||||||
|
"bmv2_json": "build/basic.json",
|
||||||
|
"table_entries": [
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyIngress.drop",
|
||||||
|
"action_params": { }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:03:00",
|
||||||
|
"port": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:04:00",
|
||||||
|
"port": 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:03:33",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:04:44",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
57
exercises/firewall/pod-topo/s3-runtime.json
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"target": "bmv2",
|
||||||
|
"p4info": "build/basic.p4.p4info.txt",
|
||||||
|
"bmv2_json": "build/basic.json",
|
||||||
|
"table_entries": [
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyIngress.drop",
|
||||||
|
"action_params": { }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
57
exercises/firewall/pod-topo/s4-runtime.json
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"target": "bmv2",
|
||||||
|
"p4info": "build/basic.p4.p4info.txt",
|
||||||
|
"bmv2_json": "build/basic.json",
|
||||||
|
"table_entries": [
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyIngress.drop",
|
||||||
|
"action_params": { }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
27
exercises/firewall/pod-topo/topology.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"hosts": {
|
||||||
|
"h1": {"ip": "10.0.1.1/24", "mac": "08:00:00:00:01:11",
|
||||||
|
"commands":["route add default gw 10.0.1.10 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.1.10 08:00:00:00:01:00"]},
|
||||||
|
"h2": {"ip": "10.0.2.2/24", "mac": "08:00:00:00:02:22",
|
||||||
|
"commands":["route add default gw 10.0.2.20 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.2.20 08:00:00:00:02:00"]},
|
||||||
|
"h3": {"ip": "10.0.3.3/24", "mac": "08:00:00:00:03:33",
|
||||||
|
"commands":["route add default gw 10.0.3.30 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.3.30 08:00:00:00:03:00"]},
|
||||||
|
"h4": {"ip": "10.0.4.4/24", "mac": "08:00:00:00:04:44",
|
||||||
|
"commands":["route add default gw 10.0.4.40 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.4.40 08:00:00:00:04:00"]}
|
||||||
|
},
|
||||||
|
"switches": {
|
||||||
|
"s1": { "runtime_json" : "pod-topo/s1-runtime.json",
|
||||||
|
"program" : "build/firewall.json" },
|
||||||
|
"s2": { "runtime_json" : "pod-topo/s2-runtime.json" },
|
||||||
|
"s3": { "runtime_json" : "pod-topo/s3-runtime.json" },
|
||||||
|
"s4": { "runtime_json" : "pod-topo/s4-runtime.json" }
|
||||||
|
},
|
||||||
|
"links": [
|
||||||
|
["h1", "s1-p1"], ["h2", "s1-p2"], ["s1-p3", "s3-p1"], ["s1-p4", "s4-p2"],
|
||||||
|
["h3", "s2-p1"], ["h4", "s2-p2"], ["s2-p3", "s4-p1"], ["s2-p4", "s3-p2"]
|
||||||
|
]
|
||||||
|
}
|
||||||
282
exercises/firewall/solution/firewall.p4
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
/* -*- P4_16 -*- */
|
||||||
|
#include <core.p4>
|
||||||
|
#include <v1model.p4>
|
||||||
|
|
||||||
|
/* CONSTANTS */
|
||||||
|
|
||||||
|
const bit<16> TYPE_IPV4 = 0x800;
|
||||||
|
const bit<8> TYPE_TCP = 6;
|
||||||
|
|
||||||
|
#define BLOOM_FILTER_ENTRIES 4096
|
||||||
|
#define BLOOM_FILTER_BIT_WIDTH 1
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** H E A D E R S ***********************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
typedef bit<9> egressSpec_t;
|
||||||
|
typedef bit<48> macAddr_t;
|
||||||
|
typedef bit<32> ip4Addr_t;
|
||||||
|
|
||||||
|
header ethernet_t {
|
||||||
|
macAddr_t dstAddr;
|
||||||
|
macAddr_t srcAddr;
|
||||||
|
bit<16> etherType;
|
||||||
|
}
|
||||||
|
|
||||||
|
header ipv4_t {
|
||||||
|
bit<4> version;
|
||||||
|
bit<4> ihl;
|
||||||
|
bit<8> diffserv;
|
||||||
|
bit<16> totalLen;
|
||||||
|
bit<16> identification;
|
||||||
|
bit<3> flags;
|
||||||
|
bit<13> fragOffset;
|
||||||
|
bit<8> ttl;
|
||||||
|
bit<8> protocol;
|
||||||
|
bit<16> hdrChecksum;
|
||||||
|
ip4Addr_t srcAddr;
|
||||||
|
ip4Addr_t dstAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
header tcp_t{
|
||||||
|
bit<16> srcPort;
|
||||||
|
bit<16> dstPort;
|
||||||
|
bit<32> seqNo;
|
||||||
|
bit<32> ackNo;
|
||||||
|
bit<4> dataOffset;
|
||||||
|
bit<4> res;
|
||||||
|
bit<1> cwr;
|
||||||
|
bit<1> ece;
|
||||||
|
bit<1> urg;
|
||||||
|
bit<1> ack;
|
||||||
|
bit<1> psh;
|
||||||
|
bit<1> rst;
|
||||||
|
bit<1> syn;
|
||||||
|
bit<1> fin;
|
||||||
|
bit<16> window;
|
||||||
|
bit<16> checksum;
|
||||||
|
bit<16> urgentPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct metadata {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
|
|
||||||
|
struct headers {
|
||||||
|
ethernet_t ethernet;
|
||||||
|
ipv4_t ipv4;
|
||||||
|
tcp_t tcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** P A R S E R ***********************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
parser MyParser(packet_in packet,
|
||||||
|
out headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
|
||||||
|
state start {
|
||||||
|
transition parse_ethernet;
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_ethernet {
|
||||||
|
packet.extract(hdr.ethernet);
|
||||||
|
transition select(hdr.ethernet.etherType) {
|
||||||
|
TYPE_IPV4: parse_ipv4;
|
||||||
|
default: accept;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_ipv4 {
|
||||||
|
packet.extract(hdr.ipv4);
|
||||||
|
transition select(hdr.ipv4.protocol){
|
||||||
|
TYPE_TCP: tcp;
|
||||||
|
default: accept;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state tcp {
|
||||||
|
packet.extract(hdr.tcp);
|
||||||
|
transition accept;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************ C H E C K S U M V E R I F I C A T I O N *************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
|
||||||
|
apply { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************** I N G R E S S P R O C E S S I N G *******************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyIngress(inout headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
|
||||||
|
register<bit<BLOOM_FILTER_BIT_WIDTH>>(BLOOM_FILTER_ENTRIES) bloom_filter_1;
|
||||||
|
register<bit<BLOOM_FILTER_BIT_WIDTH>>(BLOOM_FILTER_ENTRIES) bloom_filter_2;
|
||||||
|
bit<32> reg_pos_one; bit<32> reg_pos_two;
|
||||||
|
bit<1> reg_val_one; bit<1> reg_val_two;
|
||||||
|
bit<1> direction;
|
||||||
|
|
||||||
|
action drop() {
|
||||||
|
mark_to_drop(standard_metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
action compute_hashes(ip4Addr_t ipAddr1, ip4Addr_t ipAddr2, bit<16> port1, bit<16> port2){
|
||||||
|
//Get register position
|
||||||
|
hash(reg_pos_one, HashAlgorithm.crc16, (bit<32>)0, {ipAddr1,
|
||||||
|
ipAddr2,
|
||||||
|
port1,
|
||||||
|
port2,
|
||||||
|
hdr.ipv4.protocol},
|
||||||
|
(bit<32>)BLOOM_FILTER_ENTRIES);
|
||||||
|
|
||||||
|
hash(reg_pos_two, HashAlgorithm.crc32, (bit<32>)0, {ipAddr1,
|
||||||
|
ipAddr2,
|
||||||
|
port1,
|
||||||
|
port2,
|
||||||
|
hdr.ipv4.protocol},
|
||||||
|
(bit<32>)BLOOM_FILTER_ENTRIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
|
||||||
|
standard_metadata.egress_spec = port;
|
||||||
|
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
|
||||||
|
hdr.ethernet.dstAddr = dstAddr;
|
||||||
|
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
table ipv4_lpm {
|
||||||
|
key = {
|
||||||
|
hdr.ipv4.dstAddr: lpm;
|
||||||
|
}
|
||||||
|
actions = {
|
||||||
|
ipv4_forward;
|
||||||
|
drop;
|
||||||
|
NoAction;
|
||||||
|
}
|
||||||
|
size = 1024;
|
||||||
|
default_action = drop();
|
||||||
|
}
|
||||||
|
|
||||||
|
action set_direction(bit<1> dir) {
|
||||||
|
direction = dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
table check_ports {
|
||||||
|
key = {
|
||||||
|
standard_metadata.ingress_port: exact;
|
||||||
|
standard_metadata.egress_spec: exact;
|
||||||
|
}
|
||||||
|
actions = {
|
||||||
|
set_direction;
|
||||||
|
NoAction;
|
||||||
|
}
|
||||||
|
size = 1024;
|
||||||
|
default_action = NoAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
apply {
|
||||||
|
if (hdr.ipv4.isValid()){
|
||||||
|
ipv4_lpm.apply();
|
||||||
|
if (hdr.tcp.isValid()){
|
||||||
|
direction = 0; // default
|
||||||
|
if (check_ports.apply().hit) {
|
||||||
|
// test and set the bloom filter
|
||||||
|
if (direction == 0) {
|
||||||
|
compute_hashes(hdr.ipv4.srcAddr, hdr.ipv4.dstAddr, hdr.tcp.srcPort, hdr.tcp.dstPort);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
compute_hashes(hdr.ipv4.dstAddr, hdr.ipv4.srcAddr, hdr.tcp.dstPort, hdr.tcp.srcPort);
|
||||||
|
}
|
||||||
|
// Packet comes from internal network
|
||||||
|
if (direction == 0){
|
||||||
|
// If there is a syn we update the bloom filter and add the entry
|
||||||
|
if (hdr.tcp.syn == 1){
|
||||||
|
bloom_filter_1.write(reg_pos_one, 1);
|
||||||
|
bloom_filter_2.write(reg_pos_two, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Packet comes from outside
|
||||||
|
else if (direction == 1){
|
||||||
|
// Read bloom filter cells to check if there are 1's
|
||||||
|
bloom_filter_1.read(reg_val_one, reg_pos_one);
|
||||||
|
bloom_filter_2.read(reg_val_two, reg_pos_two);
|
||||||
|
// only allow flow to pass if both entries are set
|
||||||
|
if (reg_val_one != 1 || reg_val_two != 1){
|
||||||
|
drop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************** E G R E S S P R O C E S S I N G *******************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyEgress(inout headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
apply { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************* C H E C K S U M C O M P U T A T I O N **************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
|
||||||
|
apply {
|
||||||
|
update_checksum(
|
||||||
|
hdr.ipv4.isValid(),
|
||||||
|
{ hdr.ipv4.version,
|
||||||
|
hdr.ipv4.ihl,
|
||||||
|
hdr.ipv4.diffserv,
|
||||||
|
hdr.ipv4.totalLen,
|
||||||
|
hdr.ipv4.identification,
|
||||||
|
hdr.ipv4.flags,
|
||||||
|
hdr.ipv4.fragOffset,
|
||||||
|
hdr.ipv4.ttl,
|
||||||
|
hdr.ipv4.protocol,
|
||||||
|
hdr.ipv4.srcAddr,
|
||||||
|
hdr.ipv4.dstAddr },
|
||||||
|
hdr.ipv4.hdrChecksum,
|
||||||
|
HashAlgorithm.csum16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** D E P A R S E R *******************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyDeparser(packet_out packet, in headers hdr) {
|
||||||
|
apply {
|
||||||
|
packet.emit(hdr.ethernet);
|
||||||
|
packet.emit(hdr.ipv4);
|
||||||
|
packet.emit(hdr.tcp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** S W I T C H *******************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
V1Switch(
|
||||||
|
MyParser(),
|
||||||
|
MyVerifyChecksum(),
|
||||||
|
MyIngress(),
|
||||||
|
MyEgress(),
|
||||||
|
MyComputeChecksum(),
|
||||||
|
MyDeparser()
|
||||||
|
) main;
|
||||||
4
exercises/link_monitor/Makefile
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
BMV2_SWITCH_EXE = simple_switch_grpc
|
||||||
|
TOPO = pod-topo/topology.json
|
||||||
|
|
||||||
|
include ../../utils/Makefile
|
||||||
|
After Width: | Height: | Size: 97 B |
227
exercises/link_monitor/README.md
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
# Implementing Link Monitoring
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
The objective of this exercise is to write a P4 program that enables
|
||||||
|
a host to monitor the utilization of all links in the network. This
|
||||||
|
exercise builds upon the basic IPv4 forwarding exercise so be sure
|
||||||
|
to complete that one before attempting this one. Specifically, we
|
||||||
|
will modify the basic P4 program to process a source routed probe
|
||||||
|
packet such that it is able to pick up the egress link utilization
|
||||||
|
at each hop and deliver it to a host for monitoring purposes.
|
||||||
|
|
||||||
|
Our probe packet will contain the following three header types:
|
||||||
|
```
|
||||||
|
// Top-level probe header, indicates how many hops this probe
|
||||||
|
// packet has traversed so far.
|
||||||
|
header probe_t {
|
||||||
|
bit<8> hop_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The data added to the probe by each switch at each hop.
|
||||||
|
header probe_data_t {
|
||||||
|
bit<1> bos;
|
||||||
|
bit<7> swid;
|
||||||
|
bit<8> port;
|
||||||
|
bit<32> byte_cnt;
|
||||||
|
time_t last_time;
|
||||||
|
time_t cur_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indicates the egress port the switch should send this probe
|
||||||
|
// packet out of. There is one of these headers for each hop.
|
||||||
|
header probe_fwd_t {
|
||||||
|
bit<8> egress_spec;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
We will use the pod-topology for this exercise, which consists of
|
||||||
|
four hosts connected to four switches that are wired up as they
|
||||||
|
would be in a single pod of a fat tree topology.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
In order to monitor the link utilization our switch will maintain
|
||||||
|
two register arrays:
|
||||||
|
* `byte_cnt_reg` - counts the number of bytes transmitted out of
|
||||||
|
each port since the last probe packet was transmitted out of
|
||||||
|
the port.
|
||||||
|
* `last_time_reg` - stores the last time that a probe packet was
|
||||||
|
transmitted out of each port.
|
||||||
|
|
||||||
|
Our P4 program will be written for the V1Model architecture implemented
|
||||||
|
on P4.org's bmv2 software switch. The architecture file for the V1Model
|
||||||
|
can be found at: /usr/local/share/p4c/p4include/v1model.p4. This file
|
||||||
|
desribes the interfaces of the P4 programmable elements in the architecture,
|
||||||
|
the supported externs, as well as the architecture's standard metadata
|
||||||
|
fields. We encourage you to take a look at it.
|
||||||
|
|
||||||
|
> **Spoiler alert:** There is a reference solution in the `solution`
|
||||||
|
> sub-directory. Feel free to compare your implementation to the
|
||||||
|
> reference.
|
||||||
|
|
||||||
|
## Step 1: Run the (incomplete) starter code
|
||||||
|
|
||||||
|
The directory with this README contains a skeleton P4 program,
|
||||||
|
`link_monitor.p4`, which implements basic IPv4 forwarding, as well
|
||||||
|
as source routing of the probe packets. Your job will be to
|
||||||
|
extend this skeleton program to fill out the fields in the probe
|
||||||
|
packet.
|
||||||
|
|
||||||
|
Before that, let's compile and test the incomplete `link_monitor.p4`
|
||||||
|
program:
|
||||||
|
|
||||||
|
1. In your shell, run:
|
||||||
|
```bash
|
||||||
|
make run
|
||||||
|
```
|
||||||
|
This will:
|
||||||
|
* compile `link_monitor.p4`, and
|
||||||
|
* start the pod-topo in Mininet and configure all switches with
|
||||||
|
the `link_monitor.p4` program + table entries, and
|
||||||
|
* configure all hosts with the commands listed in
|
||||||
|
[pod-topo/topology.json](./pod-topo/topology.json)
|
||||||
|
|
||||||
|
2. You should now see a Mininet command prompt. Open two terminals
|
||||||
|
on `h1`:
|
||||||
|
```bash
|
||||||
|
mininet> xterm h1 h1
|
||||||
|
```
|
||||||
|
3. In one of the xterms run the `send.py` script to start sending
|
||||||
|
probe packets every second. Each of these probe packets takes the
|
||||||
|
path indicated in link-monitor-topo.png.
|
||||||
|
```bash
|
||||||
|
./send.py
|
||||||
|
```
|
||||||
|
4. In the other terminal run the `receive.py` script to start
|
||||||
|
receiving and parsing the probe packets. This allows us to monitor
|
||||||
|
the link utilization within the network.
|
||||||
|
```bash
|
||||||
|
./receive.py
|
||||||
|
```
|
||||||
|
The reported link utilization and the switch port numbers will
|
||||||
|
always be 0 because the probe fields have not been filled out yet.
|
||||||
|
|
||||||
|
5. Run an iperf flow between h1 and h4:
|
||||||
|
```bash
|
||||||
|
mininet> iperf h1 h4
|
||||||
|
```
|
||||||
|
6. Type `exit` to leave each xterm and the Mininet command line.
|
||||||
|
Then, to stop mininet:
|
||||||
|
```bash
|
||||||
|
make stop
|
||||||
|
```
|
||||||
|
And to delete all pcaps, build files, and logs:
|
||||||
|
```bash
|
||||||
|
make clean
|
||||||
|
```
|
||||||
|
|
||||||
|
The measured link utilizations will not agree with what iperf reports
|
||||||
|
because the probe packet fields have not been populated yet. Your
|
||||||
|
goal is to fill out the probe packet fields so that the two
|
||||||
|
measurements agree.
|
||||||
|
|
||||||
|
### A note about the control plane
|
||||||
|
|
||||||
|
A P4 program defines a packet-processing pipeline, but the rules
|
||||||
|
within each table are inserted by the control plane. When a rule
|
||||||
|
matches a packet, its action is invoked with parameters supplied by
|
||||||
|
the control plane as part of the rule.
|
||||||
|
|
||||||
|
In this exercise, we have already implemented the control plane
|
||||||
|
logic for you. As part of bringing up the Mininet instance, the
|
||||||
|
`make run` command will install packet-processing rules in the tables of
|
||||||
|
each switch. These are defined in the `sX-runtime.json` files, where
|
||||||
|
`X` corresponds to the switch number.
|
||||||
|
|
||||||
|
**Important:** We use P4Runtime to install the control plane rules. The
|
||||||
|
content of files `sX-runtime.json` refer to specific names of tables, keys, and
|
||||||
|
actions, as defined in the P4Info file produced by the compiler (look for the
|
||||||
|
file `build/link_monitor.p4.p4info.txt` after executing `make run`). Any
|
||||||
|
changes in the P4 program that add or rename tables, keys, or actions
|
||||||
|
will need to be reflected in these `sX-runtime.json` files.
|
||||||
|
|
||||||
|
## Step 2: Implement Link Monitoring Logic
|
||||||
|
|
||||||
|
The `link_monitor.p4` file contains a skeleton P4 program with key pieces of
|
||||||
|
logic replaced by `TODO` comments. Your implementation should follow
|
||||||
|
the structure given in this file---replace each `TODO` with logic
|
||||||
|
implementing the missing piece.
|
||||||
|
|
||||||
|
Here are a few more details about the design:
|
||||||
|
|
||||||
|
**Parser**
|
||||||
|
* The parser has been extended support parsing of the source routed probe packets.
|
||||||
|
The parser is the most complicated part of the design so spend a bit of time
|
||||||
|
reading over it. Note that it does not contain any TODO comments so there is
|
||||||
|
nothing you need to change here.
|
||||||
|
* To parse the probe packets, we use the `hdr.probe.hop_cnt` to determine how many
|
||||||
|
hops the packet has traversed prior to reaching the switch. If this is the first
|
||||||
|
hop then there will not be any `probe_data` in the packet so we skip that state
|
||||||
|
and transition directly to the `parse_probe_fwd` state. In the `parse_probe_fwd`
|
||||||
|
state, we use the `hdr.probe.hop_cnt` field to figure out which `egress_spec`
|
||||||
|
header field to use to perform forwarding and we save that port value into a
|
||||||
|
metadata field which is subsequently used to perform forwarding.
|
||||||
|
|
||||||
|
**Ingress Control**
|
||||||
|
* The ingress control block looks very similar to the `basic` exercise. The only
|
||||||
|
difference is that the `apply` block contains another condition to forward probe
|
||||||
|
packets using the `egress_spec` field extracted by the parser. It also increments
|
||||||
|
the `hdr.probe.hop_cnt` field.
|
||||||
|
|
||||||
|
**Egress Control**
|
||||||
|
* This is where the interesting stateful processing occurs. It uses the
|
||||||
|
`byte_cnt_reg` register to count the number of bytes that have passed through each
|
||||||
|
port since the last probe packet passed through the port.
|
||||||
|
* It adds a new `probe_data` header to the packet and filld out the `bos`
|
||||||
|
(bottom of stack) field, as well as the `swid` (switch ID) field.
|
||||||
|
* TODO: your job is to fill out the rest of the probe packet fields in order to
|
||||||
|
ensure that you can properly measure link utilization.
|
||||||
|
|
||||||
|
**Deparser**
|
||||||
|
* Simply emits all headers in the correct order.
|
||||||
|
* Note that emitting a header stack will only emit the headers within the stack
|
||||||
|
that are actually marked as valid.
|
||||||
|
|
||||||
|
## Step 3: Run your solution
|
||||||
|
|
||||||
|
Follow the instructions from Step 1. This time, the measured link
|
||||||
|
utilizations should agree with what `iperf` reports.
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
|
There are several problems that might manifest as you develop your program:
|
||||||
|
|
||||||
|
1. `link_monitor.p4` might fail to compile. In this case, `make run` will
|
||||||
|
report the error emitted from the compiler and halt.
|
||||||
|
|
||||||
|
2. `link_monitor.p4` might compile but fail to support the control plane
|
||||||
|
rules in the `s1-runtime.json` through `s4-runtime.json` files that
|
||||||
|
`make run` tries to install using P4Runtime. In this case, `make run` will
|
||||||
|
report errors if control plane rules cannot be installed. Use these error
|
||||||
|
messages to fix your `link_monitor.p4` implementation.
|
||||||
|
|
||||||
|
3. `link_monitor.p4` might compile, and the control plane rules might be
|
||||||
|
installed, but the switch might not process packets in the desired
|
||||||
|
way. The `logs/sX.log` files contain detailed logs that describing
|
||||||
|
how each switch processes each packet. The output is detailed and can
|
||||||
|
help pinpoint logic errors in your implementation.
|
||||||
|
|
||||||
|
#### Cleaning up Mininet
|
||||||
|
|
||||||
|
In the latter two cases above, `make run` may leave a Mininet instance
|
||||||
|
running in the background. Use the following command to clean up
|
||||||
|
these instances:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make stop
|
||||||
|
```
|
||||||
|
|
||||||
|
### Food For Thought
|
||||||
|
|
||||||
|
Now that you've implemented this basic monitoring framework can you
|
||||||
|
think of ways to leverage this information about link utilization
|
||||||
|
within the core of the network? For instance, how might you use this
|
||||||
|
data, either at the hosts or at the switches, to make real-time
|
||||||
|
load-balancing decisions?
|
||||||
|
|
||||||
BIN
exercises/link_monitor/link-monitor-topo.png
Normal file
|
After Width: | Height: | Size: 251 KiB |
299
exercises/link_monitor/link_monitor.p4
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
/* -*- P4_16 -*- */
|
||||||
|
#include <core.p4>
|
||||||
|
#include <v1model.p4>
|
||||||
|
|
||||||
|
const bit<16> TYPE_IPV4 = 0x800;
|
||||||
|
const bit<16> TYPE_PROBE = 0x812;
|
||||||
|
|
||||||
|
#define MAX_HOPS 10
|
||||||
|
#define MAX_PORTS 8
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** H E A D E R S ***********************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
typedef bit<9> egressSpec_t;
|
||||||
|
typedef bit<48> macAddr_t;
|
||||||
|
typedef bit<32> ip4Addr_t;
|
||||||
|
|
||||||
|
typedef bit<48> time_t;
|
||||||
|
|
||||||
|
header ethernet_t {
|
||||||
|
macAddr_t dstAddr;
|
||||||
|
macAddr_t srcAddr;
|
||||||
|
bit<16> etherType;
|
||||||
|
}
|
||||||
|
|
||||||
|
header ipv4_t {
|
||||||
|
bit<4> version;
|
||||||
|
bit<4> ihl;
|
||||||
|
bit<8> diffserv;
|
||||||
|
bit<16> totalLen;
|
||||||
|
bit<16> identification;
|
||||||
|
bit<3> flags;
|
||||||
|
bit<13> fragOffset;
|
||||||
|
bit<8> ttl;
|
||||||
|
bit<8> protocol;
|
||||||
|
bit<16> hdrChecksum;
|
||||||
|
ip4Addr_t srcAddr;
|
||||||
|
ip4Addr_t dstAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top-level probe header, indicates how many hops this probe
|
||||||
|
// packet has traversed so far.
|
||||||
|
header probe_t {
|
||||||
|
bit<8> hop_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The data added to the probe by each switch at each hop.
|
||||||
|
header probe_data_t {
|
||||||
|
bit<1> bos;
|
||||||
|
bit<7> swid;
|
||||||
|
bit<8> port;
|
||||||
|
bit<32> byte_cnt;
|
||||||
|
time_t last_time;
|
||||||
|
time_t cur_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indicates the egress port the switch should send this probe
|
||||||
|
// packet out of. There is one of these headers for each hop.
|
||||||
|
header probe_fwd_t {
|
||||||
|
bit<8> egress_spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct parser_metadata_t {
|
||||||
|
bit<8> remaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct metadata {
|
||||||
|
bit<8> egress_spec;
|
||||||
|
parser_metadata_t parser_metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct headers {
|
||||||
|
ethernet_t ethernet;
|
||||||
|
ipv4_t ipv4;
|
||||||
|
probe_t probe;
|
||||||
|
probe_data_t[MAX_HOPS] probe_data;
|
||||||
|
probe_fwd_t[MAX_HOPS] probe_fwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** P A R S E R ***********************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
parser MyParser(packet_in packet,
|
||||||
|
out headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
|
||||||
|
state start {
|
||||||
|
transition parse_ethernet;
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_ethernet {
|
||||||
|
packet.extract(hdr.ethernet);
|
||||||
|
transition select(hdr.ethernet.etherType) {
|
||||||
|
TYPE_IPV4: parse_ipv4;
|
||||||
|
TYPE_PROBE: parse_probe;
|
||||||
|
default: accept;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_ipv4 {
|
||||||
|
packet.extract(hdr.ipv4);
|
||||||
|
transition accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_probe {
|
||||||
|
packet.extract(hdr.probe);
|
||||||
|
meta.parser_metadata.remaining = hdr.probe.hop_cnt + 1;
|
||||||
|
transition select(hdr.probe.hop_cnt) {
|
||||||
|
0: parse_probe_fwd;
|
||||||
|
default: parse_probe_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_probe_data {
|
||||||
|
packet.extract(hdr.probe_data.next);
|
||||||
|
transition select(hdr.probe_data.last.bos) {
|
||||||
|
1: parse_probe_fwd;
|
||||||
|
default: parse_probe_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_probe_fwd {
|
||||||
|
packet.extract(hdr.probe_fwd.next);
|
||||||
|
meta.parser_metadata.remaining = meta.parser_metadata.remaining - 1;
|
||||||
|
// extract the forwarding data
|
||||||
|
meta.egress_spec = hdr.probe_fwd.last.egress_spec;
|
||||||
|
transition select(meta.parser_metadata.remaining) {
|
||||||
|
0: accept;
|
||||||
|
default: parse_probe_fwd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************ C H E C K S U M V E R I F I C A T I O N *************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
|
||||||
|
apply { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************** I N G R E S S P R O C E S S I N G *******************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyIngress(inout headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
|
||||||
|
action drop() {
|
||||||
|
mark_to_drop(standard_metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
|
||||||
|
standard_metadata.egress_spec = port;
|
||||||
|
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
|
||||||
|
hdr.ethernet.dstAddr = dstAddr;
|
||||||
|
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
table ipv4_lpm {
|
||||||
|
key = {
|
||||||
|
hdr.ipv4.dstAddr: lpm;
|
||||||
|
}
|
||||||
|
actions = {
|
||||||
|
ipv4_forward;
|
||||||
|
drop;
|
||||||
|
NoAction;
|
||||||
|
}
|
||||||
|
size = 1024;
|
||||||
|
default_action = drop();
|
||||||
|
}
|
||||||
|
|
||||||
|
apply {
|
||||||
|
if (hdr.ipv4.isValid()) {
|
||||||
|
ipv4_lpm.apply();
|
||||||
|
}
|
||||||
|
else if (hdr.probe.isValid()) {
|
||||||
|
standard_metadata.egress_spec = (bit<9>)meta.egress_spec;
|
||||||
|
hdr.probe.hop_cnt = hdr.probe.hop_cnt + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************** E G R E S S P R O C E S S I N G ********************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyEgress(inout headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
|
||||||
|
// count the number of bytes seen since the last probe
|
||||||
|
register<bit<32>>(MAX_PORTS) byte_cnt_reg;
|
||||||
|
// remember the time of the last probe
|
||||||
|
register<time_t>(MAX_PORTS) last_time_reg;
|
||||||
|
|
||||||
|
action set_swid(bit<7> swid) {
|
||||||
|
hdr.probe_data[0].swid = swid;
|
||||||
|
}
|
||||||
|
|
||||||
|
table swid {
|
||||||
|
actions = {
|
||||||
|
set_swid;
|
||||||
|
NoAction;
|
||||||
|
}
|
||||||
|
default_action = NoAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
apply {
|
||||||
|
bit<32> byte_cnt;
|
||||||
|
bit<32> new_byte_cnt;
|
||||||
|
time_t last_time;
|
||||||
|
time_t cur_time = standard_metadata.egress_global_timestamp;
|
||||||
|
// increment byte cnt for this packet's port
|
||||||
|
byte_cnt_reg.read(byte_cnt, (bit<32>)standard_metadata.egress_port);
|
||||||
|
byte_cnt = byte_cnt + standard_metadata.packet_length;
|
||||||
|
// reset the byte count when a probe packet passes through
|
||||||
|
new_byte_cnt = (hdr.probe.isValid()) ? 0 : byte_cnt;
|
||||||
|
byte_cnt_reg.write((bit<32>)standard_metadata.egress_port, new_byte_cnt);
|
||||||
|
|
||||||
|
if (hdr.probe.isValid()) {
|
||||||
|
// fill out probe fields
|
||||||
|
hdr.probe_data.push_front(1);
|
||||||
|
hdr.probe_data[0].setValid();
|
||||||
|
if (hdr.probe.hop_cnt == 1) {
|
||||||
|
hdr.probe_data[0].bos = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hdr.probe_data[0].bos = 0;
|
||||||
|
}
|
||||||
|
// set switch ID field
|
||||||
|
swid.apply();
|
||||||
|
// TODO: fill out the rest of the probe packet fields
|
||||||
|
// hdr.probe_data[0].port = ...
|
||||||
|
// hdr.probe_data[0].byte_cnt = ...
|
||||||
|
// TODO: read / update the last_time_reg
|
||||||
|
// last_time_reg.read(<val>, <index>);
|
||||||
|
// last_time_reg.write(<index>, <val>);
|
||||||
|
// hdr.probe_data[0].last_time = ...
|
||||||
|
// hdr.probe_data[0].cur_time = ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************* C H E C K S U M C O M P U T A T I O N ***************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
|
||||||
|
apply {
|
||||||
|
update_checksum(
|
||||||
|
hdr.ipv4.isValid(),
|
||||||
|
{ hdr.ipv4.version,
|
||||||
|
hdr.ipv4.ihl,
|
||||||
|
hdr.ipv4.diffserv,
|
||||||
|
hdr.ipv4.totalLen,
|
||||||
|
hdr.ipv4.identification,
|
||||||
|
hdr.ipv4.flags,
|
||||||
|
hdr.ipv4.fragOffset,
|
||||||
|
hdr.ipv4.ttl,
|
||||||
|
hdr.ipv4.protocol,
|
||||||
|
hdr.ipv4.srcAddr,
|
||||||
|
hdr.ipv4.dstAddr },
|
||||||
|
hdr.ipv4.hdrChecksum,
|
||||||
|
HashAlgorithm.csum16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** D E P A R S E R *******************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyDeparser(packet_out packet, in headers hdr) {
|
||||||
|
apply {
|
||||||
|
packet.emit(hdr.ethernet);
|
||||||
|
packet.emit(hdr.ipv4);
|
||||||
|
packet.emit(hdr.probe);
|
||||||
|
packet.emit(hdr.probe_data);
|
||||||
|
packet.emit(hdr.probe_fwd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** S W I T C H *******************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
V1Switch(
|
||||||
|
MyParser(),
|
||||||
|
MyVerifyChecksum(),
|
||||||
|
MyIngress(),
|
||||||
|
MyEgress(),
|
||||||
|
MyComputeChecksum(),
|
||||||
|
MyDeparser()
|
||||||
|
) main;
|
||||||
65
exercises/link_monitor/pod-topo/s1-runtime.json
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"target": "bmv2",
|
||||||
|
"p4info": "build/link_monitor.p4.p4info.txt",
|
||||||
|
"bmv2_json": "build/link_monitor.json",
|
||||||
|
"table_entries": [
|
||||||
|
{
|
||||||
|
"table": "MyEgress.swid",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyEgress.set_swid",
|
||||||
|
"action_params": {
|
||||||
|
"swid": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyIngress.drop",
|
||||||
|
"action_params": { }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:11",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:22",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:03:00",
|
||||||
|
"port": 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:04:00",
|
||||||
|
"port": 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
65
exercises/link_monitor/pod-topo/s2-runtime.json
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"target": "bmv2",
|
||||||
|
"p4info": "build/link_monitor.p4.p4info.txt",
|
||||||
|
"bmv2_json": "build/link_monitor.json",
|
||||||
|
"table_entries": [
|
||||||
|
{
|
||||||
|
"table": "MyEgress.swid",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyEgress.set_swid",
|
||||||
|
"action_params": {
|
||||||
|
"swid": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyIngress.drop",
|
||||||
|
"action_params": { }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:03:00",
|
||||||
|
"port": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:04:00",
|
||||||
|
"port": 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:03:33",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:04:44",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
65
exercises/link_monitor/pod-topo/s3-runtime.json
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"target": "bmv2",
|
||||||
|
"p4info": "build/link_monitor.p4.p4info.txt",
|
||||||
|
"bmv2_json": "build/link_monitor.json",
|
||||||
|
"table_entries": [
|
||||||
|
{
|
||||||
|
"table": "MyEgress.swid",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyEgress.set_swid",
|
||||||
|
"action_params": {
|
||||||
|
"swid": 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyIngress.drop",
|
||||||
|
"action_params": { }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
65
exercises/link_monitor/pod-topo/s4-runtime.json
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"target": "bmv2",
|
||||||
|
"p4info": "build/link_monitor.p4.p4info.txt",
|
||||||
|
"bmv2_json": "build/link_monitor.json",
|
||||||
|
"table_entries": [
|
||||||
|
{
|
||||||
|
"table": "MyEgress.swid",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyEgress.set_swid",
|
||||||
|
"action_params": {
|
||||||
|
"swid": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"default_action": true,
|
||||||
|
"action_name": "MyIngress.drop",
|
||||||
|
"action_params": { }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
|
"port": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"table": "MyIngress.ipv4_lpm",
|
||||||
|
"match": {
|
||||||
|
"hdr.ipv4.dstAddr": ["10.0.4.4", 32]
|
||||||
|
},
|
||||||
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
|
"action_params": {
|
||||||
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
|
"port": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
26
exercises/link_monitor/pod-topo/topology.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"hosts": {
|
||||||
|
"h1": {"ip": "10.0.1.1/24", "mac": "08:00:00:00:01:11",
|
||||||
|
"commands":["route add default gw 10.0.1.10 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.1.10 08:00:00:00:01:00"]},
|
||||||
|
"h2": {"ip": "10.0.2.2/24", "mac": "08:00:00:00:02:22",
|
||||||
|
"commands":["route add default gw 10.0.2.20 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.2.20 08:00:00:00:02:00"]},
|
||||||
|
"h3": {"ip": "10.0.3.3/24", "mac": "08:00:00:00:03:33",
|
||||||
|
"commands":["route add default gw 10.0.3.30 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.3.30 08:00:00:00:03:00"]},
|
||||||
|
"h4": {"ip": "10.0.4.4/24", "mac": "08:00:00:00:04:44",
|
||||||
|
"commands":["route add default gw 10.0.4.40 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.4.40 08:00:00:00:04:00"]}
|
||||||
|
},
|
||||||
|
"switches": {
|
||||||
|
"s1": { "runtime_json" : "pod-topo/s1-runtime.json" },
|
||||||
|
"s2": { "runtime_json" : "pod-topo/s2-runtime.json" },
|
||||||
|
"s3": { "runtime_json" : "pod-topo/s3-runtime.json" },
|
||||||
|
"s4": { "runtime_json" : "pod-topo/s4-runtime.json" }
|
||||||
|
},
|
||||||
|
"links": [
|
||||||
|
["h1", "s1-p1"], ["h2", "s1-p2"], ["s1-p3", "s3-p1"], ["s1-p4", "s4-p2"],
|
||||||
|
["h3", "s2-p1"], ["h4", "s2-p2"], ["s2-p3", "s4-p1"], ["s2-p4", "s3-p2"]
|
||||||
|
]
|
||||||
|
}
|
||||||
25
exercises/link_monitor/probe_hdrs.py
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
from scapy.all import *
|
||||||
|
|
||||||
|
TYPE_PROBE = 0x812
|
||||||
|
|
||||||
|
class Probe(Packet):
|
||||||
|
fields_desc = [ ByteField("hop_cnt", 0)]
|
||||||
|
|
||||||
|
class ProbeData(Packet):
|
||||||
|
fields_desc = [ BitField("bos", 0, 1),
|
||||||
|
BitField("swid", 0, 7),
|
||||||
|
ByteField("port", 0),
|
||||||
|
IntField("byte_cnt", 0),
|
||||||
|
BitField("last_time", 0, 48),
|
||||||
|
BitField("cur_time", 0, 48)]
|
||||||
|
|
||||||
|
class ProbeFwd(Packet):
|
||||||
|
fields_desc = [ ByteField("egress_spec", 0)]
|
||||||
|
|
||||||
|
bind_layers(Ether, Probe, type=TYPE_PROBE)
|
||||||
|
bind_layers(Probe, ProbeFwd, hop_cnt=0)
|
||||||
|
bind_layers(Probe, ProbeData)
|
||||||
|
bind_layers(ProbeData, ProbeData, bos=0)
|
||||||
|
bind_layers(ProbeData, ProbeFwd, bos=1)
|
||||||
|
bind_layers(ProbeFwd, ProbeFwd)
|
||||||
|
|
||||||
26
exercises/link_monitor/receive.py
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from probe_hdrs import *
|
||||||
|
|
||||||
|
def expand(x):
|
||||||
|
yield x
|
||||||
|
while x.payload:
|
||||||
|
x = x.payload
|
||||||
|
yield x
|
||||||
|
|
||||||
|
def handle_pkt(pkt):
|
||||||
|
if ProbeData in pkt:
|
||||||
|
data_layers = [l for l in expand(pkt) if l.name=='ProbeData']
|
||||||
|
print ""
|
||||||
|
for sw in data_layers:
|
||||||
|
utilization = 0 if sw.cur_time == sw.last_time else 8.0*sw.byte_cnt/(sw.cur_time - sw.last_time)
|
||||||
|
print "Switch {} - Port {}: {} Mbps".format(sw.swid, sw.port, utilization)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
iface = 'eth0'
|
||||||
|
print "sniffing on {}".format(iface)
|
||||||
|
sniff(iface = iface,
|
||||||
|
prn = lambda x: handle_pkt(x))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
28
exercises/link_monitor/send.py
Executable file
@@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from probe_hdrs import *
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
probe_pkt = Ether(dst='ff:ff:ff:ff:ff:ff', src=get_if_hwaddr('eth0')) / \
|
||||||
|
Probe(hop_cnt=0) / \
|
||||||
|
ProbeFwd(egress_spec=4) / \
|
||||||
|
ProbeFwd(egress_spec=1) / \
|
||||||
|
ProbeFwd(egress_spec=4) / \
|
||||||
|
ProbeFwd(egress_spec=1) / \
|
||||||
|
ProbeFwd(egress_spec=3) / \
|
||||||
|
ProbeFwd(egress_spec=2) / \
|
||||||
|
ProbeFwd(egress_spec=3) / \
|
||||||
|
ProbeFwd(egress_spec=2) / \
|
||||||
|
ProbeFwd(egress_spec=1)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
sendp(probe_pkt, iface='eth0')
|
||||||
|
time.sleep(1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
298
exercises/link_monitor/solution/link_monitor.p4
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
/* -*- P4_16 -*- */
|
||||||
|
#include <core.p4>
|
||||||
|
#include <v1model.p4>
|
||||||
|
|
||||||
|
const bit<16> TYPE_IPV4 = 0x800;
|
||||||
|
const bit<16> TYPE_PROBE = 0x812;
|
||||||
|
|
||||||
|
#define MAX_HOPS 10
|
||||||
|
#define MAX_PORTS 8
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** H E A D E R S ***********************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
typedef bit<9> egressSpec_t;
|
||||||
|
typedef bit<48> macAddr_t;
|
||||||
|
typedef bit<32> ip4Addr_t;
|
||||||
|
|
||||||
|
typedef bit<48> time_t;
|
||||||
|
|
||||||
|
header ethernet_t {
|
||||||
|
macAddr_t dstAddr;
|
||||||
|
macAddr_t srcAddr;
|
||||||
|
bit<16> etherType;
|
||||||
|
}
|
||||||
|
|
||||||
|
header ipv4_t {
|
||||||
|
bit<4> version;
|
||||||
|
bit<4> ihl;
|
||||||
|
bit<8> diffserv;
|
||||||
|
bit<16> totalLen;
|
||||||
|
bit<16> identification;
|
||||||
|
bit<3> flags;
|
||||||
|
bit<13> fragOffset;
|
||||||
|
bit<8> ttl;
|
||||||
|
bit<8> protocol;
|
||||||
|
bit<16> hdrChecksum;
|
||||||
|
ip4Addr_t srcAddr;
|
||||||
|
ip4Addr_t dstAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top-level probe header, indicates how many hops this probe
|
||||||
|
// packet has traversed so far.
|
||||||
|
header probe_t {
|
||||||
|
bit<8> hop_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The data added to the probe by each switch at each hop.
|
||||||
|
header probe_data_t {
|
||||||
|
bit<1> bos;
|
||||||
|
bit<7> swid;
|
||||||
|
bit<8> port;
|
||||||
|
bit<32> byte_cnt;
|
||||||
|
time_t last_time;
|
||||||
|
time_t cur_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indicates the egress port the switch should send this probe
|
||||||
|
// packet out of. There is one of these headers for each hop.
|
||||||
|
header probe_fwd_t {
|
||||||
|
bit<8> egress_spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct parser_metadata_t {
|
||||||
|
bit<8> remaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct metadata {
|
||||||
|
bit<8> egress_spec;
|
||||||
|
parser_metadata_t parser_metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct headers {
|
||||||
|
ethernet_t ethernet;
|
||||||
|
ipv4_t ipv4;
|
||||||
|
probe_t probe;
|
||||||
|
probe_data_t[MAX_HOPS] probe_data;
|
||||||
|
probe_fwd_t[MAX_HOPS] probe_fwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** P A R S E R ***********************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
parser MyParser(packet_in packet,
|
||||||
|
out headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
|
||||||
|
state start {
|
||||||
|
transition parse_ethernet;
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_ethernet {
|
||||||
|
packet.extract(hdr.ethernet);
|
||||||
|
transition select(hdr.ethernet.etherType) {
|
||||||
|
TYPE_IPV4: parse_ipv4;
|
||||||
|
TYPE_PROBE: parse_probe;
|
||||||
|
default: accept;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_ipv4 {
|
||||||
|
packet.extract(hdr.ipv4);
|
||||||
|
transition accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_probe {
|
||||||
|
packet.extract(hdr.probe);
|
||||||
|
meta.parser_metadata.remaining = hdr.probe.hop_cnt + 1;
|
||||||
|
transition select(hdr.probe.hop_cnt) {
|
||||||
|
0: parse_probe_fwd;
|
||||||
|
default: parse_probe_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_probe_data {
|
||||||
|
packet.extract(hdr.probe_data.next);
|
||||||
|
transition select(hdr.probe_data.last.bos) {
|
||||||
|
1: parse_probe_fwd;
|
||||||
|
default: parse_probe_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state parse_probe_fwd {
|
||||||
|
packet.extract(hdr.probe_fwd.next);
|
||||||
|
meta.parser_metadata.remaining = meta.parser_metadata.remaining - 1;
|
||||||
|
// extract the forwarding data
|
||||||
|
meta.egress_spec = hdr.probe_fwd.last.egress_spec;
|
||||||
|
transition select(meta.parser_metadata.remaining) {
|
||||||
|
0: accept;
|
||||||
|
default: parse_probe_fwd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************ C H E C K S U M V E R I F I C A T I O N *************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
|
||||||
|
apply { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************** I N G R E S S P R O C E S S I N G *******************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyIngress(inout headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
|
||||||
|
action drop() {
|
||||||
|
mark_to_drop(standard_metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
|
||||||
|
standard_metadata.egress_spec = port;
|
||||||
|
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
|
||||||
|
hdr.ethernet.dstAddr = dstAddr;
|
||||||
|
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
table ipv4_lpm {
|
||||||
|
key = {
|
||||||
|
hdr.ipv4.dstAddr: lpm;
|
||||||
|
}
|
||||||
|
actions = {
|
||||||
|
ipv4_forward;
|
||||||
|
drop;
|
||||||
|
NoAction;
|
||||||
|
}
|
||||||
|
size = 1024;
|
||||||
|
default_action = drop();
|
||||||
|
}
|
||||||
|
|
||||||
|
apply {
|
||||||
|
if (hdr.ipv4.isValid()) {
|
||||||
|
ipv4_lpm.apply();
|
||||||
|
}
|
||||||
|
else if (hdr.probe.isValid()) {
|
||||||
|
standard_metadata.egress_spec = (bit<9>)meta.egress_spec;
|
||||||
|
hdr.probe.hop_cnt = hdr.probe.hop_cnt + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
**************** E G R E S S P R O C E S S I N G ********************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyEgress(inout headers hdr,
|
||||||
|
inout metadata meta,
|
||||||
|
inout standard_metadata_t standard_metadata) {
|
||||||
|
|
||||||
|
// count the number of bytes seen since the last probe
|
||||||
|
register<bit<32>>(MAX_PORTS) byte_cnt_reg;
|
||||||
|
// remember the time of the last probe
|
||||||
|
register<time_t>(MAX_PORTS) last_time_reg;
|
||||||
|
|
||||||
|
action set_swid(bit<7> swid) {
|
||||||
|
hdr.probe_data[0].swid = swid;
|
||||||
|
}
|
||||||
|
|
||||||
|
table swid {
|
||||||
|
actions = {
|
||||||
|
set_swid;
|
||||||
|
NoAction;
|
||||||
|
}
|
||||||
|
default_action = NoAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
apply {
|
||||||
|
bit<32> byte_cnt;
|
||||||
|
bit<32> new_byte_cnt;
|
||||||
|
time_t last_time;
|
||||||
|
time_t cur_time = standard_metadata.egress_global_timestamp;
|
||||||
|
// increment byte cnt for this packet's port
|
||||||
|
byte_cnt_reg.read(byte_cnt, (bit<32>)standard_metadata.egress_port);
|
||||||
|
byte_cnt = byte_cnt + standard_metadata.packet_length;
|
||||||
|
// reset the byte count when a probe packet passes through
|
||||||
|
new_byte_cnt = (hdr.probe.isValid()) ? 0 : byte_cnt;
|
||||||
|
byte_cnt_reg.write((bit<32>)standard_metadata.egress_port, new_byte_cnt);
|
||||||
|
|
||||||
|
if (hdr.probe.isValid()) {
|
||||||
|
// fill out probe fields
|
||||||
|
hdr.probe_data.push_front(1);
|
||||||
|
hdr.probe_data[0].setValid();
|
||||||
|
if (hdr.probe.hop_cnt == 1) {
|
||||||
|
hdr.probe_data[0].bos = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hdr.probe_data[0].bos = 0;
|
||||||
|
}
|
||||||
|
// set switch ID field
|
||||||
|
swid.apply();
|
||||||
|
hdr.probe_data[0].port = (bit<8>)standard_metadata.egress_port;
|
||||||
|
hdr.probe_data[0].byte_cnt = byte_cnt;
|
||||||
|
// read / update the last_time_reg
|
||||||
|
last_time_reg.read(last_time, (bit<32>)standard_metadata.egress_port);
|
||||||
|
last_time_reg.write((bit<32>)standard_metadata.egress_port, cur_time);
|
||||||
|
hdr.probe_data[0].last_time = last_time;
|
||||||
|
hdr.probe_data[0].cur_time = cur_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
************* C H E C K S U M C O M P U T A T I O N ***************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
|
||||||
|
apply {
|
||||||
|
update_checksum(
|
||||||
|
hdr.ipv4.isValid(),
|
||||||
|
{ hdr.ipv4.version,
|
||||||
|
hdr.ipv4.ihl,
|
||||||
|
hdr.ipv4.diffserv,
|
||||||
|
hdr.ipv4.totalLen,
|
||||||
|
hdr.ipv4.identification,
|
||||||
|
hdr.ipv4.flags,
|
||||||
|
hdr.ipv4.fragOffset,
|
||||||
|
hdr.ipv4.ttl,
|
||||||
|
hdr.ipv4.protocol,
|
||||||
|
hdr.ipv4.srcAddr,
|
||||||
|
hdr.ipv4.dstAddr },
|
||||||
|
hdr.ipv4.hdrChecksum,
|
||||||
|
HashAlgorithm.csum16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** D E P A R S E R *******************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
control MyDeparser(packet_out packet, in headers hdr) {
|
||||||
|
apply {
|
||||||
|
packet.emit(hdr.ethernet);
|
||||||
|
packet.emit(hdr.ipv4);
|
||||||
|
packet.emit(hdr.probe);
|
||||||
|
packet.emit(hdr.probe_data);
|
||||||
|
packet.emit(hdr.probe_fwd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
*********************** S W I T C H *******************************
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
V1Switch(
|
||||||
|
MyParser(),
|
||||||
|
MyVerifyChecksum(),
|
||||||
|
MyIngress(),
|
||||||
|
MyEgress(),
|
||||||
|
MyComputeChecksum(),
|
||||||
|
MyDeparser()
|
||||||
|
) main;
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
BMV2_SWITCH_EXE = simple_switch_grpc
|
BMV2_SWITCH_EXE = simple_switch_grpc
|
||||||
NO_P4 = true
|
|
||||||
P4C_ARGS = --p4runtime-files $(basename $@).p4.p4info.txt
|
|
||||||
|
|
||||||
include ../../utils/Makefile
|
include ../../utils/Makefile
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 138 B After Width: | Height: | Size: 67 B |
@@ -27,7 +27,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.set_nhop",
|
"action_name": "MyIngress.set_nhop",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"nhop_dmac": "00:00:00:00:02:02",
|
"nhop_dmac": "08:00:00:00:02:02",
|
||||||
"nhop_ipv4": "10.0.2.2",
|
"nhop_ipv4": "10.0.2.2",
|
||||||
"port" : 1
|
"port" : 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.set_nhop",
|
"action_name": "MyIngress.set_nhop",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"nhop_dmac": "00:00:00:00:03:03",
|
"nhop_dmac": "08:00:00:00:03:03",
|
||||||
"nhop_ipv4": "10.0.3.3",
|
"nhop_ipv4": "10.0.3.3",
|
||||||
"port" : 1
|
"port" : 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
{
|
{
|
||||||
"hosts": [
|
"hosts": {
|
||||||
"h1",
|
"h1": {"ip": "10.0.1.1/24", "mac": "08:00:00:00:01:01",
|
||||||
"h2",
|
"commands":["route add default gw 10.0.1.10 dev eth0",
|
||||||
"h3"
|
"arp -i eth0 -s 10.0.1.10 08:00:00:00:01:00"]},
|
||||||
],
|
"h2": {"ip": "10.0.2.2/24", "mac": "08:00:00:00:02:02",
|
||||||
|
"commands":["route add default gw 10.0.2.20 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.2.20 08:00:00:00:02:00"]},
|
||||||
|
"h3": {"ip": "10.0.3.3/24", "mac": "08:00:00:00:03:03",
|
||||||
|
"commands":["route add default gw 10.0.3.30 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.3.30 08:00:00:00:03:00"]}
|
||||||
|
},
|
||||||
"switches": {
|
"switches": {
|
||||||
"s1": { "runtime_json" : "s1-runtime.json" },
|
"s1": { "runtime_json" : "s1-runtime.json" },
|
||||||
"s2": { "runtime_json" : "s2-runtime.json" },
|
"s2": { "runtime_json" : "s2-runtime.json" },
|
||||||
"s3": { "runtime_json" : "s3-runtime.json" }
|
"s3": { "runtime_json" : "s3-runtime.json" }
|
||||||
},
|
},
|
||||||
"links": [
|
"links": [
|
||||||
["h1", "s1"], ["s1", "s2"], ["s1", "s3"],
|
["h1", "s1-p1"], ["s1-p2", "s2-p2"], ["s1-p3", "s3-p2"],
|
||||||
["s3", "s2"], ["s2", "h2"], ["s3", "h3"]
|
["s3-p3", "s2-p3"], ["h2", "s2-p1"], ["h3", "s3-p1"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
BMV2_SWITCH_EXE = simple_switch_grpc
|
BMV2_SWITCH_EXE = simple_switch_grpc
|
||||||
NO_P4 = true
|
|
||||||
P4C_ARGS = --p4runtime-files $(basename $@).p4.p4info.txt
|
|
||||||
|
|
||||||
include ../../utils/Makefile
|
include ../../utils/Makefile
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 138 B After Width: | Height: | Size: 67 B |
@@ -18,7 +18,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:01:01",
|
"dstAddr": "08:00:00:00:01:01",
|
||||||
"port": 2
|
"port": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:01:0b",
|
"dstAddr": "08:00:00:00:01:11",
|
||||||
"port": 1
|
"port": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:02:03:00",
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
"port": 3
|
"port": 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:03:02:00",
|
"dstAddr": "08:00:00:00:03:00",
|
||||||
"port": 4
|
"port": 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:02:02",
|
"dstAddr": "08:00:00:00:02:02",
|
||||||
"port": 2
|
"port": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:02:16",
|
"dstAddr": "08:00:00:00:02:22",
|
||||||
"port": 1
|
"port": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:01:03:00",
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
"port": 3
|
"port": 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:03:03:00",
|
"dstAddr": "08:00:00:00:03:00",
|
||||||
"port": 4
|
"port": 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:00:03:03",
|
"dstAddr": "08:00:00:00:03:03",
|
||||||
"port": 1
|
"port": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:01:04:00",
|
"dstAddr": "08:00:00:00:01:00",
|
||||||
"port": 2
|
"port": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
},
|
},
|
||||||
"action_name": "MyIngress.ipv4_forward",
|
"action_name": "MyIngress.ipv4_forward",
|
||||||
"action_params": {
|
"action_params": {
|
||||||
"dstAddr": "00:00:00:02:04:00",
|
"dstAddr": "08:00:00:00:02:00",
|
||||||
"port": 3
|
"port": 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,28 @@
|
|||||||
{
|
{
|
||||||
"hosts": [
|
"hosts": {
|
||||||
"h1",
|
"h1": {"ip": "10.0.1.1/31", "mac": "08:00:00:00:01:01",
|
||||||
"h2",
|
"commands":["route add default gw 10.0.1.0 dev eth0",
|
||||||
"h3",
|
"arp -i eth0 -s 10.0.1.0 08:00:00:00:01:00"]},
|
||||||
"h11",
|
"h11": {"ip": "10.0.1.11/31", "mac": "08:00:00:00:01:11",
|
||||||
"h22"
|
"commands":["route add default gw 10.0.1.10 dev eth0",
|
||||||
],
|
"arp -i eth0 -s 10.0.1.10 08:00:00:00:01:00"]},
|
||||||
|
"h2": {"ip": "10.0.2.2/31", "mac": "08:00:00:00:02:02",
|
||||||
|
"commands":["route add default gw 10.0.2.3 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.2.3 08:00:00:00:02:00"]},
|
||||||
|
"h22": {"ip": "10.0.2.22/31", "mac": "08:00:00:00:02:22",
|
||||||
|
"commands":["route add default gw 10.0.2.23 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.2.23 08:00:00:00:02:00"]},
|
||||||
|
"h3": {"ip": "10.0.3.3/31", "mac": "08:00:00:00:03:03",
|
||||||
|
"commands":["route add default gw 10.0.3.2 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.3.2 08:00:00:00:03:00"]}
|
||||||
|
},
|
||||||
"switches": {
|
"switches": {
|
||||||
"s1": { "runtime_json" : "s1-runtime.json" },
|
"s1": { "runtime_json" : "s1-runtime.json" },
|
||||||
"s2": { "runtime_json" : "s2-runtime.json" },
|
"s2": { "runtime_json" : "s2-runtime.json" },
|
||||||
"s3": { "runtime_json" : "s3-runtime.json" }
|
"s3": { "runtime_json" : "s3-runtime.json" }
|
||||||
},
|
},
|
||||||
"links": [
|
"links": [
|
||||||
["h1", "s1"], ["h11", "s1"], ["s1", "s2", "0", 0.5], ["s1", "s3"],
|
["h1", "s1-p2"], ["h11", "s1-p1"], ["s1-p3", "s2-p3", "0", 0.5], ["s1-p4", "s3-p2"],
|
||||||
["s3", "s2"], ["s2", "h2"], ["s2", "h22"], ["s3", "h3"]
|
["s3-p3", "s2-p4"], ["h2", "s2-p2"], ["h22", "s2-p1"], ["h3", "s3-p1"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
BMV2_SWITCH_EXE = simple_switch_grpc
|
BMV2_SWITCH_EXE = simple_switch_grpc
|
||||||
NO_P4 = true
|
|
||||||
P4C_ARGS = --p4runtime-files $(basename $@).p4.p4info.txt
|
|
||||||
|
|
||||||
include ../../utils/Makefile
|
include ../../utils/Makefile
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 138 B After Width: | Height: | Size: 67 B |
@@ -160,11 +160,11 @@ def main(p4info_file_path, bmv2_file_path):
|
|||||||
|
|
||||||
# Write the rules that tunnel traffic from h1 to h2
|
# Write the rules that tunnel traffic from h1 to h2
|
||||||
writeTunnelRules(p4info_helper, ingress_sw=s1, egress_sw=s2, tunnel_id=100,
|
writeTunnelRules(p4info_helper, ingress_sw=s1, egress_sw=s2, tunnel_id=100,
|
||||||
dst_eth_addr="00:00:00:00:02:02", dst_ip_addr="10.0.2.2")
|
dst_eth_addr="08:00:00:00:02:22", dst_ip_addr="10.0.2.2")
|
||||||
|
|
||||||
# Write the rules that tunnel traffic from h2 to h1
|
# Write the rules that tunnel traffic from h2 to h1
|
||||||
writeTunnelRules(p4info_helper, ingress_sw=s2, egress_sw=s1, tunnel_id=200,
|
writeTunnelRules(p4info_helper, ingress_sw=s2, egress_sw=s1, tunnel_id=200,
|
||||||
dst_eth_addr="00:00:00:00:01:01", dst_ip_addr="10.0.1.1")
|
dst_eth_addr="08:00:00:00:01:11", dst_ip_addr="10.0.1.1")
|
||||||
|
|
||||||
# TODO Uncomment the following two lines to read table entries from s1 and s2
|
# TODO Uncomment the following two lines to read table entries from s1 and s2
|
||||||
# readTableRules(p4info_helper, s1)
|
# readTableRules(p4info_helper, s1)
|
||||||
|
|||||||
@@ -185,11 +185,11 @@ def main(p4info_file_path, bmv2_file_path):
|
|||||||
|
|
||||||
# Write the rules that tunnel traffic from h1 to h2
|
# Write the rules that tunnel traffic from h1 to h2
|
||||||
writeTunnelRules(p4info_helper, ingress_sw=s1, egress_sw=s2, tunnel_id=100,
|
writeTunnelRules(p4info_helper, ingress_sw=s1, egress_sw=s2, tunnel_id=100,
|
||||||
dst_eth_addr="00:00:00:00:02:02", dst_ip_addr="10.0.2.2")
|
dst_eth_addr="08:00:00:00:02:22", dst_ip_addr="10.0.2.2")
|
||||||
|
|
||||||
# Write the rules that tunnel traffic from h2 to h1
|
# Write the rules that tunnel traffic from h2 to h1
|
||||||
writeTunnelRules(p4info_helper, ingress_sw=s2, egress_sw=s1, tunnel_id=200,
|
writeTunnelRules(p4info_helper, ingress_sw=s2, egress_sw=s1, tunnel_id=200,
|
||||||
dst_eth_addr="00:00:00:00:01:01", dst_ip_addr="10.0.1.1")
|
dst_eth_addr="08:00:00:00:01:11", dst_ip_addr="10.0.1.1")
|
||||||
|
|
||||||
# TODO Uncomment the following two lines to read table entries from s1 and s2
|
# TODO Uncomment the following two lines to read table entries from s1 and s2
|
||||||
readTableRules(p4info_helper, s1)
|
readTableRules(p4info_helper, s1)
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
{
|
{
|
||||||
"hosts": [
|
"hosts": {
|
||||||
"h1",
|
"h1": {"ip": "10.0.1.1/24", "mac": "08:00:00:00:01:11",
|
||||||
"h2",
|
"commands":["route add default gw 10.0.1.10 dev eth0",
|
||||||
"h3"
|
"arp -i eth0 -s 10.0.1.10 08:00:00:00:01:00"]},
|
||||||
],
|
"h2": {"ip": "10.0.2.2/24", "mac": "08:00:00:00:02:22",
|
||||||
|
"commands":["route add default gw 10.0.2.20 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.2.20 08:00:00:00:02:00"]},
|
||||||
|
"h3": {"ip": "10.0.3.3/24", "mac": "08:00:00:00:03:33",
|
||||||
|
"commands":["route add default gw 10.0.3.30 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.3.30 08:00:00:00:03:00"]}
|
||||||
|
},
|
||||||
"switches": {
|
"switches": {
|
||||||
"s1": {},
|
"s1": {},
|
||||||
"s2": {},
|
"s2": {},
|
||||||
"s3": {}
|
"s3": {}
|
||||||
},
|
},
|
||||||
"links": [
|
"links": [
|
||||||
["h1", "s1"], ["s1", "s2"], ["s1", "s3"],
|
["h1", "s1-p1"], ["s1-p2", "s2-p2"], ["s1-p3", "s3-p2"],
|
||||||
["s3", "s2"], ["s2", "h2"], ["s3", "h3"]
|
["s3-p3", "s2-p3"], ["h2", "s2-p1"], ["h3", "s3-p1"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
BMV2_SWITCH_EXE = simple_switch_grpc
|
BMV2_SWITCH_EXE = simple_switch_grpc
|
||||||
NO_P4 = true
|
|
||||||
P4C_ARGS = --p4runtime-files $(basename $@).p4.p4info.txt
|
|
||||||
|
|
||||||
include ../../utils/Makefile
|
include ../../utils/Makefile
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 138 B After Width: | Height: | Size: 67 B |
@@ -49,7 +49,7 @@ bind_layers(SourceRoute, SourceRoute, bos=0)
|
|||||||
bind_layers(SourceRoute, SourceRoutingTail, bos=1)
|
bind_layers(SourceRoute, SourceRoutingTail, bos=1)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
iface = 'h2-eth0'
|
iface = 'eth0'
|
||||||
print "sniffing on %s" % iface
|
print "sniffing on %s" % iface
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
sniff(filter="udp and port 4321", iface = iface,
|
sniff(filter="udp and port 4321", iface = iface,
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
{
|
{
|
||||||
"hosts": [
|
"hosts": {
|
||||||
"h1",
|
"h1": {"ip": "10.0.1.1/24", "mac": "08:00:00:00:01:11",
|
||||||
"h2",
|
"commands":["route add default gw 10.0.1.10 dev eth0",
|
||||||
"h3"
|
"arp -i eth0 -s 10.0.1.10 08:00:00:00:01:00"]},
|
||||||
],
|
"h2": {"ip": "10.0.2.2/24", "mac": "08:00:00:00:02:22",
|
||||||
|
"commands":["route add default gw 10.0.2.20 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.2.20 08:00:00:00:02:00"]},
|
||||||
|
"h3": {"ip": "10.0.3.3/24", "mac": "08:00:00:00:03:33",
|
||||||
|
"commands":["route add default gw 10.0.3.30 dev eth0",
|
||||||
|
"arp -i eth0 -s 10.0.3.30 08:00:00:00:03:00"]}
|
||||||
|
},
|
||||||
"switches": {
|
"switches": {
|
||||||
"s1": { "runtime_json" : "s1-runtime.json" },
|
"s1": { "runtime_json" : "s1-runtime.json" },
|
||||||
"s2": { "runtime_json" : "s2-runtime.json" },
|
"s2": { "runtime_json" : "s2-runtime.json" },
|
||||||
"s3": { "runtime_json" : "s3-runtime.json" }
|
"s3": { "runtime_json" : "s3-runtime.json" }
|
||||||
},
|
},
|
||||||
"links": [
|
"links": [
|
||||||
["h1", "s1"], ["s1", "s2"], ["s1", "s3"],
|
["h1", "s1-p1"], ["s1-p2", "s2-p2"], ["s1-p3", "s3-p2"],
|
||||||
["s3", "s2"], ["s2", "h2"], ["s3", "h3"]
|
["s3-p3", "s2-p3"], ["h2", "s2-p1"], ["h3", "s3-p1"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,18 +2,26 @@ BUILD_DIR = build
|
|||||||
PCAP_DIR = pcaps
|
PCAP_DIR = pcaps
|
||||||
LOG_DIR = logs
|
LOG_DIR = logs
|
||||||
|
|
||||||
TOPO = topology.json
|
|
||||||
P4C = p4c-bm2-ss
|
P4C = p4c-bm2-ss
|
||||||
|
P4C_ARGS += --p4runtime-files $(BUILD_DIR)/$(basename $@).p4.p4info.txt
|
||||||
|
|
||||||
RUN_SCRIPT = ../../utils/run_exercise.py
|
RUN_SCRIPT = ../../utils/run_exercise.py
|
||||||
|
|
||||||
source := $(wildcard *.p4)
|
ifndef TOPO
|
||||||
outfile := $(source:.p4=.json)
|
TOPO = topology.json
|
||||||
|
endif
|
||||||
|
|
||||||
compiled_json := $(BUILD_DIR)/$(outfile)
|
source = $(wildcard *.p4)
|
||||||
|
compiled_json := $(source:.p4=.json)
|
||||||
|
|
||||||
|
ifndef DEFAULT_PROG
|
||||||
|
DEFAULT_PROG = $(wildcard *.p4)
|
||||||
|
endif
|
||||||
|
DEFAULT_JSON = $(BUILD_DIR)/$(DEFAULT_PROG:.p4=.json)
|
||||||
|
|
||||||
# Define NO_P4 to start BMv2 without a program
|
# Define NO_P4 to start BMv2 without a program
|
||||||
ifndef NO_P4
|
ifndef NO_P4
|
||||||
run_args += -j $(compiled_json)
|
run_args += -j $(DEFAULT_JSON)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Set BMV2_SWITCH_EXE to override the BMv2 target
|
# Set BMV2_SWITCH_EXE to override the BMv2 target
|
||||||
@@ -31,8 +39,8 @@ stop:
|
|||||||
|
|
||||||
build: dirs $(compiled_json)
|
build: dirs $(compiled_json)
|
||||||
|
|
||||||
$(BUILD_DIR)/%.json: %.p4
|
%.json: %.p4
|
||||||
$(P4C) --p4v 16 $(P4C_ARGS) -o $@ $<
|
$(P4C) --p4v 16 $(P4C_ARGS) -o $(BUILD_DIR)/$@ $<
|
||||||
|
|
||||||
dirs:
|
dirs:
|
||||||
mkdir -p $(BUILD_DIR) $(PCAP_DIR) $(LOG_DIR)
|
mkdir -p $(BUILD_DIR) $(PCAP_DIR) $(LOG_DIR)
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class P4RuntimeSwitch(P4Switch):
|
|||||||
if json_path is not None:
|
if json_path is not None:
|
||||||
# make sure that the provided JSON file exists
|
# make sure that the provided JSON file exists
|
||||||
if not os.path.isfile(json_path):
|
if not os.path.isfile(json_path):
|
||||||
error("Invalid JSON file.\n")
|
error("Invalid JSON file: {}\n".format(json_path))
|
||||||
exit(1)
|
exit(1)
|
||||||
self.json_path = json_path
|
self.json_path = json_path
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -66,65 +66,57 @@ def configureP4Switch(**switch_args):
|
|||||||
|
|
||||||
class ExerciseTopo(Topo):
|
class ExerciseTopo(Topo):
|
||||||
""" The mininet topology class for the P4 tutorial exercises.
|
""" The mininet topology class for the P4 tutorial exercises.
|
||||||
A custom class is used because the exercises make a few topology
|
|
||||||
assumptions, mostly about the IP and MAC addresses.
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, hosts, switches, links, log_dir, **opts):
|
def __init__(self, hosts, switches, links, log_dir, bmv2_exe, pcap_dir, **opts):
|
||||||
Topo.__init__(self, **opts)
|
Topo.__init__(self, **opts)
|
||||||
host_links = []
|
host_links = []
|
||||||
switch_links = []
|
switch_links = []
|
||||||
self.sw_port_mapping = {}
|
|
||||||
|
|
||||||
|
# assumes host always comes first for host<-->switch links
|
||||||
for link in links:
|
for link in links:
|
||||||
if link['node1'][0] == 'h':
|
if link['node1'][0] == 'h':
|
||||||
host_links.append(link)
|
host_links.append(link)
|
||||||
else:
|
else:
|
||||||
switch_links.append(link)
|
switch_links.append(link)
|
||||||
|
|
||||||
link_sort_key = lambda x: x['node1'] + x['node2']
|
for sw, params in switches.iteritems():
|
||||||
# Links must be added in a sorted order so bmv2 port numbers are predictable
|
if "program" in params:
|
||||||
host_links.sort(key=link_sort_key)
|
switchClass = configureP4Switch(
|
||||||
switch_links.sort(key=link_sort_key)
|
sw_path=bmv2_exe,
|
||||||
|
json_path=params["program"],
|
||||||
for sw in switches:
|
log_console=True,
|
||||||
self.addSwitch(sw, log_file="%s/%s.log" %(log_dir, sw))
|
pcap_dump=pcap_dir)
|
||||||
|
else:
|
||||||
|
# add default switch
|
||||||
|
switchClass = None
|
||||||
|
self.addSwitch(sw, log_file="%s/%s.log" %(log_dir, sw), cls=switchClass)
|
||||||
|
|
||||||
for link in host_links:
|
for link in host_links:
|
||||||
host_name = link['node1']
|
host_name = link['node1']
|
||||||
host_sw = link['node2']
|
sw_name, sw_port = self.parse_switch_node(link['node2'])
|
||||||
host_num = int(host_name[1:])
|
host_ip = hosts[host_name]['ip']
|
||||||
sw_num = int(host_sw[1:])
|
host_mac = hosts[host_name]['mac']
|
||||||
host_ip = "10.0.%d.%d" % (sw_num, host_num)
|
self.addHost(host_name, ip=host_ip, mac=host_mac)
|
||||||
host_mac = '00:00:00:00:%02x:%02x' % (sw_num, host_num)
|
self.addLink(host_name, sw_name,
|
||||||
# Each host IP should be /24, so all exercise traffic will use the
|
|
||||||
# default gateway (the switch) without sending ARP requests.
|
|
||||||
self.addHost(host_name, ip=host_ip+'/24', mac=host_mac)
|
|
||||||
self.addLink(host_name, host_sw,
|
|
||||||
delay=link['latency'], bw=link['bandwidth'],
|
delay=link['latency'], bw=link['bandwidth'],
|
||||||
addr1=host_mac, addr2=host_mac)
|
port2=sw_port)
|
||||||
self.addSwitchPort(host_sw, host_name)
|
|
||||||
|
|
||||||
for link in switch_links:
|
for link in switch_links:
|
||||||
self.addLink(link['node1'], link['node2'],
|
sw1_name, sw1_port = self.parse_switch_node(link['node1'])
|
||||||
|
sw2_name, sw2_port = self.parse_switch_node(link['node2'])
|
||||||
|
self.addLink(sw1_name, sw2_name,
|
||||||
|
port1=sw1_port, port2=sw2_port,
|
||||||
delay=link['latency'], bw=link['bandwidth'])
|
delay=link['latency'], bw=link['bandwidth'])
|
||||||
self.addSwitchPort(link['node1'], link['node2'])
|
|
||||||
self.addSwitchPort(link['node2'], link['node1'])
|
|
||||||
|
|
||||||
self.printPortMapping()
|
|
||||||
|
|
||||||
def addSwitchPort(self, sw, node2):
|
def parse_switch_node(self, node):
|
||||||
if sw not in self.sw_port_mapping:
|
assert(len(node.split('-')) == 2)
|
||||||
self.sw_port_mapping[sw] = []
|
sw_name, sw_port = node.split('-')
|
||||||
portno = len(self.sw_port_mapping[sw])+1
|
try:
|
||||||
self.sw_port_mapping[sw].append((portno, node2))
|
sw_port = int(sw_port[1])
|
||||||
|
except:
|
||||||
def printPortMapping(self):
|
raise Exception('Invalid switch node in topology file: {}'.format(node))
|
||||||
print "Switch port mapping:"
|
return sw_name, sw_port
|
||||||
for sw in sorted(self.sw_port_mapping.keys()):
|
|
||||||
print "%s: " % sw,
|
|
||||||
for portno, node2 in self.sw_port_mapping[sw]:
|
|
||||||
print "%d:%s\t" % (portno, node2),
|
|
||||||
print
|
|
||||||
|
|
||||||
|
|
||||||
class ExerciseRunner:
|
class ExerciseRunner:
|
||||||
@@ -134,8 +126,8 @@ class ExerciseRunner:
|
|||||||
pcap_dir : string // directory for mininet switch pcap files
|
pcap_dir : string // directory for mininet switch pcap files
|
||||||
quiet : bool // determines if we print logger messages
|
quiet : bool // determines if we print logger messages
|
||||||
|
|
||||||
hosts : list<string> // list of mininet host names
|
hosts : dict<string, dict> // mininet host names and their associated properties
|
||||||
switches : dict<string, dict> // mininet host names and their associated properties
|
switches : dict<string, dict> // mininet switch names and their associated properties
|
||||||
links : list<dict> // list of mininet link properties
|
links : list<dict> // list of mininet link properties
|
||||||
|
|
||||||
switch_json : string // json of the compiled p4 example
|
switch_json : string // json of the compiled p4 example
|
||||||
@@ -149,7 +141,7 @@ class ExerciseRunner:
|
|||||||
if not self.quiet:
|
if not self.quiet:
|
||||||
print(' '.join(items))
|
print(' '.join(items))
|
||||||
|
|
||||||
def formatLatency(self, l):
|
def format_latency(self, l):
|
||||||
""" Helper method for parsing link latencies from the topology json. """
|
""" Helper method for parsing link latencies from the topology json. """
|
||||||
if isinstance(l, (str, unicode)):
|
if isinstance(l, (str, unicode)):
|
||||||
return l
|
return l
|
||||||
@@ -232,7 +224,7 @@ class ExerciseRunner:
|
|||||||
'bandwidth':None
|
'bandwidth':None
|
||||||
}
|
}
|
||||||
if len(link) > 2:
|
if len(link) > 2:
|
||||||
link_dict['latency'] = self.formatLatency(link[2])
|
link_dict['latency'] = self.format_latency(link[2])
|
||||||
if len(link) > 3:
|
if len(link) > 3:
|
||||||
link_dict['bandwidth'] = link[3]
|
link_dict['bandwidth'] = link[3]
|
||||||
|
|
||||||
@@ -251,18 +243,18 @@ class ExerciseRunner:
|
|||||||
"""
|
"""
|
||||||
self.logger("Building mininet topology.")
|
self.logger("Building mininet topology.")
|
||||||
|
|
||||||
self.topo = ExerciseTopo(self.hosts, self.switches.keys(), self.links, self.log_dir)
|
defaultSwitchClass = configureP4Switch(
|
||||||
|
sw_path=self.bmv2_exe,
|
||||||
|
json_path=self.switch_json,
|
||||||
|
log_console=True,
|
||||||
|
pcap_dump=self.pcap_dir)
|
||||||
|
|
||||||
switchClass = configureP4Switch(
|
self.topo = ExerciseTopo(self.hosts, self.switches, self.links, self.log_dir, self.bmv2_exe, self.pcap_dir)
|
||||||
sw_path=self.bmv2_exe,
|
|
||||||
json_path=self.switch_json,
|
|
||||||
log_console=True,
|
|
||||||
pcap_dump=self.pcap_dir)
|
|
||||||
|
|
||||||
self.net = Mininet(topo = self.topo,
|
self.net = Mininet(topo = self.topo,
|
||||||
link = TCLink,
|
link = TCLink,
|
||||||
host = P4Host,
|
host = P4Host,
|
||||||
switch = switchClass,
|
switch = defaultSwitchClass,
|
||||||
controller = None)
|
controller = None)
|
||||||
|
|
||||||
def program_switch_p4runtime(self, sw_name, sw_dict):
|
def program_switch_p4runtime(self, sw_name, sw_dict):
|
||||||
@@ -312,30 +304,13 @@ class ExerciseRunner:
|
|||||||
self.program_switch_p4runtime(sw_name, sw_dict)
|
self.program_switch_p4runtime(sw_name, sw_dict)
|
||||||
|
|
||||||
def program_hosts(self):
|
def program_hosts(self):
|
||||||
""" Adds static ARP entries and default routes to each mininet host.
|
""" Execute any commands provided in the topology.json file on each Mininet host
|
||||||
|
|
||||||
Assumes:
|
|
||||||
- A mininet instance is stored as self.net and self.net.start() has
|
|
||||||
been called.
|
|
||||||
"""
|
"""
|
||||||
for host_name in self.topo.hosts():
|
for host_name, host_info in self.hosts.items():
|
||||||
h = self.net.get(host_name)
|
h = self.net.get(host_name)
|
||||||
h_iface = h.intfs.values()[0]
|
if "commands" in host_info:
|
||||||
link = h_iface.link
|
for cmd in host_info["commands"]:
|
||||||
|
h.cmd(cmd)
|
||||||
sw_iface = link.intf1 if link.intf1 != h_iface else link.intf2
|
|
||||||
# phony IP to lie to the host about
|
|
||||||
host_id = int(host_name[1:])
|
|
||||||
sw_ip = '10.0.%d.254' % host_id
|
|
||||||
|
|
||||||
# Ensure each host's interface name is unique, or else
|
|
||||||
# mininet cannot shutdown gracefully
|
|
||||||
h.defaultIntf().rename('%s-eth0' % host_name)
|
|
||||||
# static arp entries and default routes
|
|
||||||
h.cmd('arp -i %s -s %s %s' % (h_iface.name, sw_ip, sw_iface.mac))
|
|
||||||
h.cmd('ethtool --offload %s rx off tx off' % h_iface.name)
|
|
||||||
h.cmd('ip route add %s dev %s' % (sw_ip, h_iface.name))
|
|
||||||
h.setDefaultRoute("via %s" % sw_ip)
|
|
||||||
|
|
||||||
|
|
||||||
def do_net_cli(self):
|
def do_net_cli(self):
|
||||||
|
|||||||
@@ -73,10 +73,10 @@ chmod 440 /etc/sudoers.d/99_p4
|
|||||||
usermod -aG vboxsf p4
|
usermod -aG vboxsf p4
|
||||||
|
|
||||||
cd /usr/share/lubuntu/wallpapers/
|
cd /usr/share/lubuntu/wallpapers/
|
||||||
cp ~/p4-logo.png .
|
cp /home/vagrant/p4-logo.png .
|
||||||
rm lubuntu-default-wallpaper.png
|
rm lubuntu-default-wallpaper.png
|
||||||
ln -s p4-logo.png lubuntu-default-wallpaper.png
|
ln -s p4-logo.png lubuntu-default-wallpaper.png
|
||||||
rm ~/p4-logo.png
|
rm /home/vagrant/p4-logo.png
|
||||||
cd ~
|
cd ~
|
||||||
sed -i s@#background=@background=/usr/share/lubuntu/wallpapers/1604-lubuntu-default-wallpaper.png@ /etc/lightdm/lightdm-gtk-greeter.conf
|
sed -i s@#background=@background=/usr/share/lubuntu/wallpapers/1604-lubuntu-default-wallpaper.png@ /etc/lightdm/lightdm-gtk-greeter.conf
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
set -xe
|
set -xe
|
||||||
|
|
||||||
#Src
|
#Src
|
||||||
BMV2_COMMIT="884e01b531c6fd078cc2438a40258ecae011a65b" # Apr 24, 2019
|
BMV2_COMMIT="b447ac4c0cfd83e5e72a3cc6120251c1e91128ab" # August 10, 2019
|
||||||
PI_COMMIT="19de33e83bae7b737a3f8a1c9507c6e84173d96f" # Apr 24, 2019
|
PI_COMMIT="41358da0ff32c94fa13179b9cee0ab597c9ccbcc" # August 10, 2019
|
||||||
P4C_COMMIT="61409c890c58d14ec7d6790f263eb44f393e542a" # Apr 24, 2019
|
P4C_COMMIT="69e132d0d663e3408d740aaf8ed534ecefc88810" # August 10, 2019
|
||||||
PROTOBUF_COMMIT="v3.2.0"
|
PROTOBUF_COMMIT="v3.2.0"
|
||||||
GRPC_COMMIT="v1.3.2"
|
GRPC_COMMIT="v1.3.2"
|
||||||
|
|
||||||
@@ -112,6 +112,8 @@ sudo pip install crcmod
|
|||||||
git clone https://github.com/p4lang/tutorials
|
git clone https://github.com/p4lang/tutorials
|
||||||
sudo mv tutorials /home/p4
|
sudo mv tutorials /home/p4
|
||||||
sudo chown -R p4:p4 /home/p4/tutorials
|
sudo chown -R p4:p4 /home/p4/tutorials
|
||||||
|
# Install grip for offline markdown rendering
|
||||||
|
sudo pip install grip
|
||||||
|
|
||||||
# --- Emacs --- #
|
# --- Emacs --- #
|
||||||
sudo cp p4_16-mode.el /usr/share/emacs/site-lisp/
|
sudo cp p4_16-mode.el /usr/share/emacs/site-lisp/
|
||||||
|
|||||||