summaryrefslogtreecommitdiffstats
path: root/samples
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@fb.com>2016-05-05 22:49:14 -0400
committerDavid S. Miller <davem@davemloft.net>2016-05-06 16:01:54 -0400
commit65d472fb007dd73ef28f70078f43f86bb6cc67d0 (patch)
tree200d4b5fa31fe985d21d4c27f6a5ebcc7c3b3ae7 /samples
parentf9c8d19d6c7c15a59963f80ec47e68808914abd4 (diff)
samples/bpf: add 'pointer to packet' tests
parse_simple.c - packet parser exapmle with single length check that filters out udp packets for port 9 parse_varlen.c - variable length parser that understand multiple vlan headers, ipip, ipip6 and ip options to filter out udp or tcp packets on port 9. The packet is parsed layer by layer with multitple length checks. parse_ldabs.c - classic style of packet parsing using LD_ABS instruction. Same functionality as parse_simple. simple = 24.1Mpps per core varlen = 22.7Mpps ldabs = 21.4Mpps Parser with LD_ABS instructions is slower than full direct access parser which does more packet accesses and checks. These examples demonstrate the choice bpf program authors can make between flexibility of the parser vs speed. Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'samples')
-rw-r--r--samples/bpf/Makefile2
-rw-r--r--samples/bpf/parse_ldabs.c41
-rw-r--r--samples/bpf/parse_simple.c48
-rw-r--r--samples/bpf/parse_varlen.c153
-rwxr-xr-xsamples/bpf/test_cls_bpf.sh37
5 files changed, 281 insertions, 0 deletions
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 66897e61232c..0bf2478cb7df 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -60,6 +60,7 @@ always += spintest_kern.o
60always += map_perf_test_kern.o 60always += map_perf_test_kern.o
61always += test_overhead_tp_kern.o 61always += test_overhead_tp_kern.o
62always += test_overhead_kprobe_kern.o 62always += test_overhead_kprobe_kern.o
63always += parse_varlen.o parse_simple.o parse_ldabs.o
63 64
64HOSTCFLAGS += -I$(objtree)/usr/include 65HOSTCFLAGS += -I$(objtree)/usr/include
65 66
@@ -120,4 +121,5 @@ $(src)/*.c: verify_target_bpf
120$(obj)/%.o: $(src)/%.c 121$(obj)/%.o: $(src)/%.c
121 $(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) \ 122 $(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) \
122 -D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \ 123 -D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
124 -Wno-compare-distinct-pointer-types \
123 -O2 -emit-llvm -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@ 125 -O2 -emit-llvm -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@
diff --git a/samples/bpf/parse_ldabs.c b/samples/bpf/parse_ldabs.c
new file mode 100644
index 000000000000..d17550198d06
--- /dev/null
+++ b/samples/bpf/parse_ldabs.c
@@ -0,0 +1,41 @@
1/* Copyright (c) 2016 Facebook
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#include <linux/ip.h>
8#include <linux/ipv6.h>
9#include <linux/in.h>
10#include <linux/tcp.h>
11#include <linux/udp.h>
12#include <uapi/linux/bpf.h>
13#include "bpf_helpers.h"
14
15#define DEFAULT_PKTGEN_UDP_PORT 9
16#define IP_MF 0x2000
17#define IP_OFFSET 0x1FFF
18
19static inline int ip_is_fragment(struct __sk_buff *ctx, __u64 nhoff)
20{
21 return load_half(ctx, nhoff + offsetof(struct iphdr, frag_off))
22 & (IP_MF | IP_OFFSET);
23}
24
25SEC("ldabs")
26int handle_ingress(struct __sk_buff *skb)
27{
28 __u64 troff = ETH_HLEN + sizeof(struct iphdr);
29
30 if (load_half(skb, offsetof(struct ethhdr, h_proto)) != ETH_P_IP)
31 return 0;
32 if (load_byte(skb, ETH_HLEN + offsetof(struct iphdr, protocol)) != IPPROTO_UDP ||
33 load_byte(skb, ETH_HLEN) != 0x45)
34 return 0;
35 if (ip_is_fragment(skb, ETH_HLEN))
36 return 0;
37 if (load_half(skb, troff + offsetof(struct udphdr, dest)) == DEFAULT_PKTGEN_UDP_PORT)
38 return TC_ACT_SHOT;
39 return 0;
40}
41char _license[] SEC("license") = "GPL";
diff --git a/samples/bpf/parse_simple.c b/samples/bpf/parse_simple.c
new file mode 100644
index 000000000000..cf2511c33905
--- /dev/null
+++ b/samples/bpf/parse_simple.c
@@ -0,0 +1,48 @@
1/* Copyright (c) 2016 Facebook
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#include <linux/ip.h>
8#include <linux/ipv6.h>
9#include <linux/in.h>
10#include <linux/tcp.h>
11#include <linux/udp.h>
12#include <uapi/linux/bpf.h>
13#include <net/ip.h>
14#include "bpf_helpers.h"
15
16#define DEFAULT_PKTGEN_UDP_PORT 9
17
18/* copy of 'struct ethhdr' without __packed */
19struct eth_hdr {
20 unsigned char h_dest[ETH_ALEN];
21 unsigned char h_source[ETH_ALEN];
22 unsigned short h_proto;
23};
24
25SEC("simple")
26int handle_ingress(struct __sk_buff *skb)
27{
28 void *data = (void *)(long)skb->data;
29 struct eth_hdr *eth = data;
30 struct iphdr *iph = data + sizeof(*eth);
31 struct udphdr *udp = data + sizeof(*eth) + sizeof(*iph);
32 void *data_end = (void *)(long)skb->data_end;
33
34 /* single length check */
35 if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*udp) > data_end)
36 return 0;
37
38 if (eth->h_proto != htons(ETH_P_IP))
39 return 0;
40 if (iph->protocol != IPPROTO_UDP || iph->ihl != 5)
41 return 0;
42 if (ip_is_fragment(iph))
43 return 0;
44 if (udp->dest == htons(DEFAULT_PKTGEN_UDP_PORT))
45 return TC_ACT_SHOT;
46 return 0;
47}
48char _license[] SEC("license") = "GPL";
diff --git a/samples/bpf/parse_varlen.c b/samples/bpf/parse_varlen.c
new file mode 100644
index 000000000000..edab34dce79b
--- /dev/null
+++ b/samples/bpf/parse_varlen.c
@@ -0,0 +1,153 @@
1/* Copyright (c) 2016 Facebook
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#include <linux/if_ether.h>
8#include <linux/ip.h>
9#include <linux/ipv6.h>
10#include <linux/in.h>
11#include <linux/tcp.h>
12#include <linux/udp.h>
13#include <uapi/linux/bpf.h>
14#include <net/ip.h>
15#include "bpf_helpers.h"
16
17#define DEFAULT_PKTGEN_UDP_PORT 9
18#define DEBUG 0
19
20static int tcp(void *data, uint64_t tp_off, void *data_end)
21{
22 struct tcphdr *tcp = data + tp_off;
23
24 if (tcp + 1 > data_end)
25 return 0;
26 if (tcp->dest == htons(80) || tcp->source == htons(80))
27 return TC_ACT_SHOT;
28 return 0;
29}
30
31static int udp(void *data, uint64_t tp_off, void *data_end)
32{
33 struct udphdr *udp = data + tp_off;
34
35 if (udp + 1 > data_end)
36 return 0;
37 if (udp->dest == htons(DEFAULT_PKTGEN_UDP_PORT) ||
38 udp->source == htons(DEFAULT_PKTGEN_UDP_PORT)) {
39 if (DEBUG) {
40 char fmt[] = "udp port 9 indeed\n";
41
42 bpf_trace_printk(fmt, sizeof(fmt));
43 }
44 return TC_ACT_SHOT;
45 }
46 return 0;
47}
48
49static int parse_ipv4(void *data, uint64_t nh_off, void *data_end)
50{
51 struct iphdr *iph;
52 uint64_t ihl_len;
53
54 iph = data + nh_off;
55 if (iph + 1 > data_end)
56 return 0;
57
58 if (ip_is_fragment(iph))
59 return 0;
60 ihl_len = iph->ihl * 4;
61
62 if (iph->protocol == IPPROTO_IPIP) {
63 iph = data + nh_off + ihl_len;
64 if (iph + 1 > data_end)
65 return 0;
66 ihl_len += iph->ihl * 4;
67 }
68
69 if (iph->protocol == IPPROTO_TCP)
70 return tcp(data, nh_off + ihl_len, data_end);
71 else if (iph->protocol == IPPROTO_UDP)
72 return udp(data, nh_off + ihl_len, data_end);
73 return 0;
74}
75
76static int parse_ipv6(void *data, uint64_t nh_off, void *data_end)
77{
78 struct ipv6hdr *ip6h;
79 struct iphdr *iph;
80 uint64_t ihl_len = sizeof(struct ipv6hdr);
81 uint64_t nexthdr;
82
83 ip6h = data + nh_off;
84 if (ip6h + 1 > data_end)
85 return 0;
86
87 nexthdr = ip6h->nexthdr;
88
89 if (nexthdr == IPPROTO_IPIP) {
90 iph = data + nh_off + ihl_len;
91 if (iph + 1 > data_end)
92 return 0;
93 ihl_len += iph->ihl * 4;
94 nexthdr = iph->protocol;
95 } else if (nexthdr == IPPROTO_IPV6) {
96 ip6h = data + nh_off + ihl_len;
97 if (ip6h + 1 > data_end)
98 return 0;
99 ihl_len += sizeof(struct ipv6hdr);
100 nexthdr = ip6h->nexthdr;
101 }
102
103 if (nexthdr == IPPROTO_TCP)
104 return tcp(data, nh_off + ihl_len, data_end);
105 else if (nexthdr == IPPROTO_UDP)
106 return udp(data, nh_off + ihl_len, data_end);
107 return 0;
108}
109
110struct vlan_hdr {
111 uint16_t h_vlan_TCI;
112 uint16_t h_vlan_encapsulated_proto;
113};
114
115SEC("varlen")
116int handle_ingress(struct __sk_buff *skb)
117{
118 void *data = (void *)(long)skb->data;
119 struct ethhdr *eth = data;
120 void *data_end = (void *)(long)skb->data_end;
121 uint64_t h_proto, nh_off;
122
123 nh_off = sizeof(*eth);
124 if (data + nh_off > data_end)
125 return 0;
126
127 h_proto = eth->h_proto;
128
129 if (h_proto == ETH_P_8021Q || h_proto == ETH_P_8021AD) {
130 struct vlan_hdr *vhdr;
131
132 vhdr = data + nh_off;
133 nh_off += sizeof(struct vlan_hdr);
134 if (data + nh_off > data_end)
135 return 0;
136 h_proto = vhdr->h_vlan_encapsulated_proto;
137 }
138 if (h_proto == ETH_P_8021Q || h_proto == ETH_P_8021AD) {
139 struct vlan_hdr *vhdr;
140
141 vhdr = data + nh_off;
142 nh_off += sizeof(struct vlan_hdr);
143 if (data + nh_off > data_end)
144 return 0;
145 h_proto = vhdr->h_vlan_encapsulated_proto;
146 }
147 if (h_proto == htons(ETH_P_IP))
148 return parse_ipv4(data, nh_off, data_end);
149 else if (h_proto == htons(ETH_P_IPV6))
150 return parse_ipv6(data, nh_off, data_end);
151 return 0;
152}
153char _license[] SEC("license") = "GPL";
diff --git a/samples/bpf/test_cls_bpf.sh b/samples/bpf/test_cls_bpf.sh
new file mode 100755
index 000000000000..0365d5ee512c
--- /dev/null
+++ b/samples/bpf/test_cls_bpf.sh
@@ -0,0 +1,37 @@
1#!/bin/bash
2
3function pktgen {
4 ../pktgen/pktgen_bench_xmit_mode_netif_receive.sh -i $IFC -s 64 \
5 -m 90:e2:ba:ff:ff:ff -d 192.168.0.1 -t 4
6 local dropped=`tc -s qdisc show dev $IFC | tail -3 | awk '/drop/{print $7}'`
7 if [ "$dropped" == "0," ]; then
8 echo "FAIL"
9 else
10 echo "Successfully filtered " $dropped " packets"
11 fi
12}
13
14function test {
15 echo -n "Loading bpf program '$2'... "
16 tc qdisc add dev $IFC clsact
17 tc filter add dev $IFC ingress bpf da obj $1 sec $2
18 local status=$?
19 if [ $status -ne 0 ]; then
20 echo "FAIL"
21 else
22 echo "ok"
23 pktgen
24 fi
25 tc qdisc del dev $IFC clsact
26}
27
28IFC=test_veth
29
30ip link add name $IFC type veth peer name pair_$IFC
31ip link set $IFC up
32ip link set pair_$IFC up
33
34test ./parse_simple.o simple
35test ./parse_varlen.o varlen
36test ./parse_ldabs.o ldabs
37ip link del dev $IFC