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 "netlink_helpers.h"
28 #include "test_tc_neigh_fib.skel.h"
29 #include "test_tc_neigh.skel.h"
30 #include "test_tc_peer.skel.h"
31 #include "test_tc_dtime.skel.h"
32
33 #ifndef TCP_TX_DELAY
34 #define TCP_TX_DELAY 37
35 #endif
36
37 #define NS_SRC "ns_src"
38 #define NS_FWD "ns_fwd"
39 #define NS_DST "ns_dst"
40
41 #define IP4_SRC "172.16.1.100"
42 #define IP4_DST "172.16.2.100"
43 #define IP4_TUN_SRC "172.17.1.100"
44 #define IP4_TUN_FWD "172.17.1.200"
45 #define IP4_PORT 9004
46
47 #define IP6_SRC "0::1:dead:beef:cafe"
48 #define IP6_DST "0::2:dead:beef:cafe"
49 #define IP6_TUN_SRC "1::1:dead:beef:cafe"
50 #define IP6_TUN_FWD "1::2:dead:beef:cafe"
51 #define IP6_PORT 9006
52
53 #define IP4_SLL "169.254.0.1"
54 #define IP4_DLL "169.254.0.2"
55 #define IP4_NET "169.254.0.0"
56
57 #define MAC_DST_FWD "00:11:22:33:44:55"
58 #define MAC_DST "00:22:33:44:55:66"
59 #define MAC_SRC_FWD "00:33:44:55:66:77"
60 #define MAC_SRC "00:44:55:66:77:88"
61
62 #define IFADDR_STR_LEN 18
63 #define PING_ARGS "-i 0.2 -c 3 -w 10 -q"
64
65 #define TIMEOUT_MILLIS 10000
66 #define NSEC_PER_SEC 1000000000ULL
67
68 #define log_err(MSG, ...) \
69 fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", \
70 __FILE__, __LINE__, strerror(errno), ##__VA_ARGS__)
71
72 static const char * const namespaces[] = {NS_SRC, NS_FWD, NS_DST, NULL};
73 static struct netns_obj *netns_objs[3];
74
write_file(const char * path,const char * newval)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
netns_setup_namespaces(const char * verb)91 static int netns_setup_namespaces(const char *verb)
92 {
93 struct netns_obj **ns_obj = netns_objs;
94 const char * const *ns = namespaces;
95
96 while (*ns) {
97 if (strcmp(verb, "add") == 0) {
98 *ns_obj = netns_new(*ns, false);
99 if (!ASSERT_OK_PTR(*ns_obj, "netns_new"))
100 return -1;
101 } else {
102 if (!ASSERT_OK_PTR(*ns_obj, "netns_obj is NULL"))
103 return -1;
104 netns_free(*ns_obj);
105 *ns_obj = NULL;
106 }
107 ns++;
108 ns_obj++;
109 }
110 return 0;
111 }
112
netns_setup_namespaces_nofail(const char * verb)113 static void netns_setup_namespaces_nofail(const char *verb)
114 {
115 struct netns_obj **ns_obj = netns_objs;
116 const char * const *ns = namespaces;
117
118 while (*ns) {
119 if (strcmp(verb, "add") == 0) {
120 *ns_obj = netns_new(*ns, false);
121 } else {
122 if (*ns_obj)
123 netns_free(*ns_obj);
124 *ns_obj = NULL;
125 }
126 ns++;
127 ns_obj++;
128 }
129 }
130
131 enum dev_mode {
132 MODE_VETH,
133 MODE_NETKIT,
134 };
135
136 struct netns_setup_result {
137 enum dev_mode dev_mode;
138 int ifindex_src;
139 int ifindex_src_fwd;
140 int ifindex_dst;
141 int ifindex_dst_fwd;
142 };
143
get_ifaddr(const char * name,char * ifaddr)144 static int get_ifaddr(const char *name, char *ifaddr)
145 {
146 char path[PATH_MAX];
147 FILE *f;
148 int ret;
149
150 snprintf(path, PATH_MAX, "/sys/class/net/%s/address", name);
151 f = fopen(path, "r");
152 if (!ASSERT_OK_PTR(f, path))
153 return -1;
154
155 ret = fread(ifaddr, 1, IFADDR_STR_LEN, f);
156 if (!ASSERT_EQ(ret, IFADDR_STR_LEN, "fread ifaddr")) {
157 fclose(f);
158 return -1;
159 }
160 fclose(f);
161 return 0;
162 }
163
create_netkit(int mode,char * prim,char * peer)164 static int create_netkit(int mode, char *prim, char *peer)
165 {
166 struct rtattr *linkinfo, *data, *peer_info;
167 struct rtnl_handle rth = { .fd = -1 };
168 const char *type = "netkit";
169 struct {
170 struct nlmsghdr n;
171 struct ifinfomsg i;
172 char buf[1024];
173 } req = {};
174 int err;
175
176 err = rtnl_open(&rth, 0);
177 if (!ASSERT_OK(err, "open_rtnetlink"))
178 return err;
179
180 memset(&req, 0, sizeof(req));
181 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
182 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
183 req.n.nlmsg_type = RTM_NEWLINK;
184 req.i.ifi_family = AF_UNSPEC;
185
186 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, prim, strlen(prim));
187 linkinfo = addattr_nest(&req.n, sizeof(req), IFLA_LINKINFO);
188 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type, strlen(type));
189 data = addattr_nest(&req.n, sizeof(req), IFLA_INFO_DATA);
190 addattr32(&req.n, sizeof(req), IFLA_NETKIT_MODE, mode);
191 peer_info = addattr_nest(&req.n, sizeof(req), IFLA_NETKIT_PEER_INFO);
192 req.n.nlmsg_len += sizeof(struct ifinfomsg);
193 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, peer, strlen(peer));
194 addattr_nest_end(&req.n, peer_info);
195 addattr32(&req.n, sizeof(req), IFLA_NETKIT_SCRUB,
196 NETKIT_SCRUB_NONE);
197 addattr_nest_end(&req.n, data);
198 addattr_nest_end(&req.n, linkinfo);
199
200 err = rtnl_talk(&rth, &req.n, NULL);
201 ASSERT_OK(err, "talk_rtnetlink");
202 rtnl_close(&rth);
203 return err;
204 }
205
netns_setup_links_and_routes(struct netns_setup_result * result)206 static int netns_setup_links_and_routes(struct netns_setup_result *result)
207 {
208 struct nstoken *nstoken = NULL;
209 char src_fwd_addr[IFADDR_STR_LEN+1] = {};
210 char src_addr[IFADDR_STR_LEN + 1] = {};
211 int err;
212
213 if (result->dev_mode == MODE_VETH) {
214 SYS(fail, "ip link add src address " MAC_SRC " type veth "
215 "peer name src_fwd address " MAC_SRC_FWD);
216 SYS(fail, "ip link add dst address " MAC_DST " type veth "
217 "peer name dst_fwd address " MAC_DST_FWD);
218 } else if (result->dev_mode == MODE_NETKIT) {
219 err = create_netkit(NETKIT_L3, "src", "src_fwd");
220 if (!ASSERT_OK(err, "create_ifindex_src"))
221 goto fail;
222 err = create_netkit(NETKIT_L3, "dst", "dst_fwd");
223 if (!ASSERT_OK(err, "create_ifindex_dst"))
224 goto fail;
225 }
226
227 if (get_ifaddr("src_fwd", src_fwd_addr))
228 goto fail;
229
230 if (get_ifaddr("src", src_addr))
231 goto fail;
232
233 result->ifindex_src = if_nametoindex("src");
234 if (!ASSERT_GT(result->ifindex_src, 0, "ifindex_src"))
235 goto fail;
236
237 result->ifindex_src_fwd = if_nametoindex("src_fwd");
238 if (!ASSERT_GT(result->ifindex_src_fwd, 0, "ifindex_src_fwd"))
239 goto fail;
240
241 result->ifindex_dst = if_nametoindex("dst");
242 if (!ASSERT_GT(result->ifindex_dst, 0, "ifindex_dst"))
243 goto fail;
244
245 result->ifindex_dst_fwd = if_nametoindex("dst_fwd");
246 if (!ASSERT_GT(result->ifindex_dst_fwd, 0, "ifindex_dst_fwd"))
247 goto fail;
248
249 SYS(fail, "ip link set src netns " NS_SRC);
250 SYS(fail, "ip link set src_fwd netns " NS_FWD);
251 SYS(fail, "ip link set dst_fwd netns " NS_FWD);
252 SYS(fail, "ip link set dst netns " NS_DST);
253
254 /** setup in 'src' namespace */
255 nstoken = open_netns(NS_SRC);
256 if (!ASSERT_OK_PTR(nstoken, "setns src"))
257 goto fail;
258
259 SYS(fail, "ip addr add " IP4_SRC "/32 dev src");
260 SYS(fail, "ip addr add " IP6_SRC "/128 dev src nodad");
261 SYS(fail, "ip link set dev src up");
262
263 SYS(fail, "ip route add " IP4_DST "/32 dev src scope global");
264 SYS(fail, "ip route add " IP4_NET "/16 dev src scope global");
265 SYS(fail, "ip route add " IP6_DST "/128 dev src scope global");
266
267 if (result->dev_mode == MODE_VETH) {
268 SYS(fail, "ip neigh add " IP4_DST " dev src lladdr %s",
269 src_fwd_addr);
270 SYS(fail, "ip neigh add " IP6_DST " dev src lladdr %s",
271 src_fwd_addr);
272 }
273
274 close_netns(nstoken);
275
276 /** setup in 'fwd' namespace */
277 nstoken = open_netns(NS_FWD);
278 if (!ASSERT_OK_PTR(nstoken, "setns fwd"))
279 goto fail;
280
281 /* The fwd netns automatically gets a v6 LL address / routes, but also
282 * needs v4 one in order to start ARP probing. IP4_NET route is added
283 * to the endpoints so that the ARP processing will reply.
284 */
285 SYS(fail, "ip addr add " IP4_SLL "/32 dev src_fwd");
286 SYS(fail, "ip addr add " IP4_DLL "/32 dev dst_fwd");
287 SYS(fail, "ip link set dev src_fwd up");
288 SYS(fail, "ip link set dev dst_fwd up");
289
290 SYS(fail, "ip route add " IP4_SRC "/32 dev src_fwd scope global");
291 SYS(fail, "ip route add " IP6_SRC "/128 dev src_fwd scope global");
292 SYS(fail, "ip route add " IP4_DST "/32 dev dst_fwd scope global");
293 SYS(fail, "ip route add " IP6_DST "/128 dev dst_fwd scope global");
294
295 if (result->dev_mode == MODE_VETH) {
296 SYS(fail, "ip neigh add " IP4_SRC " dev src_fwd lladdr %s", src_addr);
297 SYS(fail, "ip neigh add " IP6_SRC " dev src_fwd lladdr %s", src_addr);
298 SYS(fail, "ip neigh add " IP4_DST " dev dst_fwd lladdr %s", MAC_DST);
299 SYS(fail, "ip neigh add " IP6_DST " dev dst_fwd lladdr %s", MAC_DST);
300 }
301
302 close_netns(nstoken);
303
304 /** setup in 'dst' namespace */
305 nstoken = open_netns(NS_DST);
306 if (!ASSERT_OK_PTR(nstoken, "setns dst"))
307 goto fail;
308
309 SYS(fail, "ip addr add " IP4_DST "/32 dev dst");
310 SYS(fail, "ip addr add " IP6_DST "/128 dev dst nodad");
311 SYS(fail, "ip link set dev dst up");
312 SYS(fail, "ip link set dev lo up");
313
314 SYS(fail, "ip route add " IP4_SRC "/32 dev dst scope global");
315 SYS(fail, "ip route add " IP4_NET "/16 dev dst scope global");
316 SYS(fail, "ip route add " IP6_SRC "/128 dev dst scope global");
317
318 if (result->dev_mode == MODE_VETH) {
319 SYS(fail, "ip neigh add " IP4_SRC " dev dst lladdr " MAC_DST_FWD);
320 SYS(fail, "ip neigh add " IP6_SRC " dev dst lladdr " MAC_DST_FWD);
321 }
322
323 close_netns(nstoken);
324
325 return 0;
326 fail:
327 if (nstoken)
328 close_netns(nstoken);
329 return -1;
330 }
331
qdisc_clsact_create(struct bpf_tc_hook * qdisc_hook,int ifindex)332 static int qdisc_clsact_create(struct bpf_tc_hook *qdisc_hook, int ifindex)
333 {
334 char err_str[128], ifname[16];
335 int err;
336
337 qdisc_hook->ifindex = ifindex;
338 qdisc_hook->attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
339 err = bpf_tc_hook_create(qdisc_hook);
340 snprintf(err_str, sizeof(err_str),
341 "qdisc add dev %s clsact",
342 if_indextoname(qdisc_hook->ifindex, ifname) ? : "<unknown_iface>");
343 err_str[sizeof(err_str) - 1] = 0;
344 ASSERT_OK(err, err_str);
345
346 return err;
347 }
348
xgress_filter_add(struct bpf_tc_hook * qdisc_hook,enum bpf_tc_attach_point xgress,const struct bpf_program * prog,int priority)349 static int xgress_filter_add(struct bpf_tc_hook *qdisc_hook,
350 enum bpf_tc_attach_point xgress,
351 const struct bpf_program *prog, int priority)
352 {
353 LIBBPF_OPTS(bpf_tc_opts, tc_attach);
354 char err_str[128], ifname[16];
355 int err;
356
357 qdisc_hook->attach_point = xgress;
358 tc_attach.prog_fd = bpf_program__fd(prog);
359 tc_attach.priority = priority;
360 err = bpf_tc_attach(qdisc_hook, &tc_attach);
361 snprintf(err_str, sizeof(err_str),
362 "filter add dev %s %s prio %d bpf da %s",
363 if_indextoname(qdisc_hook->ifindex, ifname) ? : "<unknown_iface>",
364 xgress == BPF_TC_INGRESS ? "ingress" : "egress",
365 priority, bpf_program__name(prog));
366 err_str[sizeof(err_str) - 1] = 0;
367 ASSERT_OK(err, err_str);
368
369 return err;
370 }
371
372 #define QDISC_CLSACT_CREATE(qdisc_hook, ifindex) ({ \
373 if ((err = qdisc_clsact_create(qdisc_hook, ifindex))) \
374 goto fail; \
375 })
376
377 #define XGRESS_FILTER_ADD(qdisc_hook, xgress, prog, priority) ({ \
378 if ((err = xgress_filter_add(qdisc_hook, xgress, prog, priority))) \
379 goto fail; \
380 })
381
netns_load_bpf(const struct bpf_program * src_prog,const struct bpf_program * dst_prog,const struct bpf_program * chk_prog,const struct netns_setup_result * setup_result)382 static int netns_load_bpf(const struct bpf_program *src_prog,
383 const struct bpf_program *dst_prog,
384 const struct bpf_program *chk_prog,
385 const struct netns_setup_result *setup_result)
386 {
387 LIBBPF_OPTS(bpf_tc_hook, qdisc_src_fwd);
388 LIBBPF_OPTS(bpf_tc_hook, qdisc_dst_fwd);
389 int err;
390
391 /* tc qdisc add dev src_fwd clsact */
392 QDISC_CLSACT_CREATE(&qdisc_src_fwd, setup_result->ifindex_src_fwd);
393 /* tc filter add dev src_fwd ingress bpf da src_prog */
394 XGRESS_FILTER_ADD(&qdisc_src_fwd, BPF_TC_INGRESS, src_prog, 0);
395 /* tc filter add dev src_fwd egress bpf da chk_prog */
396 XGRESS_FILTER_ADD(&qdisc_src_fwd, BPF_TC_EGRESS, chk_prog, 0);
397
398 /* tc qdisc add dev dst_fwd clsact */
399 QDISC_CLSACT_CREATE(&qdisc_dst_fwd, setup_result->ifindex_dst_fwd);
400 /* tc filter add dev dst_fwd ingress bpf da dst_prog */
401 XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_INGRESS, dst_prog, 0);
402 /* tc filter add dev dst_fwd egress bpf da chk_prog */
403 XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_EGRESS, chk_prog, 0);
404
405 return 0;
406 fail:
407 return -1;
408 }
409
netns_attach_nk(const char * ns,int ifindex,struct bpf_program * prog)410 static struct bpf_link *netns_attach_nk(const char *ns, int ifindex,
411 struct bpf_program *prog)
412 {
413 LIBBPF_OPTS(bpf_netkit_opts, optl);
414 struct nstoken *nstoken = NULL;
415 struct bpf_link *link = NULL;
416
417 nstoken = open_netns(ns);
418 if (!ASSERT_OK_PTR(nstoken, "setns"))
419 goto cleanup;
420
421 link = bpf_program__attach_netkit(prog, ifindex, &optl);
422 cleanup:
423 if (nstoken)
424 close_netns(nstoken);
425 return link;
426 }
427
test_tcp(int family,const char * addr,__u16 port)428 static void test_tcp(int family, const char *addr, __u16 port)
429 {
430 int listen_fd = -1, accept_fd = -1, client_fd = -1;
431 char buf[] = "testing testing";
432 int n;
433 struct nstoken *nstoken;
434
435 nstoken = open_netns(NS_DST);
436 if (!ASSERT_OK_PTR(nstoken, "setns dst"))
437 return;
438
439 listen_fd = start_server(family, SOCK_STREAM, addr, port, 0);
440 if (!ASSERT_GE(listen_fd, 0, "listen"))
441 goto done;
442
443 close_netns(nstoken);
444 nstoken = open_netns(NS_SRC);
445 if (!ASSERT_OK_PTR(nstoken, "setns src"))
446 goto done;
447
448 client_fd = connect_to_fd(listen_fd, TIMEOUT_MILLIS);
449 if (!ASSERT_GE(client_fd, 0, "connect_to_fd"))
450 goto done;
451
452 accept_fd = accept(listen_fd, NULL, NULL);
453 if (!ASSERT_GE(accept_fd, 0, "accept"))
454 goto done;
455
456 if (!ASSERT_OK(settimeo(accept_fd, TIMEOUT_MILLIS), "settimeo"))
457 goto done;
458
459 n = write(client_fd, buf, sizeof(buf));
460 if (!ASSERT_EQ(n, sizeof(buf), "send to server"))
461 goto done;
462
463 n = read(accept_fd, buf, sizeof(buf));
464 ASSERT_EQ(n, sizeof(buf), "recv from server");
465
466 done:
467 if (nstoken)
468 close_netns(nstoken);
469 if (listen_fd >= 0)
470 close(listen_fd);
471 if (accept_fd >= 0)
472 close(accept_fd);
473 if (client_fd >= 0)
474 close(client_fd);
475 }
476
test_ping(int family,const char * addr)477 static int test_ping(int family, const char *addr)
478 {
479 SYS(fail, "ip netns exec " NS_SRC " %s " PING_ARGS " %s > /dev/null", ping_command(family), addr);
480 return 0;
481 fail:
482 return -1;
483 }
484
test_connectivity(void)485 static void test_connectivity(void)
486 {
487 test_tcp(AF_INET, IP4_DST, IP4_PORT);
488 test_ping(AF_INET, IP4_DST);
489 test_tcp(AF_INET6, IP6_DST, IP6_PORT);
490 test_ping(AF_INET6, IP6_DST);
491 }
492
set_forwarding(bool enable)493 static int set_forwarding(bool enable)
494 {
495 int err;
496
497 err = write_file("/proc/sys/net/ipv4/ip_forward", enable ? "1" : "0");
498 if (!ASSERT_OK(err, "set ipv4.ip_forward=0"))
499 return err;
500
501 err = write_file("/proc/sys/net/ipv6/conf/all/forwarding", enable ? "1" : "0");
502 if (!ASSERT_OK(err, "set ipv6.forwarding=0"))
503 return err;
504
505 return 0;
506 }
507
__rcv_tstamp(int fd,const char * expected,size_t s,__u64 * tstamp)508 static int __rcv_tstamp(int fd, const char *expected, size_t s, __u64 *tstamp)
509 {
510 struct timespec pkt_ts = {};
511 char ctl[CMSG_SPACE(sizeof(pkt_ts))];
512 struct timespec now_ts;
513 struct msghdr msg = {};
514 __u64 now_ns, pkt_ns;
515 struct cmsghdr *cmsg;
516 struct iovec iov;
517 char data[32];
518 int ret;
519
520 iov.iov_base = data;
521 iov.iov_len = sizeof(data);
522 msg.msg_iov = &iov;
523 msg.msg_iovlen = 1;
524 msg.msg_control = &ctl;
525 msg.msg_controllen = sizeof(ctl);
526
527 ret = recvmsg(fd, &msg, 0);
528 if (!ASSERT_EQ(ret, s, "recvmsg"))
529 return -1;
530 ASSERT_STRNEQ(data, expected, s, "expected rcv data");
531
532 cmsg = CMSG_FIRSTHDR(&msg);
533 if (cmsg && cmsg->cmsg_level == SOL_SOCKET &&
534 cmsg->cmsg_type == SO_TIMESTAMPNS)
535 memcpy(&pkt_ts, CMSG_DATA(cmsg), sizeof(pkt_ts));
536
537 pkt_ns = pkt_ts.tv_sec * NSEC_PER_SEC + pkt_ts.tv_nsec;
538 if (tstamp) {
539 /* caller will check the tstamp itself */
540 *tstamp = pkt_ns;
541 return 0;
542 }
543
544 ASSERT_NEQ(pkt_ns, 0, "pkt rcv tstamp");
545
546 ret = clock_gettime(CLOCK_REALTIME, &now_ts);
547 ASSERT_OK(ret, "clock_gettime");
548 now_ns = now_ts.tv_sec * NSEC_PER_SEC + now_ts.tv_nsec;
549
550 if (ASSERT_GE(now_ns, pkt_ns, "check rcv tstamp"))
551 ASSERT_LT(now_ns - pkt_ns, 5 * NSEC_PER_SEC,
552 "check rcv tstamp");
553 return 0;
554 }
555
rcv_tstamp(int fd,const char * expected,size_t s)556 static void rcv_tstamp(int fd, const char *expected, size_t s)
557 {
558 __rcv_tstamp(fd, expected, s, NULL);
559 }
560
wait_netstamp_needed_key(void)561 static int wait_netstamp_needed_key(void)
562 {
563 int opt = 1, srv_fd = -1, cli_fd = -1, nretries = 0, err, n;
564 char buf[] = "testing testing";
565 struct nstoken *nstoken;
566 __u64 tstamp = 0;
567
568 nstoken = open_netns(NS_DST);
569 if (!ASSERT_OK_PTR(nstoken, "setns dst"))
570 return -1;
571
572 srv_fd = start_server(AF_INET6, SOCK_DGRAM, "::1", 0, 0);
573 if (!ASSERT_GE(srv_fd, 0, "start_server"))
574 goto done;
575
576 err = setsockopt(srv_fd, SOL_SOCKET, SO_TIMESTAMPNS,
577 &opt, sizeof(opt));
578 if (!ASSERT_OK(err, "setsockopt(SO_TIMESTAMPNS)"))
579 goto done;
580
581 cli_fd = connect_to_fd(srv_fd, TIMEOUT_MILLIS);
582 if (!ASSERT_GE(cli_fd, 0, "connect_to_fd"))
583 goto done;
584
585 again:
586 n = write(cli_fd, buf, sizeof(buf));
587 if (!ASSERT_EQ(n, sizeof(buf), "send to server"))
588 goto done;
589 err = __rcv_tstamp(srv_fd, buf, sizeof(buf), &tstamp);
590 if (!ASSERT_OK(err, "__rcv_tstamp"))
591 goto done;
592 if (!tstamp && nretries++ < 5) {
593 sleep(1);
594 printf("netstamp_needed_key retry#%d\n", nretries);
595 goto again;
596 }
597
598 done:
599 if (!tstamp && srv_fd != -1) {
600 close(srv_fd);
601 srv_fd = -1;
602 }
603 if (cli_fd != -1)
604 close(cli_fd);
605 close_netns(nstoken);
606 return srv_fd;
607 }
608
snd_tstamp(int fd,char * b,size_t s)609 static void snd_tstamp(int fd, char *b, size_t s)
610 {
611 struct sock_txtime opt = { .clockid = CLOCK_TAI };
612 char ctl[CMSG_SPACE(sizeof(__u64))];
613 struct timespec now_ts;
614 struct msghdr msg = {};
615 struct cmsghdr *cmsg;
616 struct iovec iov;
617 __u64 now_ns;
618 int ret;
619
620 ret = clock_gettime(CLOCK_TAI, &now_ts);
621 ASSERT_OK(ret, "clock_get_time(CLOCK_TAI)");
622 now_ns = now_ts.tv_sec * NSEC_PER_SEC + now_ts.tv_nsec;
623
624 iov.iov_base = b;
625 iov.iov_len = s;
626 msg.msg_iov = &iov;
627 msg.msg_iovlen = 1;
628 msg.msg_control = &ctl;
629 msg.msg_controllen = sizeof(ctl);
630
631 cmsg = CMSG_FIRSTHDR(&msg);
632 cmsg->cmsg_level = SOL_SOCKET;
633 cmsg->cmsg_type = SCM_TXTIME;
634 cmsg->cmsg_len = CMSG_LEN(sizeof(now_ns));
635 *(__u64 *)CMSG_DATA(cmsg) = now_ns;
636
637 ret = setsockopt(fd, SOL_SOCKET, SO_TXTIME, &opt, sizeof(opt));
638 ASSERT_OK(ret, "setsockopt(SO_TXTIME)");
639
640 ret = sendmsg(fd, &msg, 0);
641 ASSERT_EQ(ret, s, "sendmsg");
642 }
643
test_inet_dtime(int family,int type,const char * addr,__u16 port)644 static void test_inet_dtime(int family, int type, const char *addr, __u16 port)
645 {
646 int opt = 1, accept_fd = -1, client_fd = -1, listen_fd, err;
647 char buf[] = "testing testing";
648 struct nstoken *nstoken;
649
650 nstoken = open_netns(NS_DST);
651 if (!ASSERT_OK_PTR(nstoken, "setns dst"))
652 return;
653 listen_fd = start_server(family, type, addr, port, 0);
654 close_netns(nstoken);
655
656 if (!ASSERT_GE(listen_fd, 0, "listen"))
657 return;
658
659 /* Ensure the kernel puts the (rcv) timestamp for all skb */
660 err = setsockopt(listen_fd, SOL_SOCKET, SO_TIMESTAMPNS,
661 &opt, sizeof(opt));
662 if (!ASSERT_OK(err, "setsockopt(SO_TIMESTAMPNS)"))
663 goto done;
664
665 if (type == SOCK_STREAM) {
666 /* Ensure the kernel set EDT when sending out rst/ack
667 * from the kernel's ctl_sk.
668 */
669 err = setsockopt(listen_fd, SOL_TCP, TCP_TX_DELAY, &opt,
670 sizeof(opt));
671 if (!ASSERT_OK(err, "setsockopt(TCP_TX_DELAY)"))
672 goto done;
673 }
674
675 nstoken = open_netns(NS_SRC);
676 if (!ASSERT_OK_PTR(nstoken, "setns src"))
677 goto done;
678 client_fd = connect_to_fd(listen_fd, TIMEOUT_MILLIS);
679 close_netns(nstoken);
680
681 if (!ASSERT_GE(client_fd, 0, "connect_to_fd"))
682 goto done;
683
684 if (type == SOCK_STREAM) {
685 int n;
686
687 accept_fd = accept(listen_fd, NULL, NULL);
688 if (!ASSERT_GE(accept_fd, 0, "accept"))
689 goto done;
690
691 n = write(client_fd, buf, sizeof(buf));
692 if (!ASSERT_EQ(n, sizeof(buf), "send to server"))
693 goto done;
694 rcv_tstamp(accept_fd, buf, sizeof(buf));
695 } else {
696 snd_tstamp(client_fd, buf, sizeof(buf));
697 rcv_tstamp(listen_fd, buf, sizeof(buf));
698 }
699
700 done:
701 close(listen_fd);
702 if (accept_fd != -1)
703 close(accept_fd);
704 if (client_fd != -1)
705 close(client_fd);
706 }
707
netns_load_dtime_bpf(struct test_tc_dtime * skel,const struct netns_setup_result * setup_result)708 static int netns_load_dtime_bpf(struct test_tc_dtime *skel,
709 const struct netns_setup_result *setup_result)
710 {
711 LIBBPF_OPTS(bpf_tc_hook, qdisc_src_fwd);
712 LIBBPF_OPTS(bpf_tc_hook, qdisc_dst_fwd);
713 LIBBPF_OPTS(bpf_tc_hook, qdisc_src);
714 LIBBPF_OPTS(bpf_tc_hook, qdisc_dst);
715 struct nstoken *nstoken;
716 int err;
717
718 /* setup ns_src tc progs */
719 nstoken = open_netns(NS_SRC);
720 if (!ASSERT_OK_PTR(nstoken, "setns " NS_SRC))
721 return -1;
722 /* tc qdisc add dev src clsact */
723 QDISC_CLSACT_CREATE(&qdisc_src, setup_result->ifindex_src);
724 /* tc filter add dev src ingress bpf da ingress_host */
725 XGRESS_FILTER_ADD(&qdisc_src, BPF_TC_INGRESS, skel->progs.ingress_host, 0);
726 /* tc filter add dev src egress bpf da egress_host */
727 XGRESS_FILTER_ADD(&qdisc_src, BPF_TC_EGRESS, skel->progs.egress_host, 0);
728 close_netns(nstoken);
729
730 /* setup ns_dst tc progs */
731 nstoken = open_netns(NS_DST);
732 if (!ASSERT_OK_PTR(nstoken, "setns " NS_DST))
733 return -1;
734 /* tc qdisc add dev dst clsact */
735 QDISC_CLSACT_CREATE(&qdisc_dst, setup_result->ifindex_dst);
736 /* tc filter add dev dst ingress bpf da ingress_host */
737 XGRESS_FILTER_ADD(&qdisc_dst, BPF_TC_INGRESS, skel->progs.ingress_host, 0);
738 /* tc filter add dev dst egress bpf da egress_host */
739 XGRESS_FILTER_ADD(&qdisc_dst, BPF_TC_EGRESS, skel->progs.egress_host, 0);
740 close_netns(nstoken);
741
742 /* setup ns_fwd tc progs */
743 nstoken = open_netns(NS_FWD);
744 if (!ASSERT_OK_PTR(nstoken, "setns " NS_FWD))
745 return -1;
746 /* tc qdisc add dev dst_fwd clsact */
747 QDISC_CLSACT_CREATE(&qdisc_dst_fwd, setup_result->ifindex_dst_fwd);
748 /* tc filter add dev dst_fwd ingress prio 100 bpf da ingress_fwdns_prio100 */
749 XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_INGRESS,
750 skel->progs.ingress_fwdns_prio100, 100);
751 /* tc filter add dev dst_fwd ingress prio 101 bpf da ingress_fwdns_prio101 */
752 XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_INGRESS,
753 skel->progs.ingress_fwdns_prio101, 101);
754 /* tc filter add dev dst_fwd egress prio 100 bpf da egress_fwdns_prio100 */
755 XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_EGRESS,
756 skel->progs.egress_fwdns_prio100, 100);
757 /* tc filter add dev dst_fwd egress prio 101 bpf da egress_fwdns_prio101 */
758 XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_EGRESS,
759 skel->progs.egress_fwdns_prio101, 101);
760
761 /* tc qdisc add dev src_fwd clsact */
762 QDISC_CLSACT_CREATE(&qdisc_src_fwd, setup_result->ifindex_src_fwd);
763 /* tc filter add dev src_fwd ingress prio 100 bpf da ingress_fwdns_prio100 */
764 XGRESS_FILTER_ADD(&qdisc_src_fwd, BPF_TC_INGRESS,
765 skel->progs.ingress_fwdns_prio100, 100);
766 /* tc filter add dev src_fwd ingress prio 101 bpf da ingress_fwdns_prio101 */
767 XGRESS_FILTER_ADD(&qdisc_src_fwd, BPF_TC_INGRESS,
768 skel->progs.ingress_fwdns_prio101, 101);
769 /* tc filter add dev src_fwd egress prio 100 bpf da egress_fwdns_prio100 */
770 XGRESS_FILTER_ADD(&qdisc_src_fwd, BPF_TC_EGRESS,
771 skel->progs.egress_fwdns_prio100, 100);
772 /* tc filter add dev src_fwd egress prio 101 bpf da egress_fwdns_prio101 */
773 XGRESS_FILTER_ADD(&qdisc_src_fwd, BPF_TC_EGRESS,
774 skel->progs.egress_fwdns_prio101, 101);
775 close_netns(nstoken);
776 return 0;
777
778 fail:
779 close_netns(nstoken);
780 return err;
781 }
782
783 enum {
784 INGRESS_FWDNS_P100,
785 INGRESS_FWDNS_P101,
786 EGRESS_FWDNS_P100,
787 EGRESS_FWDNS_P101,
788 INGRESS_ENDHOST,
789 EGRESS_ENDHOST,
790 SET_DTIME,
791 __MAX_CNT,
792 };
793
794 const char *cnt_names[] = {
795 "ingress_fwdns_p100",
796 "ingress_fwdns_p101",
797 "egress_fwdns_p100",
798 "egress_fwdns_p101",
799 "ingress_endhost",
800 "egress_endhost",
801 "set_dtime",
802 };
803
804 enum {
805 TCP_IP6_CLEAR_DTIME,
806 TCP_IP4,
807 TCP_IP6,
808 UDP_IP4,
809 UDP_IP6,
810 TCP_IP4_RT_FWD,
811 TCP_IP6_RT_FWD,
812 UDP_IP4_RT_FWD,
813 UDP_IP6_RT_FWD,
814 UKN_TEST,
815 __NR_TESTS,
816 };
817
818 const char *test_names[] = {
819 "tcp ip6 clear dtime",
820 "tcp ip4",
821 "tcp ip6",
822 "udp ip4",
823 "udp ip6",
824 "tcp ip4 rt fwd",
825 "tcp ip6 rt fwd",
826 "udp ip4 rt fwd",
827 "udp ip6 rt fwd",
828 };
829
dtime_cnt_str(int test,int cnt)830 static const char *dtime_cnt_str(int test, int cnt)
831 {
832 static char name[64];
833
834 snprintf(name, sizeof(name), "%s %s", test_names[test], cnt_names[cnt]);
835
836 return name;
837 }
838
dtime_err_str(int test,int cnt)839 static const char *dtime_err_str(int test, int cnt)
840 {
841 static char name[64];
842
843 snprintf(name, sizeof(name), "%s %s errs", test_names[test],
844 cnt_names[cnt]);
845
846 return name;
847 }
848
test_tcp_clear_dtime(struct test_tc_dtime * skel)849 static void test_tcp_clear_dtime(struct test_tc_dtime *skel)
850 {
851 int i, t = TCP_IP6_CLEAR_DTIME;
852 __u32 *dtimes = skel->bss->dtimes[t];
853 __u32 *errs = skel->bss->errs[t];
854
855 skel->bss->test = t;
856 test_inet_dtime(AF_INET6, SOCK_STREAM, IP6_DST, 50000 + t);
857
858 ASSERT_EQ(dtimes[INGRESS_FWDNS_P100], 0,
859 dtime_cnt_str(t, INGRESS_FWDNS_P100));
860 ASSERT_EQ(dtimes[INGRESS_FWDNS_P101], 0,
861 dtime_cnt_str(t, INGRESS_FWDNS_P101));
862 ASSERT_GT(dtimes[EGRESS_FWDNS_P100], 0,
863 dtime_cnt_str(t, EGRESS_FWDNS_P100));
864 ASSERT_EQ(dtimes[EGRESS_FWDNS_P101], 0,
865 dtime_cnt_str(t, EGRESS_FWDNS_P101));
866 ASSERT_GT(dtimes[EGRESS_ENDHOST], 0,
867 dtime_cnt_str(t, EGRESS_ENDHOST));
868 ASSERT_GT(dtimes[INGRESS_ENDHOST], 0,
869 dtime_cnt_str(t, INGRESS_ENDHOST));
870
871 for (i = INGRESS_FWDNS_P100; i < __MAX_CNT; i++)
872 ASSERT_EQ(errs[i], 0, dtime_err_str(t, i));
873 }
874
test_tcp_dtime(struct test_tc_dtime * skel,int family,bool bpf_fwd)875 static void test_tcp_dtime(struct test_tc_dtime *skel, int family, bool bpf_fwd)
876 {
877 __u32 *dtimes, *errs;
878 const char *addr;
879 int i, t;
880
881 if (family == AF_INET) {
882 t = bpf_fwd ? TCP_IP4 : TCP_IP4_RT_FWD;
883 addr = IP4_DST;
884 } else {
885 t = bpf_fwd ? TCP_IP6 : TCP_IP6_RT_FWD;
886 addr = IP6_DST;
887 }
888
889 dtimes = skel->bss->dtimes[t];
890 errs = skel->bss->errs[t];
891
892 skel->bss->test = t;
893 test_inet_dtime(family, SOCK_STREAM, addr, 50000 + t);
894
895 /* fwdns_prio100 prog does not read delivery_time_type, so
896 * kernel puts the (rcv) timestamp in __sk_buff->tstamp
897 */
898 ASSERT_EQ(dtimes[INGRESS_FWDNS_P100], 0,
899 dtime_cnt_str(t, INGRESS_FWDNS_P100));
900 for (i = INGRESS_FWDNS_P101; i < SET_DTIME; i++)
901 ASSERT_GT(dtimes[i], 0, dtime_cnt_str(t, i));
902
903 for (i = INGRESS_FWDNS_P100; i < __MAX_CNT; i++)
904 ASSERT_EQ(errs[i], 0, dtime_err_str(t, i));
905 }
906
test_udp_dtime(struct test_tc_dtime * skel,int family,bool bpf_fwd)907 static void test_udp_dtime(struct test_tc_dtime *skel, int family, bool bpf_fwd)
908 {
909 __u32 *dtimes, *errs;
910 const char *addr;
911 int i, t;
912
913 if (family == AF_INET) {
914 t = bpf_fwd ? UDP_IP4 : UDP_IP4_RT_FWD;
915 addr = IP4_DST;
916 } else {
917 t = bpf_fwd ? UDP_IP6 : UDP_IP6_RT_FWD;
918 addr = IP6_DST;
919 }
920
921 dtimes = skel->bss->dtimes[t];
922 errs = skel->bss->errs[t];
923
924 skel->bss->test = t;
925 test_inet_dtime(family, SOCK_DGRAM, addr, 50000 + t);
926
927 ASSERT_EQ(dtimes[INGRESS_FWDNS_P100], 0,
928 dtime_cnt_str(t, INGRESS_FWDNS_P100));
929 for (i = EGRESS_FWDNS_P100; i < SET_DTIME; i++)
930 ASSERT_GT(dtimes[i], 0, dtime_cnt_str(t, i));
931
932 for (i = INGRESS_FWDNS_P100; i < __MAX_CNT; i++)
933 ASSERT_EQ(errs[i], 0, dtime_err_str(t, i));
934 }
935
test_tc_redirect_dtime(struct netns_setup_result * setup_result)936 static void test_tc_redirect_dtime(struct netns_setup_result *setup_result)
937 {
938 struct test_tc_dtime *skel;
939 struct nstoken *nstoken;
940 int hold_tstamp_fd, err;
941
942 /* Hold a sk with the SOCK_TIMESTAMP set to ensure there
943 * is no delay in the kernel net_enable_timestamp().
944 * This ensures the following tests must have
945 * non zero rcv tstamp in the recvmsg().
946 */
947 hold_tstamp_fd = wait_netstamp_needed_key();
948 if (!ASSERT_GE(hold_tstamp_fd, 0, "wait_netstamp_needed_key"))
949 return;
950
951 skel = test_tc_dtime__open();
952 if (!ASSERT_OK_PTR(skel, "test_tc_dtime__open"))
953 goto done;
954
955 skel->rodata->IFINDEX_SRC = setup_result->ifindex_src_fwd;
956 skel->rodata->IFINDEX_DST = setup_result->ifindex_dst_fwd;
957
958 err = test_tc_dtime__load(skel);
959 if (!ASSERT_OK(err, "test_tc_dtime__load"))
960 goto done;
961
962 if (netns_load_dtime_bpf(skel, setup_result))
963 goto done;
964
965 nstoken = open_netns(NS_FWD);
966 if (!ASSERT_OK_PTR(nstoken, "setns fwd"))
967 goto done;
968 err = set_forwarding(false);
969 close_netns(nstoken);
970 if (!ASSERT_OK(err, "disable forwarding"))
971 goto done;
972
973 test_tcp_clear_dtime(skel);
974
975 test_tcp_dtime(skel, AF_INET, true);
976 test_tcp_dtime(skel, AF_INET6, true);
977 test_udp_dtime(skel, AF_INET, true);
978 test_udp_dtime(skel, AF_INET6, true);
979
980 /* Test the kernel ip[6]_forward path instead
981 * of bpf_redirect_neigh().
982 */
983 nstoken = open_netns(NS_FWD);
984 if (!ASSERT_OK_PTR(nstoken, "setns fwd"))
985 goto done;
986 err = set_forwarding(true);
987 close_netns(nstoken);
988 if (!ASSERT_OK(err, "enable forwarding"))
989 goto done;
990
991 test_tcp_dtime(skel, AF_INET, false);
992 test_tcp_dtime(skel, AF_INET6, false);
993 test_udp_dtime(skel, AF_INET, false);
994 test_udp_dtime(skel, AF_INET6, false);
995
996 done:
997 test_tc_dtime__destroy(skel);
998 close(hold_tstamp_fd);
999 }
1000
test_tc_redirect_neigh_fib(struct netns_setup_result * setup_result)1001 static void test_tc_redirect_neigh_fib(struct netns_setup_result *setup_result)
1002 {
1003 struct nstoken *nstoken = NULL;
1004 struct test_tc_neigh_fib *skel = NULL;
1005
1006 nstoken = open_netns(NS_FWD);
1007 if (!ASSERT_OK_PTR(nstoken, "setns fwd"))
1008 return;
1009
1010 skel = test_tc_neigh_fib__open();
1011 if (!ASSERT_OK_PTR(skel, "test_tc_neigh_fib__open"))
1012 goto done;
1013
1014 if (!ASSERT_OK(test_tc_neigh_fib__load(skel), "test_tc_neigh_fib__load"))
1015 goto done;
1016
1017 if (netns_load_bpf(skel->progs.tc_src, skel->progs.tc_dst,
1018 skel->progs.tc_chk, setup_result))
1019 goto done;
1020
1021 /* bpf_fib_lookup() checks if forwarding is enabled */
1022 if (!ASSERT_OK(set_forwarding(true), "enable forwarding"))
1023 goto done;
1024
1025 test_connectivity();
1026
1027 done:
1028 if (skel)
1029 test_tc_neigh_fib__destroy(skel);
1030 close_netns(nstoken);
1031 }
1032
test_tc_redirect_neigh(struct netns_setup_result * setup_result)1033 static void test_tc_redirect_neigh(struct netns_setup_result *setup_result)
1034 {
1035 struct nstoken *nstoken = NULL;
1036 struct test_tc_neigh *skel = NULL;
1037 int err;
1038
1039 nstoken = open_netns(NS_FWD);
1040 if (!ASSERT_OK_PTR(nstoken, "setns fwd"))
1041 return;
1042
1043 skel = test_tc_neigh__open();
1044 if (!ASSERT_OK_PTR(skel, "test_tc_neigh__open"))
1045 goto done;
1046
1047 skel->rodata->IFINDEX_SRC = setup_result->ifindex_src_fwd;
1048 skel->rodata->IFINDEX_DST = setup_result->ifindex_dst_fwd;
1049
1050 err = test_tc_neigh__load(skel);
1051 if (!ASSERT_OK(err, "test_tc_neigh__load"))
1052 goto done;
1053
1054 if (netns_load_bpf(skel->progs.tc_src, skel->progs.tc_dst,
1055 skel->progs.tc_chk, setup_result))
1056 goto done;
1057
1058 if (!ASSERT_OK(set_forwarding(false), "disable forwarding"))
1059 goto done;
1060
1061 test_connectivity();
1062
1063 done:
1064 if (skel)
1065 test_tc_neigh__destroy(skel);
1066 close_netns(nstoken);
1067 }
1068
test_tc_redirect_peer(struct netns_setup_result * setup_result)1069 static void test_tc_redirect_peer(struct netns_setup_result *setup_result)
1070 {
1071 struct nstoken *nstoken;
1072 struct test_tc_peer *skel;
1073 int err;
1074
1075 nstoken = open_netns(NS_FWD);
1076 if (!ASSERT_OK_PTR(nstoken, "setns fwd"))
1077 return;
1078
1079 skel = test_tc_peer__open();
1080 if (!ASSERT_OK_PTR(skel, "test_tc_peer__open"))
1081 goto done;
1082
1083 skel->rodata->IFINDEX_SRC = setup_result->ifindex_src_fwd;
1084 skel->rodata->IFINDEX_DST = setup_result->ifindex_dst_fwd;
1085
1086 err = test_tc_peer__load(skel);
1087 if (!ASSERT_OK(err, "test_tc_peer__load"))
1088 goto done;
1089
1090 if (netns_load_bpf(skel->progs.tc_src, skel->progs.tc_dst,
1091 skel->progs.tc_chk, setup_result))
1092 goto done;
1093
1094 if (!ASSERT_OK(set_forwarding(false), "disable forwarding"))
1095 goto done;
1096
1097 test_connectivity();
1098
1099 done:
1100 if (skel)
1101 test_tc_peer__destroy(skel);
1102 close_netns(nstoken);
1103 }
1104
test_tc_redirect_peer_ing(struct netns_setup_result * setup_result)1105 static void test_tc_redirect_peer_ing(struct netns_setup_result *setup_result)
1106 {
1107 struct test_tc_peer *skel;
1108 struct nstoken *nstoken;
1109 int err;
1110
1111 nstoken = open_netns(NS_FWD);
1112 if (!ASSERT_OK_PTR(nstoken, "setns fwd"))
1113 return;
1114
1115 skel = test_tc_peer__open();
1116 if (!ASSERT_OK_PTR(skel, "test_tc_peer__open"))
1117 goto done;
1118
1119 skel->rodata->IFINDEX_SRC = setup_result->ifindex_src_fwd;
1120 skel->rodata->IFINDEX_DST = setup_result->ifindex_dst_fwd;
1121 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc_src_ing,
1122 BPF_NETKIT_PRIMARY), 0, "src_prog_attach_type");
1123 ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc_dst_ing,
1124 BPF_NETKIT_PRIMARY), 0, "dst_prog_attach_type");
1125
1126 err = test_tc_peer__load(skel);
1127 if (!ASSERT_OK(err, "test_tc_peer__load"))
1128 goto done;
1129
1130 skel->links.tc_src_ing = netns_attach_nk(NS_SRC,
1131 setup_result->ifindex_src,
1132 skel->progs.tc_src_ing);
1133 if (!ASSERT_OK_PTR(skel->links.tc_src_ing, "attach_src"))
1134 goto done;
1135 skel->links.tc_dst_ing = netns_attach_nk(NS_DST,
1136 setup_result->ifindex_dst,
1137 skel->progs.tc_dst_ing);
1138 if (!ASSERT_OK_PTR(skel->links.tc_dst_ing, "attach_dst"))
1139 goto done;
1140
1141 if (!ASSERT_OK(set_forwarding(false), "disable forwarding"))
1142 goto done;
1143
1144 test_connectivity();
1145
1146 done:
1147 if (skel)
1148 test_tc_peer__destroy(skel);
1149 close_netns(nstoken);
1150 }
1151
tun_open(char * name)1152 static int tun_open(char *name)
1153 {
1154 struct ifreq ifr;
1155 int fd, err;
1156
1157 fd = open("/dev/net/tun", O_RDWR);
1158 if (!ASSERT_GE(fd, 0, "open /dev/net/tun"))
1159 return -1;
1160
1161 memset(&ifr, 0, sizeof(ifr));
1162
1163 ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
1164 if (*name)
1165 strscpy(ifr.ifr_name, name);
1166
1167 err = ioctl(fd, TUNSETIFF, &ifr);
1168 if (!ASSERT_OK(err, "ioctl TUNSETIFF"))
1169 goto fail;
1170
1171 SYS(fail, "ip link set dev %s up", name);
1172
1173 return fd;
1174 fail:
1175 close(fd);
1176 return -1;
1177 }
1178
1179 enum {
1180 SRC_TO_TARGET = 0,
1181 TARGET_TO_SRC = 1,
1182 };
1183
tun_relay_loop(int src_fd,int target_fd)1184 static int tun_relay_loop(int src_fd, int target_fd)
1185 {
1186 fd_set rfds, wfds;
1187
1188 FD_ZERO(&rfds);
1189 FD_ZERO(&wfds);
1190
1191 for (;;) {
1192 char buf[1500];
1193 int direction, nread, nwrite;
1194
1195 FD_SET(src_fd, &rfds);
1196 FD_SET(target_fd, &rfds);
1197
1198 if (select(1 + MAX(src_fd, target_fd), &rfds, NULL, NULL, NULL) < 0) {
1199 log_err("select failed");
1200 return 1;
1201 }
1202
1203 direction = FD_ISSET(src_fd, &rfds) ? SRC_TO_TARGET : TARGET_TO_SRC;
1204
1205 nread = read(direction == SRC_TO_TARGET ? src_fd : target_fd, buf, sizeof(buf));
1206 if (nread < 0) {
1207 log_err("read failed");
1208 return 1;
1209 }
1210
1211 nwrite = write(direction == SRC_TO_TARGET ? target_fd : src_fd, buf, nread);
1212 if (nwrite != nread) {
1213 log_err("write failed");
1214 return 1;
1215 }
1216 }
1217 }
1218
test_tc_redirect_peer_l3(struct netns_setup_result * setup_result)1219 static void test_tc_redirect_peer_l3(struct netns_setup_result *setup_result)
1220 {
1221 LIBBPF_OPTS(bpf_tc_hook, qdisc_tun_fwd);
1222 LIBBPF_OPTS(bpf_tc_hook, qdisc_dst_fwd);
1223 struct test_tc_peer *skel = NULL;
1224 struct nstoken *nstoken = NULL;
1225 int err;
1226 int tunnel_pid = -1;
1227 int src_fd, target_fd = -1;
1228 int ifindex;
1229
1230 /* Start a L3 TUN/TAP tunnel between the src and dst namespaces.
1231 * This test is using TUN/TAP instead of e.g. IPIP or GRE tunnel as those
1232 * expose the L2 headers encapsulating the IP packet to BPF and hence
1233 * don't have skb in suitable state for this test. Alternative to TUN/TAP
1234 * would be e.g. Wireguard which would appear as a pure L3 device to BPF,
1235 * but that requires much more complicated setup.
1236 */
1237 nstoken = open_netns(NS_SRC);
1238 if (!ASSERT_OK_PTR(nstoken, "setns " NS_SRC))
1239 return;
1240
1241 src_fd = tun_open("tun_src");
1242 if (!ASSERT_GE(src_fd, 0, "tun_open tun_src"))
1243 goto fail;
1244
1245 close_netns(nstoken);
1246
1247 nstoken = open_netns(NS_FWD);
1248 if (!ASSERT_OK_PTR(nstoken, "setns " NS_FWD))
1249 goto fail;
1250
1251 target_fd = tun_open("tun_fwd");
1252 if (!ASSERT_GE(target_fd, 0, "tun_open tun_fwd"))
1253 goto fail;
1254
1255 tunnel_pid = fork();
1256 if (!ASSERT_GE(tunnel_pid, 0, "fork tun_relay_loop"))
1257 goto fail;
1258
1259 if (tunnel_pid == 0)
1260 exit(tun_relay_loop(src_fd, target_fd));
1261
1262 skel = test_tc_peer__open();
1263 if (!ASSERT_OK_PTR(skel, "test_tc_peer__open"))
1264 goto fail;
1265
1266 ifindex = if_nametoindex("tun_fwd");
1267 if (!ASSERT_GT(ifindex, 0, "if_indextoname tun_fwd"))
1268 goto fail;
1269
1270 skel->rodata->IFINDEX_SRC = ifindex;
1271 skel->rodata->IFINDEX_DST = setup_result->ifindex_dst_fwd;
1272
1273 err = test_tc_peer__load(skel);
1274 if (!ASSERT_OK(err, "test_tc_peer__load"))
1275 goto fail;
1276
1277 /* Load "tc_src_l3" to the tun_fwd interface to redirect packets
1278 * towards dst, and "tc_dst" to redirect packets
1279 * and "tc_chk" on dst_fwd to drop non-redirected packets.
1280 */
1281 /* tc qdisc add dev tun_fwd clsact */
1282 QDISC_CLSACT_CREATE(&qdisc_tun_fwd, ifindex);
1283 /* tc filter add dev tun_fwd ingress bpf da tc_src_l3 */
1284 XGRESS_FILTER_ADD(&qdisc_tun_fwd, BPF_TC_INGRESS, skel->progs.tc_src_l3, 0);
1285
1286 /* tc qdisc add dev dst_fwd clsact */
1287 QDISC_CLSACT_CREATE(&qdisc_dst_fwd, setup_result->ifindex_dst_fwd);
1288 /* tc filter add dev dst_fwd ingress bpf da tc_dst_l3 */
1289 XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_INGRESS, skel->progs.tc_dst_l3, 0);
1290 /* tc filter add dev dst_fwd egress bpf da tc_chk */
1291 XGRESS_FILTER_ADD(&qdisc_dst_fwd, BPF_TC_EGRESS, skel->progs.tc_chk, 0);
1292
1293 /* Setup route and neigh tables */
1294 SYS(fail, "ip -netns " NS_SRC " addr add dev tun_src " IP4_TUN_SRC "/24");
1295 SYS(fail, "ip -netns " NS_FWD " addr add dev tun_fwd " IP4_TUN_FWD "/24");
1296
1297 SYS(fail, "ip -netns " NS_SRC " addr add dev tun_src " IP6_TUN_SRC "/64 nodad");
1298 SYS(fail, "ip -netns " NS_FWD " addr add dev tun_fwd " IP6_TUN_FWD "/64 nodad");
1299
1300 SYS(fail, "ip -netns " NS_SRC " route del " IP4_DST "/32 dev src scope global");
1301 SYS(fail, "ip -netns " NS_SRC " route add " IP4_DST "/32 via " IP4_TUN_FWD
1302 " dev tun_src scope global");
1303 SYS(fail, "ip -netns " NS_DST " route add " IP4_TUN_SRC "/32 dev dst scope global");
1304 SYS(fail, "ip -netns " NS_SRC " route del " IP6_DST "/128 dev src scope global");
1305 SYS(fail, "ip -netns " NS_SRC " route add " IP6_DST "/128 via " IP6_TUN_FWD
1306 " dev tun_src scope global");
1307 SYS(fail, "ip -netns " NS_DST " route add " IP6_TUN_SRC "/128 dev dst scope global");
1308
1309 SYS(fail, "ip -netns " NS_DST " neigh add " IP4_TUN_SRC " dev dst lladdr " MAC_DST_FWD);
1310 SYS(fail, "ip -netns " NS_DST " neigh add " IP6_TUN_SRC " dev dst lladdr " MAC_DST_FWD);
1311
1312 if (!ASSERT_OK(set_forwarding(false), "disable forwarding"))
1313 goto fail;
1314
1315 test_connectivity();
1316
1317 fail:
1318 if (tunnel_pid > 0) {
1319 kill(tunnel_pid, SIGTERM);
1320 waitpid(tunnel_pid, NULL, 0);
1321 }
1322 if (src_fd >= 0)
1323 close(src_fd);
1324 if (target_fd >= 0)
1325 close(target_fd);
1326 if (skel)
1327 test_tc_peer__destroy(skel);
1328 if (nstoken)
1329 close_netns(nstoken);
1330 }
1331
1332 #define RUN_TEST(name, mode) \
1333 ({ \
1334 struct netns_setup_result setup_result = { .dev_mode = mode, }; \
1335 if (test__start_subtest(#name)) \
1336 if (ASSERT_OK(netns_setup_namespaces("add"), "setup namespaces")) { \
1337 if (ASSERT_OK(netns_setup_links_and_routes(&setup_result), \
1338 "setup links and routes")) \
1339 test_ ## name(&setup_result); \
1340 netns_setup_namespaces("delete"); \
1341 } \
1342 })
1343
test_tc_redirect_run_tests(void * arg)1344 static void *test_tc_redirect_run_tests(void *arg)
1345 {
1346 netns_setup_namespaces_nofail("delete");
1347
1348 RUN_TEST(tc_redirect_peer, MODE_VETH);
1349 RUN_TEST(tc_redirect_peer, MODE_NETKIT);
1350 RUN_TEST(tc_redirect_peer_ing, MODE_NETKIT);
1351 RUN_TEST(tc_redirect_peer_l3, MODE_VETH);
1352 RUN_TEST(tc_redirect_peer_l3, MODE_NETKIT);
1353 RUN_TEST(tc_redirect_neigh, MODE_VETH);
1354 RUN_TEST(tc_redirect_neigh_fib, MODE_VETH);
1355 RUN_TEST(tc_redirect_dtime, MODE_VETH);
1356 return NULL;
1357 }
1358
test_tc_redirect(void)1359 void test_tc_redirect(void)
1360 {
1361 pthread_t test_thread;
1362 int err;
1363
1364 /* Run the tests in their own thread to isolate the namespace changes
1365 * so they do not affect the environment of other tests.
1366 * (specifically needed because of unshare(CLONE_NEWNS) in open_netns())
1367 */
1368 err = pthread_create(&test_thread, NULL, &test_tc_redirect_run_tests, NULL);
1369 if (ASSERT_OK(err, "pthread_create"))
1370 ASSERT_OK(pthread_join(test_thread, NULL), "pthread_join");
1371 }
1372