-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add digest example that redirects a packet and sends a digest message that contains the source mac address and the ingress port (port where the packet arrived)
- Loading branch information
1 parent
4b21de6
commit 6ac97e2
Showing
12 changed files
with
1,212 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
## call with make PROG=xxx to build | ||
## make PROG=xxx clean|generate|realclean | ||
# | ||
## Argument for the CLANG compiler | ||
CLANG ?= clang | ||
P4C_PNA_P4TC ?= p4c-pna-p4tc | ||
PROG ?= digest | ||
#we need to have a headers package instead of this.. | ||
INCLUDES= -I../include | ||
# Optimization flags to save space | ||
CFLAGS+= -O2 -g -c -D__KERNEL__ -D__ASM_SYSREG_H -DBTF \ | ||
-Wno-unused-value -Wno-pointer-sign \ | ||
-Wno-compare-distinct-pointer-types \ | ||
-Wno-gnu-variable-sized-type-not-at-end \ | ||
-Wno-address-of-packed-member -Wno-tautological-compare \ | ||
-Wno-unknown-warning-option -Wnoparentheses-equality | ||
|
||
TMPL+=generated/$(PROG).template | ||
TMPL+=generated/$(PROG).json | ||
SRCS+=generated/$(PROG)_parser.c | ||
SRCS+=generated/$(PROG)_control_blocks.c | ||
OBJS=$(SRCS:.c=.o) | ||
all: $(OBJS) | ||
|
||
$(OBJS): %.o : %.c | ||
$(CLANG) $(CFLAGS) $(INCLUDES) --target=bpf -mcpu=probe -c $< -o $@ | ||
|
||
generate: | ||
$(P4C_PNA_P4TC) $(PROG).p4 -o generated/ | ||
|
||
clean: | ||
rm -f $(OBJS) | ||
|
||
realclean: | ||
rm -f $(OBJS) $(SRCS) $(TMPL) $(PROG)_parser.h |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,253 @@ | ||
# digest | ||
|
||
The *digest* program first parses ethernet <u>ipv4</u> packets. Any other packets are | ||
rejected. After the parser recognizes an ipv4 packet, the src ip address is used as a lookup | ||
key for table *nh_table*. On a table hit, the programmed action *send_nh(port, srcMac, dstMac)* instance is executed. | ||
The action first sets the src and destination mac address, then redirects the packet to a specified port, sets the ingress_port, sets `send_digest` to true and redirects the packet. On a table miss the packet is simply dropped. | ||
`my_ingress_metadata_t` will hold the port on where the packet arrived and `send_digest`. `send_digest` signals to the deparser to send a digest message to user space. This digest message will hold the source mac address and the port where the packet arrived: | ||
|
||
``` | ||
struct mac_learn_digest_t { | ||
@tc_type("macaddr") bit<48> srcAddr; | ||
@tc_type("dev") PortId_t ingress_port; | ||
}; | ||
``` | ||
|
||
## Setup Requirements | ||
|
||
Make sure that the p4node basic container has already been created at this point(as per instructions found in [p4node](https://github.com/p4tc-dev/p4tc-examples-pub.git)). To run the sample described setup here requires 4 terminals, three terminals inside the container and one on the VM side to generate traffic. | ||
|
||
### Terminal 1 (observation of tc commands on p4node). | ||
|
||
Enter the container p4node: | ||
|
||
`sudo ip netns exec p4node /bin/bash` | ||
|
||
setup path for TC binary | ||
|
||
`TC="/usr/sbin/tc"` | ||
|
||
setup the path to where the json introspection file can be found.. | ||
|
||
``` | ||
cd /home/vagrant/p4tc-examples-pub/digest/generated | ||
export INTROSPECTION=. | ||
``` | ||
run TC monitor: | ||
`$TC mon p4 events` | ||
|
||
### Terminal 2 (observation of p4 digest events on p4node). | ||
|
||
First enter the container and make sure you have the introspection path setup | ||
|
||
Enter the container p4node: | ||
|
||
`sudo ip netns exec p4node /bin/bash` | ||
|
||
setup path for TC binary | ||
|
||
`TC="/usr/sbin/tc"` | ||
|
||
setup the path to where the json introspection file can be found.. | ||
|
||
``` | ||
cd /home/vagrant/p4tc-examples-pub/digest/generated | ||
export INTROSPECTION=. | ||
``` | ||
|
||
run TC monitor for digest events: | ||
`$TC mon p4 digest` | ||
|
||
### Terminal 3 (observes incoming traffic into p4node) | ||
|
||
First enter the container and make sure you have the introspection path setup | ||
|
||
`sudo ip netns exec p4node /bin/bash` | ||
|
||
Now let's listen to traffic on port0 | ||
|
||
``` | ||
DEV=port0 | ||
tcpdump -n -i $DEV -e | ||
``` | ||
|
||
### Terminal 4 (to instantiate and runtime control the program) | ||
|
||
We will run commands to first load the prog and then do required runtime setup. | ||
|
||
First enter the container | ||
|
||
``` | ||
sudo ip netns exec p4node /bin/bash | ||
cd /home/vagrant/p4tc-examples-pub/digest | ||
``` | ||
|
||
``` | ||
modprobe ext_Digest | ||
``` | ||
|
||
Compile the parser and control blocks programs if you have not already | ||
|
||
`make` | ||
|
||
Make sure you have the introspection path setup and load the *digest* program | ||
|
||
``` | ||
cd generated | ||
export INTROSPECTION=. | ||
TC="/usr/sbin/tc" | ||
./digest.template | ||
``` | ||
|
||
now instantiate the prog | ||
|
||
``` | ||
$TC filter add block 21 ingress protocol all prio 10 p4 pname digest \ | ||
action bpf obj digest_parser.o section p4tc/parse \ | ||
action bpf obj digest_control_blocks.o section p4tc/main | ||
``` | ||
|
||
### Terminal 5 (on the VM side) | ||
|
||
Try sending a message of packets which will be dropped by the parser (observe tcpdump on terminal 3).. | ||
|
||
`ping -I p4port0 10.0.1.2 -c 1` | ||
|
||
Let's check some stats, below shows 3 packets dropped by the parser on <u>terminal 3</u>: | ||
|
||
``` | ||
$TC -s filter ls block 21 ingress | ||
filter protocol all pref 10 p4 chain 0 | ||
filter protocol all pref 10 p4 chain 0 handle 0x1 pname digest | ||
action order 1: bpf digest_parser.o:[p4tc/parse] id 92 name tc_parse_func tag 1bd66321c5ad54e4 jited default-action pipe | ||
index 1 ref 1 bind 1 installed 590 sec used 293 sec firstused 295 sec | ||
Action statistics: | ||
Sent 84 bytes 3 pkt (dropped 3, overlimits 0 requeues 0) | ||
backlog 0b 0p requeues 0 | ||
action order 2: bpf digest_control_blocks.o:[p4tc/main] id 94 name tc_ingress_func tag 42e6e971daa41152 jited default-action pipe | ||
index 2 ref 1 bind 1 installed 590 sec used 590 sec | ||
Action statistics: | ||
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) | ||
backlog 0b 0p requeues 0 | ||
``` | ||
|
||
Ok, back on <u>terminal 4</u> let's create an entry to match on the dst address *10.0.0.2* and rewrite the src mac to *00:01:02:03:04:05* and dst mac *06:07:08:09:11:12* then send out on *port1* - watch <u>terminal 1</u> for events. | ||
|
||
``` | ||
$TC p4ctrl create digest/table/ingress/nh_table \ | ||
dstAddr 10.0.0.2 \ | ||
action send_nh param port port1 param srcMac 06:07:08:09:11:12 param dstMac 00:01:02:03:04:05 | ||
``` | ||
|
||
On <u>terminal 4</u> watch *port1* traffic (recall that you are watching incoming traffic on <u>terminal 2</u> on *port0*): | ||
|
||
`tcpdump -n -i port1 -e` | ||
|
||
Now you can see the rewritten mac address when you generate traffic on terminal 5 as follows: | ||
|
||
``` | ||
cd /home/vagrant/p4tc-examples-pub/digest | ||
sudo ../../sendpacket/sendpacket.py ./testpkt.yml | ||
``` | ||
|
||
On <u>terminal 2</u> look for the digest event | ||
|
||
## General help on runtime CLI | ||
|
||
First just dump all possible tables in this program | ||
|
||
*$TC p4ctrl create digest/table help* | ||
|
||
``` | ||
Tables for pipeline digest: | ||
table name ingress/nh_table | ||
table id 1 | ||
``` | ||
|
||
As we can see, there is only one with a path ingress/nh_table | ||
|
||
Now let's get help on the *create* command for this table: | ||
|
||
*$TC p4ctrl create digest/table/ingress/nh_table help* | ||
|
||
``` | ||
Key fields for table nh_table: | ||
key name dstAddr | ||
key id 1 | ||
key type ipv4 | ||
key match type exact | ||
Actions for table nh_table: | ||
act name ingress/send_nh | ||
act id 1 | ||
Params for ingress/send_nh: | ||
param name port | ||
param id 1 | ||
param type dev | ||
param name srcMac | ||
param id 2 | ||
param type macaddr | ||
param name dstMac | ||
param id 3 | ||
param type macaddr | ||
act name ingress/drop | ||
act id 2 | ||
``` | ||
|
||
Above is indicating the table has a key called dstAddr which is of type ipv4 address and that it takes one action: | ||
- *send_nh* which takes 3 params 1)*port*, a linux netdev 2) *srcMac*, a mac address 3) *dstMac*, also a mac address | ||
|
||
And help on the *delete* command: | ||
|
||
*$TC p4ctrl delete digest/table/ingress/nh_table help* | ||
|
||
``` | ||
Key fields for table nh_table: | ||
key name dstAddr | ||
key id 1 | ||
key type ipv4 | ||
key match type exact | ||
``` | ||
|
||
This shows the key name "dstAddr" as an exact IPv4 address. | ||
Example to delete the entry we created: | ||
|
||
*$TC p4ctrl delete digest/table/ingress/nh_table dstAddr 10.0.0.2* | ||
|
||
And to delete/flush the whole table: | ||
|
||
*$TC p4ctrl delete digest/table/ingress/nh_table | ||
|
||
And help on the *get* command: | ||
|
||
*$TC p4ctrl get digest/table/ingress/nh_table help* | ||
|
||
``` | ||
Key fields for table nh_table: | ||
key name dstAddr | ||
key id 1 | ||
key type ipv4 | ||
key match type exact | ||
``` | ||
|
||
This shows the key name "dstAddr" as an exact IPv4 address. | ||
For example to retrieve the entry we created using our key of 10.0.0.2: | ||
|
||
*$TC p4ctrl get digest/table/ingress/nh_table dstAddr 10.0.0.2* | ||
|
||
Note, we can dump the whole table as such: | ||
|
||
*$TC p4ctrl get digest/table/ingress/nh_table* | ||
|
||
|
||
To cleanup | ||
---------- | ||
To clean up you need to run the following script on Terminal 4, where the template was installed and the program was instantiated: | ||
|
||
`./digest.purge` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* -*- P4_16 -*- */ | ||
|
||
#include <core.p4> | ||
#include <tc/pna.p4> | ||
#include "digest_metadata.p4" | ||
#include "digest_parser.p4" | ||
|
||
#define L3_TABLE_SIZE 2048 | ||
|
||
struct mac_learn_digest_t { | ||
@tc_type("macaddr") bit<48> srcAddr; | ||
@tc_type("dev") PortId_t ingress_port; | ||
}; | ||
|
||
/***************** M A T C H - A C T I O N *********************/ | ||
|
||
control ingress( | ||
inout my_ingress_headers_t hdr, | ||
inout my_ingress_metadata_t meta, | ||
in pna_main_input_metadata_t istd, | ||
inout pna_main_output_metadata_t ostd | ||
) | ||
{ | ||
action send_nh(@tc_type("dev") PortId_t port, @tc_type("macaddr") bit<48> srcMac, @tc_type("macaddr") bit<48> dstMac) { | ||
hdr.ethernet.srcAddr = srcMac; | ||
hdr.ethernet.dstAddr = dstMac; | ||
meta.ingress_port = istd.input_port; | ||
meta.send_digest = true; | ||
send_to_port(port); | ||
} | ||
|
||
action drop() { | ||
drop_packet(); | ||
} | ||
|
||
table nh_table { | ||
key = { | ||
hdr.ipv4.dstAddr : exact @tc_type("ipv4") @name("dstAddr"); | ||
} | ||
actions = { | ||
send_nh; | ||
drop; | ||
} | ||
size = L3_TABLE_SIZE; | ||
const default_action = drop; | ||
} | ||
|
||
apply { | ||
if (hdr.ipv4.isValid()) { | ||
nh_table.apply(); | ||
} | ||
} | ||
} | ||
|
||
/********************* D E P A R S E R ************************/ | ||
|
||
control Ingress_Deparser( | ||
packet_out pkt, | ||
inout my_ingress_headers_t hdr, | ||
in my_ingress_metadata_t meta, | ||
in pna_main_output_metadata_t ostd) | ||
{ | ||
Digest<mac_learn_digest_t>() digest_inst; | ||
|
||
apply { | ||
pkt.emit(hdr.ethernet); | ||
pkt.emit(hdr.ipv4); | ||
if (meta.send_digest) { | ||
mac_learn_digest_t mac_learn_digest; | ||
mac_learn_digest.srcAddr = hdr.ethernet.srcAddr; | ||
mac_learn_digest.ingress_port = meta.ingress_port; | ||
digest_inst.pack(mac_learn_digest); | ||
} | ||
} | ||
} | ||
|
||
/************ F I N A L P A C K A G E ******************************/ | ||
|
||
PNA_NIC( | ||
Ingress_Parser(), | ||
ingress(), | ||
Ingress_Deparser() | ||
) main; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/* -*- P4_16 -*- */ | ||
|
||
/****** G L O B A L I N G R E S S M E T A D A T A *********/ | ||
|
||
struct my_ingress_metadata_t { | ||
@tc_type("dev") PortId_t ingress_port; | ||
bool send_digest; | ||
} |
Oops, something went wrong.