1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 
3 /*
4  * End-to-end eBPF tunnel test suite
5  *   The file tests BPF network tunnel implementation.
6  *
7  * Topology:
8  * ---------
9  *     root namespace   |     at_ns0 namespace
10  *                       |
11  *       -----------     |     -----------
12  *       | tnl dev |     |     | tnl dev |  (overlay network)
13  *       -----------     |     -----------
14  *       metadata-mode   |     metadata-mode
15  *        with bpf       |       with bpf
16  *                       |
17  *       ----------      |     ----------
18  *       |  veth1  | --------- |  veth0  |  (underlay network)
19  *       ----------    peer    ----------
20  *
21  *
22  *  Device Configuration
23  *  --------------------
24  *  root namespace with metadata-mode tunnel + BPF
25  *  Device names and addresses:
26  *	veth1 IP 1: 172.16.1.200, IPv6: 00::22 (underlay)
27  *		IP 2: 172.16.1.20, IPv6: 00::bb (underlay)
28  *	tunnel dev <type>11, ex: gre11, IPv4: 10.1.1.200, IPv6: 1::22 (overlay)
29  *
30  *  Namespace at_ns0 with native tunnel
31  *  Device names and addresses:
32  *	veth0 IPv4: 172.16.1.100, IPv6: 00::11 (underlay)
33  *	tunnel dev <type>00, ex: gre00, IPv4: 10.1.1.100, IPv6: 1::11 (overlay)
34  *
35  *
36  * End-to-end ping packet flow
37  *  ---------------------------
38  *  Most of the tests start by namespace creation, device configuration,
39  *  then ping the underlay and overlay network.  When doing 'ping 10.1.1.100'
40  *  from root namespace, the following operations happen:
41  *  1) Route lookup shows 10.1.1.100/24 belongs to tnl dev, fwd to tnl dev.
42  *  2) Tnl device's egress BPF program is triggered and set the tunnel metadata,
43  *     with local_ip=172.16.1.200, remote_ip=172.16.1.100. BPF program choose
44  *     the primary or secondary ip of veth1 as the local ip of tunnel. The
45  *     choice is made based on the value of bpf map local_ip_map.
46  *  3) Outer tunnel header is prepended and route the packet to veth1's egress.
47  *  4) veth0's ingress queue receive the tunneled packet at namespace at_ns0.
48  *  5) Tunnel protocol handler, ex: vxlan_rcv, decap the packet.
49  *  6) Forward the packet to the overlay tnl dev.
50  */
51 
52 #include <arpa/inet.h>
53 #include <linux/if_tun.h>
54 #include <linux/limits.h>
55 #include <linux/sysctl.h>
56 #include <linux/time_types.h>
57 #include <linux/net_tstamp.h>
58 #include <net/if.h>
59 #include <stdbool.h>
60 #include <stdio.h>
61 #include <sys/stat.h>
62 #include <unistd.h>
63 
64 #include "test_progs.h"
65 #include "network_helpers.h"
66 #include "test_tunnel_kern.skel.h"
67 
68 #define IP4_ADDR_VETH0 "172.16.1.100"
69 #define IP4_ADDR1_VETH1 "172.16.1.200"
70 #define IP4_ADDR2_VETH1 "172.16.1.20"
71 #define IP4_ADDR_TUNL_DEV0 "10.1.1.100"
72 #define IP4_ADDR_TUNL_DEV1 "10.1.1.200"
73 
74 #define IP6_ADDR_VETH0 "::11"
75 #define IP6_ADDR1_VETH1 "::22"
76 #define IP6_ADDR2_VETH1 "::bb"
77 
78 #define IP4_ADDR1_HEX_VETH1 0xac1001c8
79 #define IP4_ADDR2_HEX_VETH1 0xac100114
80 #define IP6_ADDR1_HEX_VETH1 0x22
81 #define IP6_ADDR2_HEX_VETH1 0xbb
82 
83 #define MAC_TUNL_DEV0 "52:54:00:d9:01:00"
84 #define MAC_TUNL_DEV1 "52:54:00:d9:02:00"
85 #define MAC_VETH1 "52:54:00:d9:03:00"
86 
87 #define VXLAN_TUNL_DEV0 "vxlan00"
88 #define VXLAN_TUNL_DEV1 "vxlan11"
89 #define IP6VXLAN_TUNL_DEV0 "ip6vxlan00"
90 #define IP6VXLAN_TUNL_DEV1 "ip6vxlan11"
91 
92 #define PING_ARGS "-i 0.01 -c 3 -w 10 -q"
93 
94 #define SYS(fmt, ...)						\
95 	({							\
96 		char cmd[1024];					\
97 		snprintf(cmd, sizeof(cmd), fmt, ##__VA_ARGS__);	\
98 		if (!ASSERT_OK(system(cmd), cmd))		\
99 			goto fail;				\
100 	})
101 
102 #define SYS_NOFAIL(fmt, ...)					\
103 	({							\
104 		char cmd[1024];					\
105 		snprintf(cmd, sizeof(cmd), fmt, ##__VA_ARGS__);	\
106 		system(cmd);					\
107 	})
108 
109 static int config_device(void)
110 {
111 	SYS("ip netns add at_ns0");
112 	SYS("ip link add veth0 address " MAC_VETH1 " type veth peer name veth1");
113 	SYS("ip link set veth0 netns at_ns0");
114 	SYS("ip addr add " IP4_ADDR1_VETH1 "/24 dev veth1");
115 	SYS("ip link set dev veth1 up mtu 1500");
116 	SYS("ip netns exec at_ns0 ip addr add " IP4_ADDR_VETH0 "/24 dev veth0");
117 	SYS("ip netns exec at_ns0 ip link set dev veth0 up mtu 1500");
118 
119 	return 0;
120 fail:
121 	return -1;
122 }
123 
124 static void cleanup(void)
125 {
126 	SYS_NOFAIL("test -f /var/run/netns/at_ns0 && ip netns delete at_ns0");
127 	SYS_NOFAIL("ip link del veth1 2> /dev/null");
128 	SYS_NOFAIL("ip link del %s 2> /dev/null", VXLAN_TUNL_DEV1);
129 	SYS_NOFAIL("ip link del %s 2> /dev/null", IP6VXLAN_TUNL_DEV1);
130 }
131 
132 static int add_vxlan_tunnel(void)
133 {
134 	/* at_ns0 namespace */
135 	SYS("ip netns exec at_ns0 ip link add dev %s type vxlan external gbp dstport 4789",
136 	    VXLAN_TUNL_DEV0);
137 	SYS("ip netns exec at_ns0 ip link set dev %s address %s up",
138 	    VXLAN_TUNL_DEV0, MAC_TUNL_DEV0);
139 	SYS("ip netns exec at_ns0 ip addr add dev %s %s/24",
140 	    VXLAN_TUNL_DEV0, IP4_ADDR_TUNL_DEV0);
141 	SYS("ip netns exec at_ns0 ip neigh add %s lladdr %s dev %s",
142 	    IP4_ADDR_TUNL_DEV1, MAC_TUNL_DEV1, VXLAN_TUNL_DEV0);
143 	SYS("ip netns exec at_ns0 ip neigh add %s lladdr %s dev veth0",
144 	    IP4_ADDR2_VETH1, MAC_VETH1);
145 
146 	/* root namespace */
147 	SYS("ip link add dev %s type vxlan external gbp dstport 4789",
148 	    VXLAN_TUNL_DEV1);
149 	SYS("ip link set dev %s address %s up", VXLAN_TUNL_DEV1, MAC_TUNL_DEV1);
150 	SYS("ip addr add dev %s %s/24", VXLAN_TUNL_DEV1, IP4_ADDR_TUNL_DEV1);
151 	SYS("ip neigh add %s lladdr %s dev %s",
152 	    IP4_ADDR_TUNL_DEV0, MAC_TUNL_DEV0, VXLAN_TUNL_DEV1);
153 
154 	return 0;
155 fail:
156 	return -1;
157 }
158 
159 static void delete_vxlan_tunnel(void)
160 {
161 	SYS_NOFAIL("ip netns exec at_ns0 ip link delete dev %s",
162 		   VXLAN_TUNL_DEV0);
163 	SYS_NOFAIL("ip link delete dev %s", VXLAN_TUNL_DEV1);
164 }
165 
166 static int add_ip6vxlan_tunnel(void)
167 {
168 	SYS("ip netns exec at_ns0 ip -6 addr add %s/96 dev veth0",
169 	    IP6_ADDR_VETH0);
170 	SYS("ip netns exec at_ns0 ip link set dev veth0 up");
171 	SYS("ip -6 addr add %s/96 dev veth1", IP6_ADDR1_VETH1);
172 	SYS("ip -6 addr add %s/96 dev veth1", IP6_ADDR2_VETH1);
173 	SYS("ip link set dev veth1 up");
174 
175 	/* at_ns0 namespace */
176 	SYS("ip netns exec at_ns0 ip link add dev %s type vxlan external dstport 4789",
177 	    IP6VXLAN_TUNL_DEV0);
178 	SYS("ip netns exec at_ns0 ip addr add dev %s %s/24",
179 	    IP6VXLAN_TUNL_DEV0, IP4_ADDR_TUNL_DEV0);
180 	SYS("ip netns exec at_ns0 ip link set dev %s address %s up",
181 	    IP6VXLAN_TUNL_DEV0, MAC_TUNL_DEV0);
182 
183 	/* root namespace */
184 	SYS("ip link add dev %s type vxlan external dstport 4789",
185 	    IP6VXLAN_TUNL_DEV1);
186 	SYS("ip addr add dev %s %s/24", IP6VXLAN_TUNL_DEV1, IP4_ADDR_TUNL_DEV1);
187 	SYS("ip link set dev %s address %s up",
188 	    IP6VXLAN_TUNL_DEV1, MAC_TUNL_DEV1);
189 
190 	return 0;
191 fail:
192 	return -1;
193 }
194 
195 static void delete_ip6vxlan_tunnel(void)
196 {
197 	SYS_NOFAIL("ip netns exec at_ns0 ip -6 addr delete %s/96 dev veth0",
198 		   IP6_ADDR_VETH0);
199 	SYS_NOFAIL("ip -6 addr delete %s/96 dev veth1", IP6_ADDR1_VETH1);
200 	SYS_NOFAIL("ip -6 addr delete %s/96 dev veth1", IP6_ADDR2_VETH1);
201 	SYS_NOFAIL("ip netns exec at_ns0 ip link delete dev %s",
202 		   IP6VXLAN_TUNL_DEV0);
203 	SYS_NOFAIL("ip link delete dev %s", IP6VXLAN_TUNL_DEV1);
204 }
205 
206 static int test_ping(int family, const char *addr)
207 {
208 	SYS("%s %s %s > /dev/null", ping_command(family), PING_ARGS, addr);
209 	return 0;
210 fail:
211 	return -1;
212 }
213 
214 static int attach_tc_prog(struct bpf_tc_hook *hook, int igr_fd, int egr_fd)
215 {
216 	DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts1, .handle = 1,
217 			    .priority = 1, .prog_fd = igr_fd);
218 	DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts2, .handle = 1,
219 			    .priority = 1, .prog_fd = egr_fd);
220 	int ret;
221 
222 	ret = bpf_tc_hook_create(hook);
223 	if (!ASSERT_OK(ret, "create tc hook"))
224 		return ret;
225 
226 	if (igr_fd >= 0) {
227 		hook->attach_point = BPF_TC_INGRESS;
228 		ret = bpf_tc_attach(hook, &opts1);
229 		if (!ASSERT_OK(ret, "bpf_tc_attach")) {
230 			bpf_tc_hook_destroy(hook);
231 			return ret;
232 		}
233 	}
234 
235 	if (egr_fd >= 0) {
236 		hook->attach_point = BPF_TC_EGRESS;
237 		ret = bpf_tc_attach(hook, &opts2);
238 		if (!ASSERT_OK(ret, "bpf_tc_attach")) {
239 			bpf_tc_hook_destroy(hook);
240 			return ret;
241 		}
242 	}
243 
244 	return 0;
245 }
246 
247 static void test_vxlan_tunnel(void)
248 {
249 	struct test_tunnel_kern *skel = NULL;
250 	struct nstoken *nstoken;
251 	int local_ip_map_fd = -1;
252 	int set_src_prog_fd, get_src_prog_fd;
253 	int set_dst_prog_fd;
254 	int key = 0, ifindex = -1;
255 	uint local_ip;
256 	int err;
257 	DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook,
258 			    .attach_point = BPF_TC_INGRESS);
259 
260 	/* add vxlan tunnel */
261 	err = add_vxlan_tunnel();
262 	if (!ASSERT_OK(err, "add vxlan tunnel"))
263 		goto done;
264 
265 	/* load and attach bpf prog to tunnel dev tc hook point */
266 	skel = test_tunnel_kern__open_and_load();
267 	if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load"))
268 		goto done;
269 	ifindex = if_nametoindex(VXLAN_TUNL_DEV1);
270 	if (!ASSERT_NEQ(ifindex, 0, "vxlan11 ifindex"))
271 		goto done;
272 	tc_hook.ifindex = ifindex;
273 	get_src_prog_fd = bpf_program__fd(skel->progs.vxlan_get_tunnel_src);
274 	set_src_prog_fd = bpf_program__fd(skel->progs.vxlan_set_tunnel_src);
275 	if (!ASSERT_GE(get_src_prog_fd, 0, "bpf_program__fd"))
276 		goto done;
277 	if (!ASSERT_GE(set_src_prog_fd, 0, "bpf_program__fd"))
278 		goto done;
279 	if (attach_tc_prog(&tc_hook, get_src_prog_fd, set_src_prog_fd))
280 		goto done;
281 
282 	/* load and attach bpf prog to veth dev tc hook point */
283 	ifindex = if_nametoindex("veth1");
284 	if (!ASSERT_NEQ(ifindex, 0, "veth1 ifindex"))
285 		goto done;
286 	tc_hook.ifindex = ifindex;
287 	set_dst_prog_fd = bpf_program__fd(skel->progs.veth_set_outer_dst);
288 	if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd"))
289 		goto done;
290 	if (attach_tc_prog(&tc_hook, set_dst_prog_fd, -1))
291 		goto done;
292 
293 	/* load and attach prog set_md to tunnel dev tc hook point at_ns0 */
294 	nstoken = open_netns("at_ns0");
295 	if (!ASSERT_OK_PTR(nstoken, "setns src"))
296 		goto done;
297 	ifindex = if_nametoindex(VXLAN_TUNL_DEV0);
298 	if (!ASSERT_NEQ(ifindex, 0, "vxlan00 ifindex"))
299 		goto done;
300 	tc_hook.ifindex = ifindex;
301 	set_dst_prog_fd = bpf_program__fd(skel->progs.vxlan_set_tunnel_dst);
302 	if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd"))
303 		goto done;
304 	if (attach_tc_prog(&tc_hook, -1, set_dst_prog_fd))
305 		goto done;
306 	close_netns(nstoken);
307 
308 	/* use veth1 ip 2 as tunnel source ip */
309 	local_ip_map_fd = bpf_map__fd(skel->maps.local_ip_map);
310 	if (!ASSERT_GE(local_ip_map_fd, 0, "bpf_map__fd"))
311 		goto done;
312 	local_ip = IP4_ADDR2_HEX_VETH1;
313 	err = bpf_map_update_elem(local_ip_map_fd, &key, &local_ip, BPF_ANY);
314 	if (!ASSERT_OK(err, "update bpf local_ip_map"))
315 		goto done;
316 
317 	/* ping test */
318 	err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV0);
319 	if (!ASSERT_OK(err, "test_ping"))
320 		goto done;
321 
322 done:
323 	/* delete vxlan tunnel */
324 	delete_vxlan_tunnel();
325 	if (local_ip_map_fd >= 0)
326 		close(local_ip_map_fd);
327 	if (skel)
328 		test_tunnel_kern__destroy(skel);
329 }
330 
331 static void test_ip6vxlan_tunnel(void)
332 {
333 	struct test_tunnel_kern *skel = NULL;
334 	struct nstoken *nstoken;
335 	int local_ip_map_fd = -1;
336 	int set_src_prog_fd, get_src_prog_fd;
337 	int set_dst_prog_fd;
338 	int key = 0, ifindex = -1;
339 	uint local_ip;
340 	int err;
341 	DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook,
342 			    .attach_point = BPF_TC_INGRESS);
343 
344 	/* add vxlan tunnel */
345 	err = add_ip6vxlan_tunnel();
346 	if (!ASSERT_OK(err, "add_ip6vxlan_tunnel"))
347 		goto done;
348 
349 	/* load and attach bpf prog to tunnel dev tc hook point */
350 	skel = test_tunnel_kern__open_and_load();
351 	if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load"))
352 		goto done;
353 	ifindex = if_nametoindex(IP6VXLAN_TUNL_DEV1);
354 	if (!ASSERT_NEQ(ifindex, 0, "ip6vxlan11 ifindex"))
355 		goto done;
356 	tc_hook.ifindex = ifindex;
357 	get_src_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_get_tunnel_src);
358 	set_src_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_set_tunnel_src);
359 	if (!ASSERT_GE(set_src_prog_fd, 0, "bpf_program__fd"))
360 		goto done;
361 	if (!ASSERT_GE(get_src_prog_fd, 0, "bpf_program__fd"))
362 		goto done;
363 	if (attach_tc_prog(&tc_hook, get_src_prog_fd, set_src_prog_fd))
364 		goto done;
365 
366 	/* load and attach prog set_md to tunnel dev tc hook point at_ns0 */
367 	nstoken = open_netns("at_ns0");
368 	if (!ASSERT_OK_PTR(nstoken, "setns src"))
369 		goto done;
370 	ifindex = if_nametoindex(IP6VXLAN_TUNL_DEV0);
371 	if (!ASSERT_NEQ(ifindex, 0, "ip6vxlan00 ifindex"))
372 		goto done;
373 	tc_hook.ifindex = ifindex;
374 	set_dst_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_set_tunnel_dst);
375 	if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd"))
376 		goto done;
377 	if (attach_tc_prog(&tc_hook, -1, set_dst_prog_fd))
378 		goto done;
379 	close_netns(nstoken);
380 
381 	/* use veth1 ip 2 as tunnel source ip */
382 	local_ip_map_fd = bpf_map__fd(skel->maps.local_ip_map);
383 	if (!ASSERT_GE(local_ip_map_fd, 0, "get local_ip_map fd"))
384 		goto done;
385 	local_ip = IP6_ADDR2_HEX_VETH1;
386 	err = bpf_map_update_elem(local_ip_map_fd, &key, &local_ip, BPF_ANY);
387 	if (!ASSERT_OK(err, "update bpf local_ip_map"))
388 		goto done;
389 
390 	/* ping test */
391 	err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV0);
392 	if (!ASSERT_OK(err, "test_ping"))
393 		goto done;
394 
395 done:
396 	/* delete ipv6 vxlan tunnel */
397 	delete_ip6vxlan_tunnel();
398 	if (local_ip_map_fd >= 0)
399 		close(local_ip_map_fd);
400 	if (skel)
401 		test_tunnel_kern__destroy(skel);
402 }
403 
404 #define RUN_TEST(name)							\
405 	({								\
406 		if (test__start_subtest(#name)) {			\
407 			test_ ## name();				\
408 		}							\
409 	})
410 
411 static void *test_tunnel_run_tests(void *arg)
412 {
413 	cleanup();
414 	config_device();
415 
416 	RUN_TEST(vxlan_tunnel);
417 	RUN_TEST(ip6vxlan_tunnel);
418 
419 	cleanup();
420 
421 	return NULL;
422 }
423 
424 void test_tunnel(void)
425 {
426 	pthread_t test_thread;
427 	int err;
428 
429 	/* Run the tests in their own thread to isolate the namespace changes
430 	 * so they do not affect the environment of other tests.
431 	 * (specifically needed because of unshare(CLONE_NEWNS) in open_netns())
432 	 */
433 	err = pthread_create(&test_thread, NULL, &test_tunnel_run_tests, NULL);
434 	if (ASSERT_OK(err, "pthread_create"))
435 		ASSERT_OK(pthread_join(test_thread, NULL), "pthread_join");
436 }
437