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_link.h>
54#include <linux/if_tun.h>
55#include <linux/limits.h>
56#include <linux/sysctl.h>
57#include <linux/time_types.h>
58#include <linux/net_tstamp.h>
59#include <net/if.h>
60#include <stdbool.h>
61#include <stdio.h>
62#include <sys/stat.h>
63#include <unistd.h>
64
65#include "test_progs.h"
66#include "network_helpers.h"
67#include "test_tunnel_kern.skel.h"
68
69#define IP4_ADDR_VETH0 "172.16.1.100"
70#define IP4_ADDR1_VETH1 "172.16.1.200"
71#define IP4_ADDR2_VETH1 "172.16.1.20"
72#define IP4_ADDR_TUNL_DEV0 "10.1.1.100"
73#define IP4_ADDR_TUNL_DEV1 "10.1.1.200"
74
75#define IP6_ADDR_VETH0 "::11"
76#define IP6_ADDR1_VETH1 "::22"
77#define IP6_ADDR2_VETH1 "::bb"
78
79#define IP4_ADDR1_HEX_VETH1 0xac1001c8
80#define IP4_ADDR2_HEX_VETH1 0xac100114
81#define IP6_ADDR1_HEX_VETH1 0x22
82#define IP6_ADDR2_HEX_VETH1 0xbb
83
84#define MAC_TUNL_DEV0 "52:54:00:d9:01:00"
85#define MAC_TUNL_DEV1 "52:54:00:d9:02:00"
86#define MAC_VETH1 "52:54:00:d9:03:00"
87
88#define VXLAN_TUNL_DEV0 "vxlan00"
89#define VXLAN_TUNL_DEV1 "vxlan11"
90#define IP6VXLAN_TUNL_DEV0 "ip6vxlan00"
91#define IP6VXLAN_TUNL_DEV1 "ip6vxlan11"
92
93#define IPIP_TUNL_DEV0 "ipip00"
94#define IPIP_TUNL_DEV1 "ipip11"
95
96#define XFRM_AUTH "0x1111111111111111111111111111111111111111"
97#define XFRM_ENC "0x22222222222222222222222222222222"
98#define XFRM_SPI_IN_TO_OUT 0x1
99#define XFRM_SPI_OUT_TO_IN 0x2
100
101#define PING_ARGS "-i 0.01 -c 3 -w 10 -q"
102
103static int config_device(void)
104{
105	SYS(fail, "ip netns add at_ns0");
106	SYS(fail, "ip link add veth0 address " MAC_VETH1 " type veth peer name veth1");
107	SYS(fail, "ip link set veth0 netns at_ns0");
108	SYS(fail, "ip addr add " IP4_ADDR1_VETH1 "/24 dev veth1");
109	SYS(fail, "ip link set dev veth1 up mtu 1500");
110	SYS(fail, "ip netns exec at_ns0 ip addr add " IP4_ADDR_VETH0 "/24 dev veth0");
111	SYS(fail, "ip netns exec at_ns0 ip link set dev veth0 up mtu 1500");
112
113	return 0;
114fail:
115	return -1;
116}
117
118static void cleanup(void)
119{
120	SYS_NOFAIL("test -f /var/run/netns/at_ns0 && ip netns delete at_ns0");
121	SYS_NOFAIL("ip link del veth1");
122	SYS_NOFAIL("ip link del %s", VXLAN_TUNL_DEV1);
123	SYS_NOFAIL("ip link del %s", IP6VXLAN_TUNL_DEV1);
124}
125
126static int add_vxlan_tunnel(void)
127{
128	/* at_ns0 namespace */
129	SYS(fail, "ip netns exec at_ns0 ip link add dev %s type vxlan external gbp dstport 4789",
130	    VXLAN_TUNL_DEV0);
131	SYS(fail, "ip netns exec at_ns0 ip link set dev %s address %s up",
132	    VXLAN_TUNL_DEV0, MAC_TUNL_DEV0);
133	SYS(fail, "ip netns exec at_ns0 ip addr add dev %s %s/24",
134	    VXLAN_TUNL_DEV0, IP4_ADDR_TUNL_DEV0);
135	SYS(fail, "ip netns exec at_ns0 ip neigh add %s lladdr %s dev %s",
136	    IP4_ADDR_TUNL_DEV1, MAC_TUNL_DEV1, VXLAN_TUNL_DEV0);
137	SYS(fail, "ip netns exec at_ns0 ip neigh add %s lladdr %s dev veth0",
138	    IP4_ADDR2_VETH1, MAC_VETH1);
139
140	/* root namespace */
141	SYS(fail, "ip link add dev %s type vxlan external gbp dstport 4789",
142	    VXLAN_TUNL_DEV1);
143	SYS(fail, "ip link set dev %s address %s up", VXLAN_TUNL_DEV1, MAC_TUNL_DEV1);
144	SYS(fail, "ip addr add dev %s %s/24", VXLAN_TUNL_DEV1, IP4_ADDR_TUNL_DEV1);
145	SYS(fail, "ip neigh add %s lladdr %s dev %s",
146	    IP4_ADDR_TUNL_DEV0, MAC_TUNL_DEV0, VXLAN_TUNL_DEV1);
147
148	return 0;
149fail:
150	return -1;
151}
152
153static void delete_vxlan_tunnel(void)
154{
155	SYS_NOFAIL("ip netns exec at_ns0 ip link delete dev %s",
156		   VXLAN_TUNL_DEV0);
157	SYS_NOFAIL("ip link delete dev %s", VXLAN_TUNL_DEV1);
158}
159
160static int add_ip6vxlan_tunnel(void)
161{
162	SYS(fail, "ip netns exec at_ns0 ip -6 addr add %s/96 dev veth0",
163	    IP6_ADDR_VETH0);
164	SYS(fail, "ip netns exec at_ns0 ip link set dev veth0 up");
165	SYS(fail, "ip -6 addr add %s/96 dev veth1", IP6_ADDR1_VETH1);
166	SYS(fail, "ip -6 addr add %s/96 dev veth1", IP6_ADDR2_VETH1);
167	SYS(fail, "ip link set dev veth1 up");
168
169	/* at_ns0 namespace */
170	SYS(fail, "ip netns exec at_ns0 ip link add dev %s type vxlan external dstport 4789",
171	    IP6VXLAN_TUNL_DEV0);
172	SYS(fail, "ip netns exec at_ns0 ip addr add dev %s %s/24",
173	    IP6VXLAN_TUNL_DEV0, IP4_ADDR_TUNL_DEV0);
174	SYS(fail, "ip netns exec at_ns0 ip link set dev %s address %s up",
175	    IP6VXLAN_TUNL_DEV0, MAC_TUNL_DEV0);
176
177	/* root namespace */
178	SYS(fail, "ip link add dev %s type vxlan external dstport 4789",
179	    IP6VXLAN_TUNL_DEV1);
180	SYS(fail, "ip addr add dev %s %s/24", IP6VXLAN_TUNL_DEV1, IP4_ADDR_TUNL_DEV1);
181	SYS(fail, "ip link set dev %s address %s up",
182	    IP6VXLAN_TUNL_DEV1, MAC_TUNL_DEV1);
183
184	return 0;
185fail:
186	return -1;
187}
188
189static void delete_ip6vxlan_tunnel(void)
190{
191	SYS_NOFAIL("ip netns exec at_ns0 ip -6 addr delete %s/96 dev veth0",
192		   IP6_ADDR_VETH0);
193	SYS_NOFAIL("ip -6 addr delete %s/96 dev veth1", IP6_ADDR1_VETH1);
194	SYS_NOFAIL("ip -6 addr delete %s/96 dev veth1", IP6_ADDR2_VETH1);
195	SYS_NOFAIL("ip netns exec at_ns0 ip link delete dev %s",
196		   IP6VXLAN_TUNL_DEV0);
197	SYS_NOFAIL("ip link delete dev %s", IP6VXLAN_TUNL_DEV1);
198}
199
200enum ipip_encap {
201	NONE	= 0,
202	FOU	= 1,
203	GUE	= 2,
204};
205
206static int set_ipip_encap(const char *ipproto, const char *type)
207{
208	SYS(fail, "ip -n at_ns0 fou add port 5555 %s", ipproto);
209	SYS(fail, "ip -n at_ns0 link set dev %s type ipip encap %s",
210	    IPIP_TUNL_DEV0, type);
211	SYS(fail, "ip -n at_ns0 link set dev %s type ipip encap-dport 5555",
212	    IPIP_TUNL_DEV0);
213
214	return 0;
215fail:
216	return -1;
217}
218
219static int add_ipip_tunnel(enum ipip_encap encap)
220{
221	int err;
222	const char *ipproto, *type;
223
224	switch (encap) {
225	case FOU:
226		ipproto = "ipproto 4";
227		type = "fou";
228		break;
229	case GUE:
230		ipproto = "gue";
231		type = ipproto;
232		break;
233	default:
234		ipproto = NULL;
235		type = ipproto;
236	}
237
238	/* at_ns0 namespace */
239	SYS(fail, "ip -n at_ns0 link add dev %s type ipip local %s remote %s",
240	    IPIP_TUNL_DEV0, IP4_ADDR_VETH0, IP4_ADDR1_VETH1);
241
242	if (type && ipproto) {
243		err = set_ipip_encap(ipproto, type);
244		if (!ASSERT_OK(err, "set_ipip_encap"))
245			goto fail;
246	}
247
248	SYS(fail, "ip -n at_ns0 link set dev %s up", IPIP_TUNL_DEV0);
249	SYS(fail, "ip -n at_ns0 addr add dev %s %s/24",
250	    IPIP_TUNL_DEV0, IP4_ADDR_TUNL_DEV0);
251
252	/* root namespace */
253	if (type && ipproto)
254		SYS(fail, "ip fou add port 5555 %s", ipproto);
255	SYS(fail, "ip link add dev %s type ipip external", IPIP_TUNL_DEV1);
256	SYS(fail, "ip link set dev %s up", IPIP_TUNL_DEV1);
257	SYS(fail, "ip addr add dev %s %s/24", IPIP_TUNL_DEV1,
258	    IP4_ADDR_TUNL_DEV1);
259
260	return 0;
261fail:
262	return -1;
263}
264
265static void delete_ipip_tunnel(void)
266{
267	SYS_NOFAIL("ip -n at_ns0 link delete dev %s", IPIP_TUNL_DEV0);
268	SYS_NOFAIL("ip -n at_ns0 fou del port 5555");
269	SYS_NOFAIL("ip link delete dev %s", IPIP_TUNL_DEV1);
270	SYS_NOFAIL("ip fou del port 5555");
271}
272
273static int add_xfrm_tunnel(void)
274{
275	/* at_ns0 namespace
276	 * at_ns0 -> root
277	 */
278	SYS(fail,
279	    "ip netns exec at_ns0 "
280		"ip xfrm state add src %s dst %s proto esp "
281			"spi %d reqid 1 mode tunnel replay-window 42 "
282			"auth-trunc 'hmac(sha1)' %s 96 enc 'cbc(aes)' %s",
283	    IP4_ADDR_VETH0, IP4_ADDR1_VETH1, XFRM_SPI_IN_TO_OUT, XFRM_AUTH, XFRM_ENC);
284	SYS(fail,
285	    "ip netns exec at_ns0 "
286		"ip xfrm policy add src %s/32 dst %s/32 dir out "
287			"tmpl src %s dst %s proto esp reqid 1 "
288			"mode tunnel",
289	    IP4_ADDR_TUNL_DEV0, IP4_ADDR_TUNL_DEV1, IP4_ADDR_VETH0, IP4_ADDR1_VETH1);
290
291	/* root -> at_ns0 */
292	SYS(fail,
293	    "ip netns exec at_ns0 "
294		"ip xfrm state add src %s dst %s proto esp "
295			"spi %d reqid 2 mode tunnel "
296			"auth-trunc 'hmac(sha1)' %s 96 enc 'cbc(aes)' %s",
297	    IP4_ADDR1_VETH1, IP4_ADDR_VETH0, XFRM_SPI_OUT_TO_IN, XFRM_AUTH, XFRM_ENC);
298	SYS(fail,
299	    "ip netns exec at_ns0 "
300		"ip xfrm policy add src %s/32 dst %s/32 dir in "
301			"tmpl src %s dst %s proto esp reqid 2 "
302			"mode tunnel",
303	    IP4_ADDR_TUNL_DEV1, IP4_ADDR_TUNL_DEV0, IP4_ADDR1_VETH1, IP4_ADDR_VETH0);
304
305	/* address & route */
306	SYS(fail, "ip netns exec at_ns0 ip addr add dev veth0 %s/32",
307	    IP4_ADDR_TUNL_DEV0);
308	SYS(fail, "ip netns exec at_ns0 ip route add %s dev veth0 via %s src %s",
309	    IP4_ADDR_TUNL_DEV1, IP4_ADDR1_VETH1, IP4_ADDR_TUNL_DEV0);
310
311	/* root namespace
312	 * at_ns0 -> root
313	 */
314	SYS(fail,
315	    "ip xfrm state add src %s dst %s proto esp "
316		    "spi %d reqid 1 mode tunnel replay-window 42 "
317		    "auth-trunc 'hmac(sha1)' %s 96  enc 'cbc(aes)' %s",
318	    IP4_ADDR_VETH0, IP4_ADDR1_VETH1, XFRM_SPI_IN_TO_OUT, XFRM_AUTH, XFRM_ENC);
319	SYS(fail,
320	    "ip xfrm policy add src %s/32 dst %s/32 dir in "
321		    "tmpl src %s dst %s proto esp reqid 1 "
322		    "mode tunnel",
323	    IP4_ADDR_TUNL_DEV0, IP4_ADDR_TUNL_DEV1, IP4_ADDR_VETH0, IP4_ADDR1_VETH1);
324
325	/* root -> at_ns0 */
326	SYS(fail,
327	    "ip xfrm state add src %s dst %s proto esp "
328		    "spi %d reqid 2 mode tunnel "
329		    "auth-trunc 'hmac(sha1)' %s 96  enc 'cbc(aes)' %s",
330	    IP4_ADDR1_VETH1, IP4_ADDR_VETH0, XFRM_SPI_OUT_TO_IN, XFRM_AUTH, XFRM_ENC);
331	SYS(fail,
332	    "ip xfrm policy add src %s/32 dst %s/32 dir out "
333		    "tmpl src %s dst %s proto esp reqid 2 "
334		    "mode tunnel",
335	    IP4_ADDR_TUNL_DEV1, IP4_ADDR_TUNL_DEV0, IP4_ADDR1_VETH1, IP4_ADDR_VETH0);
336
337	/* address & route */
338	SYS(fail, "ip addr add dev veth1 %s/32", IP4_ADDR_TUNL_DEV1);
339	SYS(fail, "ip route add %s dev veth1 via %s src %s",
340	    IP4_ADDR_TUNL_DEV0, IP4_ADDR_VETH0, IP4_ADDR_TUNL_DEV1);
341
342	return 0;
343fail:
344	return -1;
345}
346
347static void delete_xfrm_tunnel(void)
348{
349	SYS_NOFAIL("ip xfrm policy delete dir out src %s/32 dst %s/32",
350		   IP4_ADDR_TUNL_DEV1, IP4_ADDR_TUNL_DEV0);
351	SYS_NOFAIL("ip xfrm policy delete dir in src %s/32 dst %s/32",
352		   IP4_ADDR_TUNL_DEV0, IP4_ADDR_TUNL_DEV1);
353	SYS_NOFAIL("ip xfrm state delete src %s dst %s proto esp spi %d",
354		   IP4_ADDR_VETH0, IP4_ADDR1_VETH1, XFRM_SPI_IN_TO_OUT);
355	SYS_NOFAIL("ip xfrm state delete src %s dst %s proto esp spi %d",
356		   IP4_ADDR1_VETH1, IP4_ADDR_VETH0, XFRM_SPI_OUT_TO_IN);
357}
358
359static int test_ping(int family, const char *addr)
360{
361	SYS(fail, "%s %s %s > /dev/null", ping_command(family), PING_ARGS, addr);
362	return 0;
363fail:
364	return -1;
365}
366
367static int attach_tc_prog(struct bpf_tc_hook *hook, int igr_fd, int egr_fd)
368{
369	DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts1, .handle = 1,
370			    .priority = 1, .prog_fd = igr_fd);
371	DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts2, .handle = 1,
372			    .priority = 1, .prog_fd = egr_fd);
373	int ret;
374
375	ret = bpf_tc_hook_create(hook);
376	if (!ASSERT_OK(ret, "create tc hook"))
377		return ret;
378
379	if (igr_fd >= 0) {
380		hook->attach_point = BPF_TC_INGRESS;
381		ret = bpf_tc_attach(hook, &opts1);
382		if (!ASSERT_OK(ret, "bpf_tc_attach")) {
383			bpf_tc_hook_destroy(hook);
384			return ret;
385		}
386	}
387
388	if (egr_fd >= 0) {
389		hook->attach_point = BPF_TC_EGRESS;
390		ret = bpf_tc_attach(hook, &opts2);
391		if (!ASSERT_OK(ret, "bpf_tc_attach")) {
392			bpf_tc_hook_destroy(hook);
393			return ret;
394		}
395	}
396
397	return 0;
398}
399
400static void test_vxlan_tunnel(void)
401{
402	struct test_tunnel_kern *skel = NULL;
403	struct nstoken *nstoken;
404	int local_ip_map_fd = -1;
405	int set_src_prog_fd, get_src_prog_fd;
406	int set_dst_prog_fd;
407	int key = 0, ifindex = -1;
408	uint local_ip;
409	int err;
410	DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook,
411			    .attach_point = BPF_TC_INGRESS);
412
413	/* add vxlan tunnel */
414	err = add_vxlan_tunnel();
415	if (!ASSERT_OK(err, "add vxlan tunnel"))
416		goto done;
417
418	/* load and attach bpf prog to tunnel dev tc hook point */
419	skel = test_tunnel_kern__open_and_load();
420	if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load"))
421		goto done;
422	ifindex = if_nametoindex(VXLAN_TUNL_DEV1);
423	if (!ASSERT_NEQ(ifindex, 0, "vxlan11 ifindex"))
424		goto done;
425	tc_hook.ifindex = ifindex;
426	get_src_prog_fd = bpf_program__fd(skel->progs.vxlan_get_tunnel_src);
427	set_src_prog_fd = bpf_program__fd(skel->progs.vxlan_set_tunnel_src);
428	if (!ASSERT_GE(get_src_prog_fd, 0, "bpf_program__fd"))
429		goto done;
430	if (!ASSERT_GE(set_src_prog_fd, 0, "bpf_program__fd"))
431		goto done;
432	if (attach_tc_prog(&tc_hook, get_src_prog_fd, set_src_prog_fd))
433		goto done;
434
435	/* load and attach bpf prog to veth dev tc hook point */
436	ifindex = if_nametoindex("veth1");
437	if (!ASSERT_NEQ(ifindex, 0, "veth1 ifindex"))
438		goto done;
439	tc_hook.ifindex = ifindex;
440	set_dst_prog_fd = bpf_program__fd(skel->progs.veth_set_outer_dst);
441	if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd"))
442		goto done;
443	if (attach_tc_prog(&tc_hook, set_dst_prog_fd, -1))
444		goto done;
445
446	/* load and attach prog set_md to tunnel dev tc hook point at_ns0 */
447	nstoken = open_netns("at_ns0");
448	if (!ASSERT_OK_PTR(nstoken, "setns src"))
449		goto done;
450	ifindex = if_nametoindex(VXLAN_TUNL_DEV0);
451	if (!ASSERT_NEQ(ifindex, 0, "vxlan00 ifindex"))
452		goto done;
453	tc_hook.ifindex = ifindex;
454	set_dst_prog_fd = bpf_program__fd(skel->progs.vxlan_set_tunnel_dst);
455	if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd"))
456		goto done;
457	if (attach_tc_prog(&tc_hook, -1, set_dst_prog_fd))
458		goto done;
459	close_netns(nstoken);
460
461	/* use veth1 ip 2 as tunnel source ip */
462	local_ip_map_fd = bpf_map__fd(skel->maps.local_ip_map);
463	if (!ASSERT_GE(local_ip_map_fd, 0, "bpf_map__fd"))
464		goto done;
465	local_ip = IP4_ADDR2_HEX_VETH1;
466	err = bpf_map_update_elem(local_ip_map_fd, &key, &local_ip, BPF_ANY);
467	if (!ASSERT_OK(err, "update bpf local_ip_map"))
468		goto done;
469
470	/* ping test */
471	err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV0);
472	if (!ASSERT_OK(err, "test_ping"))
473		goto done;
474
475done:
476	/* delete vxlan tunnel */
477	delete_vxlan_tunnel();
478	if (local_ip_map_fd >= 0)
479		close(local_ip_map_fd);
480	if (skel)
481		test_tunnel_kern__destroy(skel);
482}
483
484static void test_ip6vxlan_tunnel(void)
485{
486	struct test_tunnel_kern *skel = NULL;
487	struct nstoken *nstoken;
488	int local_ip_map_fd = -1;
489	int set_src_prog_fd, get_src_prog_fd;
490	int set_dst_prog_fd;
491	int key = 0, ifindex = -1;
492	uint local_ip;
493	int err;
494	DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook,
495			    .attach_point = BPF_TC_INGRESS);
496
497	/* add vxlan tunnel */
498	err = add_ip6vxlan_tunnel();
499	if (!ASSERT_OK(err, "add_ip6vxlan_tunnel"))
500		goto done;
501
502	/* load and attach bpf prog to tunnel dev tc hook point */
503	skel = test_tunnel_kern__open_and_load();
504	if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load"))
505		goto done;
506	ifindex = if_nametoindex(IP6VXLAN_TUNL_DEV1);
507	if (!ASSERT_NEQ(ifindex, 0, "ip6vxlan11 ifindex"))
508		goto done;
509	tc_hook.ifindex = ifindex;
510	get_src_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_get_tunnel_src);
511	set_src_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_set_tunnel_src);
512	if (!ASSERT_GE(set_src_prog_fd, 0, "bpf_program__fd"))
513		goto done;
514	if (!ASSERT_GE(get_src_prog_fd, 0, "bpf_program__fd"))
515		goto done;
516	if (attach_tc_prog(&tc_hook, get_src_prog_fd, set_src_prog_fd))
517		goto done;
518
519	/* load and attach prog set_md to tunnel dev tc hook point at_ns0 */
520	nstoken = open_netns("at_ns0");
521	if (!ASSERT_OK_PTR(nstoken, "setns src"))
522		goto done;
523	ifindex = if_nametoindex(IP6VXLAN_TUNL_DEV0);
524	if (!ASSERT_NEQ(ifindex, 0, "ip6vxlan00 ifindex"))
525		goto done;
526	tc_hook.ifindex = ifindex;
527	set_dst_prog_fd = bpf_program__fd(skel->progs.ip6vxlan_set_tunnel_dst);
528	if (!ASSERT_GE(set_dst_prog_fd, 0, "bpf_program__fd"))
529		goto done;
530	if (attach_tc_prog(&tc_hook, -1, set_dst_prog_fd))
531		goto done;
532	close_netns(nstoken);
533
534	/* use veth1 ip 2 as tunnel source ip */
535	local_ip_map_fd = bpf_map__fd(skel->maps.local_ip_map);
536	if (!ASSERT_GE(local_ip_map_fd, 0, "get local_ip_map fd"))
537		goto done;
538	local_ip = IP6_ADDR2_HEX_VETH1;
539	err = bpf_map_update_elem(local_ip_map_fd, &key, &local_ip, BPF_ANY);
540	if (!ASSERT_OK(err, "update bpf local_ip_map"))
541		goto done;
542
543	/* ping test */
544	err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV0);
545	if (!ASSERT_OK(err, "test_ping"))
546		goto done;
547
548done:
549	/* delete ipv6 vxlan tunnel */
550	delete_ip6vxlan_tunnel();
551	if (local_ip_map_fd >= 0)
552		close(local_ip_map_fd);
553	if (skel)
554		test_tunnel_kern__destroy(skel);
555}
556
557static void test_ipip_tunnel(enum ipip_encap encap)
558{
559	struct test_tunnel_kern *skel = NULL;
560	struct nstoken *nstoken;
561	int set_src_prog_fd, get_src_prog_fd;
562	int ifindex = -1;
563	int err;
564	DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook,
565			    .attach_point = BPF_TC_INGRESS);
566
567	/* add ipip tunnel */
568	err = add_ipip_tunnel(encap);
569	if (!ASSERT_OK(err, "add_ipip_tunnel"))
570		goto done;
571
572	/* load and attach bpf prog to tunnel dev tc hook point */
573	skel = test_tunnel_kern__open_and_load();
574	if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load"))
575		goto done;
576	ifindex = if_nametoindex(IPIP_TUNL_DEV1);
577	if (!ASSERT_NEQ(ifindex, 0, "ipip11 ifindex"))
578		goto done;
579	tc_hook.ifindex = ifindex;
580
581	switch (encap) {
582	case FOU:
583		get_src_prog_fd = bpf_program__fd(
584			skel->progs.ipip_encap_get_tunnel);
585		set_src_prog_fd = bpf_program__fd(
586			skel->progs.ipip_fou_set_tunnel);
587		break;
588	case GUE:
589		get_src_prog_fd = bpf_program__fd(
590			skel->progs.ipip_encap_get_tunnel);
591		set_src_prog_fd = bpf_program__fd(
592			skel->progs.ipip_gue_set_tunnel);
593		break;
594	default:
595		get_src_prog_fd = bpf_program__fd(
596			skel->progs.ipip_get_tunnel);
597		set_src_prog_fd = bpf_program__fd(
598			skel->progs.ipip_set_tunnel);
599	}
600
601	if (!ASSERT_GE(set_src_prog_fd, 0, "bpf_program__fd"))
602		goto done;
603	if (!ASSERT_GE(get_src_prog_fd, 0, "bpf_program__fd"))
604		goto done;
605	if (attach_tc_prog(&tc_hook, get_src_prog_fd, set_src_prog_fd))
606		goto done;
607
608	/* ping from root namespace test */
609	err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV0);
610	if (!ASSERT_OK(err, "test_ping"))
611		goto done;
612
613	/* ping from at_ns0 namespace test */
614	nstoken = open_netns("at_ns0");
615	err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV1);
616	if (!ASSERT_OK(err, "test_ping"))
617		goto done;
618	close_netns(nstoken);
619
620done:
621	/* delete ipip tunnel */
622	delete_ipip_tunnel();
623	if (skel)
624		test_tunnel_kern__destroy(skel);
625}
626
627static void test_xfrm_tunnel(void)
628{
629	DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook,
630			    .attach_point = BPF_TC_INGRESS);
631	LIBBPF_OPTS(bpf_xdp_attach_opts, opts);
632	struct test_tunnel_kern *skel = NULL;
633	struct nstoken *nstoken;
634	int xdp_prog_fd;
635	int tc_prog_fd;
636	int ifindex;
637	int err;
638
639	err = add_xfrm_tunnel();
640	if (!ASSERT_OK(err, "add_xfrm_tunnel"))
641		return;
642
643	skel = test_tunnel_kern__open_and_load();
644	if (!ASSERT_OK_PTR(skel, "test_tunnel_kern__open_and_load"))
645		goto done;
646
647	ifindex = if_nametoindex("veth1");
648	if (!ASSERT_NEQ(ifindex, 0, "veth1 ifindex"))
649		goto done;
650
651	/* attach tc prog to tunnel dev */
652	tc_hook.ifindex = ifindex;
653	tc_prog_fd = bpf_program__fd(skel->progs.xfrm_get_state);
654	if (!ASSERT_GE(tc_prog_fd, 0, "bpf_program__fd"))
655		goto done;
656	if (attach_tc_prog(&tc_hook, tc_prog_fd, -1))
657		goto done;
658
659	/* attach xdp prog to tunnel dev */
660	xdp_prog_fd = bpf_program__fd(skel->progs.xfrm_get_state_xdp);
661	if (!ASSERT_GE(xdp_prog_fd, 0, "bpf_program__fd"))
662		goto done;
663	err = bpf_xdp_attach(ifindex, xdp_prog_fd, XDP_FLAGS_REPLACE, &opts);
664	if (!ASSERT_OK(err, "bpf_xdp_attach"))
665		goto done;
666
667	/* ping from at_ns0 namespace test */
668	nstoken = open_netns("at_ns0");
669	err = test_ping(AF_INET, IP4_ADDR_TUNL_DEV1);
670	close_netns(nstoken);
671	if (!ASSERT_OK(err, "test_ping"))
672		goto done;
673
674	if (!ASSERT_EQ(skel->bss->xfrm_reqid, 1, "req_id"))
675		goto done;
676	if (!ASSERT_EQ(skel->bss->xfrm_spi, XFRM_SPI_IN_TO_OUT, "spi"))
677		goto done;
678	if (!ASSERT_EQ(skel->bss->xfrm_remote_ip, 0xac100164, "remote_ip"))
679		goto done;
680	if (!ASSERT_EQ(skel->bss->xfrm_replay_window, 42, "replay_window"))
681		goto done;
682
683done:
684	delete_xfrm_tunnel();
685	if (skel)
686		test_tunnel_kern__destroy(skel);
687}
688
689#define RUN_TEST(name, ...)						\
690	({								\
691		if (test__start_subtest(#name)) {			\
692			config_device();				\
693			test_ ## name(__VA_ARGS__);			\
694			cleanup();					\
695		}							\
696	})
697
698static void *test_tunnel_run_tests(void *arg)
699{
700	RUN_TEST(vxlan_tunnel);
701	RUN_TEST(ip6vxlan_tunnel);
702	RUN_TEST(ipip_tunnel, NONE);
703	RUN_TEST(ipip_tunnel, FOU);
704	RUN_TEST(ipip_tunnel, GUE);
705	RUN_TEST(xfrm_tunnel);
706
707	return NULL;
708}
709
710void test_tunnel(void)
711{
712	pthread_t test_thread;
713	int err;
714
715	/* Run the tests in their own thread to isolate the namespace changes
716	 * so they do not affect the environment of other tests.
717	 * (specifically needed because of unshare(CLONE_NEWNS) in open_netns())
718	 */
719	err = pthread_create(&test_thread, NULL, &test_tunnel_run_tests, NULL);
720	if (ASSERT_OK(err, "pthread_create"))
721		ASSERT_OK(pthread_join(test_thread, NULL), "pthread_join");
722}
723