added simple_nat example

This commit is contained in:
Antonin Bas 2016-03-12 11:31:47 -08:00
parent bd33b7df18
commit 82d764a2ba
12 changed files with 1030 additions and 2 deletions

View File

@ -1,2 +1 @@
sudo killall simple_switch
redis-cli FLUSHDB
sudo killall lt-simple_switch

View File

@ -15,6 +15,7 @@ included:
- `counter`: how to use counters in P4
- `action_profile`: how to use action profiles in P4, using ECMP as support
- `resubmit`: how to resubmit packets to the ingress pipelines
- `simple_nat`: a basic implementation of a full-cone NAT for TCP traffic
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

View File

@ -0,0 +1,62 @@
# Simple NAT
## Description
This program implements a very basic full-cone NAT for TCP traffic (over
IPv4). According to [Wikipedia]
(https://en.wikipedia.org/wiki/Network_address_translation#Methods_of_translation),
a full-cone NAT is defined as follows:
Once an internal address (iAddr:iPort) is mapped to an external address
(eAddr:ePort), any packets from iAddr:iPort are sent through eAddr:ePort. Any
external host can send packets to iAddr:iPort by sending packets to eAddr:ePort.
Note that this program was built on top of the simple_router P4 program, so you
will find some similarities.
This program was added to illustrate two things:
- how to re-compute a TCP checksum after having modified the TCP header (which
is required for a TCP NAT)
- how to write a simple app that receives and emits "CPU packets"
This program is slightly more advanced than most others in this repository, so
we recommend that you become familiar with the copy_to_cpu example before
studying this one.
The program implements very basic funtionality only. For example it supports
only one internal interface, even though we may extend this in the future. The
Mininet topology used for the demo is the following:
![Simple NAT topology](resources/topo.png)
The program in a nutshell:
- non-TCP traffic is dropped.
- when a TCP packet is received on the external interface, for which there is no
mapping, the packet is dropped.
- when a TCP packet is received on the internal interface, for which there is no
mapping, the packet is sent to CPU and 2 new rules are added to the `nat` table
to allow translation and forwarding of TCP packets in both directions. The
packet is then re-injected in the dataplane (to avoid dropping the SYN packet).
- when a TCP packet is received on the either interface, for which there is a
mapping, the appropriate rewrites are executed for the IPv4 and TCP headers and
the packet is forwarded appropriately.
The most important part of the program is the `nat` table. If you understand
what this table is doing, the rest of the program is mostly IPv4 forwarding. You
should also take a long look at [nat_app.py] (nat_app.py), which manages the
mappings and dynamically adds rules to the `nat` table.
We use 11 as the CPU port. There is a special CPU veth pair (`cpu-veth-0` /
`cpu-veth-1`), which is use by the switch / the app to send and receive CPU
packets. The veth pair is created by `run_demo.sh` and can be destroyed with
`cleanup.sh`.
### Running the demo
To run the demo:
- start the 1-switch Mininet topo with `sudo ./run_demo.sh`.
- start the app with `sudo python nat_app.py`.
- create a TCP flow in Mininet from `h1` (internal host) to `h2` (external host)
- `h2 iperf -s&`
- `h1 iperf -c h2`
- you can cleanup the demo with `sudo ./cleanup.sh`

27
examples/simple_nat/cleanup.sh Executable file
View File

@ -0,0 +1,27 @@
#!/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.
if [[ $EUID -ne 0 ]]; then
echo "This script should be run using sudo or as the root user"
exit 1
fi
killall lt-simple_switch &> /dev/null
mn -c &> /dev/null
intf="cpu-veth-0"
if ip link show $intf &> /dev/null; then
ip link delete $intf type veth
fi

View File

@ -0,0 +1,17 @@
table_set_default if_info _drop
table_add if_info set_if_info 1 => 10.0.0.1 00:aa:bb:00:00:04 0
table_add if_info set_if_info 2 => 192.168.0.1 00:aa:bb:00:00:05 1
table_set_default nat _drop
table_add nat nat_miss_ext_to_int 1 1 1 0.0.0.0&&&0.0.0.0 0.0.0.0&&&0.0.0.0 0&&&0 0&&&0 => 99
table_add nat nat_miss_int_to_ext 0 1 1 0.0.0.0&&&0.0.0.0 0.0.0.0&&&0.0.0.0 0&&&0 0&&&0 => 99
table_set_default ipv4_lpm _drop
table_add ipv4_lpm set_nhop 10.0.0.10/32 => 10.0.0.10 1
table_add ipv4_lpm set_nhop 192.168.0.10/32 => 192.168.0.10 2
table_set_default forward _drop
table_add forward set_dmac 10.0.0.10 => 00:04:00:00:00:10
table_add forward set_dmac 192.168.0.10 => 00:05:00:00:00:10
table_set_default send_frame _drop
table_add send_frame do_rewrites 1 => 00:aa:bb:00:00:04
table_add send_frame do_rewrites 2 => 00:aa:bb:00:00:05
mirroring_add 250 11
table_set_default send_to_cpu do_cpu_encap

View File

@ -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.
from scapy.all import *
import subprocess
import os
CLI_PATH = None
EXTERN_IP = "192.168.0.1"
current_nat_port = 1025
nat_mappings = {}
def send_to_CLI(cmd):
this_dir = os.path.dirname(os.path.realpath(__file__))
p = Popen(os.path.join(this_dir, 'sswitch_CLI.sh'), stdout=PIPE, stdin=PIPE)
output = p.communicate(input=cmd)[0]
# print output
# This is a very basic implementation of a full-cone NAT for TCP traffic
# We do not maintain a state machine for each connection, so we are not able to
# cleanup the port mappings, but this is sufficient for demonstration purposes
def process_cpu_pkt(p):
global current_nat_port
global EXTERN_IP
p_str = str(p)
# 0-7 : preamble
# 8 : device
# 9 : reason
# 10 : iface
# 11- : data packet (TCP)
if p_str[:8] != '\x00' * 8 or p_str[8] != '\x00' or p_str[9] != '\xab':
return
ip_hdr = None
tcp_hdr = None
try:
p2 = Ether(p_str[11:])
ip_hdr = p2['IP']
tcp_hdr = p2['TCP']
except:
return
print "Packet received"
print p2.summary()
if (ip_hdr.src, tcp_hdr.sport) not in nat_mappings:
ext_port = current_nat_port
current_nat_port += 1
print "Allocating external port", ext_port
nat_mappings[(ip_hdr.src, tcp_hdr.sport)] = ext_port
# internal to external rule for this mapping
send_to_CLI("table_add nat nat_hit_int_to_ext 0 1 1 %s&&&255.255.255.255 0.0.0.0&&&0.0.0.0 %d&&&0xffff 0&&&0 => %s %d 1" %\
(ip_hdr.src, tcp_hdr.sport, EXTERN_IP, ext_port))
# external to internal rule for this mapping
send_to_CLI("table_add nat nat_hit_ext_to_int 1 1 1 0.0.0.0&&&0.0.0.0 %s&&&255.255.255.255 0&&&0 %d&&&0xffff => %s %d 1" %\
(EXTERN_IP, ext_port, ip_hdr.src, tcp_hdr.sport))
# a little bit hacky, this essentially ensures that the packet we re-inject
# in the CPU iface will not be processed again by this method
new_p = p_str[:9] + '\xac' + p_str[10:]
sendp(new_p, iface="cpu-veth-0", verbose=0)
def main():
sniff(iface="cpu-veth-0", prn=lambda x: process_cpu_pkt(x))
if __name__ == '__main__':
main()

View File

@ -0,0 +1,364 @@
/*
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;
}
}
parser start {
set_metadata(meta.if_index, standard_metadata.ingress_port);
return select(current(0, 64)) {
0 : parse_cpu_header; // dummy transition
default: parse_ethernet;
}
}
header_type cpu_header_t {
fields {
preamble: 64;
device: 8;
reason: 8;
if_index: 8;
}
}
header cpu_header_t cpu_header;
parser parse_cpu_header {
extract(cpu_header);
set_metadata(meta.if_index, cpu_header.if_index);
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_PROT_TCP 0x06
parser parse_ipv4 {
extract(ipv4);
set_metadata(meta.ipv4_sa, ipv4.srcAddr);
set_metadata(meta.ipv4_da, ipv4.dstAddr);
set_metadata(meta.tcpLength, ipv4.totalLen - 20);
return select(ipv4.protocol) {
IP_PROT_TCP : parse_tcp;
default : ingress;
}
}
header_type tcp_t {
fields {
srcPort : 16;
dstPort : 16;
seqNo : 32;
ackNo : 32;
dataOffset : 4;
res : 4;
flags : 8;
window : 16;
checksum : 16;
urgentPtr : 16;
}
}
header tcp_t tcp;
parser parse_tcp {
extract(tcp);
set_metadata(meta.tcp_sp, tcp.srcPort);
set_metadata(meta.tcp_dp, tcp.dstPort);
return ingress;
}
field_list tcp_checksum_list {
ipv4.srcAddr;
ipv4.dstAddr;
8'0;
ipv4.protocol;
meta.tcpLength;
tcp.srcPort;
tcp.dstPort;
tcp.seqNo;
tcp.ackNo;
tcp.dataOffset;
tcp.res;
tcp.flags;
tcp.window;
tcp.urgentPtr;
payload;
}
field_list_calculation tcp_checksum {
input {
tcp_checksum_list;
}
algorithm : csum16;
output_width : 16;
}
calculated_field tcp.checksum {
verify tcp_checksum if(valid(tcp));
update tcp_checksum if(valid(tcp));
}
action _drop() {
drop();
}
header_type intrinsic_metadata_t {
fields {
mcast_grp : 4;
egress_rid : 4;
mcast_hash : 16;
lf_field_list: 32;
}
}
metadata intrinsic_metadata_t intrinsic_metadata;
header_type meta_t {
fields {
do_forward : 1;
ipv4_sa : 32;
ipv4_da : 32;
tcp_sp : 16;
tcp_dp : 16;
nhop_ipv4 : 32;
if_ipv4_addr : 32;
if_mac_addr : 48;
is_ext_if : 1;
tcpLength : 16;
if_index : 8;
}
}
metadata meta_t meta;
action set_if_info(ipv4_addr, mac_addr, is_ext) {
modify_field(meta.if_ipv4_addr, ipv4_addr);
modify_field(meta.if_mac_addr, mac_addr);
modify_field(meta.is_ext_if, is_ext);
}
table if_info {
reads {
meta.if_index : exact;
}
actions {
_drop;
set_if_info;
}
}
action nat_miss_ext_to_int() {
modify_field(meta.do_forward, 0);
drop();
}
#define CPU_MIRROR_SESSION_ID 250
field_list copy_to_cpu_fields {
standard_metadata;
}
action nat_miss_int_to_ext() {
clone_ingress_pkt_to_egress(CPU_MIRROR_SESSION_ID, copy_to_cpu_fields);
}
action nat_hit_int_to_ext(srcAddr, srcPort) {
modify_field(meta.do_forward, 1);
modify_field(meta.ipv4_sa, srcAddr);
modify_field(meta.tcp_sp, srcPort);
}
action nat_hit_ext_to_int(dstAddr, dstPort) {
modify_field(meta.do_forward, 1);
modify_field(meta.ipv4_da, dstAddr);
modify_field(meta.tcp_dp, dstPort);
}
action nat_no_nat() {
modify_field(meta.do_forward, 1);
}
table nat {
reads {
meta.is_ext_if : exact;
ipv4 : valid;
tcp : valid;
ipv4.srcAddr : ternary;
ipv4.dstAddr : ternary;
tcp.srcPort : ternary;
tcp.dstPort : ternary;
}
actions {
_drop;
nat_miss_int_to_ext;
nat_miss_ext_to_int;
nat_hit_int_to_ext;
nat_hit_ext_to_int;
nat_no_nat; // for debugging
}
size : 128;
}
action set_nhop(nhop_ipv4, port) {
modify_field(meta.nhop_ipv4, nhop_ipv4);
modify_field(standard_metadata.egress_spec, port);
add_to_field(ipv4.ttl, -1);
}
table ipv4_lpm {
reads {
meta.ipv4_da : lpm;
}
actions {
set_nhop;
_drop;
}
size: 1024;
}
action set_dmac(dmac) {
modify_field(ethernet.dstAddr, dmac);
}
table forward {
reads {
meta.nhop_ipv4 : exact;
}
actions {
set_dmac;
_drop;
}
size: 512;
}
action do_rewrites(smac) {
// in case packet was injected by CPU
remove_header(cpu_header);
modify_field(ethernet.srcAddr, smac);
modify_field(ipv4.srcAddr, meta.ipv4_sa);
modify_field(ipv4.dstAddr, meta.ipv4_da);
modify_field(tcp.srcPort, meta.tcp_sp);
modify_field(tcp.dstPort, meta.tcp_dp);
}
table send_frame {
reads {
standard_metadata.egress_port: exact;
}
actions {
do_rewrites;
_drop;
}
size: 256;
}
action do_cpu_encap() {
add_header(cpu_header);
modify_field(cpu_header.preamble, 0);
modify_field(cpu_header.device, 0);
modify_field(cpu_header.reason, 0xab); // does not mean anything
modify_field(cpu_header.if_index, meta.if_index);
}
table send_to_cpu {
actions { do_cpu_encap; }
size : 0;
}
control ingress {
// retrieve information on the ingress interface
apply(if_info);
// determine what to do with the packet and which rewrites to apply
// depending on direction (int -> ext or ext -> int) and existing nat rules
apply(nat);
// forward packet
if (meta.do_forward == 1 and ipv4.ttl > 0) {
apply(ipv4_lpm);
apply(forward);
}
}
control egress {
if (standard_metadata.instance_type == 0) {
// regular packet: execute rewrites
apply(send_frame);
} else {
// cpu packet: encap
apply(send_to_cpu);
}
}

View File

@ -0,0 +1,306 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
<!--Created by yEd 3.14-->
<key attr.name="Description" attr.type="string" for="graph" id="d0"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
<key for="port" id="d3" yfiles.type="portuserdata"/>
<key attr.name="url" attr.type="string" for="node" id="d4"/>
<key attr.name="description" attr.type="string" for="node" id="d5"/>
<key for="node" id="d6" yfiles.type="nodegraphics"/>
<key for="graphml" id="d7" yfiles.type="resources"/>
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
<graph edgedefault="directed" id="G">
<data key="d0"/>
<node id="n0">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="107.0" width="144.0" x="685.0" y="215.0"/>
<y:Fill color="#FFCC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.296875" modelName="custom" textColor="#000000" visible="true" width="20.201171875" x="61.8994140625" y="43.3515625">s1<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n1">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="107.0" width="104.078125" x="969.0" y="215.0"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.296875" modelName="custom" textColor="#000000" visible="true" width="21.7802734375" x="41.14892578125" y="43.3515625">h2<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n2">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="107.0" width="104.078125" x="440.921875" y="215.0"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.296875" modelName="custom" textColor="#000000" visible="true" width="21.7802734375" x="41.14892578125" y="43.3515625">h1<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n3">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="47.0" width="144.0" x="685.0" y="426.0"/>
<y:Fill color="#FF00FF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.296875" modelName="custom" textColor="#000000" visible="true" width="81.916015625" x="31.0419921875" y="13.3515625">nat_app.py<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n4">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="153.0" x="680.5" y="402.5"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.296875" modelName="custom" textColor="#000000" visible="true" width="79.728515625" x="36.6357421875" y="4.8515625">cpu-veth-0<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n5">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="153.0" x="680.5" y="322.0"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="20.296875" modelName="custom" textColor="#000000" visible="true" width="139.5908203125" x="6.70458984375" y="4.8515625">cpu-veth-1, port 11<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n6">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="61.0" width="153.0" x="581.0" y="179.5"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="52.890625" modelName="custom" textColor="#000000" visible="true" width="133.7734375" x="9.61328125" y="4.0546875">port 1
00:aa:bb:00:00:04
10.0.0.1<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n7">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="61.0" width="153.0" x="776.0" y="179.5"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="52.890625" modelName="custom" textColor="#000000" visible="true" width="133.7734375" x="9.61328125" y="4.0546875">port 2
00:aa:bb:00:00:05
192.168.0.1<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n8">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.5" width="153.0" x="486.5" y="276.5"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.59375" modelName="custom" textColor="#000000" visible="true" width="134.470703125" x="9.2646484375" y="4.453125">00:04:00:00:00:10
10.0.0.10<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n9">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.5" width="153.0" x="872.5000000000001" y="276.5"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="14" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="36.59375" modelName="custom" textColor="#000000" visible="true" width="134.470703125" x="9.2646484375" y="4.453125">00:05:00:00:00:10
192.168.0.10<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n10">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="61.0" width="58.0" x="728.0" y="51.0"/>
<y:Fill hasColor="false" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="27.0" y="28.5">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n11">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="61.0" width="83.0" x="620.0" y="82.5"/>
<y:Fill hasColor="false" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.625" modelName="custom" textColor="#000000" visible="true" width="65.9453125" x="8.52734375" y="19.1875">Internal<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n12">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="61.0" width="83.0" x="811.0" y="82.5"/>
<y:Fill hasColor="false" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.625" modelName="custom" textColor="#000000" visible="true" width="70.6640625" x="6.16796875" y="19.1875">External<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<edge id="e0" source="n2" target="n0">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="2.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e1" source="n0" target="n1">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="2.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e2" source="n0" target="n3">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e3" source="n10" target="n0">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="dashed" width="2.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d7">
<y:Resources/>
</data>
</graphml>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

53
examples/simple_nat/run_demo.sh Executable file
View File

@ -0,0 +1,53 @@
#!/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.
if [[ $EUID -ne 0 ]]; then
echo "This script should be run using sudo or as the root user"
exit 1
fi
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
# create CPU port
intf0="cpu-veth-0"
intf1="cpu-veth-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
$P4C_BM_SCRIPT p4src/simple_nat.p4 --json simple_nat.json
PYTHONPATH=$PYTHONPATH:$BMV2_PATH/mininet/ python topo.py \
--behavioral-exe $BMV2_PATH/targets/simple_switch/simple_switch \
--json simple_nat.json \
--cli $CLI_PATH \
--thrift-port 22222

View File

@ -0,0 +1,9 @@
#!/bin/bash
THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
source $THIS_DIR/../env.sh
CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI
$CLI_PATH simple_nat.json 22222

113
examples/simple_nat/topo.py Normal file
View File

@ -0,0 +1,113 @@
#!/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, info
from mininet.cli import CLI
from mininet.link import TCLink, Intf
from p4_mininet import P4Switch, P4Host
import argparse
from time import sleep
import os
import subprocess
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)
parser.add_argument('--thrift-port', help='Thrift server port for table updates',
type=int, action="store", required=True)
args = parser.parse_args()
class MyTopo(Topo):
def __init__(self, sw_path, json_path, thrift_port, **opts):
# Initialize topology and default options
Topo.__init__(self, **opts)
switch = self.addSwitch('s1',
sw_path = sw_path,
json_path = json_path,
thrift_port = thrift_port,
pcap_dump = True)
# internal host
h1 = self.addHost('h1',
ip = "10.0.0.10",
mac = "00:04:00:00:00:10")
self.addLink(h1, switch)
# external host
h2 = self.addHost('h2',
ip = "192.168.0.10",
mac = "00:05:00:00:00:10")
self.addLink(h2, switch)
def main():
topo = MyTopo(args.behavioral_exe,
args.json,
args.thrift_port)
net = Mininet(topo = topo,
host = P4Host,
switch = P4Switch,
controller = None)
cpu_intf = Intf("cpu-veth-1", net.get('s1'), 11)
net.start()
sw_macs = ["00:aa:bb:00:00:04", "00:aa:bb:00:00:05"]
sw_addrs = ["10.0.0.1", "192.168.0.1"]
for n in xrange(2):
h = net.get('h%d' % (n + 1))
h.setARP(sw_addrs[n], sw_macs[n])
h.setDefaultRoute("dev eth0 via %s" % sw_addrs[n])
for n in xrange(2):
h = net.get('h%d' % (n + 1))
h.describe()
sleep(1)
cmd = [args.cli, args.json, str(args.thrift_port)]
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()