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