Add Heavy Hitter to examples master (#10)

Add Heavy Hitter to SIGCOMM 2016 in master
This commit is contained in:
Sean Choi 2016-08-29 17:57:36 -07:00 committed by Antonin Bas
parent b3c8eb35c3
commit 6efda9ba22
18 changed files with 979 additions and 0 deletions

View File

@ -14,11 +14,24 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
// TODO: define headers & header instances
parser start { parser start {
// TODO // TODO
return ingress; 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 { control ingress {
// TODO // TODO
} }

View File

@ -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.

View File

@ -0,0 +1,4 @@
sudo mn -c
sudo killall lt-simple_switch
sudo rm -f *.pcap
sudo rm -f *.json

View File

@ -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

View File

@ -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

View File

@ -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);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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)

Binary file not shown.

View File

@ -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()

View File

@ -0,0 +1,5 @@
switches 1
hosts 3
h1 s1
h2 s1
h3 s1