added ECMP exercise for May 2016 P4 workshop
This commit is contained in:
parent
f9ccd265f3
commit
547fc0a75f
2
SIGCOMM_2015/.gitignore → .gitignore
vendored
2
SIGCOMM_2015/.gitignore → .gitignore
vendored
@ -10,4 +10,4 @@
|
||||
*.pcap
|
||||
|
||||
# Extracted solutions
|
||||
solution/
|
||||
solution*/
|
@ -80,9 +80,9 @@ like this:
|
||||
|
||||
You need to tell us where you cloned the `bmv2` and `p4c-bm` repositories
|
||||
:). Please update the values of the shell variables `BMV2_PATH` and
|
||||
`P4C_BM_PATH` in the `env.sh` file - located in this directory. Note that if you
|
||||
cloned both repositories in the same directory as this one (`tutorials`), you
|
||||
will not need to change the value of the variables.
|
||||
`P4C_BM_PATH` in the `env.sh` file - located in the root directory of this
|
||||
repository. Note that if you cloned both repositories in the same directory as
|
||||
this one (`tutorials`), you will not need to change the value of the variables.
|
||||
|
||||
That's all :)
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py
|
||||
|
||||
@ -30,8 +30,9 @@ CLI_PATH=$BMV2_PATH/tools/runtime_CLI.py
|
||||
# process back in the foreground
|
||||
set -m
|
||||
$P4C_BM_SCRIPT p4src/simple_router.p4 --json simple_router.json
|
||||
sudo echo "sudo" > /dev/null
|
||||
sudo $BMV2_PATH/targets/simple_switch/simple_switch simple_router.json \
|
||||
# This gets root permissions, and gives libtool the opportunity to "warm-up"
|
||||
sudo $SWITCH_PATH >/dev/null 2>&1
|
||||
sudo $SWITCH_PATH simple_router.json \
|
||||
-i 0@veth0 -i 1@veth2 -i 2@veth4 -i 3@veth6 -i 4@veth8 \
|
||||
--nanolog ipc:///tmp/bm-0-log.ipc \
|
||||
--pcap &
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py
|
||||
|
||||
@ -25,7 +25,9 @@ SWITCH_PATH=$BMV2_PATH/targets/simple_switch/simple_switch
|
||||
CLI_PATH=$BMV2_PATH/tools/runtime_CLI.py
|
||||
|
||||
$P4C_BM_SCRIPT p4src/source_routing.p4 --json source_routing.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 $BMV2_PATH/targets/simple_switch/simple_switch \
|
||||
--behavioral-exe $SWITCH_PATH \
|
||||
--json source_routing.json \
|
||||
--cli $CLI_PATH
|
||||
|
@ -1,8 +1,8 @@
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
# ---------------- EDIT THIS ------------------
|
||||
BMV2_PATH=$THIS_DIR/../../bmv2
|
||||
BMV2_PATH=$THIS_DIR/../bmv2
|
||||
# e.g. BMV2_PATH=$THIS_DIR/../bmv2
|
||||
P4C_BM_PATH=$THIS_DIR/../../p4c-bmv2
|
||||
P4C_BM_PATH=$THIS_DIR/../p4c-bmv2
|
||||
# e.g P4C_BM_PATH=$THIS_DIR/../p4c-bm
|
||||
# ---------------- END ------------------
|
10
examples/.gitignore
vendored
10
examples/.gitignore
vendored
@ -1,10 +0,0 @@
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Emacs
|
||||
*~
|
||||
|
||||
# Compiled JSON
|
||||
*.json
|
||||
|
||||
*.pcap
|
@ -55,9 +55,9 @@ build the code once all the dependencies have been installed:
|
||||
|
||||
You need to tell us where you cloned the `bmv2` and `p4c-bm` repositories
|
||||
:). Please update the values of the shell variables `BMV2_PATH` and
|
||||
`P4C_BM_PATH` in the `env.sh` file - located in this directory. Note that if you
|
||||
cloned both repositories in the same directory as this one (`tutorials`), you
|
||||
will not need to change the value of the variables.
|
||||
`P4C_BM_PATH` in the `env.sh` file - located in the root directory of this
|
||||
repository. Note that if you cloned both repositories in the same directory as
|
||||
this one (`tutorials`), you will not need to change the value of the variables.
|
||||
|
||||
You will also need to run the `veth_setup.sh` script included in this directory
|
||||
as `sudo` to setup the veth interfaces needed by the switch.
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py
|
||||
|
||||
@ -30,8 +30,9 @@ CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI
|
||||
# process back in the foreground
|
||||
set -m
|
||||
$P4C_BM_SCRIPT p4src/TLV_parsing.p4 --json TLV_parsing.json
|
||||
sudo echo "sudo" > /dev/null
|
||||
sudo $BMV2_PATH/targets/simple_switch/simple_switch TLV_parsing.json \
|
||||
# This gets root permissions, and gives libtool the opportunity to "warm-up"
|
||||
sudo $SWITCH_PATH >/dev/null 2>&1
|
||||
sudo $SWITCH_PATH TLV_parsing.json \
|
||||
-i 0@veth0 -i 1@veth2 -i 2@veth4 -i 3@veth6 -i 4@veth8 \
|
||||
--nanolog ipc:///tmp/bm-0-log.ipc \
|
||||
--pcap &
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py
|
||||
|
||||
@ -30,8 +30,9 @@ CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI
|
||||
# process back in the foreground
|
||||
set -m
|
||||
$P4C_BM_SCRIPT p4src/action_profile.p4 --json action_profile.json
|
||||
sudo echo "sudo" > /dev/null
|
||||
sudo $BMV2_PATH/targets/simple_switch/simple_switch action_profile.json \
|
||||
# This gets root permissions, and gives libtool the opportunity to "warm-up"
|
||||
sudo $SWITCH_PATH >/dev/null 2>&1
|
||||
sudo $SWITCH_PATH action_profile.json \
|
||||
-i 0@veth0 -i 1@veth2 -i 2@veth4 -i 3@veth6 -i 4@veth8 \
|
||||
--nanolog ipc:///tmp/bm-0-log.ipc \
|
||||
--pcap &
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py
|
||||
|
||||
@ -25,7 +25,9 @@ SWITCH_PATH=$BMV2_PATH/targets/simple_switch/simple_switch
|
||||
CLI_PATH=$BMV2_PATH/tools/runtime_CLI.py
|
||||
|
||||
$P4C_BM_SCRIPT p4src/axon.p4 --json axon.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 $BMV2_PATH/targets/simple_switch/simple_switch \
|
||||
--behavioral-exe $SWITCH_PATH \
|
||||
--json axon.json \
|
||||
--cli $CLI_PATH
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py
|
||||
|
||||
@ -30,8 +30,9 @@ CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI
|
||||
# process back in the foreground
|
||||
set -m
|
||||
$P4C_BM_SCRIPT p4src/copy_to_cpu.p4 --json copy_to_cpu.json
|
||||
sudo echo "sudo" > /dev/null
|
||||
sudo $BMV2_PATH/targets/simple_switch/simple_switch copy_to_cpu.json \
|
||||
# This gets root permissions, and gives libtool the opportunity to "warm-up"
|
||||
sudo $SWITCH_PATH >/dev/null 2>&1
|
||||
sudo $SWITCH_PATH copy_to_cpu.json \
|
||||
-i 0@veth0 -i 1@veth2 -i 2@veth4 -i 3@veth6 -i 4@veth8 \
|
||||
--nanolog ipc:///tmp/bm-0-log.ipc \
|
||||
--pcap &
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py
|
||||
|
||||
@ -30,8 +30,9 @@ CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI
|
||||
# process back in the foreground
|
||||
set -m
|
||||
$P4C_BM_SCRIPT p4src/counter.p4 --json counter.json
|
||||
sudo echo "sudo" > /dev/null
|
||||
sudo $BMV2_PATH/targets/simple_switch/simple_switch counter.json \
|
||||
# This gets root permissions, and gives libtool the opportunity to "warm-up"
|
||||
sudo $SWITCH_PATH >/dev/null 2>&1
|
||||
sudo $SWITCH_PATH counter.json \
|
||||
-i 0@veth0 -i 1@veth2 -i 2@veth4 -i 3@veth6 -i 4@veth8 \
|
||||
--nanolog ipc:///tmp/bm-0-log.ipc \
|
||||
--pcap &
|
||||
|
@ -1,8 +0,0 @@
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
# ---------------- EDIT THIS ------------------
|
||||
BMV2_PATH=$THIS_DIR/../../bmv2
|
||||
# e.g. BMV2_PATH=$THIS_DIR/../bmv2
|
||||
P4C_BM_PATH=$THIS_DIR/../../p4c-bmv2
|
||||
# e.g P4C_BM_PATH=$THIS_DIR/../p4c-bm
|
||||
# ---------------- END ------------------
|
@ -16,7 +16,7 @@
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py
|
||||
|
||||
@ -30,8 +30,9 @@ CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI
|
||||
# process back in the foreground
|
||||
set -m
|
||||
$P4C_BM_SCRIPT p4src/meter.p4 --json meter.json
|
||||
sudo echo "sudo" > /dev/null
|
||||
sudo $BMV2_PATH/targets/simple_switch/simple_switch meter.json \
|
||||
# This gets root permissions, and gives libtool the opportunity to "warm-up"
|
||||
sudo $SWITCH_PATH >/dev/null 2>&1
|
||||
sudo $SWITCH_PATH meter.json \
|
||||
-i 0@veth0 -i 1@veth2 -i 2@veth4 -i 3@veth6 -i 4@veth8 \
|
||||
--nanolog ipc:///tmp/bm-0-log.ipc \
|
||||
--pcap &
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py
|
||||
|
||||
@ -30,8 +30,9 @@ CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI
|
||||
# process back in the foreground
|
||||
set -m
|
||||
$P4C_BM_SCRIPT p4src/register.p4 --json register.json
|
||||
sudo echo "sudo" > /dev/null
|
||||
sudo $BMV2_PATH/targets/simple_switch/simple_switch register.json \
|
||||
# This gets root permissions, and gives libtool the opportunity to "warm-up"
|
||||
sudo $SWITCH_PATH >/dev/null 2>&1
|
||||
sudo $SWITCH_PATH register.json \
|
||||
-i 0@veth0 -i 1@veth2 -i 2@veth4 -i 3@veth6 -i 4@veth8 \
|
||||
--nanolog ipc:///tmp/bm-0-log.ipc \
|
||||
--pcap
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py
|
||||
|
||||
@ -30,8 +30,9 @@ CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI
|
||||
# process back in the foreground
|
||||
set -m
|
||||
$P4C_BM_SCRIPT p4src/resubmit.p4 --json resubmit.json
|
||||
sudo echo "sudo" > /dev/null
|
||||
sudo $BMV2_PATH/targets/simple_switch/simple_switch resubmit.json \
|
||||
# This gets root permissions, and gives libtool the opportunity to "warm-up"
|
||||
sudo $SWITCH_PATH >/dev/null 2>&1
|
||||
sudo $SWITCH_PATH resubmit.json \
|
||||
-i 0@veth0 -i 1@veth2 -i 2@veth4 -i 3@veth6 -i 4@veth8 \
|
||||
--nanolog ipc:///tmp/bm-0-log.ipc --log-console \
|
||||
--pcap &
|
||||
|
@ -21,7 +21,7 @@ fi
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py
|
||||
|
||||
@ -46,8 +46,10 @@ sysctl net.ipv6.conf.$intf0.disable_ipv6=1
|
||||
sysctl net.ipv6.conf.$intf1.disable_ipv6=1
|
||||
|
||||
$P4C_BM_SCRIPT p4src/simple_nat.p4 --json simple_nat.json
|
||||
# This gives libtool the opportunity to "warm-up"
|
||||
$SWITCH_PATH >/dev/null 2>&1
|
||||
PYTHONPATH=$PYTHONPATH:$BMV2_PATH/mininet/ python topo.py \
|
||||
--behavioral-exe $BMV2_PATH/targets/simple_switch/simple_switch \
|
||||
--behavioral-exe $SWITCH_PATH \
|
||||
--json simple_nat.json \
|
||||
--cli $CLI_PATH \
|
||||
--thrift-port 22222
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source $THIS_DIR/../env.sh
|
||||
source $THIS_DIR/../../env.sh
|
||||
|
||||
CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI
|
||||
|
||||
|
6
workshop_05_2016/ecmp/.starter_code/commands.txt
Normal file
6
workshop_05_2016/ecmp/.starter_code/commands.txt
Normal file
@ -0,0 +1,6 @@
|
||||
table_set_default send_frame _drop
|
||||
table_set_default forward _drop
|
||||
table_set_default ipv4_lpm _drop
|
||||
table_add send_frame rewrite_mac 1 => 00:aa:bb:00:00:00
|
||||
table_add forward set_dmac 10.0.1.1 => 00:04:00:00:00:00
|
||||
table_add ipv4_lpm set_nhop 10.0.0.1/32 => 10.0.1.1 1
|
190
workshop_05_2016/ecmp/.starter_code/p4src/simple_router.p4
Normal file
190
workshop_05_2016/ecmp/.starter_code/p4src/simple_router.p4
Normal file
@ -0,0 +1,190 @@
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
action _drop() {
|
||||
drop();
|
||||
}
|
||||
|
||||
header_type routing_metadata_t {
|
||||
fields {
|
||||
nhop_ipv4 : 32;
|
||||
// TODO: if you need extra metadata for ECMP, define it here
|
||||
}
|
||||
}
|
||||
|
||||
metadata routing_metadata_t routing_metadata;
|
||||
|
||||
action set_nhop(nhop_ipv4, port) {
|
||||
modify_field(routing_metadata.nhop_ipv4, nhop_ipv4);
|
||||
modify_field(standard_metadata.egress_spec, port);
|
||||
add_to_field(ipv4.ttl, -1);
|
||||
}
|
||||
|
||||
table ipv4_lpm {
|
||||
reads {
|
||||
ipv4.dstAddr : lpm;
|
||||
}
|
||||
actions {
|
||||
set_nhop;
|
||||
_drop;
|
||||
}
|
||||
size: 1024;
|
||||
}
|
||||
|
||||
action set_dmac(dmac) {
|
||||
modify_field(ethernet.dstAddr, dmac);
|
||||
}
|
||||
|
||||
table forward {
|
||||
reads {
|
||||
routing_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 {
|
||||
if(valid(ipv4) and ipv4.ttl > 0) {
|
||||
// TODO: implement ECMP here
|
||||
apply(ipv4_lpm);
|
||||
apply(forward);
|
||||
}
|
||||
}
|
||||
|
||||
control egress {
|
||||
apply(send_frame);
|
||||
}
|
98
workshop_05_2016/ecmp/README.md
Normal file
98
workshop_05_2016/ecmp/README.md
Normal file
@ -0,0 +1,98 @@
|
||||
# Implementing ECMP on top of simple_router.p4
|
||||
|
||||
## Introduction
|
||||
|
||||
simple_router.p4 is a very simple P4 program which does L3 routing. All the P4
|
||||
code can be found in the [p4src/simple_router.p4] (p4src/simple_router.p4)
|
||||
file. In this exercise we will try to build ECMP on top of the starter code. We
|
||||
will be assuming the following network topology:
|
||||
|
||||
```
|
||||
--------------------------------- nhop-0 10.0.1.1
|
||||
| 00:04:00:00:00:00
|
||||
1 - 00:aa:bb:00:00:00
|
||||
|
|
||||
-------- 3--sw
|
||||
|
|
||||
2 - 00:aa:bb:00:00:01
|
||||
|
|
||||
--------------------------------- nhop-1 10.0.2.1
|
||||
00:04:00:00:00:01
|
||||
```
|
||||
|
||||
Note that we do not assign IPv4 addresses to the 3 switch interfaces, we do not
|
||||
need to for this exercise.
|
||||
We will be sending test packets on interface `3` of the switch. These packets
|
||||
will have destination IP `10.0.0.1`. We will assume that both `nhop-0` and
|
||||
`nhop-1` have a path to `10.0.0.1`, which is the final destination of our test
|
||||
packets.
|
||||
|
||||
## Running the starter code
|
||||
|
||||
*Before starting make sure that you run `sudo ./veth_setup.sh` to create the
|
||||
veth pairs required for the demo.*
|
||||
|
||||
To compile and run the starter code, simply use `./run_demo.sh`. The
|
||||
[run_demo.sh] (run_demo.sh) script will run the P4 compiler (for bmv2), start
|
||||
the switch and populate the tables using the CLI commands from [commands.txt]
|
||||
(commands.txt).
|
||||
|
||||
When the switch is running, you can send test packets with `sudo
|
||||
./run_test.py`. Note that this script will take a few seconds to complete. The
|
||||
test sends a few hundred identical TCP packets through the switch, in bursts,
|
||||
on port 3. If you take a look at the P4 code and at commands.txt, you will see
|
||||
that each TCP packet is forwarded out of port 1; since we do not have ECMP
|
||||
working yet.
|
||||
|
||||
## What you need to do
|
||||
|
||||
1. In this exercise, you need to update the provided [P4 program]
|
||||
(p4src/simple_router.p4) to perform ECMP. When you are done, each incoming TCP
|
||||
test packet should be forwarded to either port 1 or port 2, based on the result
|
||||
of a crc16 hash computation performed on the TCP 5-tuple (`ipv4.srcAddr`,
|
||||
`ipv4.dstAddr`, `ipv4.protocol`, `tcp.srcPort`, `tcp.dstPort`). You will need to
|
||||
refer to the [P4 spec] (http://p4.org/wp-content/uploads/2015/04/p4-latest.pdf)
|
||||
to familiarize yourself with the P4 constructs you will need.
|
||||
|
||||
2. Once you are done with the P4 code, you will need to update [commands.txt]
|
||||
(commands.txt) to configure your new tables.
|
||||
|
||||
3. After that you can run the above test again. Once again, you will observe
|
||||
that all packets go to the same egress port. Don't panic :)! This is because all
|
||||
packets are identical and therefore are forwarded in the same way, If you add
|
||||
`--random-dport` when running `sudo ./run_test.py`, you should observe an even
|
||||
distribution for the ports. This option assigns a random destination port to
|
||||
each test TCP packet (the 5-tuple is different, so the hash is likely to be
|
||||
different).
|
||||
|
||||
## Hints and directions
|
||||
|
||||
1. You can easily check the syntax of your P4 program with `p4-validate <path to
|
||||
simple_router.p4>`.
|
||||
|
||||
2. There are 2 major ways of implementing ECMP on top of simple_router.p4. The
|
||||
first one requires 2 tables and the use of the
|
||||
`modify_field_with_hash_based_offset` primitive. The second one uses a single
|
||||
table with an action profile. You can read about
|
||||
`modify_field_with_hash_based_offset` and action profiles in the [P4 spec]
|
||||
(http://p4.org/wp-content/uploads/2015/04/p4-latest.pdf).
|
||||
|
||||
3. If you choose to use the first way (with 2 tables), your first table will
|
||||
match on the destination IP address and be in charge of computing an index
|
||||
(using `modify_field_with_hash_based_offset`), while the second table will match
|
||||
on this computed index to obtain the outgoing interface. This is a high level
|
||||
view of what needs to be implemented in P4.
|
||||
```
|
||||
T1
|
||||
IP_prefix_1 ---> "random" index in [0, 1] using modify_field_with_hash_based_offset
|
||||
IP_prefix_2 ---> "random" index in [2, 4] ...
|
||||
...
|
||||
|
||||
T2
|
||||
index(0) ---> nhop A
|
||||
index(1) ---> nhop B
|
||||
index(2) ---> nhop C
|
||||
index(3) ---> nhop D
|
||||
index(4) ---> nhop E
|
||||
```
|
||||
Remember that `T1` and `T2`'s entries will come from your modified commands.txt.
|
6
workshop_05_2016/ecmp/commands.txt
Normal file
6
workshop_05_2016/ecmp/commands.txt
Normal file
@ -0,0 +1,6 @@
|
||||
table_set_default send_frame _drop
|
||||
table_set_default forward _drop
|
||||
table_set_default ipv4_lpm _drop
|
||||
table_add send_frame rewrite_mac 1 => 00:aa:bb:00:00:00
|
||||
table_add forward set_dmac 10.0.1.1 => 00:04:00:00:00:00
|
||||
table_add ipv4_lpm set_nhop 10.0.0.1/32 => 10.0.1.1 1
|
190
workshop_05_2016/ecmp/p4src/simple_router.p4
Normal file
190
workshop_05_2016/ecmp/p4src/simple_router.p4
Normal file
@ -0,0 +1,190 @@
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
action _drop() {
|
||||
drop();
|
||||
}
|
||||
|
||||
header_type routing_metadata_t {
|
||||
fields {
|
||||
nhop_ipv4 : 32;
|
||||
// TODO: if you need extra metadata for ECMP, define it here
|
||||
}
|
||||
}
|
||||
|
||||
metadata routing_metadata_t routing_metadata;
|
||||
|
||||
action set_nhop(nhop_ipv4, port) {
|
||||
modify_field(routing_metadata.nhop_ipv4, nhop_ipv4);
|
||||
modify_field(standard_metadata.egress_spec, port);
|
||||
add_to_field(ipv4.ttl, -1);
|
||||
}
|
||||
|
||||
table ipv4_lpm {
|
||||
reads {
|
||||
ipv4.dstAddr : lpm;
|
||||
}
|
||||
actions {
|
||||
set_nhop;
|
||||
_drop;
|
||||
}
|
||||
size: 1024;
|
||||
}
|
||||
|
||||
action set_dmac(dmac) {
|
||||
modify_field(ethernet.dstAddr, dmac);
|
||||
}
|
||||
|
||||
table forward {
|
||||
reads {
|
||||
routing_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 {
|
||||
if(valid(ipv4) and ipv4.ttl > 0) {
|
||||
// TODO: implement ECMP here
|
||||
apply(ipv4_lpm);
|
||||
apply(forward);
|
||||
}
|
||||
}
|
||||
|
||||
control egress {
|
||||
apply(send_frame);
|
||||
}
|
49
workshop_05_2016/ecmp/run_demo.sh
Executable file
49
workshop_05_2016/ecmp/run_demo.sh
Executable file
@ -0,0 +1,49 @@
|
||||
#!/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
|
||||
|
||||
# Probably not very elegant but it works nice here: we enable interactive mode
|
||||
# to be able to use fg. We start the switch in the background, sleep for 2
|
||||
# minutes to give it time to start, then add the entries and put the switch
|
||||
# process back in the foreground
|
||||
set -m
|
||||
$P4C_BM_SCRIPT p4src/simple_router.p4 --json simple_router.json
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "p4 compilation failed"
|
||||
exit 1
|
||||
fi
|
||||
# This gets root permissions, and gives libtool the opportunity to "warm-up"
|
||||
sudo $SWITCH_PATH >/dev/null 2>&1
|
||||
sudo $SWITCH_PATH simple_router.json \
|
||||
-i 0@veth0 -i 1@veth2 -i 2@veth4 -i 3@veth6 -i 4@veth8 \
|
||||
--log-console \
|
||||
--pcap &
|
||||
sleep 2
|
||||
echo "**************************************"
|
||||
echo "Sending commands to switch through CLI"
|
||||
echo "**************************************"
|
||||
$CLI_PATH --json simple_router.json < commands.txt
|
||||
echo "READY!!!"
|
||||
fg
|
147
workshop_05_2016/ecmp/run_test.py
Executable file
147
workshop_05_2016/ecmp/run_test.py
Executable file
@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env 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.
|
||||
|
||||
import time
|
||||
|
||||
NUM_PACKETS = 500
|
||||
|
||||
import random
|
||||
import argparse
|
||||
|
||||
import threading
|
||||
from scapy.all import sniff
|
||||
from scapy.all import Ether, IP, IPv6, TCP
|
||||
|
||||
parser = argparse.ArgumentParser(description='run_test.py')
|
||||
parser.add_argument('--random-dport',
|
||||
help='Use a random TCP dest port for each packet',
|
||||
action="store_true", default=False)
|
||||
args = parser.parse_args()
|
||||
|
||||
class PacketQueue:
|
||||
def __init__(self):
|
||||
self.pkts = []
|
||||
self.lock = threading.Lock()
|
||||
self.ifaces = set()
|
||||
|
||||
def add_iface(self, iface):
|
||||
self.ifaces.add(iface)
|
||||
|
||||
def get(self):
|
||||
self.lock.acquire()
|
||||
if not self.pkts:
|
||||
self.lock.release()
|
||||
return None, None
|
||||
pkt = self.pkts.pop(0)
|
||||
self.lock.release()
|
||||
return pkt
|
||||
|
||||
def add(self, iface, pkt):
|
||||
if iface not in self.ifaces:
|
||||
return
|
||||
self.lock.acquire()
|
||||
self.pkts.append( (iface, pkt) )
|
||||
self.lock.release()
|
||||
|
||||
queue = PacketQueue()
|
||||
|
||||
def pkt_handler(pkt, iface):
|
||||
if IPv6 in pkt:
|
||||
return
|
||||
queue.add(iface, pkt)
|
||||
|
||||
class SnifferThread(threading.Thread):
|
||||
def __init__(self, iface, handler = pkt_handler):
|
||||
threading.Thread.__init__(self)
|
||||
self.iface = iface
|
||||
self.handler = handler
|
||||
|
||||
def run(self):
|
||||
sniff(
|
||||
iface = self.iface,
|
||||
prn = lambda x: self.handler(x, self.iface)
|
||||
)
|
||||
|
||||
class PacketDelay:
|
||||
def __init__(self, bsize, bdelay, imin, imax, num_pkts = 100):
|
||||
self.bsize = bsize
|
||||
self.bdelay = bdelay
|
||||
self.imin = imin
|
||||
self.imax = imax
|
||||
self.num_pkts = num_pkts
|
||||
self.current = 1
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
if self.num_pkts <= 0:
|
||||
raise StopIteration
|
||||
self.num_pkts -= 1
|
||||
if self.current == self.bsize:
|
||||
self.current = 1
|
||||
return random.randint(self.imin, self.imax)
|
||||
else:
|
||||
self.current += 1
|
||||
return self.bdelay
|
||||
|
||||
|
||||
pkt = Ether()/IP(dst='10.0.0.1', ttl=64)/TCP()
|
||||
|
||||
port_map = {
|
||||
1: "veth3",
|
||||
2: "veth5",
|
||||
3: "veth7"
|
||||
}
|
||||
|
||||
iface_map = {}
|
||||
for p, i in port_map.items():
|
||||
iface_map[i] = p
|
||||
|
||||
queue.add_iface("veth3")
|
||||
queue.add_iface("veth5")
|
||||
|
||||
for p, iface in port_map.items():
|
||||
t = SnifferThread(iface)
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
import socket
|
||||
|
||||
send_socket = socket.socket(socket.AF_PACKET, socket.SOCK_RAW,
|
||||
socket.htons(0x03))
|
||||
send_socket.bind((port_map[3], 0))
|
||||
|
||||
delays = PacketDelay(10, 5, 25, 100, NUM_PACKETS)
|
||||
ports = []
|
||||
print "Sending", NUM_PACKETS, "packets ..."
|
||||
for d in delays:
|
||||
# sendp is too slow...
|
||||
# sendp(pkt, iface=port_map[3], verbose=0)
|
||||
if args.random_dport:
|
||||
pkt["TCP"].dport = random.randint(1025, 65535)
|
||||
send_socket.send(str(pkt))
|
||||
time.sleep(d / 1000.)
|
||||
time.sleep(1)
|
||||
iface, pkt = queue.get()
|
||||
while pkt:
|
||||
ports.append(iface_map[iface])
|
||||
iface, pkt = queue.get()
|
||||
print ports
|
||||
print "DISTRIBUTION..."
|
||||
for p in port_map:
|
||||
c = ports.count(p)
|
||||
print "port {}: {:>3} [ {:>5}% ]".format(p, c, 100. * c / NUM_PACKETS)
|
BIN
workshop_05_2016/ecmp/solution_1.tar.gz
Normal file
BIN
workshop_05_2016/ecmp/solution_1.tar.gz
Normal file
Binary file not shown.
BIN
workshop_05_2016/ecmp/solution_2.tar.gz
Normal file
BIN
workshop_05_2016/ecmp/solution_2.tar.gz
Normal file
Binary file not shown.
26
workshop_05_2016/ecmp/veth_setup.sh
Executable file
26
workshop_05_2016/ecmp/veth_setup.sh
Executable file
@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
noOfVeths=18
|
||||
if [ $# -eq 1 ]; then
|
||||
noOfVeths=$1
|
||||
fi
|
||||
echo "No of Veths is $noOfVeths"
|
||||
idx=0
|
||||
let "vethpairs=$noOfVeths/2"
|
||||
while [ $idx -lt $vethpairs ]
|
||||
do
|
||||
intf0="veth$(($idx*2))"
|
||||
intf1="veth$(($idx*2+1))"
|
||||
idx=$((idx + 1))
|
||||
if ! ip link show $intf0 &> /dev/null; then
|
||||
ip link add name $intf0 type veth peer name $intf1
|
||||
ip link set dev $intf0 up
|
||||
ip link set dev $intf1 up
|
||||
TOE_OPTIONS="rx tx sg tso ufo gso gro lro rxvlan txvlan rxhash"
|
||||
for TOE_OPTION in $TOE_OPTIONS; do
|
||||
/sbin/ethtool --offload $intf0 "$TOE_OPTION" off
|
||||
/sbin/ethtool --offload $intf1 "$TOE_OPTION" off
|
||||
done
|
||||
fi
|
||||
sysctl net.ipv6.conf.$intf0.disable_ipv6=1
|
||||
sysctl net.ipv6.conf.$intf1.disable_ipv6=1
|
||||
done
|
Loading…
x
Reference in New Issue
Block a user