Skip to content

Commit d4932a8

Browse files
committed
added ternary match example
1 parent 3597fb1 commit d4932a8

File tree

7 files changed

+375
-43
lines changed

7 files changed

+375
-43
lines changed

examples/ternary_match/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Ternary Match Example
2+
3+
```
4+
+----+ +----+ +----+
5+
| h1 +-------+ s1 +---------+ h2 |
6+
+----+ +----+ +----+
7+
```
8+
9+
# Introduction
10+
11+
Very simple forwarding program that uses a ternary match. See `s1-commands.txt` to see
12+
how to populate tables with ternary matches using the CLI API. You will see that matches are
13+
of the form `value&mask`, for example: `0x00000000&&&0x80000000`, and the last action parameter
14+
is used as priority (lower better).
15+
16+
# How to run
17+
18+
To start the topology with the P4 switches:
19+
20+
```
21+
sudo p4run
22+
```
23+
24+
You can send packets and set different destination ip addresses to play with the program.
25+
26+
```
27+
mx h1
28+
python send.py
29+
```

examples/ternary_match/p4app.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"program": "ternary-match.p4",
3+
"switch": "simple_switch",
4+
"compiler": "p4c",
5+
"options": "--target bmv2 --arch v1model --std p4-16",
6+
"switch_cli": "simple_switch_CLI",
7+
"cli": true,
8+
"pcap_dump": true,
9+
"enable_log": true,
10+
"topo_module": {
11+
"file_path": "",
12+
"module_name": "p4utils.mininetlib.apptopo",
13+
"object_name": "AppTopo"
14+
},
15+
"controller_module": null,
16+
"topodb_module": {
17+
"file_path": "",
18+
"module_name": "p4utils.utils.topology",
19+
"object_name": "Topology"
20+
},
21+
"mininet_module": {
22+
"file_path": "",
23+
"module_name": "p4utils.mininetlib.p4net",
24+
"object_name": "P4Mininet"
25+
},
26+
"topology": {
27+
"assignment_strategy": "mixed",
28+
"links": [["h1", "s1"], ["h2", "s1"]],
29+
"hosts": {
30+
"h1": {
31+
},
32+
"h2": {
33+
}
34+
},
35+
"switches": {
36+
"s1": {
37+
"cli_input": "s1-commands.txt"
38+
}
39+
}
40+
}
41+
}

examples/ternary_match/run.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env bash
2+
3+
#run
4+
P4APPRUNNER=p4run
5+
sudo $P4APPRUNNER "$@"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
table_set_default ternary_table drop
2+
table_add ternary_table ipv4_forward 0x00000000&&&0x80000000 => 00:00:00:00:00:01 2 5
3+
table_add ternary_table ipv4_forward 0x80000000&&&0x80000000 => 00:00:00:00:00:02 2 4
4+
table_add ternary_table ipv4_forward 0x80000000&&&0xc0000000 => 00:00:00:00:00:03 2 3
5+
table_add ternary_table ipv4_forward 0xe0000000&&&0xe0000000 => 00:00:00:00:00:04 2 2
6+
table_add ternary_table ipv4_forward 0xa0000000&&&0xe0000000 => 00:00:00:00:00:05 2 1

