Sigcomm 17 (#52)
This problem contains the tutorial exercises and solutions presented at SIGCOMM '17.
This commit is contained in:
143
SIGCOMM_2017/exercises/load_balance/README.md
Normal file
143
SIGCOMM_2017/exercises/load_balance/README.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# Load Balancing
|
||||
|
||||
In this exercise, you will implement a form of load balancing based on
|
||||
a single version of Equal-Cost Multipath Forwarding. The switch you
|
||||
will implement will use two tables to forward packets to one of two
|
||||
destination hosts at random. The first table will use a hash function
|
||||
(applied to a 5-tuple consisting of the source and destination
|
||||
Ethernet addresses, source and destination IP addresses, and IP
|
||||
protocol) to select one of two hosts. The second table will use the
|
||||
computed hash value to forward the packet to the selected host.
|
||||
|
||||
> **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,
|
||||
`load_balance.p4`, which initially drops all packets. Your job (in
|
||||
the next step) will be to extend it to properly forward packets.
|
||||
|
||||
Before that, let's compile the incomplete `load_balance.p4` and bring
|
||||
up a switch in Mininet to test its behavior.
|
||||
|
||||
1. In your shell, run:
|
||||
```bash
|
||||
./run.sh
|
||||
```
|
||||
This will:
|
||||
* compile `load_balance.p4`, and
|
||||
* start a Mininet instance with three switches (`s1`, `s2`, `s3`) configured
|
||||
in a triangle, each connected to one host (`h1`, `h2`, `h3`).
|
||||
* The hosts are assigned IPs of `10.0.1.1`, `10.0.2.2`, etc.
|
||||
* We use the IP address 10.0.0.1 to indicate traffic that should be
|
||||
load balanced between `h2` and `h3`.
|
||||
|
||||
2. You should now see a Mininet command prompt. Open three terminals
|
||||
for `h1`, `h2` and `h3`, respectively:
|
||||
```bash
|
||||
mininet> xterm h1 h2 h3
|
||||
```
|
||||
3. Each host includes a small Python-based messaging client and
|
||||
server. In `h2` and `h3`'s XTerms, start the servers:
|
||||
```bash
|
||||
./receive.py
|
||||
```
|
||||
4. In `h1`'s XTerm, send a message from the client:
|
||||
```bash
|
||||
./send.py 10.0.0.1 "P4 is cool"
|
||||
```
|
||||
The message will not be received.
|
||||
5. Type `exit` to leave each XTerm and the Mininet command line.
|
||||
|
||||
The message was not received because each switch is programmed with
|
||||
`load_balance.p4`, which drops all packets on arrival. Your job is to
|
||||
extend this file.
|
||||
|
||||
### A note about the control plane
|
||||
|
||||
P4 programs define a packet-processing pipeline, but the rules
|
||||
governing packet processing are inserted into the pipeline 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, the control plane logic has already been
|
||||
implemented. As part of bringing up the Mininet instance, the
|
||||
`run.sh` script will install packet-processing rules in the tables of
|
||||
each switch. These are defined in the `s1-commands.txt` file.
|
||||
|
||||
**Important:** A P4 program also defines the interface between the
|
||||
switch pipeline and control plane. The `s1-commands.txt` file contains
|
||||
a list of commands for the BMv2 switch API. These commands refer to
|
||||
specific tables, keys, and actions by name, and any changes in the P4
|
||||
program that add or rename tables, keys, or actions will need to be
|
||||
reflected in these command files.
|
||||
|
||||
## Step 2: Implement Load Balancing
|
||||
|
||||
The `load_balance.p4` file contains a skeleton P4 program with key
|
||||
pieces of logic replaced by `TODO` comments. These should guide your
|
||||
implementation---replace each `TODO` with logic implementing the
|
||||
missing piece.
|
||||
|
||||
A complete `load_balance.p4` will contain the following components:
|
||||
|
||||
1. Header type definitions for Ethernet (`ethernet_t`) and IPv4 (`ipv4_t`).
|
||||
2. Parsers for Ethernet and IPv4 that populate `ethernet_t` and `ipv4_t` fields.
|
||||
3. An action to drop a packet, using `mark_to_drop()`.
|
||||
4. **TODO:** An action (called `set_ecmp_select`), which will:
|
||||
1. Hashes the 5-tuple specified above using the `hash` extern
|
||||
2. Stores the result in the `meta.ecmp_select` field
|
||||
5. **TODO:** A control that:
|
||||
1. Applies the `ecmp_group` table.
|
||||
2. Applies the `ecmp_nhop` table.
|
||||
6. A deparser that selects the order in which fields inserted into the outgoing
|
||||
packet.
|
||||
7. 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, your message from
|
||||
`h1` should be delivered to `h2` or `h3`. If you send several
|
||||
messages, some should be received by each server.
|
||||
|
||||
### Food for thought
|
||||
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
There are several ways that problems might manifest:
|
||||
|
||||
1. `load_balance.p4` fails to compile. In this case, `run.sh` will
|
||||
report the error emitted from the compiler and stop.
|
||||
|
||||
2. `load_balance.p4` compiles but does not support the control plane
|
||||
rules in the `sX-commands.txt` files that `run.sh` tries to install
|
||||
using the BMv2 CLI. In this case, `run.sh` will report these errors
|
||||
to `stderr`. Use these error messages to fix your `load_balance.p4`
|
||||
implementation.
|
||||
|
||||
3. `load_balance.p4` compiles, and the control plane rules are
|
||||
installed, but the switch does not process packets in the desired way.
|
||||
The `build/logs/<switch-name>.log` files contain trace messages
|
||||
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, `run.sh` may leave a Mininet instance
|
||||
running in the background. Use the following command to clean up
|
||||
these instances:
|
||||
|
||||
```bash
|
||||
mn -c
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
Congratulations, your implementation works! Move on to the next
|
||||
exercise: [HULA](../hula).
|
||||
218
SIGCOMM_2017/exercises/load_balance/load_balance.p4
Normal file
218
SIGCOMM_2017/exercises/load_balance/load_balance.p4
Normal file
@@ -0,0 +1,218 @@
|
||||
/* -*- P4_16 -*- */
|
||||
#include <core.p4>
|
||||
#include <v1model.p4>
|
||||
|
||||
/*************************************************************************
|
||||
*********************** H E A D E R S ***********************************
|
||||
*************************************************************************/
|
||||
|
||||
header ethernet_t {
|
||||
bit<48> dstAddr;
|
||||
bit<48> 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;
|
||||
bit<32> srcAddr;
|
||||
bit<32> dstAddr;
|
||||
}
|
||||
|
||||
header tcp_t {
|
||||
bit<16> srcPort;
|
||||
bit<16> dstPort;
|
||||
bit<32> seqNo;
|
||||
bit<32> ackNo;
|
||||
bit<4> dataOffset;
|
||||
bit<3> res;
|
||||
bit<3> ecn;
|
||||
bit<6> ctrl;
|
||||
bit<16> window;
|
||||
bit<16> checksum;
|
||||
bit<16> urgentPtr;
|
||||
}
|
||||
|
||||
struct metadata {
|
||||
bit<14> ecmp_select;
|
||||
}
|
||||
|
||||
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) {
|
||||
0x800: parse_ipv4;
|
||||
default: accept;
|
||||
}
|
||||
}
|
||||
state parse_ipv4 {
|
||||
packet.extract(hdr.ipv4);
|
||||
transition select(hdr.ipv4.protocol) {
|
||||
6: parse_tcp;
|
||||
default: accept;
|
||||
}
|
||||
}
|
||||
state parse_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(in 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();
|
||||
}
|
||||
action set_ecmp_select(bit<16> ecmp_base, bit<32> ecmp_count) {
|
||||
/* TODO: hash on 5-tuple and save the hash result in meta.ecmp_select
|
||||
so that the ecmp_nhop table can use it to make a forwarding decision accordingly */
|
||||
}
|
||||
action set_nhop(bit<48> nhop_dmac, bit<32> nhop_ipv4, bit<9> port) {
|
||||
hdr.ethernet.dstAddr = nhop_dmac;
|
||||
hdr.ipv4.dstAddr = nhop_ipv4;
|
||||
standard_metadata.egress_spec = port;
|
||||
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
|
||||
}
|
||||
table ecmp_group {
|
||||
key = {
|
||||
hdr.ipv4.dstAddr: lpm;
|
||||
}
|
||||
actions = {
|
||||
drop;
|
||||
set_ecmp_select;
|
||||
}
|
||||
size = 1024;
|
||||
}
|
||||
table ecmp_nhop {
|
||||
key = {
|
||||
meta.ecmp_select: exact;
|
||||
}
|
||||
actions = {
|
||||
drop;
|
||||
set_nhop;
|
||||
}
|
||||
size = 2;
|
||||
}
|
||||
apply {
|
||||
if (hdr.ipv4.isValid() && hdr.ipv4.ttl > 0) {
|
||||
ecmp_group.apply();
|
||||
ecmp_nhop.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) {
|
||||
|
||||
action rewrite_mac(bit<48> smac) {
|
||||
hdr.ethernet.srcAddr = smac;
|
||||
}
|
||||
action drop() {
|
||||
mark_to_drop();
|
||||
}
|
||||
table send_frame {
|
||||
key = {
|
||||
standard_metadata.egress_port: exact;
|
||||
}
|
||||
actions = {
|
||||
rewrite_mac;
|
||||
drop;
|
||||
}
|
||||
size = 256;
|
||||
}
|
||||
apply {
|
||||
send_frame.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;
|
||||
32
SIGCOMM_2017/exercises/load_balance/p4app.json
Normal file
32
SIGCOMM_2017/exercises/load_balance/p4app.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"program": "load_balance.p4",
|
||||
"language": "p4-16",
|
||||
"targets": {
|
||||
"multiswitch": {
|
||||
"auto-control-plane": true,
|
||||
"cli": true,
|
||||
"pcap_dump": true,
|
||||
"bmv2_log": true,
|
||||
"links": [["h1", "s1"], ["s1", "s2"], ["s1", "s3"], ["s3", "s2"], ["s2", "h2"], ["s3", "h3"]],
|
||||
"hosts": {
|
||||
"h1": {
|
||||
},
|
||||
"h2": {
|
||||
},
|
||||
"h3": {
|
||||
}
|
||||
},
|
||||
"switches": {
|
||||
"s1": {
|
||||
"entries": "s1-commands.txt"
|
||||
},
|
||||
"s2": {
|
||||
"entries": "s2-commands.txt"
|
||||
},
|
||||
"s3": {
|
||||
"entries": "s3-commands.txt"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
SIGCOMM_2017/exercises/load_balance/receive.py
Executable file
52
SIGCOMM_2017/exercises/load_balance/receive.py
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
import struct
|
||||
import os
|
||||
|
||||
from scapy.all import sniff, sendp, hexdump, get_if_list, get_if_hwaddr
|
||||
from scapy.all import Packet, IPOption
|
||||
from scapy.all import ShortField, IntField, LongField, BitField, FieldListField, FieldLenField
|
||||
from scapy.all import IP, UDP, Raw
|
||||
from scapy.layers.inet import _IPOption_HDR
|
||||
|
||||
def get_if():
|
||||
ifs=get_if_list()
|
||||
iface=None
|
||||
for i in get_if_list():
|
||||
if "eth0" in i:
|
||||
iface=i
|
||||
break;
|
||||
if not iface:
|
||||
print "Cannot find eth0 interface"
|
||||
exit(1)
|
||||
return iface
|
||||
|
||||
class IPOption_MRI(IPOption):
|
||||
name = "MRI"
|
||||
option = 31
|
||||
fields_desc = [ _IPOption_HDR,
|
||||
FieldLenField("length", None, fmt="B",
|
||||
length_of="swids",
|
||||
adjust=lambda pkt,l:l+4),
|
||||
ShortField("count", 0),
|
||||
FieldListField("swids",
|
||||
[],
|
||||
IntField("", 0),
|
||||
length_from=lambda pkt:pkt.count*4) ]
|
||||
def handle_pkt(pkt):
|
||||
print "got a packet"
|
||||
pkt.show2()
|
||||
# hexdump(pkt)
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def main():
|
||||
ifaces = filter(lambda i: 'eth' in i, os.listdir('/sys/class/net/'))
|
||||
iface = ifaces[0]
|
||||
print "sniffing on %s" % iface
|
||||
sys.stdout.flush()
|
||||
sniff(filter="tcp", iface = iface,
|
||||
prn = lambda x: handle_pkt(x))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
4
SIGCOMM_2017/exercises/load_balance/run.sh
Executable file
4
SIGCOMM_2017/exercises/load_balance/run.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
P4APPRUNNER=../../utils/p4apprunner.py
|
||||
mkdir -p build
|
||||
tar -czf build/p4app.tgz * --exclude='build'
|
||||
sudo python $P4APPRUNNER p4app.tgz --build-dir ./build
|
||||
6
SIGCOMM_2017/exercises/load_balance/s1-commands.txt
Normal file
6
SIGCOMM_2017/exercises/load_balance/s1-commands.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
table_set_default ecmp_group drop
|
||||
table_add ecmp_group set_ecmp_select 10.0.0.1/32 => 0 2
|
||||
table_add ecmp_nhop set_nhop 0 => 00:00:00:00:01:02 10.0.2.2 2
|
||||
table_add ecmp_nhop set_nhop 1 => 00:00:00:00:01:03 10.0.3.3 3
|
||||
table_add send_frame rewrite_mac 2 => 00:00:00:01:02:00
|
||||
table_add send_frame rewrite_mac 3 => 00:00:00:01:03:00
|
||||
4
SIGCOMM_2017/exercises/load_balance/s2-commands.txt
Normal file
4
SIGCOMM_2017/exercises/load_balance/s2-commands.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
table_set_default ecmp_group drop
|
||||
table_add ecmp_group set_ecmp_select 10.0.2.2/32 => 0 1
|
||||
table_add ecmp_nhop set_nhop 0 => 00:00:00:00:02:02 10.0.2.2 1
|
||||
table_add send_frame rewrite_mac 1 => 00:00:00:02:01:00
|
||||
4
SIGCOMM_2017/exercises/load_balance/s3-commands.txt
Normal file
4
SIGCOMM_2017/exercises/load_balance/s3-commands.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
table_set_default ecmp_group drop
|
||||
table_add ecmp_group set_ecmp_select 10.0.3.3/32 => 0 1
|
||||
table_add ecmp_nhop set_nhop 0 => 00:00:00:00:03:03 10.0.3.3 1
|
||||
table_add send_frame rewrite_mac 1 => 00:00:00:03:01:00
|
||||
41
SIGCOMM_2017/exercises/load_balance/send.py
Executable file
41
SIGCOMM_2017/exercises/load_balance/send.py
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python
|
||||
import argparse
|
||||
import sys
|
||||
import socket
|
||||
import random
|
||||
import struct
|
||||
|
||||
from scapy.all import sendp, send, get_if_list, get_if_hwaddr
|
||||
from scapy.all import Packet
|
||||
from scapy.all import Ether, IP, UDP, TCP
|
||||
|
||||
def get_if():
|
||||
ifs=get_if_list()
|
||||
iface=None # "h1-eth0"
|
||||
for i in get_if_list():
|
||||
if "eth0" in i:
|
||||
iface=i
|
||||
break;
|
||||
if not iface:
|
||||
print "Cannot find eth0 interface"
|
||||
exit(1)
|
||||
return iface
|
||||
|
||||
def main():
|
||||
|
||||
if len(sys.argv)<3:
|
||||
print 'pass 2 arguments: <destination> "<message>"'
|
||||
exit(1)
|
||||
|
||||
addr = socket.gethostbyname(sys.argv[1])
|
||||
iface = get_if()
|
||||
|
||||
print "sending on interface %s to %s" % (iface, str(addr))
|
||||
pkt = Ether(src=get_if_hwaddr(iface), dst='ff:ff:ff:ff:ff:ff')
|
||||
pkt = pkt /IP(dst=addr) / TCP(dport=1234, sport=random.randint(49152,65535)) / sys.argv[2]
|
||||
pkt.show2()
|
||||
sendp(pkt, iface=iface, verbose=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
225
SIGCOMM_2017/exercises/load_balance/solution/load_balance.p4
Normal file
225
SIGCOMM_2017/exercises/load_balance/solution/load_balance.p4
Normal file
@@ -0,0 +1,225 @@
|
||||
/* -*- P4_16 -*- */
|
||||
#include <core.p4>
|
||||
#include <v1model.p4>
|
||||
|
||||
/*************************************************************************
|
||||
*********************** H E A D E R S ***********************************
|
||||
*************************************************************************/
|
||||
|
||||
header ethernet_t {
|
||||
bit<48> dstAddr;
|
||||
bit<48> 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;
|
||||
bit<32> srcAddr;
|
||||
bit<32> dstAddr;
|
||||
}
|
||||
|
||||
header tcp_t {
|
||||
bit<16> srcPort;
|
||||
bit<16> dstPort;
|
||||
bit<32> seqNo;
|
||||
bit<32> ackNo;
|
||||
bit<4> dataOffset;
|
||||
bit<3> res;
|
||||
bit<3> ecn;
|
||||
bit<6> ctrl;
|
||||
bit<16> window;
|
||||
bit<16> checksum;
|
||||
bit<16> urgentPtr;
|
||||
}
|
||||
|
||||
struct metadata {
|
||||
bit<14> ecmp_select;
|
||||
}
|
||||
|
||||
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) {
|
||||
0x800: parse_ipv4;
|
||||
default: accept;
|
||||
}
|
||||
}
|
||||
state parse_ipv4 {
|
||||
packet.extract(hdr.ipv4);
|
||||
transition select(hdr.ipv4.protocol) {
|
||||
6: parse_tcp;
|
||||
default: accept;
|
||||
}
|
||||
}
|
||||
state parse_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(in 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();
|
||||
}
|
||||
action set_ecmp_select(bit<16> ecmp_base, bit<32> ecmp_count) {
|
||||
hash(meta.ecmp_select,
|
||||
HashAlgorithm.crc16,
|
||||
ecmp_base,
|
||||
{ hdr.ipv4.srcAddr,
|
||||
hdr.ipv4.dstAddr,
|
||||
hdr.ipv4.protocol,
|
||||
hdr.tcp.srcPort,
|
||||
hdr.tcp.dstPort },
|
||||
ecmp_count);
|
||||
}
|
||||
action set_nhop(bit<48> nhop_dmac, bit<32> nhop_ipv4, bit<9> port) {
|
||||
hdr.ethernet.dstAddr = nhop_dmac;
|
||||
hdr.ipv4.dstAddr = nhop_ipv4;
|
||||
standard_metadata.egress_spec = port;
|
||||
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
|
||||
}
|
||||
table ecmp_group {
|
||||
key = {
|
||||
hdr.ipv4.dstAddr: lpm;
|
||||
}
|
||||
actions = {
|
||||
drop;
|
||||
set_ecmp_select;
|
||||
}
|
||||
size = 1024;
|
||||
}
|
||||
table ecmp_nhop {
|
||||
key = {
|
||||
meta.ecmp_select: exact;
|
||||
}
|
||||
actions = {
|
||||
drop;
|
||||
set_nhop;
|
||||
}
|
||||
size = 2;
|
||||
}
|
||||
apply {
|
||||
if (hdr.ipv4.isValid() && hdr.ipv4.ttl > 0) {
|
||||
ecmp_group.apply();
|
||||
ecmp_nhop.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) {
|
||||
|
||||
action rewrite_mac(bit<48> smac) {
|
||||
hdr.ethernet.srcAddr = smac;
|
||||
}
|
||||
action drop() {
|
||||
mark_to_drop();
|
||||
}
|
||||
table send_frame {
|
||||
key = {
|
||||
standard_metadata.egress_port: exact;
|
||||
}
|
||||
actions = {
|
||||
rewrite_mac;
|
||||
drop;
|
||||
}
|
||||
size = 256;
|
||||
}
|
||||
apply {
|
||||
send_frame.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;
|
||||
Reference in New Issue
Block a user