diff --git a/README.md b/README.md index f5bb2f7..6502fd5 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/exercises/qos/Makefile b/exercises/qos/Makefile new file mode 100644 index 0000000..23bdc5b --- /dev/null +++ b/exercises/qos/Makefile @@ -0,0 +1,3 @@ +BMV2_SWITCH_EXE = simple_switch_grpc + +include ../../utils/Makefile diff --git a/exercises/qos/README.md b/exercises/qos/README.md new file mode 100644 index 0000000..8b62c7d --- /dev/null +++ b/exercises/qos/README.md @@ -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..`). + * 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. + +![Setup](setup.png) + +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..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/-.pcap` also contains the + pcap of packets on each interface. Use `tcpdump -r -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 +``` diff --git a/exercises/qos/qos.p4 b/exercises/qos/qos.p4 new file mode 100644 index 0000000..f08586a --- /dev/null +++ b/exercises/qos/qos.p4 @@ -0,0 +1,202 @@ +/* -*- P4_16 -*- */ +#include +#include + +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; diff --git a/exercises/qos/receive.py b/exercises/qos/receive.py new file mode 100755 index 0000000..486f0d9 --- /dev/null +++ b/exercises/qos/receive.py @@ -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() diff --git a/exercises/qos/s1-runtime.json b/exercises/qos/s1-runtime.json new file mode 100644 index 0000000..e79c845 --- /dev/null +++ b/exercises/qos/s1-runtime.json @@ -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 + } + } + ] +} diff --git a/exercises/qos/s2-runtime.json b/exercises/qos/s2-runtime.json new file mode 100644 index 0000000..243f1d2 --- /dev/null +++ b/exercises/qos/s2-runtime.json @@ -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 + } + } + ] +} diff --git a/exercises/qos/s3-runtime.json b/exercises/qos/s3-runtime.json new file mode 100644 index 0000000..9e0f7fa --- /dev/null +++ b/exercises/qos/s3-runtime.json @@ -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 + } + } + ] +} diff --git a/exercises/qos/send.py b/exercises/qos/send.py new file mode 100755 index 0000000..9887a3e --- /dev/null +++ b/exercises/qos/send.py @@ -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() diff --git a/exercises/qos/setup.png b/exercises/qos/setup.png new file mode 100644 index 0000000..bf2a66b Binary files /dev/null and b/exercises/qos/setup.png differ diff --git a/exercises/qos/solution/qos.p4 b/exercises/qos/solution/qos.p4 new file mode 100644 index 0000000..01c6aff --- /dev/null +++ b/exercises/qos/solution/qos.p4 @@ -0,0 +1,276 @@ +/* -*- P4_16 -*- */ +#include +#include + +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; diff --git a/exercises/qos/topology.json b/exercises/qos/topology.json new file mode 100644 index 0000000..6d4be03 --- /dev/null +++ b/exercises/qos/topology.json @@ -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"] + ] +}