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
This commit is contained in:
4
exercises/link_monitor/Makefile
Normal file
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
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
BIN
exercises/link_monitor/link-monitor-topo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 251 KiB |
299
exercises/link_monitor/link_monitor.p4
Normal file
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
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
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
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
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
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
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
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
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
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;
|
||||
Reference in New Issue
Block a user