diff --git a/SIGCOMM_2015/source_routing/p4src/source_routing.p4 b/SIGCOMM_2015/source_routing/p4src/source_routing.p4 index 04fcd9e..804f831 100644 --- a/SIGCOMM_2015/source_routing/p4src/source_routing.p4 +++ b/SIGCOMM_2015/source_routing/p4src/source_routing.p4 @@ -14,11 +14,24 @@ See the License for the specific language governing permissions and limitations under the License. */ +// TODO: define headers & header instances + parser start { // TODO return ingress; } +// TODO: define parser states + +action _drop() { + drop(); +} + +action route() { + modify_field(standard_metadata.egress_spec, /* TODO: port field from your header */); + // TODO: update your header +} + control ingress { // TODO } diff --git a/SIGCOMM_2016/heavy_hitter/README.md b/SIGCOMM_2016/heavy_hitter/README.md new file mode 100644 index 0000000..e2ab3e5 --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/README.md @@ -0,0 +1,78 @@ +# Implementing Heavy Hitter Dectection + +## Introduction + +The objective of this tutorial is to detect the heavy hitters on the network. +Heavy hitters can simply be defined as the traffic sources who send unusually large traffic. This can be categorized solely by source IP address or can be classified to each application, or application session that sends the traffic. +There are various ways to detect and determine the host of the heavy hitter and we will explore two different methods using P4 in this tutorial. + +First method is to use the counters in P4. Counters allow you to keep a measurement of every table match value that occurs in the data plane. +Thus, for every entry in the table, P4 counter keeps a cell to store the counted value in. + +The main advantage of using a counter is that it is fairly easy to use and it can give an accurate count of the table entry that we want to count. You can simply specify the counter indices of where the table match should be stored and the counting happens automatically. + +However, it comes with disadvantages. Unless we involve the control-plane to add proper entries to the counter table in advance, it is not possible to count for new entries (i.e. unknown flow entries) for the table. Learning a new flow arrival and inserting a matching flow entry through the control plane can be slow. + +Therefore, we propose that the attendees of this tutorial to come up a solution that utilizes P4 registers and hashes to perform flexible heavy hitter detection solely on the data plane. + +The main idea of the solution is to implement counting bloom filter. The idea of the counting bloom filter is to compute multiple hashes of some values and increment the corresponding hash indices of a data structure. In the case of P4, we will use register as the data structure to store the counter values indexed by the hash values. After incrementing the values of the given hash indices, +we can check to see if the new packet belongs to a heavy hitter by looking at the minimum of the values in the multiple indices. The image below shows a general idea of how counting bloom filter looks like. + +![Alt text](images/counting_bloom_filter.png?raw=true "Counting Bloom Filter") + +Given this, we can see that we gain the flexibility of counting on new flows without having to add table entry rules, because the hashes can be computed regardless of the match values. + +This method, however, can suffer from hash collisions when there are too many heavy hitters for the filter to track, falsely increasing the count value computed by the filter. We ignore this issue in our tutorial by creating only small number of connections. + +In this tutorial, we simply react to detected heavy hitters by dropping the packets from the heavy hitters. In real world scenario, there are multitude of possible reactions that you can take on queuing policy, traffic enginnering, etc. + +## Running the starter code + +The starter code named `heavy_hitter.p4` is located under the `p4src` directory. The starter code contains the logic for simple L2 forwarding. In addition to that, it contains the logic to increment the P4 counter when a known flow rule is detected. The flow rule that is installed by the user (or by a control plane) is located in `commands.txt`. It contains the list of CLI commands to set the default table action, as well as actions for a particular match. Please make sure to understand both files before moving on. + +To compile the p4 code under `p4src` and run the switch and the mininet instance, simply run `./run_demo.sh`, which will fire up a mininet instance of 3 hosts (`h1, h2, h3`) and 1 switch (`s1`). +Once the p4 source compiles without error and after all the flow rules has been added, run `xterm h1 h2` on the mininet prompt. It will look something like the below. (If there are any errors at this stage, something is not right. Please let the organizer know as soon as possible.) + +``` +mininet> xterm h1 h2 +``` + +This will bring up two terminals for two hosts. To test the workflow, run `./receive.py` on `h2`'s window first and `./send.py h2` on `h1`'s window. This will send random flows from `h1` to `h2` with varying sizes and ports. (If interested, please refer to `send.py` to see what kinds of packets are being sent.) If the packet transfer is successful, we can see that packet counts are being made in `h2`'s window for each of the 5 tuples (src ip, dst ip, protocol id, src port, dst port). + +After running the flows, run `./read_counter.sh` in another shell to view the counter for each host. Note that this script will also reset all counters. We can see that it records the total number of packets from `h1` to `h2`, but lacks any other information. At this stage, you have successfully completed the example program. +Type `exit' in the mininet terminal to exit. + +## What to do? + +Now, we are going to implement the heavy hitter detection based on the counting bloom filter method. For this, there are two files to modify which are the p4 file and `commands.txt`. + +First let's discuss what to add in the p4 file. Under `p4src` there is a file called `heavy_hitter_template.p4`. Under this file, places to modify are marked by `TODO`. + +The overview of things to complete are as follows. + +1. Define constants for determining heavy hitters. For simplicity, let's define a five tuple who sends 100 or more packets to be the heavy hitter. +2. Update the metadata to contain the hash values and the counter values. +3. Define field_list to compute the hash for the flow. This should basically be the five tuple that we discussed above. +4. Define two separate hashes to generate the hash indices + * You don't have to worry about writing the hash functions. You can simply use csum16 and crc16. Also, refer to how ipv4_checksum is computed to generate the hash value +5. Define registers with enough space to store the counts +6. Define action to compute the hash, read the current value of the register and update the register as packets come in + * Hint: You will have to use these primitives. `modify_field_with_hash_based_offset`, `register_read`, `register_write`, `add_to_field`. You can find more about the primitives at the following [link.](https://github.com/p4lang/p4-hlir/blob/master/p4_hlir/frontend/primitives.json "List of P4 Primitives") + * You can choose to write two separate actions or a single action that updates both hashes. +7. Define tables to run the action(s) as defined above. +8. Define tables to drop the table when you detect the heavy hitter. +9. Modify the control flow to apply one table or the other. + +After completing this, you must change the name of the file to `heavy_hitter.p4` and overwrite it in `p4src` directory. + +Now, we must modify `commands.txt`: remove the CLI commands for count_table and add commands to set the default actions for the new tables. + +After all of this is done. First run `./cleanup` to remove any remnants of the prior run. Then we can again run `./run_demo.sh` to compile the new p4 file, install the new flow rule and open the mininet prompt. + +(Note: Mininet can still be running with errors in compilation or switch initalization. Please see the logs that are generated to see if all of the p4 code has been successfully compiled and/or the switch has been configured with the correct table rules). + +We can then generate random traffic as before using the terminals of the two hosts. One thing to notice now is that the traffic will start dropping after the sender reaches more than 1000 packets per five tuple instances. Also note that the traffic is organized by the five tuples rather than a single host, which makes heavy hitter detection much more fine tuned for some specific application. + +If all of this works well. Congratulations! You have finished this tutorial. + +There are also reference solution in soltion.tar.gz. Feel free to compare your solution to the reference solutions and provie comments and/or updates that can be made to the solution. diff --git a/SIGCOMM_2016/heavy_hitter/cleanup b/SIGCOMM_2016/heavy_hitter/cleanup new file mode 100755 index 0000000..66158df --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/cleanup @@ -0,0 +1,4 @@ +sudo mn -c +sudo killall lt-simple_switch +sudo rm -f *.pcap +sudo rm -f *.json diff --git a/SIGCOMM_2016/heavy_hitter/commands.txt b/SIGCOMM_2016/heavy_hitter/commands.txt new file mode 100644 index 0000000..34b6f22 --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/commands.txt @@ -0,0 +1,16 @@ +table_set_default send_frame _drop +table_set_default forward _drop +table_set_default ipv4_lpm _drop +table_set_default count_table _drop +table_add count_table count_action 10.0.0.1/32 => 0 +table_add count_table count_action 10.0.0.2/32 => 1 +table_add count_table count_action 10.0.0.3/32 => 2 +table_add send_frame rewrite_mac 1 => 00:00:00:00:00:01 +table_add send_frame rewrite_mac 2 => 00:00:00:00:00:02 +table_add send_frame rewrite_mac 3 => 00:00:00:00:00:03 +table_add forward set_dmac 10.0.0.1 => 00:00:00:00:00:01 +table_add forward set_dmac 10.0.0.2 => 00:00:00:00:00:02 +table_add forward set_dmac 10.0.0.3 => 00:00:00:00:00:03 +table_add ipv4_lpm set_nhop 10.0.0.1/32 => 10.0.0.1 1 +table_add ipv4_lpm set_nhop 10.0.0.2/32 => 10.0.0.2 2 +table_add ipv4_lpm set_nhop 10.0.0.3/32 => 10.0.0.3 3 diff --git a/SIGCOMM_2016/heavy_hitter/counter_example/commands.txt b/SIGCOMM_2016/heavy_hitter/counter_example/commands.txt new file mode 100644 index 0000000..34b6f22 --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/counter_example/commands.txt @@ -0,0 +1,16 @@ +table_set_default send_frame _drop +table_set_default forward _drop +table_set_default ipv4_lpm _drop +table_set_default count_table _drop +table_add count_table count_action 10.0.0.1/32 => 0 +table_add count_table count_action 10.0.0.2/32 => 1 +table_add count_table count_action 10.0.0.3/32 => 2 +table_add send_frame rewrite_mac 1 => 00:00:00:00:00:01 +table_add send_frame rewrite_mac 2 => 00:00:00:00:00:02 +table_add send_frame rewrite_mac 3 => 00:00:00:00:00:03 +table_add forward set_dmac 10.0.0.1 => 00:00:00:00:00:01 +table_add forward set_dmac 10.0.0.2 => 00:00:00:00:00:02 +table_add forward set_dmac 10.0.0.3 => 00:00:00:00:00:03 +table_add ipv4_lpm set_nhop 10.0.0.1/32 => 10.0.0.1 1 +table_add ipv4_lpm set_nhop 10.0.0.2/32 => 10.0.0.2 2 +table_add ipv4_lpm set_nhop 10.0.0.3/32 => 10.0.0.3 3 diff --git a/SIGCOMM_2016/heavy_hitter/counter_example/heavy_hitter.p4 b/SIGCOMM_2016/heavy_hitter/counter_example/heavy_hitter.p4 new file mode 100644 index 0000000..eaae17e --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/counter_example/heavy_hitter.p4 @@ -0,0 +1,134 @@ +/* Copyright 2013-present Barefoot Networks, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "includes/headers.p4" +#include "includes/parser.p4" + +field_list ipv4_checksum_list { + ipv4.version; + ipv4.ihl; + ipv4.diffserv; + ipv4.totalLen; + ipv4.identification; + ipv4.flags; + ipv4.fragOffset; + ipv4.ttl; + ipv4.protocol; + ipv4.srcAddr; + ipv4.dstAddr; +} + +field_list_calculation ipv4_checksum { + input { + ipv4_checksum_list; + } + algorithm : csum16; + output_width : 16; +} + +calculated_field ipv4.hdrChecksum { + verify ipv4_checksum; + update ipv4_checksum; +} + +action _drop() { + drop(); +} + +header_type custom_metadata_t { + fields { + nhop_ipv4: 32; + } +} + +metadata custom_metadata_t custom_metadata; + +action set_nhop(nhop_ipv4, port) { + modify_field(custom_metadata.nhop_ipv4, nhop_ipv4); + modify_field(standard_metadata.egress_spec, port); + add_to_field(ipv4.ttl, -1); +} + +action set_dmac(dmac) { + modify_field(ethernet.dstAddr, dmac); +} + +counter ip_src_counter { + type: packets; + static: count_table; + instance_count: 1024; +} + +action count_action(idx) { + count(ip_src_counter, idx); +} + +table count_table { + reads { + ipv4.srcAddr : lpm; + } + actions { + count_action; + _drop; + } + size : 1024; +} + +table ipv4_lpm { + reads { + ipv4.dstAddr : lpm; + } + actions { + set_nhop; + _drop; + } + size: 1024; +} + +table forward { + reads { + custom_metadata.nhop_ipv4 : exact; + } + actions { + set_dmac; + _drop; + } + size: 512; +} + +action rewrite_mac(smac) { + modify_field(ethernet.srcAddr, smac); +} + +table send_frame { + reads { + standard_metadata.egress_port: exact; + } + actions { + rewrite_mac; + _drop; + } + size: 256; +} + +control ingress { + apply(count_table); + apply(ipv4_lpm); + apply(forward); +} + +control egress { + apply(send_frame); +} diff --git a/SIGCOMM_2016/heavy_hitter/images/counting_bloom_filter.png b/SIGCOMM_2016/heavy_hitter/images/counting_bloom_filter.png new file mode 100644 index 0000000..2a47d85 Binary files /dev/null and b/SIGCOMM_2016/heavy_hitter/images/counting_bloom_filter.png differ diff --git a/SIGCOMM_2016/heavy_hitter/p4src/heavy_hitter.p4 b/SIGCOMM_2016/heavy_hitter/p4src/heavy_hitter.p4 new file mode 100644 index 0000000..eaae17e --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/p4src/heavy_hitter.p4 @@ -0,0 +1,134 @@ +/* Copyright 2013-present Barefoot Networks, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "includes/headers.p4" +#include "includes/parser.p4" + +field_list ipv4_checksum_list { + ipv4.version; + ipv4.ihl; + ipv4.diffserv; + ipv4.totalLen; + ipv4.identification; + ipv4.flags; + ipv4.fragOffset; + ipv4.ttl; + ipv4.protocol; + ipv4.srcAddr; + ipv4.dstAddr; +} + +field_list_calculation ipv4_checksum { + input { + ipv4_checksum_list; + } + algorithm : csum16; + output_width : 16; +} + +calculated_field ipv4.hdrChecksum { + verify ipv4_checksum; + update ipv4_checksum; +} + +action _drop() { + drop(); +} + +header_type custom_metadata_t { + fields { + nhop_ipv4: 32; + } +} + +metadata custom_metadata_t custom_metadata; + +action set_nhop(nhop_ipv4, port) { + modify_field(custom_metadata.nhop_ipv4, nhop_ipv4); + modify_field(standard_metadata.egress_spec, port); + add_to_field(ipv4.ttl, -1); +} + +action set_dmac(dmac) { + modify_field(ethernet.dstAddr, dmac); +} + +counter ip_src_counter { + type: packets; + static: count_table; + instance_count: 1024; +} + +action count_action(idx) { + count(ip_src_counter, idx); +} + +table count_table { + reads { + ipv4.srcAddr : lpm; + } + actions { + count_action; + _drop; + } + size : 1024; +} + +table ipv4_lpm { + reads { + ipv4.dstAddr : lpm; + } + actions { + set_nhop; + _drop; + } + size: 1024; +} + +table forward { + reads { + custom_metadata.nhop_ipv4 : exact; + } + actions { + set_dmac; + _drop; + } + size: 512; +} + +action rewrite_mac(smac) { + modify_field(ethernet.srcAddr, smac); +} + +table send_frame { + reads { + standard_metadata.egress_port: exact; + } + actions { + rewrite_mac; + _drop; + } + size: 256; +} + +control ingress { + apply(count_table); + apply(ipv4_lpm); + apply(forward); +} + +control egress { + apply(send_frame); +} diff --git a/SIGCOMM_2016/heavy_hitter/p4src/heavy_hitter_template.p4 b/SIGCOMM_2016/heavy_hitter/p4src/heavy_hitter_template.p4 new file mode 100644 index 0000000..19655e5 --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/p4src/heavy_hitter_template.p4 @@ -0,0 +1,139 @@ +/* Copyright 2013-present Barefoot Networks, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "includes/headers.p4" +#include "includes/parser.p4" + +// TODO: Define the threshold value + +field_list ipv4_checksum_list { + ipv4.version; + ipv4.ihl; + ipv4.diffserv; + ipv4.totalLen; + ipv4.identification; + ipv4.flags; + ipv4.fragOffset; + ipv4.ttl; + ipv4.protocol; + ipv4.srcAddr; + ipv4.dstAddr; +} + +field_list_calculation ipv4_checksum { + input { + ipv4_checksum_list; + } + algorithm : csum16; + output_width : 16; +} + +calculated_field ipv4.hdrChecksum { + verify ipv4_checksum; + update ipv4_checksum; +} + +action _drop() { + drop(); +} + +header_type custom_metadata_t { + fields { + nhop_ipv4: 32; + // TODO: Add the metadata for hash indices and count values + } +} + +metadata custom_metadata_t custom_metadata; + +action set_nhop(nhop_ipv4, port) { + modify_field(custom_metadata.nhop_ipv4, nhop_ipv4); + modify_field(standard_metadata.egress_spec, port); + add_to_field(ipv4.ttl, -1); +} + +action set_dmac(dmac) { + modify_field(ethernet.dstAddr, dmac); +} + +// TODO: Define the field list to compute the hash on +// Use the 5 tuple of +// (src ip, dst ip, src port, dst port, ip protocol) + +// TODO: Define two different hash functions to store the counts +// Note: Please use csum16 and crc16 for the hash functions + +// TODO: Define the registers to store the counts + + +// TODO: Actions to set heavy hitter filter + + +// TODO: Define the tables to run actions + + +// TODO: Define table to drop the heavy hitter traffic + + +table ipv4_lpm { + reads { + ipv4.dstAddr : lpm; + } + actions { + set_nhop; + _drop; + } + size: 1024; +} + +table forward { + reads { + custom_metadata.nhop_ipv4 : exact; + } + actions { + set_dmac; + _drop; + } + size: 512; +} + +action rewrite_mac(smac) { + modify_field(ethernet.srcAddr, smac); +} + +table send_frame { + reads { + standard_metadata.egress_port: exact; + } + actions { + rewrite_mac; + _drop; + } + size: 256; +} + +control ingress { + // TODO: Add table control here + if (// TODO: Add conditional here) { + // TODO: apply table here + } else { + apply(ipv4_lpm); + apply(forward); + } +} + +control egress { + apply(send_frame); +} diff --git a/SIGCOMM_2016/heavy_hitter/p4src/includes/headers.p4 b/SIGCOMM_2016/heavy_hitter/p4src/includes/headers.p4 new file mode 100644 index 0000000..9034367 --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/p4src/includes/headers.p4 @@ -0,0 +1,57 @@ +/* Copyright 2013-present Barefoot Networks, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +header_type ethernet_t { + fields { + dstAddr : 48; + srcAddr : 48; + etherType : 16; + } +} + +header_type ipv4_t { + fields { + version : 4; + ihl : 4; + diffserv : 8; + totalLen : 16; + identification : 16; + flags : 3; + fragOffset : 13; + ttl : 8; + protocol : 8; + hdrChecksum : 16; + srcAddr : 32; + dstAddr: 32; + } +} + +header_type tcp_t { + fields { + srcPort : 16; + dstPort : 16; + seqNo : 32; + ackNo : 32; + dataOffset : 4; + res : 3; + ecn : 3; + ctrl : 6; + window : 16; + checksum : 16; + urgentPtr : 16; + } +} + + diff --git a/SIGCOMM_2016/heavy_hitter/p4src/includes/parser.p4 b/SIGCOMM_2016/heavy_hitter/p4src/includes/parser.p4 new file mode 100644 index 0000000..66d453e --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/p4src/includes/parser.p4 @@ -0,0 +1,49 @@ +/* Copyright 2013-present Barefoot Networks, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +parser start { + return parse_ethernet; +} + +#define ETHERTYPE_IPV4 0x0800 + +header ethernet_t ethernet; + +parser parse_ethernet { + extract(ethernet); + return select(latest.etherType) { + ETHERTYPE_IPV4 : parse_ipv4; + default: ingress; + } +} + +header ipv4_t ipv4; + +#define IP_PROTOCOLS_TCP 6 + +parser parse_ipv4 { + extract(ipv4); + return select(latest.protocol) { + IP_PROTOCOLS_TCP : parse_tcp; + default: ingress; + } +} + +header tcp_t tcp; + +parser parse_tcp { + extract(tcp); + return ingress; +} diff --git a/SIGCOMM_2016/heavy_hitter/read_counters.sh b/SIGCOMM_2016/heavy_hitter/read_counters.sh new file mode 100755 index 0000000..bbce420 --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/read_counters.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# Copyright 2013-present Barefoot Networks, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + +source $THIS_DIR/../../env.sh + +CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI + +echo "displaying counters for h1" +echo "counter_read ip_src_counter 0" | $CLI_PATH heavy_hitter.json 22222 +echo +echo "displaying counters for h2" +echo "counter_read ip_src_counter 1" | $CLI_PATH heavy_hitter.json 22222 +echo +echo "displaying counters for h3" +echo "counter_read ip_src_counter 2" | $CLI_PATH heavy_hitter.json 22222 +echo +echo "resetting counters" +echo "counter_reset ip_src_counter" | $CLI_PATH heavy_hitter.json 22222 +echo + + diff --git a/SIGCOMM_2016/heavy_hitter/receive.py b/SIGCOMM_2016/heavy_hitter/receive.py new file mode 100755 index 0000000..39ef4e9 --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/receive.py @@ -0,0 +1,43 @@ +#!/usr/bin/python + +# Copyright 2013-present Barefoot Networks, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from scapy.all import sniff +from scapy.all import IP, TCP + +VALID_IPS = ("10.0.0.1", "10.0.0.2", "10.0.0.3") +totals = {} + +def handle_pkt(pkt): + if IP in pkt and TCP in pkt: + src_ip = pkt[IP].src + dst_ip = pkt[IP].dst + proto = pkt[IP].proto + sport = pkt[TCP].sport + dport = pkt[TCP].dport + id_tup = (src_ip, dst_ip, proto, sport, dport) + if src_ip in VALID_IPS: + if id_tup not in totals: + totals[id_tup] = 0 + totals[id_tup] += 1 + print ("Received from %s total: %s" % + (id_tup, totals[id_tup])) + +def main(): + sniff(iface = "eth0", + prn = lambda x: handle_pkt(x)) + +if __name__ == '__main__': + main() diff --git a/SIGCOMM_2016/heavy_hitter/run_demo.sh b/SIGCOMM_2016/heavy_hitter/run_demo.sh new file mode 100755 index 0000000..53e0062 --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/run_demo.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# Copyright 2013-present Barefoot Networks, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + +source $THIS_DIR/../../env.sh + +P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py + +SWITCH_PATH=$BMV2_PATH/targets/simple_switch/simple_switch + +CLI_PATH=$BMV2_PATH/tools/runtime_CLI.py + +$P4C_BM_SCRIPT p4src/heavy_hitter.p4 --json heavy_hitter.json +# This gives libtool the opportunity to "warm-up" +sudo $SWITCH_PATH >/dev/null 2>&1 +sudo PYTHONPATH=$PYTHONPATH:$BMV2_PATH/mininet/ python topo.py \ + --behavioral-exe $SWITCH_PATH \ + --json heavy_hitter.json \ + --cli $CLI_PATH diff --git a/SIGCOMM_2016/heavy_hitter/send.py b/SIGCOMM_2016/heavy_hitter/send.py new file mode 100755 index 0000000..5c7f971 --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/send.py @@ -0,0 +1,93 @@ +#!/usr/bin/python + +# Copyright 2013-present Barefoot Networks, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from scapy.all import Ether, IP, sendp, get_if_hwaddr, get_if_list, TCP, Raw +import sys +import random, string + +def randomword(max_length): + length = random.randint(1, max_length) + return ''.join(random.choice(string.lowercase) for i in range(length)) + +def read_topo(): + nb_hosts = 0 + nb_switches = 0 + links = [] + with open("topo.txt", "r") as f: + line = f.readline()[:-1] + w, nb_switches = line.split() + assert(w == "switches") + line = f.readline()[:-1] + w, nb_hosts = line.split() + assert(w == "hosts") + for line in f: + if not f: break + a, b = line.split() + links.append( (a, b) ) + return int(nb_hosts), int(nb_switches), links + +def send_random_traffic(dst): + dst_mac = None + dst_ip = None + src_mac = [get_if_hwaddr(i) for i in get_if_list() if i == 'eth0'] + if len(src_mac) < 1: + print ("No interface for output") + sys.exit(1) + src_mac = src_mac[0] + src_ip = None + if src_mac =="00:00:00:00:00:01": + src_ip = "10.0.0.1" + elif src_mac =="00:00:00:00:00:02": + src_ip = "10.0.0.2" + elif src_mac =="00:00:00:00:00:03": + src_ip = "10.0.0.3" + else: + print ("Invalid source host") + sys.exit(1) + + if dst == 'h1': + dst_mac = "00:00:00:00:00:01" + dst_ip = "10.0.0.1" + elif dst == 'h2': + dst_mac = "00:00:00:00:00:02" + dst_ip = "10.0.0.2" + elif dst == 'h3': + dst_mac = "00:00:00:00:00:03" + dst_ip = "10.0.0.3" + else: + print ("Invalid host to send to") + sys.exit(1) + + total_pkts = 0 + random_ports = random.sample(xrange(1024, 65535), 10) + for port in random_ports: + num_packets = random.randint(50, 250) + for i in range(num_packets): + data = randomword(100) + p = Ether(dst=dst_mac,src=src_mac)/IP(dst=dst_ip,src=src_ip) + p = p/TCP(dport=port)/Raw(load=data) + print p.show() + sendp(p, iface = "eth0") + total_pkts += 1 + print "Sent %s packets in total" % total_pkts + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("Usage: python send.py dst_host_name") + sys.exit(1) + else: + dst_name = sys.argv[1] + send_random_traffic(dst_name) diff --git a/SIGCOMM_2016/heavy_hitter/solution.tar.gz b/SIGCOMM_2016/heavy_hitter/solution.tar.gz new file mode 100644 index 0000000..cd87a8d Binary files /dev/null and b/SIGCOMM_2016/heavy_hitter/solution.tar.gz differ diff --git a/SIGCOMM_2016/heavy_hitter/topo.py b/SIGCOMM_2016/heavy_hitter/topo.py new file mode 100644 index 0000000..1bff8f4 --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/topo.py @@ -0,0 +1,129 @@ +#!/usr/bin/python + +# Copyright 2013-present Barefoot Networks, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from mininet.net import Mininet +from mininet.topo import Topo +from mininet.log import setLogLevel +from mininet.cli import CLI + +from p4_mininet import P4Switch, P4Host + +import argparse +from time import sleep +import os +import subprocess + +_THIS_DIR = os.path.dirname(os.path.realpath(__file__)) +_THRIFT_BASE_PORT = 22222 + +parser = argparse.ArgumentParser(description='Mininet demo') +parser.add_argument('--behavioral-exe', help='Path to behavioral executable', + type=str, action="store", required=True) +parser.add_argument('--json', help='Path to JSON config file', + type=str, action="store", required=True) +parser.add_argument('--cli', help='Path to BM CLI', + type=str, action="store", required=True) + +args = parser.parse_args() + +class MyTopo(Topo): + def __init__(self, sw_path, json_path, nb_hosts, nb_switches, links, **opts): + # Initialize topology and default options + Topo.__init__(self, **opts) + + for i in xrange(nb_switches): + self.addSwitch('s%d' % (i + 1), + sw_path = sw_path, + json_path = json_path, + thrift_port = _THRIFT_BASE_PORT + i, + pcap_dump = True, + device_id = i) + + for h in xrange(nb_hosts): + self.addHost('h%d' % (h + 1), ip="10.0.0.%d" % (h + 1), + mac="00:00:00:00:00:0%d" % (h+1)) + + for a, b in links: + self.addLink(a, b) + +def read_topo(): + nb_hosts = 0 + nb_switches = 0 + links = [] + with open("topo.txt", "r") as f: + line = f.readline()[:-1] + w, nb_switches = line.split() + assert(w == "switches") + line = f.readline()[:-1] + w, nb_hosts = line.split() + assert(w == "hosts") + for line in f: + if not f: break + a, b = line.split() + links.append( (a, b) ) + return int(nb_hosts), int(nb_switches), links + + +def main(): + nb_hosts, nb_switches, links = read_topo() + + topo = MyTopo(args.behavioral_exe, + args.json, + nb_hosts, nb_switches, links) + + net = Mininet(topo = topo, + host = P4Host, + switch = P4Switch, + controller = None ) + net.start() + + for n in xrange(nb_hosts): + h = net.get('h%d' % (n + 1)) + for off in ["rx", "tx", "sg"]: + cmd = "/sbin/ethtool --offload eth0 %s off" % off + print cmd + h.cmd(cmd) + print "disable ipv6" + h.cmd("sysctl -w net.ipv6.conf.all.disable_ipv6=1") + h.cmd("sysctl -w net.ipv6.conf.default.disable_ipv6=1") + h.cmd("sysctl -w net.ipv6.conf.lo.disable_ipv6=1") + h.cmd("sysctl -w net.ipv4.tcp_congestion_control=reno") + h.cmd("iptables -I OUTPUT -p icmp --icmp-type destination-unreachable -j DROP") + + sleep(1) + + for i in xrange(nb_switches): + cmd = [args.cli, "--json", args.json, + "--thrift-port", str(_THRIFT_BASE_PORT + i)] + with open("commands.txt", "r") as f: + print " ".join(cmd) + try: + output = subprocess.check_output(cmd, stdin = f) + print output + except subprocess.CalledProcessError as e: + print e + print e.output + + sleep(1) + + print "Ready !" + + CLI( net ) + net.stop() + +if __name__ == '__main__': + setLogLevel( 'info' ) + main() diff --git a/SIGCOMM_2016/heavy_hitter/topo.txt b/SIGCOMM_2016/heavy_hitter/topo.txt new file mode 100644 index 0000000..42b6aa2 --- /dev/null +++ b/SIGCOMM_2016/heavy_hitter/topo.txt @@ -0,0 +1,5 @@ +switches 1 +hosts 3 +h1 s1 +h2 s1 +h3 s1