examples/ternary_match/send.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env python
2+
import sys
3+
import socket
4+
import random
5+
from subprocess import Popen, PIPE
6+
import re
7+
8+
from scapy.all import sendp, get_if_list, get_if_hwaddr
9+
from scapy.all import Ether, IP, UDP, TCP
10+
11+
def get_if():
12+
ifs=get_if_list()
13+
iface=None # "h1-eth0"
14+
for i in get_if_list():
15+
if "eth0" in i:
16+
iface=i
17+
break;
18+
if not iface:
19+
print "Cannot find eth0 interface"
20+
exit(1)
21+
return iface
22+
23+
def get_dst_mac(ip):
24+
25+
try:
26+
pid = Popen(["arp", "-n", ip], stdout=PIPE)
27+
s = pid.communicate()[0]
28+
mac = re.search(r"(([a-f\d]{1,2}\:){5}[a-f\d]{1,2})", s).groups()[0]
29+
return mac
30+
except:
31+
return None
32+
33+
def main():
34+
35+
if len(sys.argv)<3:
36+
print 'pass 2 arguments: <destination> "<message>"'
37+
exit(1)
38+
39+
addr = socket.gethostbyname(sys.argv[1])
40+
iface = get_if()
41+
42+
if len(sys.argv) > 3:
43+
tos = int(sys.argv[3]) % 256
44+
else:
45+
tos = 0
46+
47+
#ether_dst = get_dst_mac(addr)
48+
49+
print "Sending on interface %s to %s" % (iface, str(addr))
50+
pkt = Ether(src=get_if_hwaddr(iface), dst="01:01:01:01:01:01")
51+
pkt = pkt /IP(dst=addr,tos=tos) / sys.argv[2]
52+
sendp(pkt, iface=iface, verbose=False)
53+
54+
55+
if __name__ == '__main__':
56+
main()
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/* -*- P4_16 -*- */
2+
#include <core.p4>
3+
#include <v1model.p4>
4+
5+
const bit<16> TYPE_IPV4 = 0x800;
6+
7+
/*************************************************************************
8+
*********************** H E A D E R S ***********************************
9+
*************************************************************************/
10+
11+
typedef bit<9> egressSpec_t;
12+
typedef bit<48> macAddr_t;
13+
typedef bit<32> ip4Addr_t;
14+
15+
header ethernet_t {
16+
macAddr_t dstAddr;
17+
macAddr_t srcAddr;
18+
bit<16> etherType;
19+
}
20+
21+
header ipv4_t {
22+
bit<4> version;
23+
bit<4> ihl;
24+
bit<8> diffserv;
25+
bit<16> totalLen;
26+
bit<16> identification;
27+
bit<3> flags;
28+
bit<13> fragOffset;
29+
bit<8> ttl;
30+
bit<8> protocol;
31+
bit<16> hdrChecksum;
32+
ip4Addr_t srcAddr;
33+
ip4Addr_t dstAddr;
34+
}
35+
36+
struct metadata {
37+
/* empty */
38+
}
39+
40+
struct headers {
41+
ethernet_t ethernet;
42+
ipv4_t ipv4;
43+
}
44+
45+
/*************************************************************************
46+
*********************** P A R S E R ***********************************
47+
*************************************************************************/
48+
49+
parser MyParser(packet_in packet,
50+
out headers hdr,
51+
inout metadata meta,
52+
inout standard_metadata_t standard_metadata) {
53+
54+
state start {
55+
56+
packet.extract(hdr.ethernet);
57+
transition select(hdr.ethernet.etherType){
58+
59+
TYPE_IPV4: ipv4;
60+
default: accept;
61+
62+
}
63+
64+
}
65+
66+
state ipv4 {
67+
68+
packet.extract(hdr.ipv4);
69+
transition accept;
70+
}
71+
72+
}
73+
74+
75+
/*************************************************************************
76+
************ C H E C K S U M V E R I F I C A T I O N *************
77+
*************************************************************************/
78+
79+
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
80+
apply { }
81+
}
82+
83+
84+
/*************************************************************************
85+
************** I N G R E S S P R O C E S S I N G *******************
86+
*************************************************************************/
87+
88+
control MyIngress(inout headers hdr,
89+
inout metadata meta,
90+
inout standard_metadata_t standard_metadata) {
91+
92+
action drop() {
93+
mark_to_drop(standard_metadata);
94+
}
95+
96+
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
97+
98+
//set the src mac address as the previous dst, this is not correct right?
99+
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
100+
101+
//set the destination mac address that we got from the match in the table
102+
hdr.ethernet.dstAddr = dstAddr;
103+
104+
//set the output port that we also get from the table
105+
standard_metadata.egress_spec = port;
106+
107+
//decrease ttl by 1
108+
hdr.ipv4.ttl = hdr.ipv4.ttl -1;
109+
}
110+
111+
table ternary_table {
112+
key = {
113+
hdr.ipv4.dstAddr: ternary;
114+
}
115+
actions = {
116+
ipv4_forward;
117+
drop;
118+
NoAction;
119+
}
120+
size = 1024;
121+
default_action = NoAction();
122+
}
123+
124+
apply {
125+
126+
//only if IPV4 the rule is applied. Therefore other packets will not be forwarded.
127+
if (hdr.ipv4.isValid()){
128+
ternary_table.apply();
129+
130+
}
131+
}
132+
}
133+
134+
/*************************************************************************
135+
**************** E G R E S S P R O C E S S I N G *******************
136+
*************************************************************************/
137+
138+
control MyEgress(inout headers hdr,
139+
inout metadata meta,
140+
inout standard_metadata_t standard_metadata) {
141+
apply { }
142+
}
143+
144+
/*************************************************************************
145+
************* C H E C K S U M C O M P U T A T I O N **************
146+
*************************************************************************/
147+
148+
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
149+
apply {
150+
update_checksum(
151+
hdr.ipv4.isValid(),
152+
{ hdr.ipv4.version,
153+
hdr.ipv4.ihl,
154+
hdr.ipv4.diffserv,
155+
hdr.ipv4.totalLen,
156+
hdr.ipv4.identification,
157+
hdr.ipv4.flags,
158+
hdr.ipv4.fragOffset,
159+
hdr.ipv4.ttl,
160+
hdr.ipv4.protocol,
161+
hdr.ipv4.srcAddr,
162+
hdr.ipv4.dstAddr },
163+
hdr.ipv4.hdrChecksum,
164+
HashAlgorithm.csum16);
165+
}
166+
}
167+
168+
169+
/*************************************************************************
170+
*********************** D E P A R S E R *******************************
171+
*************************************************************************/
172+
173+
control MyDeparser(packet_out packet, in headers hdr) {
174+
apply {
175+
176+
//parsed headers have to be added again into the packet.
177+
packet.emit(hdr.ethernet);
178+
packet.emit(hdr.ipv4);
179+
180+
}
181+
}
182+
183+
/*************************************************************************
184+
*********************** S W I T C H *******************************
185+
*************************************************************************/
186+
187+
//switch architecture
188+
V1Switch(
189+
MyParser(),
190+
MyVerifyChecksum(),
191+
MyIngress(),
192+
MyEgress(),
193+
MyComputeChecksum(),
194+
MyDeparser()
195+
) main;

0 commit comments

Comments
 (0)