Added quality of service(QOS) via Differentiated services (#330)
* Added quality of service(QOS) via Differentiated services * Altered to classify network traffic in Ingress * Updated readme for QoS
This commit is contained in:
parent
05174e8a95
commit
971ceb7d90
@ -25,6 +25,7 @@ you get started with P4 programming, organized into several modules:
|
||||
* [Source Routing](./exercises/source_routing)
|
||||
* [Calculator](./exercises/calc)
|
||||
* [Load Balancing](./exercises/load_balance)
|
||||
* [Quality of Service](./exercises/qos)
|
||||
|
||||
5. Stateful Packet Processing
|
||||
* [Firewall](./exercises/firewall)
|
||||
|
3
exercises/qos/Makefile
Normal file
3
exercises/qos/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
BMV2_SWITCH_EXE = simple_switch_grpc
|
||||
|
||||
include ../../utils/Makefile
|
After Width: | Height: | Size: 67 B |
166
exercises/qos/README.md
Normal file
166
exercises/qos/README.md
Normal file
@ -0,0 +1,166 @@
|
||||
# Implementing QOS
|
||||
|
||||
## Introduction
|
||||
|
||||
The objective of this tutorial is to extend basic L3 forwarding with
|
||||
an implementation of Quality of Service (QOS) using Differentiated Services.
|
||||
|
||||
Diffserv is simple and scalable. It classifies and manages network traffic and provides QOS on modern IP networks.
|
||||
|
||||
As before, we have already defined the control plane rules for
|
||||
routing, 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,
|
||||
`qos.p4`, which initially implements L3 forwarding. Your job (in the
|
||||
next step) will be to extend it to properly set the `diffserv` bits.
|
||||
|
||||
Before that, let's compile the incomplete `qos.p4` and bring up a
|
||||
network in Mininet to test its behavior.
|
||||
|
||||
1. In your shell, run:
|
||||
```bash
|
||||
make
|
||||
```
|
||||
This will:
|
||||
* compile `qos.p4`, and
|
||||
* start a Mininet instance with three switches (`s1`, `s2`, `s3`) configured
|
||||
in a triangle. There are 5 hosts. `h1` and `h11` are connected to `s1`.
|
||||
`h2` and `h22` are connected to `s2` and `h3` is connected to `s3`.
|
||||
* The hosts are assigned IPs of `10.0.1.1`, `10.0.2.2`, etc
|
||||
(`10.0.<Switchid>.<hostID>`).
|
||||
* The control plane programs the P4 tables in each switch based on
|
||||
`sx-runtime.json`
|
||||
|
||||
2. We want to send traffic from `h1` to `h2`. If we
|
||||
capture packets at `h2`, we should see the right diffserv value.
|
||||
|
||||

|
||||
|
||||
3. You should now see a Mininet command prompt. Open two terminals
|
||||
for `h1` and `h2`, respectively:
|
||||
```bash
|
||||
mininet> xterm h1 h2
|
||||
```
|
||||
4. In `h2`'s XTerm, start the server that captures packets:
|
||||
```bash
|
||||
./receive.py
|
||||
```
|
||||
5. In `h1`'s XTerm, send one packet per second to `h2` using send.py
|
||||
say for 30 seconds.
|
||||
To send UDP:
|
||||
```bash
|
||||
./send.py --p=UDP --des=10.0.2.2 --m="P4 is cool" --dur=30
|
||||
```
|
||||
To send TCP:
|
||||
```bash
|
||||
./send.py --p=TCP --des=10.0.2.2 --m="P4 is cool" --dur=30
|
||||
```
|
||||
The message "P4 is cool" should be received in `h2`'s xterm,
|
||||
6. At `h2`, the `ipv4.tos` field (DiffServ+ECN) is always 1
|
||||
7. type `exit` to close each XTerm window
|
||||
|
||||
Your job is to extend the code in `qos.p4` to implement the diffserv logic
|
||||
for setting the diffserv flag.
|
||||
|
||||
## Step 2: Implement Diffserv
|
||||
|
||||
The `qos.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.
|
||||
|
||||
First we have to change the ipv4_t header by splitting the TOS field
|
||||
into DiffServ and ECN fields. Remember to update the checksum block
|
||||
accordingly. Then, in the egress control block we must compare the
|
||||
protocol in IP header with IP protocols. Based on the traffic classes
|
||||
and priority, the `diffserv` flag will be set.
|
||||
|
||||
A complete `qos.p4` will contain the following components:
|
||||
|
||||
1. Header type definitions for Ethernet (`ethernet_t`) and IPv4 (`ipv4_t`).
|
||||
2. Parsers for Ethernet, IPv4,
|
||||
3. An action to drop a packet, using `mark_to_drop()`.
|
||||
4. An action (called `ipv4_forward`), which will:
|
||||
1. Set the egress port for the next hop.
|
||||
2. Update the ethernet destination address with the address of
|
||||
the next hop.
|
||||
3. Update the ethernet source address with the address of the switch.
|
||||
4. Decrement the TTL.
|
||||
5. An ingress control block that checks the protocols and sets the ipv4.diffserv.
|
||||
6. A deparser that selects the order in which headers are inserted into the outgoing
|
||||
packet.
|
||||
7. A `package` instantiation supplied with the parser, control,
|
||||
checksum verification and recomputation and deparser.
|
||||
|
||||
## Step 3: Run your solution
|
||||
|
||||
Follow the instructions from Step 1. This time, when your message from
|
||||
`h1` is delivered to `h2`, you should see `tos` values change from 0x1
|
||||
to 0xb9 for UDP and 0xb1 for TCP. It depends upon the action you choose
|
||||
in Ingress processing.
|
||||
|
||||
To easily track the `tos` values you may want to redirect the output
|
||||
of `h2` to a file by running the following for `h2`
|
||||
```bash
|
||||
./receive.py > h2.log
|
||||
```
|
||||
and just print the `tos` values `grep tos h2.log` in a separate window
|
||||
```
|
||||
tos = 0xb9
|
||||
tos = 0xb9
|
||||
tos = 0xb9
|
||||
tos = 0xb9
|
||||
tos = 0xb9
|
||||
tos = 0xb9
|
||||
tos = 0xb9
|
||||
tos = 0xb9
|
||||
tos = 0xb1
|
||||
tos = 0xb1
|
||||
tos = 0xb1
|
||||
tos = 0xb1
|
||||
tos = 0xb1
|
||||
tos = 0xb1
|
||||
tos = 0xb1
|
||||
tos = 0xb1
|
||||
|
||||
```
|
||||
|
||||
### Food for thought
|
||||
|
||||
How can we let the user use other protocols?
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
There are several ways that problems might manifest:
|
||||
|
||||
1. `qos.p4` fails to compile. In this case, `make` will report the
|
||||
error emitted from the compiler and stop.
|
||||
2. `qos.p4` compiles but does not support the control plane rules in
|
||||
the `sX-runtime.json` files that `make` tries to install using
|
||||
a Python controller. In this case, `make` will log the controller output
|
||||
in the `logs` directory. Use these error messages to fix your `qos.p4`
|
||||
implementation.
|
||||
3. `qos.p4` compiles, and the control plane rules are installed, but
|
||||
the switch does not process packets in the desired way. The
|
||||
`/tmp/p4s.<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.
|
||||
The `build/<switch-name>-<interface-name>.pcap` also contains the
|
||||
pcap of packets on each interface. Use `tcpdump -r <filename> -xxx`
|
||||
to print the hexdump of the packets.
|
||||
|
||||
#### Cleaning up Mininet
|
||||
|
||||
In the latter two cases above, `make` may leave a Mininet instance
|
||||
running in the background. Use the following command to clean up
|
||||
these instances:
|
||||
|
||||
```bash
|
||||
make stop
|
||||
```
|
202
exercises/qos/qos.p4
Normal file
202
exercises/qos/qos.p4
Normal file
@ -0,0 +1,202 @@
|
||||
/* -*- P4_16 -*- */
|
||||
#include <core.p4>
|
||||
#include <v1model.p4>
|
||||
|
||||
const bit<16> TYPE_IPV4 = 0x800;
|
||||
|
||||
/* IP protocols */
|
||||
const bit<8> IP_PROTOCOLS_ICMP = 1;
|
||||
const bit<8> IP_PROTOCOLS_IGMP = 2;
|
||||
const bit<8> IP_PROTOCOLS_IPV4 = 4;
|
||||
const bit<8> IP_PROTOCOLS_TCP = 6;
|
||||
const bit<8> IP_PROTOCOLS_UDP = 17;
|
||||
const bit<8> IP_PROTOCOLS_IPV6 = 41;
|
||||
const bit<8> IP_PROTOCOLS_GRE = 47;
|
||||
const bit<8> IP_PROTOCOLS_IPSEC_ESP = 50;
|
||||
const bit<8> IP_PROTOCOLS_IPSEC_AH = 51;
|
||||
const bit<8> IP_PROTOCOLS_ICMPV6 = 58;
|
||||
const bit<8> IP_PROTOCOLS_EIGRP = 88;
|
||||
const bit<8> IP_PROTOCOLS_OSPF = 89;
|
||||
const bit<8> IP_PROTOCOLS_PIM = 103;
|
||||
const bit<8> IP_PROTOCOLS_VRRP = 112;
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*********************** 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: split tos to two fields 6 bit diffserv and 2 bit ecn
|
||||
*/
|
||||
header ipv4_t {
|
||||
bit<4> version;
|
||||
bit<4> ihl;
|
||||
bit<8> tos;
|
||||
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 {
|
||||
}
|
||||
|
||||
struct headers {
|
||||
ethernet_t ethernet;
|
||||
ipv4_t ipv4;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** P A R S E R ***********************************
|
||||
*************************************************************************/
|
||||
|
||||
parser MyParser(packet_in packet,
|
||||
out headers hdr,
|
||||
inout metadata meta,
|
||||
inout standard_metadata_t standard_metadata) {
|
||||
|
||||
state start {
|
||||
transition parse_ethernet;
|
||||
}
|
||||
|
||||
state parse_ethernet {
|
||||
packet.extract(hdr.ethernet);
|
||||
transition select(hdr.ethernet.etherType) {
|
||||
TYPE_IPV4: parse_ipv4;
|
||||
default: accept;
|
||||
}
|
||||
}
|
||||
|
||||
state parse_ipv4 {
|
||||
packet.extract(hdr.ipv4);
|
||||
transition accept;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
************ C H E C K S U M V E R I F I C A T I O N *************
|
||||
*************************************************************************/
|
||||
|
||||
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
|
||||
apply { }
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
************** I N G R E S S P R O C E S S I N G *******************
|
||||
*************************************************************************/
|
||||
|
||||
control MyIngress(inout headers hdr,
|
||||
inout metadata meta,
|
||||
inout standard_metadata_t standard_metadata) {
|
||||
action drop() {
|
||||
mark_to_drop(standard_metadata);
|
||||
}
|
||||
|
||||
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
|
||||
standard_metadata.egress_spec = port;
|
||||
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
|
||||
hdr.ethernet.dstAddr = dstAddr;
|
||||
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
|
||||
}
|
||||
|
||||
/* TODO: Implement actions for different traffic classes */
|
||||
|
||||
|
||||
table ipv4_lpm {
|
||||
key = {
|
||||
hdr.ipv4.dstAddr: lpm;
|
||||
}
|
||||
actions = {
|
||||
ipv4_forward;
|
||||
drop;
|
||||
NoAction;
|
||||
}
|
||||
size = 1024;
|
||||
default_action = NoAction();
|
||||
}
|
||||
|
||||
/* TODO: set hdr.ipv4.diffserv on the basis of protocol */
|
||||
apply {
|
||||
if (hdr.ipv4.isValid()) {
|
||||
ipv4_lpm.apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
**************** E G R E S S P R O C E S S I N G *******************
|
||||
*************************************************************************/
|
||||
|
||||
control MyEgress(inout headers hdr,
|
||||
inout metadata meta,
|
||||
inout standard_metadata_t standard_metadata) {
|
||||
apply { }
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
************* C H E C K S U M C O M P U T A T I O N **************
|
||||
*************************************************************************/
|
||||
|
||||
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
|
||||
apply {
|
||||
/* TODO: replace tos with diffserv and ecn */
|
||||
update_checksum(
|
||||
hdr.ipv4.isValid(),
|
||||
{ hdr.ipv4.version,
|
||||
hdr.ipv4.ihl,
|
||||
hdr.ipv4.tos,
|
||||
hdr.ipv4.totalLen,
|
||||
hdr.ipv4.identification,
|
||||
hdr.ipv4.flags,
|
||||
hdr.ipv4.fragOffset,
|
||||
hdr.ipv4.ttl,
|
||||
hdr.ipv4.protocol,
|
||||
hdr.ipv4.srcAddr,
|
||||
hdr.ipv4.dstAddr },
|
||||
hdr.ipv4.hdrChecksum,
|
||||
HashAlgorithm.csum16);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** D E P A R S E R *******************************
|
||||
*************************************************************************/
|
||||
|
||||
control MyDeparser(packet_out packet, in headers hdr) {
|
||||
apply {
|
||||
packet.emit(hdr.ethernet);
|
||||
packet.emit(hdr.ipv4);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** S W I T C H *******************************
|
||||
*************************************************************************/
|
||||
|
||||
V1Switch(
|
||||
MyParser(),
|
||||
MyVerifyChecksum(),
|
||||
MyIngress(),
|
||||
MyEgress(),
|
||||
MyComputeChecksum(),
|
||||
MyDeparser()
|
||||
) main;
|
21
exercises/qos/receive.py
Executable file
21
exercises/qos/receive.py
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
from scapy.all import sniff, get_if_list
|
||||
|
||||
|
||||
def handle_pkt(pkt):
|
||||
print "got a packet"
|
||||
pkt.show2()
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def main():
|
||||
iface = 'eth0'
|
||||
print "sniffing on %s" % iface
|
||||
sys.stdout.flush()
|
||||
sniff(iface=iface, prn=lambda x: handle_pkt(x))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
52
exercises/qos/s1-runtime.json
Normal file
52
exercises/qos/s1-runtime.json
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"target": "bmv2",
|
||||
"p4info": "build/qos.p4.p4info.txt",
|
||||
"bmv2_json": "build/qos.json",
|
||||
"table_entries": [
|
||||
{
|
||||
"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:01",
|
||||
"port": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.1.11", 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.0", 24]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:02:00",
|
||||
"port": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.3.0", 24]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:03:00",
|
||||
"port": 4
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
51
exercises/qos/s2-runtime.json
Normal file
51
exercises/qos/s2-runtime.json
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"target": "bmv2",
|
||||
"p4info": "build/qos.p4.p4info.txt",
|
||||
"bmv2_json": "build/qos.json",
|
||||
"table_entries": [
|
||||
{
|
||||
"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:02",
|
||||
"port": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.2.22", 32]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:02:22",
|
||||
"port": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.1.0", 24]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:01:00",
|
||||
"port": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.3.0", 24]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:03:00",
|
||||
"port": 4
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
40
exercises/qos/s3-runtime.json
Normal file
40
exercises/qos/s3-runtime.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"target": "bmv2",
|
||||
"p4info": "build/qos.p4.p4info.txt",
|
||||
"bmv2_json": "build/qos.json",
|
||||
"table_entries": [
|
||||
{
|
||||
"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:03",
|
||||
"port": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"table": "MyIngress.ipv4_lpm",
|
||||
"match": {
|
||||
"hdr.ipv4.dstAddr": ["10.0.1.0", 24]
|
||||
},
|
||||
"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.0", 24]
|
||||
},
|
||||
"action_name": "MyIngress.ipv4_forward",
|
||||
"action_params": {
|
||||
"dstAddr": "08:00:00:00:02:00",
|
||||
"port": 3
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
56
exercises/qos/send.py
Executable file
56
exercises/qos/send.py
Executable file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
import socket
|
||||
|
||||
from scapy.all import sendp, send, hexdump, get_if_list, get_if_hwaddr
|
||||
from scapy.all import Ether, IP, UDP, TCP
|
||||
|
||||
from time import sleep
|
||||
|
||||
|
||||
def get_if():
|
||||
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 main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--p", help="Protocol name To send TCP/UDP etc packets", type=str)
|
||||
parser.add_argument("--des", help="IP address of the destination", type=str)
|
||||
parser.add_argument("--m", help="Raw Message", type=str)
|
||||
parser.add_argument("--dur", help="in seconds", type=str)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.p and args.des and args.m and args.dur:
|
||||
addr = socket.gethostbyname(args.des)
|
||||
iface = get_if()
|
||||
if args.p == 'UDP':
|
||||
pkt = Ether(src=get_if_hwaddr(iface), dst="ff:ff:ff:ff:ff:ff") / IP(dst=addr, tos=1) / UDP(dport=4321, sport=1234) / args.m
|
||||
pkt.show2()
|
||||
try:
|
||||
for i in range(int(args.dur)):
|
||||
sendp(pkt, iface=iface)
|
||||
sleep(1)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
elif args.p == 'TCP':
|
||||
pkt = Ether(src=get_if_hwaddr(iface), dst="ff:ff:ff:ff:ff:ff") / IP(dst=addr, tos=1) / TCP() / args.m
|
||||
pkt.show2()
|
||||
try:
|
||||
for i in range(int(args.dur)):
|
||||
sendp(pkt, iface=iface)
|
||||
sleep(1)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
BIN
exercises/qos/setup.png
Normal file
BIN
exercises/qos/setup.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 101 KiB |
276
exercises/qos/solution/qos.p4
Normal file
276
exercises/qos/solution/qos.p4
Normal file
@ -0,0 +1,276 @@
|
||||
/* -*- P4_16 -*- */
|
||||
#include <core.p4>
|
||||
#include <v1model.p4>
|
||||
|
||||
const bit<16> TYPE_IPV4 = 0x800;
|
||||
|
||||
/* IP protocols */
|
||||
const bit<8> IP_PROTOCOLS_ICMP = 1;
|
||||
const bit<8> IP_PROTOCOLS_IGMP = 2;
|
||||
const bit<8> IP_PROTOCOLS_IPV4 = 4;
|
||||
const bit<8> IP_PROTOCOLS_TCP = 6;
|
||||
const bit<8> IP_PROTOCOLS_UDP = 17;
|
||||
const bit<8> IP_PROTOCOLS_IPV6 = 41;
|
||||
const bit<8> IP_PROTOCOLS_GRE = 47;
|
||||
const bit<8> IP_PROTOCOLS_IPSEC_ESP = 50;
|
||||
const bit<8> IP_PROTOCOLS_IPSEC_AH = 51;
|
||||
const bit<8> IP_PROTOCOLS_ICMPV6 = 58;
|
||||
const bit<8> IP_PROTOCOLS_EIGRP = 88;
|
||||
const bit<8> IP_PROTOCOLS_OSPF = 89;
|
||||
const bit<8> IP_PROTOCOLS_PIM = 103;
|
||||
const bit<8> IP_PROTOCOLS_VRRP = 112;
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*********************** H E A D E R S ***********************************
|
||||
*************************************************************************/
|
||||
|
||||
typedef bit<9> egressSpec_t;
|
||||
typedef bit<48> macAddr_t;
|
||||
typedef bit<32> ip4Addr_t;
|
||||
|
||||
header ethernet_t {
|
||||
macAddr_t dstAddr;
|
||||
macAddr_t srcAddr;
|
||||
bit<16> etherType;
|
||||
}
|
||||
|
||||
header ipv4_t {
|
||||
bit<4> version;
|
||||
bit<4> ihl;
|
||||
bit<6> diffserv;
|
||||
bit<2> ecn;
|
||||
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 {
|
||||
}
|
||||
|
||||
struct headers {
|
||||
ethernet_t ethernet;
|
||||
ipv4_t ipv4;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** P A R S E R ***********************************
|
||||
*************************************************************************/
|
||||
|
||||
parser MyParser(packet_in packet,
|
||||
out headers hdr,
|
||||
inout metadata meta,
|
||||
inout standard_metadata_t standard_metadata) {
|
||||
|
||||
state start {
|
||||
transition parse_ethernet;
|
||||
}
|
||||
|
||||
state parse_ethernet {
|
||||
packet.extract(hdr.ethernet);
|
||||
transition select(hdr.ethernet.etherType) {
|
||||
TYPE_IPV4: parse_ipv4;
|
||||
default: accept;
|
||||
}
|
||||
}
|
||||
|
||||
state parse_ipv4 {
|
||||
packet.extract(hdr.ipv4);
|
||||
transition accept;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
************ C H E C K S U M V E R I F I C A T I O N *************
|
||||
*************************************************************************/
|
||||
|
||||
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
|
||||
apply { }
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
************** I N G R E S S P R O C E S S I N G *******************
|
||||
*************************************************************************/
|
||||
|
||||
control MyIngress(inout headers hdr,
|
||||
inout metadata meta,
|
||||
inout standard_metadata_t standard_metadata) {
|
||||
action drop() {
|
||||
mark_to_drop(standard_metadata);
|
||||
}
|
||||
|
||||
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
|
||||
standard_metadata.egress_spec = port;
|
||||
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
|
||||
hdr.ethernet.dstAddr = dstAddr;
|
||||
hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
|
||||
}
|
||||
|
||||
/* Default Forwarding */
|
||||
action default_forwarding() {
|
||||
hdr.ipv4.diffserv = 0;
|
||||
}
|
||||
|
||||
/* Expedited Forwarding */
|
||||
action expedited_forwarding() {
|
||||
hdr.ipv4.diffserv = 46;
|
||||
}
|
||||
|
||||
/* Voice Admit */
|
||||
action voice_admit() {
|
||||
hdr.ipv4.diffserv = 44;
|
||||
}
|
||||
|
||||
/* Assured Forwarding */
|
||||
/* Class 1 Low drop probability */
|
||||
action af_11() {
|
||||
hdr.ipv4.diffserv = 10;
|
||||
}
|
||||
|
||||
/* Class 1 Med drop probability */
|
||||
action af_12() {
|
||||
hdr.ipv4.diffserv = 12;
|
||||
}
|
||||
|
||||
/* Class 1 High drop probability */
|
||||
action af_13() {
|
||||
hdr.ipv4.diffserv = 14;
|
||||
}
|
||||
|
||||
/* Class 2 Low drop probability */
|
||||
action af_21() {
|
||||
hdr.ipv4.diffserv = 18;
|
||||
}
|
||||
|
||||
/* Class 2 Med drop probability */
|
||||
action af_22() {
|
||||
hdr.ipv4.diffserv = 20;
|
||||
}
|
||||
|
||||
/* Class 2 High drop probability */
|
||||
action af_23() {
|
||||
hdr.ipv4.diffserv = 22;
|
||||
}
|
||||
|
||||
/* Class 3 Low drop probability */
|
||||
action af_31() {
|
||||
hdr.ipv4.diffserv = 26;
|
||||
}
|
||||
|
||||
/* Class 3 Med drop probability */
|
||||
action af_32() {
|
||||
hdr.ipv4.diffserv = 28;
|
||||
}
|
||||
|
||||
/* Class 3 High drop probability */
|
||||
action af_33() {
|
||||
hdr.ipv4.diffserv = 30;
|
||||
}
|
||||
|
||||
/* Class 4 Low drop probability */
|
||||
action af_41() {
|
||||
hdr.ipv4.diffserv = 34;
|
||||
}
|
||||
|
||||
/* Class 4 Med drop probability */
|
||||
action af_42() {
|
||||
hdr.ipv4.diffserv = 36;
|
||||
}
|
||||
|
||||
/* Class 4 High drop probability */
|
||||
action af_43() {
|
||||
hdr.ipv4.diffserv = 38;
|
||||
}
|
||||
|
||||
table ipv4_lpm {
|
||||
key = {
|
||||
hdr.ipv4.dstAddr: lpm;
|
||||
}
|
||||
actions = {
|
||||
ipv4_forward;
|
||||
drop;
|
||||
NoAction;
|
||||
}
|
||||
size = 1024;
|
||||
default_action = NoAction();
|
||||
}
|
||||
|
||||
apply {
|
||||
if (hdr.ipv4.isValid()) {
|
||||
if (hdr.ipv4.protocol == IP_PROTOCOLS_UDP) {
|
||||
expedited_forwarding();
|
||||
}
|
||||
else if (hdr.ipv4.protocol == IP_PROTOCOLS_TCP) {
|
||||
voice_admit();
|
||||
}
|
||||
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.ecn,
|
||||
hdr.ipv4.totalLen,
|
||||
hdr.ipv4.identification,
|
||||
hdr.ipv4.flags,
|
||||
hdr.ipv4.fragOffset,
|
||||
hdr.ipv4.ttl,
|
||||
hdr.ipv4.protocol,
|
||||
hdr.ipv4.srcAddr,
|
||||
hdr.ipv4.dstAddr },
|
||||
hdr.ipv4.hdrChecksum,
|
||||
HashAlgorithm.csum16);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** D E P A R S E R *******************************
|
||||
*************************************************************************/
|
||||
|
||||
control MyDeparser(packet_out packet, in headers hdr) {
|
||||
apply {
|
||||
packet.emit(hdr.ethernet);
|
||||
packet.emit(hdr.ipv4);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*********************** S W I T C H *******************************
|
||||
*************************************************************************/
|
||||
|
||||
V1Switch(
|
||||
MyParser(),
|
||||
MyVerifyChecksum(),
|
||||
MyIngress(),
|
||||
MyEgress(),
|
||||
MyComputeChecksum(),
|
||||
MyDeparser()
|
||||
) main;
|
28
exercises/qos/topology.json
Normal file
28
exercises/qos/topology.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"hosts": {
|
||||
"h1": {"ip": "10.0.1.1/31", "mac": "08:00:00:00:01:01",
|
||||
"commands":["route add default gw 10.0.1.0 dev eth0",
|
||||
"arp -i eth0 -s 10.0.1.0 08:00:00:00:01:00"]},
|
||||
"h11": {"ip": "10.0.1.11/31", "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/31", "mac": "08:00:00:00:02:02",
|
||||
"commands":["route add default gw 10.0.2.3 dev eth0",
|
||||
"arp -i eth0 -s 10.0.2.3 08:00:00:00:02:00"]},
|
||||
"h22": {"ip": "10.0.2.22/31", "mac": "08:00:00:00:02:22",
|
||||
"commands":["route add default gw 10.0.2.23 dev eth0",
|
||||
"arp -i eth0 -s 10.0.2.23 08:00:00:00:02:00"]},
|
||||
"h3": {"ip": "10.0.3.3/31", "mac": "08:00:00:00:03:03",
|
||||
"commands":["route add default gw 10.0.3.2 dev eth0",
|
||||
"arp -i eth0 -s 10.0.3.2 08:00:00:00:03:00"]}
|
||||
},
|
||||
"switches": {
|
||||
"s1": { "runtime_json" : "s1-runtime.json" },
|
||||
"s2": { "runtime_json" : "s2-runtime.json" },
|
||||
"s3": { "runtime_json" : "s3-runtime.json" }
|
||||
},
|
||||
"links": [
|
||||
["h1", "s1-p2"], ["h11", "s1-p1"], ["s1-p3", "s2-p3"], ["s1-p4", "s3-p2"],
|
||||
["s3-p3", "s2-p4"], ["h2", "s2-p2"], ["h22", "s2-p1"], ["h3", "s3-p1"]
|
||||
]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user