1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 
3 /*
4  * This test sets up 3 netns (src <-> fwd <-> dst). There is no direct veth link
5  * between src and dst. The netns fwd has veth links to each src and dst. The
6  * client is in src and server in dst. The test installs a TC BPF program to each
7  * host facing veth in fwd which calls into i) bpf_redirect_neigh() to perform the
8  * neigh addr population and redirect or ii) bpf_redirect_peer() for namespace
9  * switch from ingress side; it also installs a checker prog on the egress side
10  * to drop unexpected traffic.
11  */
12 
13 #include <arpa/inet.h>
14 #include <linux/if_tun.h>
15 #include <linux/limits.h>
16 #include <linux/sysctl.h>
17 #include <linux/time_types.h>
18 #include <linux/net_tstamp.h>
19 #include <net/if.h>
20 #include <stdbool.h>
21 #include <stdio.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 
25 #include "test_progs.h"
26 #include "network_helpers.h"
27 #include "test_tc_neigh_fib.skel.h"
28 #include "test_tc_neigh.skel.h"
29 #include "test_tc_peer.skel.h"
30 #include "test_tc_dtime.skel.h"
31 
32 #ifndef TCP_TX_DELAY
33 #define TCP_TX_DELAY 37
34 #endif
35 
36 #define NS_SRC "ns_src"
37 #define NS_FWD "ns_fwd"
38 #define NS_DST "ns_dst"
39 
40 #define IP4_SRC "172.16.1.100"
41 #define IP4_DST "172.16.2.100"
42 #define IP4_TUN_SRC "172.17.1.100"
43 #define IP4_TUN_FWD "172.17.1.200"
44 #define IP4_PORT 9004
45 
46 #define IP6_SRC "0::1:dead:beef:cafe"
47 #define IP6_DST "0::2:dead:beef:cafe"
48 #define IP6_TUN_SRC "1::1:dead:beef:cafe"
49 #define IP6_TUN_FWD "1::2:dead:beef:cafe"
50 #define IP6_PORT 9006
51 
52 #define IP4_SLL "169.254.0.1"
53 #define IP4_DLL "169.254.0.2"
54 #define IP4_NET "169.254.0.0"
55 
56 #define MAC_DST_FWD "00:11:22:33:44:55"
57 #define MAC_DST "00:22:33:44:55:66"
58 
59 #define IFADDR_STR_LEN 18
60 #define PING_ARGS "-i 0.2 -c 3 -w 10 -q"
61 
62 #define TIMEOUT_MILLIS 10000
63 #define NSEC_PER_SEC 1000000000ULL
64 
65 #define log_err(MSG, ...) \
66 	fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", \
67 		__FILE__, __LINE__, strerror(errno), ##__VA_ARGS__)
68 
69 static const char * const namespaces[] = {NS_SRC, NS_FWD, NS_DST, NULL};
70 
71 static int write_file(const char *path, const char *newval)
72 {
73 	FILE *f;
74 
75 	f = fopen(path, "r+");
76 	if (!f)
77 		return -1;
78 	if (fwrite(newval, strlen(newval), 1, f) != 1) {
79 		log_err("writing to %s failed", path);
80 		fclose(f);
81 		return -1;
82 	}
83 	fclose(f);
84 	return 0;
85 }
86 
87 static int netns_setup_namespaces(const char *verb)
88 {
89 	const char * const *ns = namespaces;
90 	char cmd[128];
91 
92 	while (*ns) {
93 		snprintf(cmd, sizeof(cmd), "ip netns %s %s", verb, *ns);
94 		if (!ASSERT_OK(system(cmd), cmd))
95 			return -1;
96 		ns++;
97 	}
98 	return 0;
99 }
100 
101 static void netns_setup_namespaces_nofail(const char *verb)
102 {
103 	const char * const *ns = namespaces;
104 	char cmd[128];
105 
106 	while (*ns) {
107 		snprintf(cmd, sizeof(cmd), "ip netns %s %s > /dev/null 2>&1", verb, *ns);
108 		system(cmd);
109 		ns++;
110 	}
111 }
112 
113 struct netns_setup_result {
114 	int ifindex_veth_src;
115 	int ifindex_veth_src_fwd;
116 	int ifindex_veth_dst;
117 	int ifindex_veth_dst_fwd;
118 };
119 
120 static int get_ifaddr(const char *name, char *ifaddr)
121 {
122 	char path[PATH_MAX];
123 	FILE *f;
124 	int ret;
125 
126 	snprintf(path, PATH_MAX, "/sys/class/net/%s/address", name);
127 	f = fopen(path, "r");
128 	if (!ASSERT_OK_PTR(f, path))
129 		return -1;
130 
131 	ret = fread(ifaddr, 1, IFADDR_STR_LEN, f);
132 	if (!ASSERT_EQ(ret, IFADDR_STR_LEN, "fread ifaddr")) {
133 		fclose(f);
134 		return -1;
135 	}
136 	fclose(f);
137 	return 0;
138 }
139 
140 #define SYS(fmt, ...)						\
141 	({							\
142 		char cmd[1024];					\
143 		snprintf(cmd, sizeof(cmd), fmt, ##__VA_ARGS__);	\
144 		if (!ASSERT_OK(system(cmd), cmd))		\
145 			goto fail;				\
146 	})
147 
148 static int netns_setup_links_and_routes(struct netns_setup_result *result)
149 {
150 	struct nstoken *nstoken = NULL;
151 	char veth_src_fwd_addr[IFADDR_STR_LEN+1] = {};
152 
153 	SYS("ip link add veth_src type veth peer name veth_src_fwd");
154 	SYS("ip link add veth_dst type veth peer name veth_dst_fwd");
155 
156 	SYS("ip link set veth_dst_fwd address " MAC_DST_FWD);
157 	SYS("ip link set veth_dst address " MAC_DST);
158 
159 	if (get_ifaddr("veth_src_fwd", veth_src_fwd_addr))
160 		goto fail;
161 
162 	result->ifindex_veth_src = if_nametoindex("veth_src");
163 	if (!ASSERT_GT(result->ifindex_veth_src, 0, "ifindex_veth_src"))
164 		goto fail;
165 
166 	result->ifindex_veth_src_fwd = if_nametoindex("veth_src_fwd");
167 	if (!ASSERT_GT(result->ifindex_veth_src_fwd, 0, "ifindex_veth_src_fwd"))
168 		goto fail;
169 
170 	result->ifindex_veth_dst = if_nametoindex("veth_dst");
171 	if (!ASSERT_GT(result->ifindex_veth_dst, 0, "ifindex_veth_dst"))
172 		goto fail;
173 
174 	result->ifindex_veth_dst_fwd = if_nametoindex("veth_dst_fwd");
175 	if (!ASSERT_GT(result->ifindex_veth_dst_fwd, 0, "ifindex_veth_dst_fwd"))
176 		goto fail;
177 
178 	SYS("ip link set veth_src netns " NS_SRC);
179 	SYS("ip link set veth_src_fwd netns " NS_FWD);
180 	SYS("ip link set veth_dst_fwd netns " NS_FWD);
181 	SYS("ip link set veth_dst netns " NS_DST);
182 
183 	/** setup in 'src' namespace */
184 	nstoken = open_netns(NS_SRC);
185 	if (!ASSERT_OK_PTR(nstoken, "setns src"))
186 		goto fail;
187 
188 	SYS("ip addr add " IP4_SRC "/32 dev veth_src");
189 	SYS("ip addr add " IP6_SRC "/128 dev veth_src nodad");
190 	SYS("ip link set dev veth_src up");
191 
192 	SYS("ip route add " IP4_DST "/32 dev veth_src scope global");
193 	SYS("ip route add " IP4_NET "/16 dev veth_src scope global");
194 	SYS("ip route add " IP6_DST "/128 dev veth_src scope global");
195 
196 	SYS("ip neigh add " IP4_DST " dev veth_src lladdr %s",
197 	    veth_src_fwd_addr);
198 	SYS("ip neigh add " IP6_DST " dev veth_src lladdr %s",
199 	    veth_src_fwd_addr);
200 
201 	close_netns(nstoken);
202 
203 	/** setup in 'fwd' namespace */
204 	nstoken = open_netns(NS_FWD);
205 	if (!ASSERT_OK_PTR(nstoken, "setns fwd"))
206 		goto fail;
207 
208 	/* The fwd netns automatically gets a v6 LL address / routes, but also
209 	 * needs v4 one in order to start ARP probing. IP4_NET route is added
210 	 * to the endpoints so that the ARP processing will reply.
211 	 */
212 	SYS("ip addr add " IP4_SLL "/32 dev veth_src_fwd");
213 	SYS("ip addr add " IP4_DLL "/32 dev veth_dst_fwd");
214 	SYS("ip link set dev veth_src_fwd up");
215 	SYS("ip link set dev veth_dst_fwd up");
216 
217 	SYS("ip route add " IP4_SRC "/32 dev veth_src_fwd scope global");
218 	SYS("ip route add " IP6_SRC "/128 dev veth_src_fwd scope global");
219 	SYS("ip route add " IP4_DST "/32 dev veth_dst_fwd scope global");
220 	SYS("ip route add " IP6_DST "/128 dev veth_dst_fwd scope global");
221 
222 	close_netns(nstoken);
223 
224 	/** setup in 'dst' namespace */
225 	nstoken = open_netns(NS_DST);
226 	if (!ASSERT_OK_PTR(nstoken, "setns dst"))
227 		goto fail;
228 
229 	SYS("ip addr add " IP4_DST "/32 dev veth_dst");
230 	SYS("ip addr add " IP6_DST "/128 dev veth_dst nodad");
231 	SYS("ip link set dev veth_dst up");
232 
233 	SYS("ip route add " IP4_SRC "/32 dev veth_dst scope global");
234 	SYS("ip route add " IP4_NET "/16 dev veth_dst scope global");
235 	SYS("ip route add " IP6_SRC "/128 dev veth_dst scope global");
236 
237 	SYS("ip neigh add " IP4_SRC " dev veth_dst lladdr " MAC_DST_FWD);
238 	SYS("ip neigh add " IP6_SRC " dev veth_dst lladdr " MAC_DST_FWD);
239 
240 	close_netns(nstoken);
241 
242 	return 0;
243 fail:
244 	if (nstoken)
245 		close_netns(nstoken);
246 	return -1;
247 }
248 
249 static int qdisc_clsact_create(struct bpf_tc_hook *qdisc_hook, int ifindex)
250 {
251 	char err_str[128], ifname[16];
252 	int err;
253 
254 	qdisc_hook->ifindex = ifindex;
255 	qdisc_hook->attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
256 	err = bpf_tc_hook_create(qdisc_hook);
257 	snprintf(err_str, sizeof(err_str),
258 		 "qdisc add dev %s clsact",
259 		 if_indextoname(qdisc_hook->ifindex, ifname) ? : "<unknown_iface>");
260 	err_str[sizeof(err_str) - 1] = 0;
261 	ASSERT_OK(err, err_str);
262 
263 	return err;
264 }
265 
266 static int xgress_filter_add(struct bpf_tc_hook *qdisc_hook,
267 			     enum bpf_tc_attach_point xgress,
268 			     const struct bpf_program *prog, int priority)
269 {
270 	LIBBPF_OPTS(bpf_tc_opts, tc_attach);
271 	char err_str[128], ifname[16];
272 	int err;
273 
274 	qdisc_hook->attach_point = xgress;
275 	tc_attach.prog_fd = bpf_program__fd(prog);
276 	tc_attach.priority = priority;
277 	err = bpf_tc_attach(qdisc_hook, &tc_attach);
278 	snprintf(err_str, sizeof(err_str),
279 		 "filter add dev %s %s prio %d bpf da %s",
280 		 if_indextoname(qdisc_hook->ifindex, ifname) ? : "<unknown_iface>",
281 		 xgress == BPF_TC_INGRESS ? "ingress" : "egress",
282 		 priority, bpf_program__name(prog));
283 	err_str[sizeof(err_str) - 1] = 0;
284 	ASSERT_OK(err, err_str);
285 
286 	return err;
287 }
288 
289 #define QDISC_CLSACT_CREATE(qdisc_hook, ifindex) ({		\
290 	if ((err = qdisc_clsact_create(qdisc_hook, ifindex)))	\
291 		goto fail;					\
292 })
293 
294 #define XGRESS_FILTER_ADD(qdisc_hook, xgress, prog, priority) ({		\
295 	if ((err = xgress_filter_add(qdisc_hook, xgress, prog, priority)))	\
296 		goto fail;							\
297 })
298 
299 static int netns_load_bpf(const struct bpf_program *src_prog,
300 			  const struct bpf_program *dst_prog,
301 			  const struct bpf_program *chk_prog,
302 			  const struct netns_setup_result *setup_result)
303 {
304 	LIBBPF_OPTS(bpf_tc_hook, qdisc_veth_src_fwd);
305 	LIBBPF_OPTS(bpf_tc_hook, qdisc_veth_dst_fwd);
306 	int err;
307 
308 	/* tc qdisc add dev veth_src_fwd clsact */
309 	QDISC_CLSACT_CREATE(&qdisc_veth_src_fwd, setup_result->ifindex_veth_src_fwd);
310 	/* tc filter add dev veth_src_fwd ingress bpf da src_prog */
311 	XGRESS_FILTER_ADD(&qdisc_veth_src_fwd, BPF_TC_INGRESS, src_prog, 0);
312 	/* tc filter add dev veth_src_fwd egress bpf da chk_prog */
313 	XGRESS_FILTER_ADD(&qdisc_veth_src_fwd, BPF_TC_EGRESS, chk_prog, 0);
314 
315 	/* tc qdisc add dev veth_dst_fwd clsact */
316 	QDISC_CLSACT_CREATE(&qdisc_veth_dst_fwd, setup_result->ifindex_veth_dst_fwd);
317 	/* tc filter add dev veth_dst_fwd ingress bpf da dst_prog */
318 	XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_INGRESS, dst_prog, 0);
319 	/* tc filter add dev veth_dst_fwd egress bpf da chk_prog */
320 	XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_EGRESS, chk_prog, 0);
321 
322 	return 0;
323 fail:
324 	return -1;
325 }
326 
327 static void test_tcp(int family, const char *addr, __u16 port)
328 {
329 	int listen_fd = -1, accept_fd = -1, client_fd = -1;
330 	char buf[] = "testing testing";
331 	int n;
332 	struct nstoken *nstoken;
333 
334 	nstoken = open_netns(NS_DST);
335 	if (!ASSERT_OK_PTR(nstoken, "setns dst"))
336 		return;
337 
338 	listen_fd = start_server(family, SOCK_STREAM, addr, port, 0);
339 	if (!ASSERT_GE(listen_fd, 0, "listen"))
340 		goto done;
341 
342 	close_netns(nstoken);
343 	nstoken = open_netns(NS_SRC);
344 	if (!ASSERT_OK_PTR(nstoken, "setns src"))
345 		goto done;
346 
347 	client_fd = connect_to_fd(listen_fd, TIMEOUT_MILLIS);
348 	if (!ASSERT_GE(client_fd, 0, "connect_to_fd"))
349 		goto done;
350 
351 	accept_fd = accept(listen_fd, NULL, NULL);
352 	if (!ASSERT_GE(accept_fd, 0, "accept"))
353 		goto done;
354 
355 	if (!ASSERT_OK(settimeo(accept_fd, TIMEOUT_MILLIS), "settimeo"))
356 		goto done;
357 
358 	n = write(client_fd, buf, sizeof(buf));
359 	if (!ASSERT_EQ(n, sizeof(buf), "send to server"))
360 		goto done;
361 
362 	n = read(accept_fd, buf, sizeof(buf));
363 	ASSERT_EQ(n, sizeof(buf), "recv from server");
364 
365 done:
366 	if (nstoken)
367 		close_netns(nstoken);
368 	if (listen_fd >= 0)
369 		close(listen_fd);
370 	if (accept_fd >= 0)
371 		close(accept_fd);
372 	if (client_fd >= 0)
373 		close(client_fd);
374 }
375 
376 static int test_ping(int family, const char *addr)
377 {
378 	SYS("ip netns exec " NS_SRC " %s " PING_ARGS " %s > /dev/null", ping_command(family), addr);
379 	return 0;
380 fail:
381 	return -1;
382 }
383 
384 static void test_connectivity(void)
385 {
386 	test_tcp(AF_INET, IP4_DST, IP4_PORT);
387 	test_ping(AF_INET, IP4_DST);
388 	test_tcp(AF_INET6, IP6_DST, IP6_PORT);
389 	test_ping(AF_INET6, IP6_DST);
390 }
391 
392 static int set_forwarding(bool enable)
393 {
394 	int err;
395 
396 	err = write_file("/proc/sys/net/ipv4/ip_forward", enable ? "1" : "0");
397 	if (!ASSERT_OK(err, "set ipv4.ip_forward=0"))
398 		return err;
399 
400 	err = write_file("/proc/sys/net/ipv6/conf/all/forwarding", enable ? "1" : "0");
401 	if (!ASSERT_OK(err, "set ipv6.forwarding=0"))
402 		return err;
403 
404 	return 0;
405 }
406 
407 static void rcv_tstamp(int fd, const char *expected, size_t s)
408 {
409 	struct __kernel_timespec pkt_ts = {};
410 	char ctl[CMSG_SPACE(sizeof(pkt_ts))];
411 	struct timespec now_ts;
412 	struct msghdr msg = {};
413 	__u64 now_ns, pkt_ns;
414 	struct cmsghdr *cmsg;
415 	struct iovec iov;
416 	char data[32];
417 	int ret;
418 
419 	iov.iov_base = data;
420 	iov.iov_len = sizeof(data);
421 	msg.msg_iov = &iov;
422 	msg.msg_iovlen = 1;
423 	msg.msg_control = &ctl;
424 	msg.msg_controllen = sizeof(ctl);
425 
426 	ret = recvmsg(fd, &msg, 0);
427 	if (!ASSERT_EQ(ret, s, "recvmsg"))
428 		return;
429 	ASSERT_STRNEQ(data, expected, s, "expected rcv data");
430 
431 	cmsg = CMSG_FIRSTHDR(&msg);
432 	if (cmsg && cmsg->cmsg_level == SOL_SOCKET &&
433 	    cmsg->cmsg_type == SO_TIMESTAMPNS_NEW)
434 		memcpy(&pkt_ts, CMSG_DATA(cmsg), sizeof(pkt_ts));
435 
436 	pkt_ns = pkt_ts.tv_sec * NSEC_PER_SEC + pkt_ts.tv_nsec;
437 	ASSERT_NEQ(pkt_ns, 0, "pkt rcv tstamp");
438 
439 	ret = clock_gettime(CLOCK_REALTIME, &now_ts);
440 	ASSERT_OK(ret, "clock_gettime");
441 	now_ns = now_ts.tv_sec * NSEC_PER_SEC + now_ts.tv_nsec;
442 
443 	if (ASSERT_GE(now_ns, pkt_ns, "check rcv tstamp"))
444 		ASSERT_LT(now_ns - pkt_ns, 5 * NSEC_PER_SEC,
445 			  "check rcv tstamp");
446 }
447 
448 static void snd_tstamp(int fd, char *b, size_t s)
449 {
450 	struct sock_txtime opt = { .clockid = CLOCK_TAI };
451 	char ctl[CMSG_SPACE(sizeof(__u64))];
452 	struct timespec now_ts;
453 	struct msghdr msg = {};
454 	struct cmsghdr *cmsg;
455 	struct iovec iov;
456 	__u64 now_ns;
457 	int ret;
458 
459 	ret = clock_gettime(CLOCK_TAI, &now_ts);
460 	ASSERT_OK(ret, "clock_get_time(CLOCK_TAI)");
461 	now_ns = now_ts.tv_sec * NSEC_PER_SEC + now_ts.tv_nsec;
462 
463 	iov.iov_base = b;
464 	iov.iov_len = s;
465 	msg.msg_iov = &iov;
466 	msg.msg_iovlen = 1;
467 	msg.msg_control = &ctl;
468 	msg.msg_controllen = sizeof(ctl);
469 
470 	cmsg = CMSG_FIRSTHDR(&msg);
471 	cmsg->cmsg_level = SOL_SOCKET;
472 	cmsg->cmsg_type = SCM_TXTIME;
473 	cmsg->cmsg_len = CMSG_LEN(sizeof(now_ns));
474 	*(__u64 *)CMSG_DATA(cmsg) = now_ns;
475 
476 	ret = setsockopt(fd, SOL_SOCKET, SO_TXTIME, &opt, sizeof(opt));
477 	ASSERT_OK(ret, "setsockopt(SO_TXTIME)");
478 
479 	ret = sendmsg(fd, &msg, 0);
480 	ASSERT_EQ(ret, s, "sendmsg");
481 }
482 
483 static void test_inet_dtime(int family, int type, const char *addr, __u16 port)
484 {
485 	int opt = 1, accept_fd = -1, client_fd = -1, listen_fd, err;
486 	char buf[] = "testing testing";
487 	struct nstoken *nstoken;
488 
489 	nstoken = open_netns(NS_DST);
490 	if (!ASSERT_OK_PTR(nstoken, "setns dst"))
491 		return;
492 	listen_fd = start_server(family, type, addr, port, 0);
493 	close_netns(nstoken);
494 
495 	if (!ASSERT_GE(listen_fd, 0, "listen"))
496 		return;
497 
498 	/* Ensure the kernel puts the (rcv) timestamp for all skb */
499 	err = setsockopt(listen_fd, SOL_SOCKET, SO_TIMESTAMPNS_NEW,
500 			 &opt, sizeof(opt));
501 	if (!ASSERT_OK(err, "setsockopt(SO_TIMESTAMPNS_NEW)"))
502 		goto done;
503 
504 	if (type == SOCK_STREAM) {
505 		/* Ensure the kernel set EDT when sending out rst/ack
506 		 * from the kernel's ctl_sk.
507 		 */
508 		err = setsockopt(listen_fd, SOL_TCP, TCP_TX_DELAY, &opt,
509 				 sizeof(opt));
510 		if (!ASSERT_OK(err, "setsockopt(TCP_TX_DELAY)"))
511 			goto done;
512 	}
513 
514 	nstoken = open_netns(NS_SRC);
515 	if (!ASSERT_OK_PTR(nstoken, "setns src"))
516 		goto done;
517 	client_fd = connect_to_fd(listen_fd, TIMEOUT_MILLIS);
518 	close_netns(nstoken);
519 
520 	if (!ASSERT_GE(client_fd, 0, "connect_to_fd"))
521 		goto done;
522 
523 	if (type == SOCK_STREAM) {
524 		int n;
525 
526 		accept_fd = accept(listen_fd, NULL, NULL);
527 		if (!ASSERT_GE(accept_fd, 0, "accept"))
528 			goto done;
529 
530 		n = write(client_fd, buf, sizeof(buf));
531 		if (!ASSERT_EQ(n, sizeof(buf), "send to server"))
532 			goto done;
533 		rcv_tstamp(accept_fd, buf, sizeof(buf));
534 	} else {
535 		snd_tstamp(client_fd, buf, sizeof(buf));
536 		rcv_tstamp(listen_fd, buf, sizeof(buf));
537 	}
538 
539 done:
540 	close(listen_fd);
541 	if (accept_fd != -1)
542 		close(accept_fd);
543 	if (client_fd != -1)
544 		close(client_fd);
545 }
546 
547 static int netns_load_dtime_bpf(struct test_tc_dtime *skel,
548 				const struct netns_setup_result *setup_result)
549 {
550 	LIBBPF_OPTS(bpf_tc_hook, qdisc_veth_src_fwd);
551 	LIBBPF_OPTS(bpf_tc_hook, qdisc_veth_dst_fwd);
552 	LIBBPF_OPTS(bpf_tc_hook, qdisc_veth_src);
553 	LIBBPF_OPTS(bpf_tc_hook, qdisc_veth_dst);
554 	struct nstoken *nstoken;
555 	int err;
556 
557 	/* setup ns_src tc progs */
558 	nstoken = open_netns(NS_SRC);
559 	if (!ASSERT_OK_PTR(nstoken, "setns " NS_SRC))
560 		return -1;
561 	/* tc qdisc add dev veth_src clsact */
562 	QDISC_CLSACT_CREATE(&qdisc_veth_src, setup_result->ifindex_veth_src);
563 	/* tc filter add dev veth_src ingress bpf da ingress_host */
564 	XGRESS_FILTER_ADD(&qdisc_veth_src, BPF_TC_INGRESS, skel->progs.ingress_host, 0);
565 	/* tc filter add dev veth_src egress bpf da egress_host */
566 	XGRESS_FILTER_ADD(&qdisc_veth_src, BPF_TC_EGRESS, skel->progs.egress_host, 0);
567 	close_netns(nstoken);
568 
569 	/* setup ns_dst tc progs */
570 	nstoken = open_netns(NS_DST);
571 	if (!ASSERT_OK_PTR(nstoken, "setns " NS_DST))
572 		return -1;
573 	/* tc qdisc add dev veth_dst clsact */
574 	QDISC_CLSACT_CREATE(&qdisc_veth_dst, setup_result->ifindex_veth_dst);
575 	/* tc filter add dev veth_dst ingress bpf da ingress_host */
576 	XGRESS_FILTER_ADD(&qdisc_veth_dst, BPF_TC_INGRESS, skel->progs.ingress_host, 0);
577 	/* tc filter add dev veth_dst egress bpf da egress_host */
578 	XGRESS_FILTER_ADD(&qdisc_veth_dst, BPF_TC_EGRESS, skel->progs.egress_host, 0);
579 	close_netns(nstoken);
580 
581 	/* setup ns_fwd tc progs */
582 	nstoken = open_netns(NS_FWD);
583 	if (!ASSERT_OK_PTR(nstoken, "setns " NS_FWD))
584 		return -1;
585 	/* tc qdisc add dev veth_dst_fwd clsact */
586 	QDISC_CLSACT_CREATE(&qdisc_veth_dst_fwd, setup_result->ifindex_veth_dst_fwd);
587 	/* tc filter add dev veth_dst_fwd ingress prio 100 bpf da ingress_fwdns_prio100 */
588 	XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_INGRESS,
589 			  skel->progs.ingress_fwdns_prio100, 100);
590 	/* tc filter add dev veth_dst_fwd ingress prio 101 bpf da ingress_fwdns_prio101 */
591 	XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_INGRESS,
592 			  skel->progs.ingress_fwdns_prio101, 101);
593 	/* tc filter add dev veth_dst_fwd egress prio 100 bpf da egress_fwdns_prio100 */
594 	XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_EGRESS,
595 			  skel->progs.egress_fwdns_prio100, 100);
596 	/* tc filter add dev veth_dst_fwd egress prio 101 bpf da egress_fwdns_prio101 */
597 	XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_EGRESS,
598 			  skel->progs.egress_fwdns_prio101, 101);
599 
600 	/* tc qdisc add dev veth_src_fwd clsact */
601 	QDISC_CLSACT_CREATE(&qdisc_veth_src_fwd, setup_result->ifindex_veth_src_fwd);
602 	/* tc filter add dev veth_src_fwd ingress prio 100 bpf da ingress_fwdns_prio100 */
603 	XGRESS_FILTER_ADD(&qdisc_veth_src_fwd, BPF_TC_INGRESS,
604 			  skel->progs.ingress_fwdns_prio100, 100);
605 	/* tc filter add dev veth_src_fwd ingress prio 101 bpf da ingress_fwdns_prio101 */
606 	XGRESS_FILTER_ADD(&qdisc_veth_src_fwd, BPF_TC_INGRESS,
607 			  skel->progs.ingress_fwdns_prio101, 101);
608 	/* tc filter add dev veth_src_fwd egress prio 100 bpf da egress_fwdns_prio100 */
609 	XGRESS_FILTER_ADD(&qdisc_veth_src_fwd, BPF_TC_EGRESS,
610 			  skel->progs.egress_fwdns_prio100, 100);
611 	/* tc filter add dev veth_src_fwd egress prio 101 bpf da egress_fwdns_prio101 */
612 	XGRESS_FILTER_ADD(&qdisc_veth_src_fwd, BPF_TC_EGRESS,
613 			  skel->progs.egress_fwdns_prio101, 101);
614 	close_netns(nstoken);
615 	return 0;
616 
617 fail:
618 	close_netns(nstoken);
619 	return err;
620 }
621 
622 enum {
623 	INGRESS_FWDNS_P100,
624 	INGRESS_FWDNS_P101,
625 	EGRESS_FWDNS_P100,
626 	EGRESS_FWDNS_P101,
627 	INGRESS_ENDHOST,
628 	EGRESS_ENDHOST,
629 	SET_DTIME,
630 	__MAX_CNT,
631 };
632 
633 const char *cnt_names[] = {
634 	"ingress_fwdns_p100",
635 	"ingress_fwdns_p101",
636 	"egress_fwdns_p100",
637 	"egress_fwdns_p101",
638 	"ingress_endhost",
639 	"egress_endhost",
640 	"set_dtime",
641 };
642 
643 enum {
644 	TCP_IP6_CLEAR_DTIME,
645 	TCP_IP4,
646 	TCP_IP6,
647 	UDP_IP4,
648 	UDP_IP6,
649 	TCP_IP4_RT_FWD,
650 	TCP_IP6_RT_FWD,
651 	UDP_IP4_RT_FWD,
652 	UDP_IP6_RT_FWD,
653 	UKN_TEST,
654 	__NR_TESTS,
655 };
656 
657 const char *test_names[] = {
658 	"tcp ip6 clear dtime",
659 	"tcp ip4",
660 	"tcp ip6",
661 	"udp ip4",
662 	"udp ip6",
663 	"tcp ip4 rt fwd",
664 	"tcp ip6 rt fwd",
665 	"udp ip4 rt fwd",
666 	"udp ip6 rt fwd",
667 };
668 
669 static const char *dtime_cnt_str(int test, int cnt)
670 {
671 	static char name[64];
672 
673 	snprintf(name, sizeof(name), "%s %s", test_names[test], cnt_names[cnt]);
674 
675 	return name;
676 }
677 
678 static const char *dtime_err_str(int test, int cnt)
679 {
680 	static char name[64];
681 
682 	snprintf(name, sizeof(name), "%s %s errs", test_names[test],
683 		 cnt_names[cnt]);
684 
685 	return name;
686 }
687 
688 static void test_tcp_clear_dtime(struct test_tc_dtime *skel)
689 {
690 	int i, t = TCP_IP6_CLEAR_DTIME;
691 	__u32 *dtimes = skel->bss->dtimes[t];
692 	__u32 *errs = skel->bss->errs[t];
693 
694 	skel->bss->test = t;
695 	test_inet_dtime(AF_INET6, SOCK_STREAM, IP6_DST, 50000 + t);
696 
697 	ASSERT_EQ(dtimes[INGRESS_FWDNS_P100], 0,
698 		  dtime_cnt_str(t, INGRESS_FWDNS_P100));
699 	ASSERT_EQ(dtimes[INGRESS_FWDNS_P101], 0,
700 		  dtime_cnt_str(t, INGRESS_FWDNS_P101));
701 	ASSERT_GT(dtimes[EGRESS_FWDNS_P100], 0,
702 		  dtime_cnt_str(t, EGRESS_FWDNS_P100));
703 	ASSERT_EQ(dtimes[EGRESS_FWDNS_P101], 0,
704 		  dtime_cnt_str(t, EGRESS_FWDNS_P101));
705 	ASSERT_GT(dtimes[EGRESS_ENDHOST], 0,
706 		  dtime_cnt_str(t, EGRESS_ENDHOST));
707 	ASSERT_GT(dtimes[INGRESS_ENDHOST], 0,
708 		  dtime_cnt_str(t, INGRESS_ENDHOST));
709 
710 	for (i = INGRESS_FWDNS_P100; i < __MAX_CNT; i++)
711 		ASSERT_EQ(errs[i], 0, dtime_err_str(t, i));
712 }
713 
714 static void test_tcp_dtime(struct test_tc_dtime *skel, int family, bool bpf_fwd)
715 {
716 	__u32 *dtimes, *errs;
717 	const char *addr;
718 	int i, t;
719 
720 	if (family == AF_INET) {
721 		t = bpf_fwd ? TCP_IP4 : TCP_IP4_RT_FWD;
722 		addr = IP4_DST;
723 	} else {
724 		t = bpf_fwd ? TCP_IP6 : TCP_IP6_RT_FWD;
725 		addr = IP6_DST;
726 	}
727 
728 	dtimes = skel->bss->dtimes[t];
729 	errs = skel->bss->errs[t];
730 
731 	skel->bss->test = t;
732 	test_inet_dtime(family, SOCK_STREAM, addr, 50000 + t);
733 
734 	/* fwdns_prio100 prog does not read delivery_time_type, so
735 	 * kernel puts the (rcv) timetamp in __sk_buff->tstamp
736 	 */
737 	ASSERT_EQ(dtimes[INGRESS_FWDNS_P100], 0,
738 		  dtime_cnt_str(t, INGRESS_FWDNS_P100));
739 	for (i = INGRESS_FWDNS_P101; i < SET_DTIME; i++)
740 		ASSERT_GT(dtimes[i], 0, dtime_cnt_str(t, i));
741 
742 	for (i = INGRESS_FWDNS_P100; i < __MAX_CNT; i++)
743 		ASSERT_EQ(errs[i], 0, dtime_err_str(t, i));
744 }
745 
746 static void test_udp_dtime(struct test_tc_dtime *skel, int family, bool bpf_fwd)
747 {
748 	__u32 *dtimes, *errs;
749 	const char *addr;
750 	int i, t;
751 
752 	if (family == AF_INET) {
753 		t = bpf_fwd ? UDP_IP4 : UDP_IP4_RT_FWD;
754 		addr = IP4_DST;
755 	} else {
756 		t = bpf_fwd ? UDP_IP6 : UDP_IP6_RT_FWD;
757 		addr = IP6_DST;
758 	}
759 
760 	dtimes = skel->bss->dtimes[t];
761 	errs = skel->bss->errs[t];
762 
763 	skel->bss->test = t;
764 	test_inet_dtime(family, SOCK_DGRAM, addr, 50000 + t);
765 
766 	ASSERT_EQ(dtimes[INGRESS_FWDNS_P100], 0,
767 		  dtime_cnt_str(t, INGRESS_FWDNS_P100));
768 	/* non mono delivery time is not forwarded */
769 	ASSERT_EQ(dtimes[INGRESS_FWDNS_P101], 0,
770 		  dtime_cnt_str(t, INGRESS_FWDNS_P101));
771 	for (i = EGRESS_FWDNS_P100; i < SET_DTIME; i++)
772 		ASSERT_GT(dtimes[i], 0, dtime_cnt_str(t, i));
773 
774 	for (i = INGRESS_FWDNS_P100; i < __MAX_CNT; i++)
775 		ASSERT_EQ(errs[i], 0, dtime_err_str(t, i));
776 }
777 
778 static void test_tc_redirect_dtime(struct netns_setup_result *setup_result)
779 {
780 	struct test_tc_dtime *skel;
781 	struct nstoken *nstoken;
782 	int err;
783 
784 	skel = test_tc_dtime__open();
785 	if (!ASSERT_OK_PTR(skel, "test_tc_dtime__open"))
786 		return;
787 
788 	skel->rodata->IFINDEX_SRC = setup_result->ifindex_veth_src_fwd;
789 	skel->rodata->IFINDEX_DST = setup_result->ifindex_veth_dst_fwd;
790 
791 	err = test_tc_dtime__load(skel);
792 	if (!ASSERT_OK(err, "test_tc_dtime__load"))
793 		goto done;
794 
795 	if (netns_load_dtime_bpf(skel, setup_result))
796 		goto done;
797 
798 	nstoken = open_netns(NS_FWD);
799 	if (!ASSERT_OK_PTR(nstoken, "setns fwd"))
800 		goto done;
801 	err = set_forwarding(false);
802 	close_netns(nstoken);
803 	if (!ASSERT_OK(err, "disable forwarding"))
804 		goto done;
805 
806 	test_tcp_clear_dtime(skel);
807 
808 	test_tcp_dtime(skel, AF_INET, true);
809 	test_tcp_dtime(skel, AF_INET6, true);
810 	test_udp_dtime(skel, AF_INET, true);
811 	test_udp_dtime(skel, AF_INET6, true);
812 
813 	/* Test the kernel ip[6]_forward path instead
814 	 * of bpf_redirect_neigh().
815 	 */
816 	nstoken = open_netns(NS_FWD);
817 	if (!ASSERT_OK_PTR(nstoken, "setns fwd"))
818 		goto done;
819 	err = set_forwarding(true);
820 	close_netns(nstoken);
821 	if (!ASSERT_OK(err, "enable forwarding"))
822 		goto done;
823 
824 	test_tcp_dtime(skel, AF_INET, false);
825 	test_tcp_dtime(skel, AF_INET6, false);
826 	test_udp_dtime(skel, AF_INET, false);
827 	test_udp_dtime(skel, AF_INET6, false);
828 
829 done:
830 	test_tc_dtime__destroy(skel);
831 }
832 
833 static void test_tc_redirect_neigh_fib(struct netns_setup_result *setup_result)
834 {
835 	struct nstoken *nstoken = NULL;
836 	struct test_tc_neigh_fib *skel = NULL;
837 
838 	nstoken = open_netns(NS_FWD);
839 	if (!ASSERT_OK_PTR(nstoken, "setns fwd"))
840 		return;
841 
842 	skel = test_tc_neigh_fib__open();
843 	if (!ASSERT_OK_PTR(skel, "test_tc_neigh_fib__open"))
844 		goto done;
845 
846 	if (!ASSERT_OK(test_tc_neigh_fib__load(skel), "test_tc_neigh_fib__load"))
847 		goto done;
848 
849 	if (netns_load_bpf(skel->progs.tc_src, skel->progs.tc_dst,
850 			   skel->progs.tc_chk, setup_result))
851 		goto done;
852 
853 	/* bpf_fib_lookup() checks if forwarding is enabled */
854 	if (!ASSERT_OK(set_forwarding(true), "enable forwarding"))
855 		goto done;
856 
857 	test_connectivity();
858 
859 done:
860 	if (skel)
861 		test_tc_neigh_fib__destroy(skel);
862 	close_netns(nstoken);
863 }
864 
865 static void test_tc_redirect_neigh(struct netns_setup_result *setup_result)
866 {
867 	struct nstoken *nstoken = NULL;
868 	struct test_tc_neigh *skel = NULL;
869 	int err;
870 
871 	nstoken = open_netns(NS_FWD);
872 	if (!ASSERT_OK_PTR(nstoken, "setns fwd"))
873 		return;
874 
875 	skel = test_tc_neigh__open();
876 	if (!ASSERT_OK_PTR(skel, "test_tc_neigh__open"))
877 		goto done;
878 
879 	skel->rodata->IFINDEX_SRC = setup_result->ifindex_veth_src_fwd;
880 	skel->rodata->IFINDEX_DST = setup_result->ifindex_veth_dst_fwd;
881 
882 	err = test_tc_neigh__load(skel);
883 	if (!ASSERT_OK(err, "test_tc_neigh__load"))
884 		goto done;
885 
886 	if (netns_load_bpf(skel->progs.tc_src, skel->progs.tc_dst,
887 			   skel->progs.tc_chk, setup_result))
888 		goto done;
889 
890 	if (!ASSERT_OK(set_forwarding(false), "disable forwarding"))
891 		goto done;
892 
893 	test_connectivity();
894 
895 done:
896 	if (skel)
897 		test_tc_neigh__destroy(skel);
898 	close_netns(nstoken);
899 }
900 
901 static void test_tc_redirect_peer(struct netns_setup_result *setup_result)
902 {
903 	struct nstoken *nstoken;
904 	struct test_tc_peer *skel;
905 	int err;
906 
907 	nstoken = open_netns(NS_FWD);
908 	if (!ASSERT_OK_PTR(nstoken, "setns fwd"))
909 		return;
910 
911 	skel = test_tc_peer__open();
912 	if (!ASSERT_OK_PTR(skel, "test_tc_peer__open"))
913 		goto done;
914 
915 	skel->rodata->IFINDEX_SRC = setup_result->ifindex_veth_src_fwd;
916 	skel->rodata->IFINDEX_DST = setup_result->ifindex_veth_dst_fwd;
917 
918 	err = test_tc_peer__load(skel);
919 	if (!ASSERT_OK(err, "test_tc_peer__load"))
920 		goto done;
921 
922 	if (netns_load_bpf(skel->progs.tc_src, skel->progs.tc_dst,
923 			   skel->progs.tc_chk, setup_result))
924 		goto done;
925 
926 	if (!ASSERT_OK(set_forwarding(false), "disable forwarding"))
927 		goto done;
928 
929 	test_connectivity();
930 
931 done:
932 	if (skel)
933 		test_tc_peer__destroy(skel);
934 	close_netns(nstoken);
935 }
936 
937 static int tun_open(char *name)
938 {
939 	struct ifreq ifr;
940 	int fd, err;
941 
942 	fd = open("/dev/net/tun", O_RDWR);
943 	if (!ASSERT_GE(fd, 0, "open /dev/net/tun"))
944 		return -1;
945 
946 	memset(&ifr, 0, sizeof(ifr));
947 
948 	ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
949 	if (*name)
950 		strncpy(ifr.ifr_name, name, IFNAMSIZ);
951 
952 	err = ioctl(fd, TUNSETIFF, &ifr);
953 	if (!ASSERT_OK(err, "ioctl TUNSETIFF"))
954 		goto fail;
955 
956 	SYS("ip link set dev %s up", name);
957 
958 	return fd;
959 fail:
960 	close(fd);
961 	return -1;
962 }
963 
964 enum {
965 	SRC_TO_TARGET = 0,
966 	TARGET_TO_SRC = 1,
967 };
968 
969 static int tun_relay_loop(int src_fd, int target_fd)
970 {
971 	fd_set rfds, wfds;
972 
973 	FD_ZERO(&rfds);
974 	FD_ZERO(&wfds);
975 
976 	for (;;) {
977 		char buf[1500];
978 		int direction, nread, nwrite;
979 
980 		FD_SET(src_fd, &rfds);
981 		FD_SET(target_fd, &rfds);
982 
983 		if (select(1 + MAX(src_fd, target_fd), &rfds, NULL, NULL, NULL) < 0) {
984 			log_err("select failed");
985 			return 1;
986 		}
987 
988 		direction = FD_ISSET(src_fd, &rfds) ? SRC_TO_TARGET : TARGET_TO_SRC;
989 
990 		nread = read(direction == SRC_TO_TARGET ? src_fd : target_fd, buf, sizeof(buf));
991 		if (nread < 0) {
992 			log_err("read failed");
993 			return 1;
994 		}
995 
996 		nwrite = write(direction == SRC_TO_TARGET ? target_fd : src_fd, buf, nread);
997 		if (nwrite != nread) {
998 			log_err("write failed");
999 			return 1;
1000 		}
1001 	}
1002 }
1003 
1004 static void test_tc_redirect_peer_l3(struct netns_setup_result *setup_result)
1005 {
1006 	LIBBPF_OPTS(bpf_tc_hook, qdisc_tun_fwd);
1007 	LIBBPF_OPTS(bpf_tc_hook, qdisc_veth_dst_fwd);
1008 	struct test_tc_peer *skel = NULL;
1009 	struct nstoken *nstoken = NULL;
1010 	int err;
1011 	int tunnel_pid = -1;
1012 	int src_fd, target_fd = -1;
1013 	int ifindex;
1014 
1015 	/* Start a L3 TUN/TAP tunnel between the src and dst namespaces.
1016 	 * This test is using TUN/TAP instead of e.g. IPIP or GRE tunnel as those
1017 	 * expose the L2 headers encapsulating the IP packet to BPF and hence
1018 	 * don't have skb in suitable state for this test. Alternative to TUN/TAP
1019 	 * would be e.g. Wireguard which would appear as a pure L3 device to BPF,
1020 	 * but that requires much more complicated setup.
1021 	 */
1022 	nstoken = open_netns(NS_SRC);
1023 	if (!ASSERT_OK_PTR(nstoken, "setns " NS_SRC))
1024 		return;
1025 
1026 	src_fd = tun_open("tun_src");
1027 	if (!ASSERT_GE(src_fd, 0, "tun_open tun_src"))
1028 		goto fail;
1029 
1030 	close_netns(nstoken);
1031 
1032 	nstoken = open_netns(NS_FWD);
1033 	if (!ASSERT_OK_PTR(nstoken, "setns " NS_FWD))
1034 		goto fail;
1035 
1036 	target_fd = tun_open("tun_fwd");
1037 	if (!ASSERT_GE(target_fd, 0, "tun_open tun_fwd"))
1038 		goto fail;
1039 
1040 	tunnel_pid = fork();
1041 	if (!ASSERT_GE(tunnel_pid, 0, "fork tun_relay_loop"))
1042 		goto fail;
1043 
1044 	if (tunnel_pid == 0)
1045 		exit(tun_relay_loop(src_fd, target_fd));
1046 
1047 	skel = test_tc_peer__open();
1048 	if (!ASSERT_OK_PTR(skel, "test_tc_peer__open"))
1049 		goto fail;
1050 
1051 	ifindex = if_nametoindex("tun_fwd");
1052 	if (!ASSERT_GT(ifindex, 0, "if_indextoname tun_fwd"))
1053 		goto fail;
1054 
1055 	skel->rodata->IFINDEX_SRC = ifindex;
1056 	skel->rodata->IFINDEX_DST = setup_result->ifindex_veth_dst_fwd;
1057 
1058 	err = test_tc_peer__load(skel);
1059 	if (!ASSERT_OK(err, "test_tc_peer__load"))
1060 		goto fail;
1061 
1062 	/* Load "tc_src_l3" to the tun_fwd interface to redirect packets
1063 	 * towards dst, and "tc_dst" to redirect packets
1064 	 * and "tc_chk" on veth_dst_fwd to drop non-redirected packets.
1065 	 */
1066 	/* tc qdisc add dev tun_fwd clsact */
1067 	QDISC_CLSACT_CREATE(&qdisc_tun_fwd, ifindex);
1068 	/* tc filter add dev tun_fwd ingress bpf da tc_src_l3 */
1069 	XGRESS_FILTER_ADD(&qdisc_tun_fwd, BPF_TC_INGRESS, skel->progs.tc_src_l3, 0);
1070 
1071 	/* tc qdisc add dev veth_dst_fwd clsact */
1072 	QDISC_CLSACT_CREATE(&qdisc_veth_dst_fwd, setup_result->ifindex_veth_dst_fwd);
1073 	/* tc filter add dev veth_dst_fwd ingress bpf da tc_dst_l3 */
1074 	XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_INGRESS, skel->progs.tc_dst_l3, 0);
1075 	/* tc filter add dev veth_dst_fwd egress bpf da tc_chk */
1076 	XGRESS_FILTER_ADD(&qdisc_veth_dst_fwd, BPF_TC_EGRESS, skel->progs.tc_chk, 0);
1077 
1078 	/* Setup route and neigh tables */
1079 	SYS("ip -netns " NS_SRC " addr add dev tun_src " IP4_TUN_SRC "/24");
1080 	SYS("ip -netns " NS_FWD " addr add dev tun_fwd " IP4_TUN_FWD "/24");
1081 
1082 	SYS("ip -netns " NS_SRC " addr add dev tun_src " IP6_TUN_SRC "/64 nodad");
1083 	SYS("ip -netns " NS_FWD " addr add dev tun_fwd " IP6_TUN_FWD "/64 nodad");
1084 
1085 	SYS("ip -netns " NS_SRC " route del " IP4_DST "/32 dev veth_src scope global");
1086 	SYS("ip -netns " NS_SRC " route add " IP4_DST "/32 via " IP4_TUN_FWD
1087 	    " dev tun_src scope global");
1088 	SYS("ip -netns " NS_DST " route add " IP4_TUN_SRC "/32 dev veth_dst scope global");
1089 	SYS("ip -netns " NS_SRC " route del " IP6_DST "/128 dev veth_src scope global");
1090 	SYS("ip -netns " NS_SRC " route add " IP6_DST "/128 via " IP6_TUN_FWD
1091 	    " dev tun_src scope global");
1092 	SYS("ip -netns " NS_DST " route add " IP6_TUN_SRC "/128 dev veth_dst scope global");
1093 
1094 	SYS("ip -netns " NS_DST " neigh add " IP4_TUN_SRC " dev veth_dst lladdr " MAC_DST_FWD);
1095 	SYS("ip -netns " NS_DST " neigh add " IP6_TUN_SRC " dev veth_dst lladdr " MAC_DST_FWD);
1096 
1097 	if (!ASSERT_OK(set_forwarding(false), "disable forwarding"))
1098 		goto fail;
1099 
1100 	test_connectivity();
1101 
1102 fail:
1103 	if (tunnel_pid > 0) {
1104 		kill(tunnel_pid, SIGTERM);
1105 		waitpid(tunnel_pid, NULL, 0);
1106 	}
1107 	if (src_fd >= 0)
1108 		close(src_fd);
1109 	if (target_fd >= 0)
1110 		close(target_fd);
1111 	if (skel)
1112 		test_tc_peer__destroy(skel);
1113 	if (nstoken)
1114 		close_netns(nstoken);
1115 }
1116 
1117 #define RUN_TEST(name)                                                                      \
1118 	({                                                                                  \
1119 		struct netns_setup_result setup_result;                                     \
1120 		if (test__start_subtest(#name))                                             \
1121 			if (ASSERT_OK(netns_setup_namespaces("add"), "setup namespaces")) { \
1122 				if (ASSERT_OK(netns_setup_links_and_routes(&setup_result),  \
1123 					      "setup links and routes"))                    \
1124 					test_ ## name(&setup_result);                       \
1125 				netns_setup_namespaces("delete");                           \
1126 			}                                                                   \
1127 	})
1128 
1129 static void *test_tc_redirect_run_tests(void *arg)
1130 {
1131 	netns_setup_namespaces_nofail("delete");
1132 
1133 	RUN_TEST(tc_redirect_peer);
1134 	RUN_TEST(tc_redirect_peer_l3);
1135 	RUN_TEST(tc_redirect_neigh);
1136 	RUN_TEST(tc_redirect_neigh_fib);
1137 	RUN_TEST(tc_redirect_dtime);
1138 	return NULL;
1139 }
1140 
1141 void test_tc_redirect(void)
1142 {
1143 	pthread_t test_thread;
1144 	int err;
1145 
1146 	/* Run the tests in their own thread to isolate the namespace changes
1147 	 * so they do not affect the environment of other tests.
1148 	 * (specifically needed because of unshare(CLONE_NEWNS) in open_netns())
1149 	 */
1150 	err = pthread_create(&test_thread, NULL, &test_tc_redirect_run_tests, NULL);
1151 	if (ASSERT_OK(err, "pthread_create"))
1152 		ASSERT_OK(pthread_join(test_thread, NULL), "pthread_join");
1153 }
1154