Basic Encapsulation Example (#64)
* Adding initial implementation of basic_encap example * Updated basic_encap example to count the number of valid packets * Updated basic_encap example to put encapsulation layer after Ethernet header. * Added solution file for basic_encap example * Changed the name of the basic_encap example to basic_tunnel and called the new header myTunnel. Also changed the myTunnel field names slightly.
This commit is contained in:
parent
597b5b401c
commit
7738341012
163
P4D2_2017_Fall/exercises/basic_tunnel/README.md
Normal file
163
P4D2_2017_Fall/exercises/basic_tunnel/README.md
Normal file
@ -0,0 +1,163 @@
|
||||
# Implementing Basic Forwarding
|
||||
|
||||
## Introduction
|
||||
|
||||
The objective of this exercise is to write a P4 program that
|
||||
implements basic forwarding. To keep things simple, we will just
|
||||
implement forwarding for IPv4.
|
||||
|
||||
With IPv4 forwarding, the switch must perform the following actions
|
||||
for every packet: (i) update the source and destination MAC addresses,
|
||||
(ii) decrement the time-to-live (TTL) in the IP header, and (iii)
|
||||
forward the packet out the appropriate port.
|
||||
|
||||
Your switch will have a single table, which the control plane will
|
||||
populate with static rules. Each rule will map an IP address to the
|
||||
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
|
||||
logic of your P4 program.
|
||||
|
||||
> **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,
|
||||
`basic.p4`, which initially drops all packets. Your job will be to
|
||||
extend this skeleton program to properly forward IPv4 packets.
|
||||
|
||||
Before that, let's compile the incomplete `basic.p4` and bring
|
||||
up a switch in Mininet to test its behavior.
|
||||
|
||||
1. In your shell, run:
|
||||
```bash
|
||||
./run.sh
|
||||
```
|
||||
This will:
|
||||
* compile `basic.p4`, and
|
||||
* start a Mininet instance with three switches (`s1`, `s2`, `s3`)
|
||||
configured in a triangle, each connected to one host (`h1`, `h2`,
|
||||
and `h3`).
|
||||
* The hosts are assigned IPs of `10.0.1.1`, `10.0.2.2`, etc.
|
||||
|
||||
2. You should now see a Mininet command prompt. Open two terminals
|
||||
for `h1` and `h2`, respectively:
|
||||
```bash
|
||||
mininet> xterm h1 h2
|
||||
```
|
||||
3. Each host includes a small Python-based messaging client and
|
||||
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.
|
||||
|
||||
The message was not received because each switch is programmed
|
||||
according to `basic.p4`, which drops all packets on arrival.
|
||||
Your job is to extend this file so it forwards packets.
|
||||
|
||||
### 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
|
||||
`run.sh` script will install packet-processing rules in the tables of
|
||||
each switch. These are defined in the `sX-commands.txt` files, where
|
||||
`X` corresponds to the switch number.
|
||||
|
||||
**Important:** A P4 program also defines the interface between the
|
||||
switch pipeline and control plane. The commands in the files
|
||||
`sX-commands.txt` 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 L3 forwarding
|
||||
|
||||
The `basic.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.
|
||||
|
||||
A complete `basic.p4` will contain the following components:
|
||||
|
||||
1. Header type definitions for Ethernet (`ethernet_t`) and IPv4 (`ipv4_t`).
|
||||
2. **TODO:** 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 `ipv4_forward`) that:
|
||||
1. Sets the egress port for the next hop.
|
||||
2. Updates the ethernet destination address with the address of the next hop.
|
||||
3. Updates the ethernet source address with the address of the switch.
|
||||
4. Decrements the TTL.
|
||||
5. **TODO:** A control that:
|
||||
1. Defines a table that will read an IPv4 destination address, and
|
||||
invoke either `drop` or `ipv4_forward`.
|
||||
2. An `apply` block that applies the table.
|
||||
6. **TODO:** 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`.
|
||||
|
||||
### Food for thought
|
||||
|
||||
The "test suite" for your solution---sending a message from `h1` to
|
||||
`h2`---is not very robust. What else should you test to be confident
|
||||
of your implementation?
|
||||
|
||||
> 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
|
||||
> to use it.
|
||||
|
||||
Other questions to consider:
|
||||
- How would you enhance your program to support next hops?
|
||||
- Is this program enough to replace a router? What's missing?
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
There are several problems that might manifest as you develop your program:
|
||||
|
||||
1. `basic.p4` might fails to compile. In this case, `run.sh` will
|
||||
report the error emitted from the compiler and halt.
|
||||
|
||||
2. `basic.p4` might compile but fail to support the control plane
|
||||
rules in the `s1-commands.txt` through `s3-command.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 `basic.p4` implementation.
|
||||
|
||||
3. `basic.p4` might compile, and the control plane rules might be
|
||||
installed, but the switch might not process packets in the desired
|
||||
way. The `build/logs/<switch-name>.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, `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: implementing the [scrambler](../scrambler)!
|
211
P4D2_2017_Fall/exercises/basic_tunnel/basic_tunnel.p4
Normal file
211
P4D2_2017_Fall/exercises/basic_tunnel/basic_tunnel.p4
Normal file
@ -0,0 +1,211 @@
|
||||
/* -*- P4_16 -*- */
|
||||
#include <core.p4>
|
||||
#include <v1model.p4>
|
||||
|
||||
const bit<16> TYPE_MYTUNNEL = 0x1212;
|
||||
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 myTunnel_t {
|
||||
bit<16> proto_id;
|
||||
bit<16> dst_id;
|
||||
}
|
||||
|
||||
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;
|
||||
myTunnel_t myTunnel;
|
||||
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_MYTUNNEL: parse_myTunnel;
|
||||
TYPE_IPV4: parse_ipv4;
|
||||
default: accept;
|
||||
}
|
||||
}
|
||||
|
||||
state parse_myTunnel {
|
||||
packet.extract(hdr.myTunnel);
|
||||
transition select(hdr.myTunnel.proto_id) {
|
||||
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(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 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 = NoAction();
|
||||
}
|
||||
|
||||
action myTunnel_forward(egressSpec_t port) {
|
||||
standard_metadata.egress_spec = port;
|
||||
}
|
||||
|
||||
table myTunnel_exact {
|
||||
key = {
|
||||
hdr.myTunnel.dst_id: exact;
|
||||
}
|
||||
actions = {
|
||||
myTunnel_forward;
|
||||
drop;
|
||||
}
|
||||
size = 1024;
|
||||
default_action = drop();
|
||||
}
|
||||
|
||||
apply {
|
||||
if (hdr.myTunnel.isValid()) {
|
||||
myTunnel_exact.apply();
|
||||
} else 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.myTunnel);
|
||||
packet.emit(hdr.ipv4);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** S W I T C H *******************************
|
||||
*************************************************************************/
|
||||
|
||||
V1Switch(
|
||||
MyParser(),
|
||||
MyVerifyChecksum(),
|
||||
MyIngress(),
|
||||
MyEgress(),
|
||||
MyComputeChecksum(),
|
||||
MyDeparser()
|
||||
) main;
|
20
P4D2_2017_Fall/exercises/basic_tunnel/myTunnel_header.py
Normal file
20
P4D2_2017_Fall/exercises/basic_tunnel/myTunnel_header.py
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
from scapy.all import *
|
||||
import sys, os
|
||||
|
||||
TYPE_MYTUNNEL = 0x1212
|
||||
TYPE_IPV4 = 0x0800
|
||||
|
||||
class MyTunnel(Packet):
|
||||
name = "MyTunnel"
|
||||
fields_desc = [
|
||||
ShortField("pid", 0),
|
||||
ShortField("dst_id", 0)
|
||||
]
|
||||
def mysummary(self):
|
||||
return self.sprintf("pid=%pid%, dst_id=%dst_id%")
|
||||
|
||||
|
||||
bind_layers(Ether, MyTunnel, type=TYPE_MYTUNNEL)
|
||||
bind_layers(MyTunnel, IP, pid=TYPE_IPV4)
|
||||
|
32
P4D2_2017_Fall/exercises/basic_tunnel/p4app.json
Normal file
32
P4D2_2017_Fall/exercises/basic_tunnel/p4app.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"program": "basic_tunnel.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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
P4D2_2017_Fall/exercises/basic_tunnel/receive.py
Executable file
43
P4D2_2017_Fall/exercises/basic_tunnel/receive.py
Executable file
@ -0,0 +1,43 @@
|
||||
#!/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
|
||||
from myTunnel_header import MyTunnel
|
||||
|
||||
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
|
||||
|
||||
def handle_pkt(pkt):
|
||||
if MyTunnel in pkt:
|
||||
print "got a packet"
|
||||
pkt.show2()
|
||||
# hexdump(pkt)
|
||||
# print "len(pkt) = ", len(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(iface = iface,
|
||||
prn = lambda x: handle_pkt(x))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
5
P4D2_2017_Fall/exercises/basic_tunnel/run.sh
Executable file
5
P4D2_2017_Fall/exercises/basic_tunnel/run.sh
Executable file
@ -0,0 +1,5 @@
|
||||
P4APPRUNNER=../../utils/p4apprunner.py
|
||||
mkdir -p build
|
||||
tar -czf build/p4app.tgz * --exclude='build'
|
||||
#cd build
|
||||
sudo python $P4APPRUNNER p4app.tgz --build-dir ./build
|
9
P4D2_2017_Fall/exercises/basic_tunnel/s1-commands.txt
Normal file
9
P4D2_2017_Fall/exercises/basic_tunnel/s1-commands.txt
Normal file
@ -0,0 +1,9 @@
|
||||
table_set_default ipv4_lpm drop
|
||||
table_add ipv4_lpm ipv4_forward 10.0.1.1/32 => 00:00:00:00:01:01 1
|
||||
table_add ipv4_lpm ipv4_forward 10.0.2.2/32 => 00:00:00:02:02:00 2
|
||||
table_add ipv4_lpm ipv4_forward 10.0.3.3/32 => 00:00:00:03:03:00 3
|
||||
|
||||
table_set_default myTunnel_exact drop
|
||||
table_add myTunnel_exact myTunnel_forward 1 => 1
|
||||
table_add myTunnel_exact myTunnel_forward 2 => 2
|
||||
table_add myTunnel_exact myTunnel_forward 3 => 3
|
9
P4D2_2017_Fall/exercises/basic_tunnel/s2-commands.txt
Normal file
9
P4D2_2017_Fall/exercises/basic_tunnel/s2-commands.txt
Normal file
@ -0,0 +1,9 @@
|
||||
table_set_default ipv4_lpm drop
|
||||
table_add ipv4_lpm ipv4_forward 10.0.1.1/32 => 00:00:00:01:02:00 2
|
||||
table_add ipv4_lpm ipv4_forward 10.0.2.2/32 => 00:00:00:00:02:02 1
|
||||
table_add ipv4_lpm ipv4_forward 10.0.3.3/32 => 00:00:00:03:03:00 3
|
||||
|
||||
table_set_default myTunnel_exact drop
|
||||
table_add myTunnel_exact myTunnel_forward 1 => 2
|
||||
table_add myTunnel_exact myTunnel_forward 2 => 1
|
||||
table_add myTunnel_exact myTunnel_forward 3 => 3
|
9
P4D2_2017_Fall/exercises/basic_tunnel/s3-commands.txt
Normal file
9
P4D2_2017_Fall/exercises/basic_tunnel/s3-commands.txt
Normal file
@ -0,0 +1,9 @@
|
||||
table_set_default ipv4_lpm drop
|
||||
table_add ipv4_lpm ipv4_forward 10.0.1.1/32 => 00:00:00:01:03:00 2
|
||||
table_add ipv4_lpm ipv4_forward 10.0.2.2/32 => 00:00:00:02:03:00 3
|
||||
table_add ipv4_lpm ipv4_forward 10.0.3.3/32 => 00:00:00:00:03:03 1
|
||||
|
||||
table_set_default myTunnel_exact drop
|
||||
table_add myTunnel_exact myTunnel_forward 1 => 2
|
||||
table_add myTunnel_exact myTunnel_forward 2 => 3
|
||||
table_add myTunnel_exact myTunnel_forward 3 => 1
|
45
P4D2_2017_Fall/exercises/basic_tunnel/send.py
Executable file
45
P4D2_2017_Fall/exercises/basic_tunnel/send.py
Executable file
@ -0,0 +1,45 @@
|
||||
#!/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, hexdump
|
||||
from scapy.all import Packet
|
||||
from scapy.all import Ether, IP, UDP, TCP
|
||||
from myTunnel_header import MyTunnel
|
||||
|
||||
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)<4:
|
||||
print 'pass 2 arguments: <ip_addr> <dst_nid> "<message>"'
|
||||
exit(1)
|
||||
|
||||
addr = socket.gethostbyname(sys.argv[1])
|
||||
dst_id = int(sys.argv[2])
|
||||
iface = get_if()
|
||||
|
||||
print "sending on interface %s to id %s" % (iface, str(dst_id))
|
||||
pkt = Ether(src=get_if_hwaddr(iface), dst='ff:ff:ff:ff:ff:ff')
|
||||
pkt = pkt / MyTunnel(dst_id=dst_id) / IP(dst=addr) / sys.argv[3]
|
||||
pkt.show2()
|
||||
# hexdump(pkt)
|
||||
# print "len(pkt) = ", len(pkt)
|
||||
sendp(pkt, iface=iface, verbose=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
211
P4D2_2017_Fall/exercises/basic_tunnel/solution/basic_tunnel.p4
Normal file
211
P4D2_2017_Fall/exercises/basic_tunnel/solution/basic_tunnel.p4
Normal file
@ -0,0 +1,211 @@
|
||||
/* -*- P4_16 -*- */
|
||||
#include <core.p4>
|
||||
#include <v1model.p4>
|
||||
|
||||
const bit<16> TYPE_MYTUNNEL = 0x1212;
|
||||
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 myTunnel_t {
|
||||
bit<16> proto_id;
|
||||
bit<16> dst_id;
|
||||
}
|
||||
|
||||
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;
|
||||
myTunnel_t myTunnel;
|
||||
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_MYTUNNEL: parse_myTunnel;
|
||||
TYPE_IPV4: parse_ipv4;
|
||||
default: accept;
|
||||
}
|
||||
}
|
||||
|
||||
state parse_myTunnel {
|
||||
packet.extract(hdr.myTunnel);
|
||||
transition select(hdr.myTunnel.proto_id) {
|
||||
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(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 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 = NoAction();
|
||||
}
|
||||
|
||||
action myTunnel_forward(egressSpec_t port) {
|
||||
standard_metadata.egress_spec = port;
|
||||
}
|
||||
|
||||
table myTunnel_exact {
|
||||
key = {
|
||||
hdr.myTunnel.dst_id: exact;
|
||||
}
|
||||
actions = {
|
||||
myTunnel_forward;
|
||||
drop;
|
||||
}
|
||||
size = 1024;
|
||||
default_action = drop();
|
||||
}
|
||||
|
||||
apply {
|
||||
if (hdr.myTunnel.isValid()) {
|
||||
myTunnel_exact.apply();
|
||||
} else 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.myTunnel);
|
||||
packet.emit(hdr.ipv4);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** S W I T C H *******************************
|
||||
*************************************************************************/
|
||||
|
||||
V1Switch(
|
||||
MyParser(),
|
||||
MyVerifyChecksum(),
|
||||
MyIngress(),
|
||||
MyEgress(),
|
||||
MyComputeChecksum(),
|
||||
MyDeparser()
|
||||
) main;
|
Loading…
x
Reference in New Issue
Block a user