xref: /linux/tools/testing/selftests/bpf/prog_tests/tc_redirect.c (revision 5a8cd539ac19f7a68e68e1d25ef9ca2ff55b8500)
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