added resubmit example

This commit is contained in:
Antonin Bas 2015-12-17 11:54:22 -08:00
parent 97b2a77733
commit 6d8a0232dc
6 changed files with 206 additions and 1 deletions

View File

@ -13,7 +13,8 @@ included:
- `register`: how to use registers in P4 and read / write the state from the - `register`: how to use registers in P4 and read / write the state from the
control plane control plane
- `counter`: how to use counters in P4 - `counter`: how to use counters in P4
- `action_profile`: how to use action profiles in P4, using ECMP has support - `action_profile`: how to use action profiles in P4, using ECMP as support
- `resubmit`: how to resubmit packets to the ingress pipelines
All examples are orgranized the same way, with a `p4src` directory containing All examples are orgranized the same way, with a `p4src` directory containing
the P4 source code, and a `README` file describing the P4 program and explaining the P4 source code, and a `README` file describing the P4 program and explaining

View File

@ -0,0 +1,28 @@
# Resubmit
## Description
This program illustrates as simply as possible how to use the `resubmit()`
primitive. This primitive is used to make a packet go twice through the ingress
pipeline. For more information, please refer to the P4 specification.
The P4 program only consists of an ingress pipeline, with 2 tables:
`t_ingress_1` and `t_ingress_2`. When a packet enters the pipeline, the
following happens (based on the P4 program and the [commands.txt] (commands.txt)
files):
- the packet hits `table_ingress_1` and the egress port is set to 2.
- the packet hits `table_ingress_2`, `mymeta.f1` is set to 1 and the
`resubmit()` primitive is called. Because `mymeta` is resubmitted along with
the packet, `mymeta.f1` will now be equal to 1 for the second pass.
- the packet hits `table_ingress_1`, this time the egress port is set to 3.
- the packet hits `table_ingress_2` which is a no-op.
### Running the demo
We provide a small demo to let you test the program. It consists of the
following scripts, which you need to run one after the other, in 2 separate
terminals:
- [run_switch.sh] (run_switch.sh): compile the P4 program and starts the switch,
also configures the data plane by running the CLI [commands] (commands.txt).
- [send_and_receive.py] (send_and_receive.py): send a packet on port 0 (veth1),
wait for the forwarded packet on port 3 (veth7).

View File

@ -0,0 +1,5 @@
table_set_default t_ingress_1 _nop
table_set_default t_ingress_2 _nop
table_add t_ingress_1 set_port 0 => 2
table_add t_ingress_1 set_port 1 => 3
table_add t_ingress_2 _resubmit 0 =>

View File

@ -0,0 +1,101 @@
/*
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 intrinsic_metadata_t {
fields {
mcast_grp : 4;
egress_rid : 4;
mcast_hash : 16;
lf_field_list : 32;
resubmit_flag : 16;
}
}
header_type mymeta_t {
fields {
f1 : 8;
}
}
header ethernet_t ethernet;
metadata intrinsic_metadata_t intrinsic_metadata;
metadata mymeta_t mymeta;
parser start {
return parse_ethernet;
}
parser parse_ethernet {
extract(ethernet);
return ingress;
}
action _drop() {
drop();
}
action _nop() {
}
action set_port(port) {
modify_field(standard_metadata.egress_spec, port);
}
field_list resubmit_FL {
standard_metadata;
mymeta;
}
action _resubmit() {
modify_field(mymeta.f1, 1);
resubmit(resubmit_FL);
}
table t_ingress_1 {
reads {
mymeta.f1 : exact;
}
actions {
_nop; set_port;
}
size : 128;
}
table t_ingress_2 {
reads {
mymeta.f1 : exact;
}
actions {
_nop; _resubmit;
}
size : 128;
}
control ingress {
apply(t_ingress_1);
apply(t_ingress_2);
}
control egress {
}

41
examples/resubmit/run_switch.sh Executable file
View File

@ -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/targets/simple_switch/sswitch_CLI
# 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/resubmit.p4 --json resubmit.json
sudo echo "sudo" > /dev/null
sudo $BMV2_PATH/targets/simple_switch/simple_switch 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 &
sleep 2
$CLI_PATH resubmit.json < commands.txt
echo "READY!!!"
fg

View File

@ -0,0 +1,29 @@
from scapy.all import *
import sys
import threading
class Receiver(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def received(self, p):
print "Received packet on port 3, exiting"
sys.exit(0)
def run(self):
sniff(iface="veth7", prn=lambda x: self.received(x))
def main():
Receiver().start()
p = Ether(src="aa:aa:aa:aa:aa:aa") / IP(dst="10.0.1.10") / TCP() / "aaaaaaaaaaaaaaaaaaa"
print "Sending packet on port 0, listening on port 3"
time.sleep(1)
sendp(p, iface="veth1", verbose=0)
if __name__ == '__main__':
main()