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