From a67330c4f477f68c84d83d3d9624eab3ef32d005 Mon Sep 17 00:00:00 2001 From: Antonin Bas Date: Wed, 30 Sep 2015 14:09:06 -0700 Subject: [PATCH] adde flowlet_switching exercise --- README.md | 2 +- SIGCOMM_2015/flowlet_switching/commands.txt | 11 ++ .../p4src/includes/headers.p4 | 56 ++++++++ .../p4src/includes/intrinsic.p4 | 26 ++++ .../p4src/includes/parser.p4 | 77 ++++++++++ .../flowlet_switching/p4src/simple_router.p4 | 132 +++++++++++++++++ SIGCOMM_2015/flowlet_switching/run_demo.sh | 41 ++++++ SIGCOMM_2015/flowlet_switching/run_test.py | 135 ++++++++++++++++++ .../flowlet_switching/solution.tar.gz | Bin 0 -> 2446 bytes SIGCOMM_2015/flowlet_switching/veth_setup.sh | 26 ++++ 10 files changed, 505 insertions(+), 1 deletion(-) create mode 100644 SIGCOMM_2015/flowlet_switching/commands.txt create mode 100644 SIGCOMM_2015/flowlet_switching/p4src/includes/headers.p4 create mode 100644 SIGCOMM_2015/flowlet_switching/p4src/includes/intrinsic.p4 create mode 100644 SIGCOMM_2015/flowlet_switching/p4src/includes/parser.p4 create mode 100644 SIGCOMM_2015/flowlet_switching/p4src/simple_router.p4 create mode 100755 SIGCOMM_2015/flowlet_switching/run_demo.sh create mode 100755 SIGCOMM_2015/flowlet_switching/run_test.py create mode 100644 SIGCOMM_2015/flowlet_switching/solution.tar.gz create mode 100755 SIGCOMM_2015/flowlet_switching/veth_setup.sh diff --git a/README.md b/README.md index fa04115..b62cab9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # tutorials -Holds different P4 language tutorials +P4 language tutorials diff --git a/SIGCOMM_2015/flowlet_switching/commands.txt b/SIGCOMM_2015/flowlet_switching/commands.txt new file mode 100644 index 0000000..7c0e3ae --- /dev/null +++ b/SIGCOMM_2015/flowlet_switching/commands.txt @@ -0,0 +1,11 @@ +table_set_default ecmp_group _drop +table_set_default ecmp_nhop _drop +table_set_default forward _drop +table_set_default send_frame _drop +table_add ecmp_group set_ecmp_select 10.0.0.1/32 => 0 2 +table_add ecmp_nhop set_nhop 0 => 10.0.1.1 1 +table_add ecmp_nhop set_nhop 1 => 10.0.2.1 2 +table_add forward set_dmac 10.0.1.1 => 00:04:00:00:00:00 +table_add forward set_dmac 10.0.2.1 => 00:04:00:00:00:01 +table_add send_frame rewrite_mac 1 => 00:aa:bb:00:00:00 +table_add send_frame rewrite_mac 2 => 00:aa:bb:00:00:01 diff --git a/SIGCOMM_2015/flowlet_switching/p4src/includes/headers.p4 b/SIGCOMM_2015/flowlet_switching/p4src/includes/headers.p4 new file mode 100644 index 0000000..b9b0725 --- /dev/null +++ b/SIGCOMM_2015/flowlet_switching/p4src/includes/headers.p4 @@ -0,0 +1,56 @@ +/* +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_2015/flowlet_switching/p4src/includes/intrinsic.p4 b/SIGCOMM_2015/flowlet_switching/p4src/includes/intrinsic.p4 new file mode 100644 index 0000000..1785cd0 --- /dev/null +++ b/SIGCOMM_2015/flowlet_switching/p4src/includes/intrinsic.p4 @@ -0,0 +1,26 @@ +/* +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 intrinsic_metadata_t { + fields { + ingress_global_timestamp : 48; + lf_field_list : 32; + mcast_grp : 16; + egress_rid : 16; + } +} + +metadata intrinsic_metadata_t intrinsic_metadata; diff --git a/SIGCOMM_2015/flowlet_switching/p4src/includes/parser.p4 b/SIGCOMM_2015/flowlet_switching/p4src/includes/parser.p4 new file mode 100644 index 0000000..6d92708 --- /dev/null +++ b/SIGCOMM_2015/flowlet_switching/p4src/includes/parser.p4 @@ -0,0 +1,77 @@ +/* +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; + +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; +} diff --git a/SIGCOMM_2015/flowlet_switching/p4src/simple_router.p4 b/SIGCOMM_2015/flowlet_switching/p4src/simple_router.p4 new file mode 100644 index 0000000..2df930c --- /dev/null +++ b/SIGCOMM_2015/flowlet_switching/p4src/simple_router.p4 @@ -0,0 +1,132 @@ +/* +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" +#include "includes/intrinsic.p4" + +header_type ingress_metadata_t { + fields { + ecmp_offset : 14; // offset into the ecmp table + + nhop_ipv4 : 32; + + // TODO: add your flowlet metadata here + } +} + +metadata ingress_metadata_t ingress_metadata; + +action _drop() { + drop(); +} + +action set_nhop(nhop_ipv4, port) { + modify_field(ingress_metadata.nhop_ipv4, nhop_ipv4); + modify_field(standard_metadata.egress_spec, port); + add_to_field(ipv4.ttl, -1); +} + +#define ECMP_BIT_WIDTH 10 +#define ECMP_GROUP_TABLE_SIZE 1024 +#define ECMP_NHOP_TABLE_SIZE 16384 + +// TODO: add flowlet id to hash fields + +field_list l3_hash_fields { + ipv4.srcAddr; + ipv4.dstAddr; + ipv4.protocol; + tcp.srcPort; + tcp.dstPort; +} + +field_list_calculation ecmp_hash { + input { + l3_hash_fields; + } + algorithm : crc16; + output_width : ECMP_BIT_WIDTH; +} + + +action set_ecmp_select(ecmp_base, ecmp_count) { + modify_field_with_hash_based_offset(ingress_metadata.ecmp_offset, ecmp_base, + ecmp_hash, ecmp_count); +} + +table ecmp_group { + reads { + ipv4.dstAddr : lpm; + } + actions { + _drop; + set_ecmp_select; + } + size : ECMP_GROUP_TABLE_SIZE; +} + +table ecmp_nhop { + reads { + ingress_metadata.ecmp_offset : exact; + } + actions { + _drop; + set_nhop; + } + size : ECMP_NHOP_TABLE_SIZE; +} + +action set_dmac(dmac) { + modify_field(ethernet.dstAddr, dmac); +} + +table forward { + reads { + ingress_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: flowlet switching + apply(ecmp_group); + apply(ecmp_nhop); + apply(forward); +} + +control egress { + apply(send_frame); +} diff --git a/SIGCOMM_2015/flowlet_switching/run_demo.sh b/SIGCOMM_2015/flowlet_switching/run_demo.sh new file mode 100755 index 0000000..25bf7f6 --- /dev/null +++ b/SIGCOMM_2015/flowlet_switching/run_demo.sh @@ -0,0 +1,41 @@ +#!/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 +sudo echo "sudo" > /dev/null +sudo $BMV2_PATH/targets/simple_switch/simple_switch 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 & +sleep 2 +$CLI_PATH --json simple_router.json < commands.txt +echo "READY!!!" +fg diff --git a/SIGCOMM_2015/flowlet_switching/run_test.py b/SIGCOMM_2015/flowlet_switching/run_test.py new file mode 100755 index 0000000..5e09682 --- /dev/null +++ b/SIGCOMM_2015/flowlet_switching/run_test.py @@ -0,0 +1,135 @@ +#!/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 threading +from scapy.all import sniff +from scapy.all import Ether, IP, IPv6 +from scapy.all import sendp + +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) + +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) + 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 diff --git a/SIGCOMM_2015/flowlet_switching/solution.tar.gz b/SIGCOMM_2015/flowlet_switching/solution.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..4ed6ac6c03cce489c196a58c4ddc3a13eb676467 GIT binary patch literal 2446 zcmV;9332uxiwFQ0PYhN71MM2yZreDv&-w}?^RUUlu_fP>oK z5(Dib7c-JA@Z1z1yRIr6UoIYF;uD7<%WU(1R;SlR|9p!~)YaDsiTN_|#pGCGk=3@4 z^)RxPA$I{;-C1f%NVCOGz9nbEyfFJ0{4@Q3aACK4p~{}3drJ1y16_&b={k%rZf~my z)~xGRt+R~3+p!yX6lC!~>c`aiK2^Yz^1sFNe{VQEYx4hVfM);L+eUEQAwV)h+fn~T zXgr+%Et3~}GXI+v;8|y8x8LOd*MQEC#$_1YQ*XUts0%0WG@=9|Jwxv>C95!GXhzsR zq+jC}ng&iA8OD|8kRT>5+66A5h;0ZON7#Ws=}ZfKA~XiCLfy8Bjyb|nI(2k1GVa42 z+Twc@z~;M{zy@B7R-R7~xpPRwkQX2*MAK@5SaIiSdO4ZhOiqDQ!}u8ZB#t4y{kHQc2zYys za0GlfJP9Hn?@>q*UQ+^dEaZIhJm>}M7K+0agM3U3*NYkTZs7o_3X)ubq$&ca2nXnB ze1oPpN9f)7W_r^yK2Mh)<{y{n^Z5FDJX=mDH)wv1F6XoN)8%wNgQuU-c=iSTGM&9| zAp+_FBIJ%6F6IpKGwcz!ZQKx2APyyic#b3Dcq`8ViGuYGuL)X*-v|ZwUZaT6trv6S z#lV_t_}CxU(S`P-BQ7M^)1irm=`Gm9t&|`Uzss z5eUW)P~>?5K|f#3KVMCj_OIiGeKY;{1X(?9-%bae|58Gl&c>I^>8FXk^=g+1Z%E8drKIG`Vrd<{Vx1x^;=0S;; zF_+H#BSw43kjm1^~&kzrtmJ6X~W9G|56P98>lJ7EXghr@&Xp1r~G#x9tKv(SbdHg;V) z%17LoX(JI0S?Gj*GQ^ySuUdqZ@j$+B`31PWdngb3K?rnQ)=) z$ybtOCmz#Mg2^&yS!@L1E_6O$0Zqjfzg&0=PhUZohS7u8mu`Gck`LF?HRIH$v#q%6nE?@iME%t5h zyI|REl-ll*(n+^ZXqHAFCmUZH?`|0dkAU_z-2Md#GeHk9TC$#KqmTaz=apPMP1A4+ zL@dwpN#gg($$+q0aX3avXipDM>82$+JH^BIfOjHGH+fMdk8{x)Wz>>Yg;%eRbOn?I zOyyT{QD(bW%Si`h6Qap-Xma`M!hSbh+MlQImmiR27H9r-J^#3{m*aO=leDCQ#;b@j z`!FwJ414GOgIQ5j6Az@tYOOszJr?ED(~)w$cPzg1*xgD>9g)VK73!6WDcw_S|Kwnw z>8ik);-Si=}oCZ-wf!H+oy$Bc3SiC7UXV;iMprn9UERtT*#vZtucq>Mth+K}cDS zT=fF=74Cnu`@gIQe@Ploxc?mt`#t{tuYWdd?tfnc>g=E0(7XVR1Mh!(%KP8Jz!dkt zT^MTae_sKb``_mN_qq4KNvz;y0cBaqz;-l1V#bywN3kYrNYgLs|v@Ejcu!;;6UrwGpW1pm3(&v|$!9 z>|c@6dKXSJx3(~%Ho5ZgI@ZT1Ue85ot`lH7C&jik8!mLbIoq=9t-n+)=%}W3EbFnh zZ3KjxzR^l+%9J*Ad4i*a(Tz(lB@ZcKFb$N@McT>6$rXVVK1)d%lYN}>c(DP zF3?bOWYHKDomjd3taM8sSP4Ll#} z>Ob`z+;eFh`u$%YYJRQ$JAc6J`dv5(#e2uQZfvA6xUiWGOGFSgRPg(xT zR?4XSttN-9gQ0|2(@1$!DKb>DGnH@6^DL*lm9F5lJUIH_&SZ7*KmP&8^JyH2|J~m3 zOppJ)VYi9@uK`W`Z{q(;#($-8uZjBkdnz@^r!Av4nl8maX4v(5ndZ5C?evGcVw#xrTA0!8oOvPE4HCnyd$jB<4-H1}TM zhI@?>r&>Wfx&~V<7}Xr;?+&{SG|)f;4K&a|0}V9LKm!dl&_DwXG|)f;4K&a|1K$n) M1nGJCasW^O05WXKb^rhX literal 0 HcmV?d00001 diff --git a/SIGCOMM_2015/flowlet_switching/veth_setup.sh b/SIGCOMM_2015/flowlet_switching/veth_setup.sh new file mode 100755 index 0000000..4083541 --- /dev/null +++ b/SIGCOMM_2015/flowlet_switching/veth_setup.sh @@ -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