diff options
author | Willem de Bruijn <willemb@google.com> | 2019-03-22 14:32:51 -0400 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2019-03-22 16:52:44 -0400 |
commit | ef81bd054942e2bd8289c91a3528e6fc0ca26c1c (patch) | |
tree | bc86962f5146e23b8ab0b88db564d7da6ef8d13e | |
parent | ccd34cd3577dd6e244269bb8ccfab228360aa53d (diff) |
selftests/bpf: expand bpf tunnel test to ipv6
The test only uses ipv4 so far, expand to ipv6.
This is mostly a boilerplate near copy of the ipv4 path.
Signed-off-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
-rw-r--r-- | tools/testing/selftests/bpf/config | 2 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/progs/test_tc_tunnel.c | 116 | ||||
-rwxr-xr-x | tools/testing/selftests/bpf/test_tc_tunnel.sh | 53 |
3 files changed, 149 insertions, 22 deletions
diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 37f947ec44ed..a42f4fc4dc11 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config | |||
@@ -23,3 +23,5 @@ CONFIG_LWTUNNEL=y | |||
23 | CONFIG_BPF_STREAM_PARSER=y | 23 | CONFIG_BPF_STREAM_PARSER=y |
24 | CONFIG_XDP_SOCKETS=y | 24 | CONFIG_XDP_SOCKETS=y |
25 | CONFIG_FTRACE_SYSCALLS=y | 25 | CONFIG_FTRACE_SYSCALLS=y |
26 | CONFIG_IPV6_TUNNEL=y | ||
27 | CONFIG_IPV6_GRE=y | ||
diff --git a/tools/testing/selftests/bpf/progs/test_tc_tunnel.c b/tools/testing/selftests/bpf/progs/test_tc_tunnel.c index 25db148635ab..591f540ce513 100644 --- a/tools/testing/selftests/bpf/progs/test_tc_tunnel.c +++ b/tools/testing/selftests/bpf/progs/test_tc_tunnel.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/if_ether.h> | 7 | #include <linux/if_ether.h> |
8 | #include <linux/in.h> | 8 | #include <linux/in.h> |
9 | #include <linux/ip.h> | 9 | #include <linux/ip.h> |
10 | #include <linux/ipv6.h> | ||
10 | #include <linux/tcp.h> | 11 | #include <linux/tcp.h> |
11 | #include <linux/pkt_cls.h> | 12 | #include <linux/pkt_cls.h> |
12 | #include <linux/types.h> | 13 | #include <linux/types.h> |
@@ -31,15 +32,11 @@ static __always_inline void set_ipv4_csum(struct iphdr *iph) | |||
31 | iph->check = ~((csum & 0xffff) + (csum >> 16)); | 32 | iph->check = ~((csum & 0xffff) + (csum >> 16)); |
32 | } | 33 | } |
33 | 34 | ||
34 | SEC("encap") | 35 | static int encap_ipv4(struct __sk_buff *skb) |
35 | int encap_f(struct __sk_buff *skb) | ||
36 | { | 36 | { |
37 | struct iphdr iph_outer, iph_inner; | 37 | struct iphdr iph_outer, iph_inner; |
38 | struct tcphdr tcph; | 38 | struct tcphdr tcph; |
39 | 39 | ||
40 | if (skb->protocol != __bpf_constant_htons(ETH_P_IP)) | ||
41 | return TC_ACT_OK; | ||
42 | |||
43 | if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_inner, | 40 | if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_inner, |
44 | sizeof(iph_inner)) < 0) | 41 | sizeof(iph_inner)) < 0) |
45 | return TC_ACT_OK; | 42 | return TC_ACT_OK; |
@@ -80,35 +77,118 @@ int encap_f(struct __sk_buff *skb) | |||
80 | return TC_ACT_OK; | 77 | return TC_ACT_OK; |
81 | } | 78 | } |
82 | 79 | ||
83 | SEC("decap") | 80 | static int encap_ipv6(struct __sk_buff *skb) |
84 | int decap_f(struct __sk_buff *skb) | ||
85 | { | 81 | { |
86 | struct iphdr iph_outer, iph_inner; | 82 | struct ipv6hdr iph_outer, iph_inner; |
83 | struct tcphdr tcph; | ||
87 | 84 | ||
88 | if (skb->protocol != __bpf_constant_htons(ETH_P_IP)) | 85 | if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_inner, |
86 | sizeof(iph_inner)) < 0) | ||
89 | return TC_ACT_OK; | 87 | return TC_ACT_OK; |
90 | 88 | ||
91 | if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_outer, | 89 | /* filter only packets we want */ |
92 | sizeof(iph_outer)) < 0) | 90 | if (bpf_skb_load_bytes(skb, ETH_HLEN + sizeof(iph_inner), |
91 | &tcph, sizeof(tcph)) < 0) | ||
93 | return TC_ACT_OK; | 92 | return TC_ACT_OK; |
94 | 93 | ||
95 | if (iph_outer.ihl != 5 || iph_outer.protocol != IPPROTO_IPIP) | 94 | if (tcph.dest != __bpf_constant_htons(cfg_port)) |
95 | return TC_ACT_OK; | ||
96 | |||
97 | /* add room between mac and network header */ | ||
98 | if (bpf_skb_adjust_room(skb, sizeof(iph_outer), BPF_ADJ_ROOM_NET, 0)) | ||
99 | return TC_ACT_SHOT; | ||
100 | |||
101 | /* prepare new outer network header */ | ||
102 | iph_outer = iph_inner; | ||
103 | iph_outer.nexthdr = IPPROTO_IPV6; | ||
104 | iph_outer.payload_len = bpf_htons(sizeof(iph_outer) + | ||
105 | bpf_ntohs(iph_outer.payload_len)); | ||
106 | |||
107 | /* store new outer network header */ | ||
108 | if (bpf_skb_store_bytes(skb, ETH_HLEN, &iph_outer, sizeof(iph_outer), | ||
109 | BPF_F_INVALIDATE_HASH) < 0) | ||
110 | return TC_ACT_SHOT; | ||
111 | |||
112 | /* bpf_skb_adjust_room has moved header to start of room: restore */ | ||
113 | if (bpf_skb_store_bytes(skb, ETH_HLEN + sizeof(iph_outer), | ||
114 | &iph_inner, sizeof(iph_inner), | ||
115 | BPF_F_INVALIDATE_HASH) < 0) | ||
116 | return TC_ACT_SHOT; | ||
117 | |||
118 | return TC_ACT_OK; | ||
119 | } | ||
120 | |||
121 | SEC("encap") | ||
122 | int encap_f(struct __sk_buff *skb) | ||
123 | { | ||
124 | switch (skb->protocol) { | ||
125 | case __bpf_constant_htons(ETH_P_IP): | ||
126 | return encap_ipv4(skb); | ||
127 | case __bpf_constant_htons(ETH_P_IPV6): | ||
128 | return encap_ipv6(skb); | ||
129 | default: | ||
130 | /* does not match, ignore */ | ||
96 | return TC_ACT_OK; | 131 | return TC_ACT_OK; |
132 | } | ||
133 | } | ||
97 | 134 | ||
98 | if (bpf_skb_load_bytes(skb, ETH_HLEN + sizeof(iph_outer), | 135 | static int decap_internal(struct __sk_buff *skb, int off, int len) |
99 | &iph_inner, sizeof(iph_inner)) < 0) | 136 | { |
137 | char buf[sizeof(struct ipv6hdr)]; | ||
138 | |||
139 | if (bpf_skb_load_bytes(skb, off + len, &buf, len) < 0) | ||
100 | return TC_ACT_OK; | 140 | return TC_ACT_OK; |
101 | 141 | ||
102 | if (bpf_skb_adjust_room(skb, -(int)sizeof(iph_outer), | 142 | if (bpf_skb_adjust_room(skb, -len, BPF_ADJ_ROOM_NET, 0)) |
103 | BPF_ADJ_ROOM_NET, 0)) | ||
104 | return TC_ACT_SHOT; | 143 | return TC_ACT_SHOT; |
105 | 144 | ||
106 | /* bpf_skb_adjust_room has moved outer over inner header: restore */ | 145 | /* bpf_skb_adjust_room has moved outer over inner header: restore */ |
107 | if (bpf_skb_store_bytes(skb, ETH_HLEN, &iph_inner, sizeof(iph_inner), | 146 | if (bpf_skb_store_bytes(skb, off, buf, len, BPF_F_INVALIDATE_HASH) < 0) |
108 | BPF_F_INVALIDATE_HASH) < 0) | ||
109 | return TC_ACT_SHOT; | 147 | return TC_ACT_SHOT; |
110 | 148 | ||
111 | return TC_ACT_OK; | 149 | return TC_ACT_OK; |
112 | } | 150 | } |
113 | 151 | ||
152 | static int decap_ipv4(struct __sk_buff *skb) | ||
153 | { | ||
154 | struct iphdr iph_outer; | ||
155 | |||
156 | if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_outer, | ||
157 | sizeof(iph_outer)) < 0) | ||
158 | return TC_ACT_OK; | ||
159 | |||
160 | if (iph_outer.ihl != 5 || iph_outer.protocol != IPPROTO_IPIP) | ||
161 | return TC_ACT_OK; | ||
162 | |||
163 | return decap_internal(skb, ETH_HLEN, sizeof(iph_outer)); | ||
164 | } | ||
165 | |||
166 | static int decap_ipv6(struct __sk_buff *skb) | ||
167 | { | ||
168 | struct ipv6hdr iph_outer; | ||
169 | |||
170 | if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph_outer, | ||
171 | sizeof(iph_outer)) < 0) | ||
172 | return TC_ACT_OK; | ||
173 | |||
174 | if (iph_outer.nexthdr != IPPROTO_IPV6) | ||
175 | return TC_ACT_OK; | ||
176 | |||
177 | return decap_internal(skb, ETH_HLEN, sizeof(iph_outer)); | ||
178 | } | ||
179 | |||
180 | SEC("decap") | ||
181 | int decap_f(struct __sk_buff *skb) | ||
182 | { | ||
183 | switch (skb->protocol) { | ||
184 | case __bpf_constant_htons(ETH_P_IP): | ||
185 | return decap_ipv4(skb); | ||
186 | case __bpf_constant_htons(ETH_P_IPV6): | ||
187 | return decap_ipv6(skb); | ||
188 | default: | ||
189 | /* does not match, ignore */ | ||
190 | return TC_ACT_OK; | ||
191 | } | ||
192 | } | ||
193 | |||
114 | char __license[] SEC("license") = "GPL"; | 194 | char __license[] SEC("license") = "GPL"; |
diff --git a/tools/testing/selftests/bpf/test_tc_tunnel.sh b/tools/testing/selftests/bpf/test_tc_tunnel.sh index 91151d91e5a1..7b1758f3006b 100755 --- a/tools/testing/selftests/bpf/test_tc_tunnel.sh +++ b/tools/testing/selftests/bpf/test_tc_tunnel.sh | |||
@@ -12,6 +12,9 @@ readonly ns2="${ns_prefix}2" | |||
12 | 12 | ||
13 | readonly ns1_v4=192.168.1.1 | 13 | readonly ns1_v4=192.168.1.1 |
14 | readonly ns2_v4=192.168.1.2 | 14 | readonly ns2_v4=192.168.1.2 |
15 | readonly ns1_v6=fd::1 | ||
16 | readonly ns2_v6=fd::2 | ||
17 | |||
15 | 18 | ||
16 | setup() { | 19 | setup() { |
17 | ip netns add "${ns1}" | 20 | ip netns add "${ns1}" |
@@ -25,6 +28,8 @@ setup() { | |||
25 | 28 | ||
26 | ip -netns "${ns1}" -4 addr add "${ns1_v4}/24" dev veth1 | 29 | ip -netns "${ns1}" -4 addr add "${ns1_v4}/24" dev veth1 |
27 | ip -netns "${ns2}" -4 addr add "${ns2_v4}/24" dev veth2 | 30 | ip -netns "${ns2}" -4 addr add "${ns2_v4}/24" dev veth2 |
31 | ip -netns "${ns1}" -6 addr add "${ns1_v6}/64" dev veth1 nodad | ||
32 | ip -netns "${ns2}" -6 addr add "${ns2_v6}/64" dev veth2 nodad | ||
28 | 33 | ||
29 | sleep 1 | 34 | sleep 1 |
30 | } | 35 | } |
@@ -35,16 +40,56 @@ cleanup() { | |||
35 | } | 40 | } |
36 | 41 | ||
37 | server_listen() { | 42 | server_listen() { |
38 | ip netns exec "${ns2}" nc -l -p "${port}" & | 43 | ip netns exec "${ns2}" nc "${netcat_opt}" -l -p "${port}" & |
39 | sleep 0.2 | 44 | sleep 0.2 |
40 | } | 45 | } |
41 | 46 | ||
42 | client_connect() { | 47 | client_connect() { |
43 | ip netns exec "${ns1}" nc -z -w 1 "${ns2_v4}" "${port}" | 48 | ip netns exec "${ns1}" nc "${netcat_opt}" -z -w 1 "${addr2}" "${port}" |
44 | echo $? | 49 | echo $? |
45 | } | 50 | } |
46 | 51 | ||
47 | set -e | 52 | set -e |
53 | |||
54 | # no arguments: automated test, run all | ||
55 | if [[ "$#" -eq "0" ]]; then | ||
56 | echo "ipip" | ||
57 | $0 ipv4 | ||
58 | |||
59 | echo "ip6ip6" | ||
60 | $0 ipv6 | ||
61 | |||
62 | echo "OK. All tests passed" | ||
63 | exit 0 | ||
64 | fi | ||
65 | |||
66 | if [[ "$#" -ne "1" ]]; then | ||
67 | echo "Usage: $0" | ||
68 | echo " or: $0 <ipv4|ipv6>" | ||
69 | exit 1 | ||
70 | fi | ||
71 | |||
72 | case "$1" in | ||
73 | "ipv4") | ||
74 | readonly tuntype=ipip | ||
75 | readonly addr1="${ns1_v4}" | ||
76 | readonly addr2="${ns2_v4}" | ||
77 | readonly netcat_opt=-4 | ||
78 | ;; | ||
79 | "ipv6") | ||
80 | readonly tuntype=ip6tnl | ||
81 | readonly addr1="${ns1_v6}" | ||
82 | readonly addr2="${ns2_v6}" | ||
83 | readonly netcat_opt=-6 | ||
84 | ;; | ||
85 | *) | ||
86 | echo "unknown arg: $1" | ||
87 | exit 1 | ||
88 | ;; | ||
89 | esac | ||
90 | |||
91 | echo "encap ${addr1} to ${addr2}, type ${tuntype}" | ||
92 | |||
48 | trap cleanup EXIT | 93 | trap cleanup EXIT |
49 | 94 | ||
50 | setup | 95 | setup |
@@ -66,8 +111,8 @@ server_listen | |||
66 | # serverside, insert decap module | 111 | # serverside, insert decap module |
67 | # server is still running | 112 | # server is still running |
68 | # client can connect again | 113 | # client can connect again |
69 | ip netns exec "${ns2}" ip link add dev testtun0 type ipip \ | 114 | ip netns exec "${ns2}" ip link add dev testtun0 type "${tuntype}" \ |
70 | remote "${ns1_v4}" local "${ns2_v4}" | 115 | remote "${addr1}" local "${addr2}" |
71 | ip netns exec "${ns2}" ip link set dev testtun0 up | 116 | ip netns exec "${ns2}" ip link set dev testtun0 up |
72 | echo "test bpf encap with tunnel device decap" | 117 | echo "test bpf encap with tunnel device decap" |
73 | client_connect | 118 | client_connect |