aboutsummaryrefslogtreecommitdiffstats
path: root/samples/bpf
diff options
context:
space:
mode:
authorWilliam Tu <u9012063@gmail.com>2016-08-19 14:55:44 -0400
committerDavid S. Miller <davem@davemloft.net>2016-08-20 01:42:44 -0400
commit6afb1e28b8596443d72f82e085b4b2e8f410eae0 (patch)
tree5a29556ab856c6b7773b7387d5205cf7537f8556 /samples/bpf
parentc0b558e5a393b77d2fe53335b5e07ca0e77178f8 (diff)
samples/bpf: Add tunnel set/get tests.
The patch creates sample code exercising bpf_skb_{set,get}_tunnel_key, and bpf_skb_{set,get}_tunnel_opt for GRE, VXLAN, and GENEVE. A native tunnel device is created in a namespace to interact with a lwtunnel device out of the namespace, with metadata enabled. The bpf_skb_set_* program is attached to tc egress and bpf_skb_get_* is attached to egress qdisc. A ping between two tunnels is used to verify correctness and the result of bpf_skb_get_* printed by bpf_trace_printk. Signed-off-by: William Tu <u9012063@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'samples/bpf')
-rw-r--r--samples/bpf/Makefile1
-rw-r--r--samples/bpf/bpf_helpers.h8
-rw-r--r--samples/bpf/tcbpf2_kern.c191
-rwxr-xr-xsamples/bpf/test_tunnel_bpf.sh127
4 files changed, 327 insertions, 0 deletions
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index eb582c6264c3..db3cb061bfcd 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -67,6 +67,7 @@ always += tracex6_kern.o
67always += test_probe_write_user_kern.o 67always += test_probe_write_user_kern.o
68always += trace_output_kern.o 68always += trace_output_kern.o
69always += tcbpf1_kern.o 69always += tcbpf1_kern.o
70always += tcbpf2_kern.o
70always += lathist_kern.o 71always += lathist_kern.o
71always += offwaketime_kern.o 72always += offwaketime_kern.o
72always += spintest_kern.o 73always += spintest_kern.o
diff --git a/samples/bpf/bpf_helpers.h b/samples/bpf/bpf_helpers.h
index 6f1672a7254e..bbdf62a1e45e 100644
--- a/samples/bpf/bpf_helpers.h
+++ b/samples/bpf/bpf_helpers.h
@@ -47,6 +47,14 @@ static int (*bpf_probe_write_user)(void *dst, void *src, int size) =
47 (void *) BPF_FUNC_probe_write_user; 47 (void *) BPF_FUNC_probe_write_user;
48static int (*bpf_current_task_under_cgroup)(void *map, int index) = 48static int (*bpf_current_task_under_cgroup)(void *map, int index) =
49 (void *) BPF_FUNC_current_task_under_cgroup; 49 (void *) BPF_FUNC_current_task_under_cgroup;
50static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) =
51 (void *) BPF_FUNC_skb_get_tunnel_key;
52static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) =
53 (void *) BPF_FUNC_skb_set_tunnel_key;
54static int (*bpf_skb_get_tunnel_opt)(void *ctx, void *md, int size) =
55 (void *) BPF_FUNC_skb_get_tunnel_opt;
56static int (*bpf_skb_set_tunnel_opt)(void *ctx, void *md, int size) =
57 (void *) BPF_FUNC_skb_set_tunnel_opt;
50 58
51/* llvm builtin functions that eBPF C program may use to 59/* llvm builtin functions that eBPF C program may use to
52 * emit BPF_LD_ABS and BPF_LD_IND instructions 60 * emit BPF_LD_ABS and BPF_LD_IND instructions
diff --git a/samples/bpf/tcbpf2_kern.c b/samples/bpf/tcbpf2_kern.c
new file mode 100644
index 000000000000..7a15289da6cc
--- /dev/null
+++ b/samples/bpf/tcbpf2_kern.c
@@ -0,0 +1,191 @@
1/* Copyright (c) 2016 VMware
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 <uapi/linux/bpf.h>
8#include <uapi/linux/if_ether.h>
9#include <uapi/linux/if_packet.h>
10#include <uapi/linux/ip.h>
11#include <uapi/linux/in.h>
12#include <uapi/linux/tcp.h>
13#include <uapi/linux/filter.h>
14#include <uapi/linux/pkt_cls.h>
15#include "bpf_helpers.h"
16
17#define ERROR(ret) do {\
18 char fmt[] = "ERROR line:%d ret:%d\n";\
19 bpf_trace_printk(fmt, sizeof(fmt), __LINE__, ret); \
20 } while(0)
21
22struct geneve_opt {
23 __be16 opt_class;
24 u8 type;
25 u8 length:5;
26 u8 r3:1;
27 u8 r2:1;
28 u8 r1:1;
29 u8 opt_data[8]; /* hard-coded to 8 byte */
30};
31
32struct vxlan_metadata {
33 u32 gbp;
34};
35
36SEC("gre_set_tunnel")
37int _gre_set_tunnel(struct __sk_buff *skb)
38{
39 int ret;
40 struct bpf_tunnel_key key;
41
42 __builtin_memset(&key, 0x0, sizeof(key));
43 key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
44 key.tunnel_id = 2;
45 key.tunnel_tos = 0;
46 key.tunnel_ttl = 64;
47
48 ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), BPF_F_ZERO_CSUM_TX);
49 if (ret < 0) {
50 ERROR(ret);
51 return TC_ACT_SHOT;
52 }
53
54 return TC_ACT_OK;
55}
56
57SEC("gre_get_tunnel")
58int _gre_get_tunnel(struct __sk_buff *skb)
59{
60 int ret;
61 struct bpf_tunnel_key key;
62 char fmt[] = "key %d remote ip 0x%x\n";
63
64 ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
65 if (ret < 0) {
66 ERROR(ret);
67 return TC_ACT_SHOT;
68 }
69
70 bpf_trace_printk(fmt, sizeof(fmt), key.tunnel_id, key.remote_ipv4);
71 return TC_ACT_OK;
72}
73
74SEC("vxlan_set_tunnel")
75int _vxlan_set_tunnel(struct __sk_buff *skb)
76{
77 int ret;
78 struct bpf_tunnel_key key;
79 struct vxlan_metadata md;
80
81 __builtin_memset(&key, 0x0, sizeof(key));
82 key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
83 key.tunnel_id = 2;
84 key.tunnel_tos = 0;
85 key.tunnel_ttl = 64;
86
87 ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), BPF_F_ZERO_CSUM_TX);
88 if (ret < 0) {
89 ERROR(ret);
90 return TC_ACT_SHOT;
91 }
92
93 md.gbp = 0x800FF; /* Set VXLAN Group Policy extension */
94 ret = bpf_skb_set_tunnel_opt(skb, &md, sizeof(md));
95 if (ret < 0) {
96 ERROR(ret);
97 return TC_ACT_SHOT;
98 }
99
100 return TC_ACT_OK;
101}
102
103SEC("vxlan_get_tunnel")
104int _vxlan_get_tunnel(struct __sk_buff *skb)
105{
106 int ret;
107 struct bpf_tunnel_key key;
108 struct vxlan_metadata md;
109 char fmt[] = "key %d remote ip 0x%x vxlan gbp 0x%x\n";
110
111 ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
112 if (ret < 0) {
113 ERROR(ret);
114 return TC_ACT_SHOT;
115 }
116
117 ret = bpf_skb_get_tunnel_opt(skb, &md, sizeof(md));
118 if (ret < 0) {
119 ERROR(ret);
120 return TC_ACT_SHOT;
121 }
122
123 bpf_trace_printk(fmt, sizeof(fmt),
124 key.tunnel_id, key.remote_ipv4, md.gbp);
125
126 return TC_ACT_OK;
127}
128
129SEC("geneve_set_tunnel")
130int _geneve_set_tunnel(struct __sk_buff *skb)
131{
132 int ret, ret2;
133 struct bpf_tunnel_key key;
134 struct geneve_opt gopt;
135
136 __builtin_memset(&key, 0x0, sizeof(key));
137 key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */
138 key.tunnel_id = 2;
139 key.tunnel_tos = 0;
140 key.tunnel_ttl = 64;
141
142 __builtin_memset(&gopt, 0x0, sizeof(gopt));
143 gopt.opt_class = 0x102; /* Open Virtual Networking (OVN) */
144 gopt.type = 0x08;
145 gopt.r1 = 1;
146 gopt.r2 = 0;
147 gopt.r3 = 1;
148 gopt.length = 2; /* 4-byte multiple */
149 *(int *) &gopt.opt_data = 0xdeadbeef;
150
151 ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), BPF_F_ZERO_CSUM_TX);
152 if (ret < 0) {
153 ERROR(ret);
154 return TC_ACT_SHOT;
155 }
156
157 ret = bpf_skb_set_tunnel_opt(skb, &gopt, sizeof(gopt));
158 if (ret < 0) {
159 ERROR(ret);
160 return TC_ACT_SHOT;
161 }
162
163 return TC_ACT_OK;
164}
165
166SEC("geneve_get_tunnel")
167int _geneve_get_tunnel(struct __sk_buff *skb)
168{
169 int ret;
170 struct bpf_tunnel_key key;
171 struct geneve_opt gopt;
172 char fmt[] = "key %d remote ip 0x%x geneve class 0x%x\n";
173
174 ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0);
175 if (ret < 0) {
176 ERROR(ret);
177 return TC_ACT_SHOT;
178 }
179
180 ret = bpf_skb_get_tunnel_opt(skb, &gopt, sizeof(gopt));
181 if (ret < 0) {
182 ERROR(ret);
183 return TC_ACT_SHOT;
184 }
185
186 bpf_trace_printk(fmt, sizeof(fmt),
187 key.tunnel_id, key.remote_ipv4, gopt.opt_class);
188 return TC_ACT_OK;
189}
190
191char _license[] SEC("license") = "GPL";
diff --git a/samples/bpf/test_tunnel_bpf.sh b/samples/bpf/test_tunnel_bpf.sh
new file mode 100755
index 000000000000..4956589a83ae
--- /dev/null
+++ b/samples/bpf/test_tunnel_bpf.sh
@@ -0,0 +1,127 @@
1#!/bin/bash
2# In Namespace 0 (at_ns0) using native tunnel
3# Overlay IP: 10.1.1.100
4# local 192.16.1.100 remote 192.16.1.200
5# veth0 IP: 172.16.1.100, tunnel dev <type>00
6
7# Out of Namespace using BPF set/get on lwtunnel
8# Overlay IP: 10.1.1.200
9# local 172.16.1.200 remote 172.16.1.100
10# veth1 IP: 172.16.1.200, tunnel dev <type>11
11
12set -e
13
14function config_device {
15 ip netns add at_ns0
16 ip link add veth0 type veth peer name veth1
17 ip link set veth0 netns at_ns0
18 ip netns exec at_ns0 ip addr add 172.16.1.100/24 dev veth0
19 ip netns exec at_ns0 ip link set dev veth0 up
20 ip link set dev veth1 up
21 ip addr add dev veth1 172.16.1.200/24
22}
23
24function add_gre_tunnel {
25 # in namespace
26 ip netns exec at_ns0 \
27 ip link add dev $DEV_NS type $TYPE key 2 local 172.16.1.100 remote 172.16.1.200
28 ip netns exec at_ns0 ip link set dev $DEV_NS up
29 ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
30
31 # out of namespace
32 ip link add dev $DEV type $TYPE key 2 external
33 ip link set dev $DEV up
34 ip addr add dev $DEV 10.1.1.200/24
35}
36
37function add_vxlan_tunnel {
38 # Set static ARP entry here because iptables set-mark works
39 # on L3 packet, as a result not applying to ARP packets,
40 # causing errors at get_tunnel_{key/opt}.
41
42 # in namespace
43 ip netns exec at_ns0 \
44 ip link add dev $DEV_NS type $TYPE id 2 dstport 4789 gbp remote 172.16.1.200
45 ip netns exec at_ns0 ip link set dev $DEV_NS address 52:54:00:d9:01:00 up
46 ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
47 ip netns exec at_ns0 arp -s 10.1.1.200 52:54:00:d9:02:00
48 ip netns exec at_ns0 iptables -A OUTPUT -j MARK --set-mark 0x800FF
49
50 # out of namespace
51 ip link add dev $DEV type $TYPE external gbp dstport 4789
52 ip link set dev $DEV address 52:54:00:d9:02:00 up
53 ip addr add dev $DEV 10.1.1.200/24
54 arp -s 10.1.1.100 52:54:00:d9:01:00
55}
56
57function add_geneve_tunnel {
58 # in namespace
59 ip netns exec at_ns0 \
60 ip link add dev $DEV_NS type $TYPE id 2 dstport 6081 remote 172.16.1.200
61 ip netns exec at_ns0 ip link set dev $DEV_NS up
62 ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
63
64 # out of namespace
65 ip link add dev $DEV type $TYPE dstport 6081 external
66 ip link set dev $DEV up
67 ip addr add dev $DEV 10.1.1.200/24
68}
69
70function attach_bpf {
71 DEV=$1
72 SET_TUNNEL=$2
73 GET_TUNNEL=$3
74 tc qdisc add dev $DEV clsact
75 tc filter add dev $DEV egress bpf da obj tcbpf2_kern.o sec $SET_TUNNEL
76 tc filter add dev $DEV ingress bpf da obj tcbpf2_kern.o sec $GET_TUNNEL
77}
78
79function test_gre {
80 TYPE=gretap
81 DEV_NS=gretap00
82 DEV=gretap11
83 config_device
84 add_gre_tunnel
85 attach_bpf $DEV gre_set_tunnel gre_get_tunnel
86 ping -c 1 10.1.1.100
87 ip netns exec at_ns0 ping -c 1 10.1.1.200
88}
89
90function test_vxlan {
91 TYPE=vxlan
92 DEV_NS=vxlan00
93 DEV=vxlan11
94 config_device
95 add_vxlan_tunnel
96 attach_bpf $DEV vxlan_set_tunnel vxlan_get_tunnel
97 ping -c 1 10.1.1.100
98 ip netns exec at_ns0 ping -c 1 10.1.1.200
99}
100
101function test_geneve {
102 TYPE=geneve
103 DEV_NS=geneve00
104 DEV=geneve11
105 config_device
106 add_geneve_tunnel
107 attach_bpf $DEV geneve_set_tunnel geneve_get_tunnel
108 ping -c 1 10.1.1.100
109 ip netns exec at_ns0 ping -c 1 10.1.1.200
110}
111
112function cleanup {
113 ip netns delete at_ns0
114 ip link del veth1
115 ip link del $DEV
116}
117
118echo "Testing GRE tunnel..."
119test_gre
120cleanup
121echo "Testing VXLAN tunnel..."
122test_vxlan
123cleanup
124echo "Testing GENEVE tunnel..."
125test_geneve
126cleanup
127echo "Success"