xref: /linux/tools/testing/selftests/bpf/prog_tests/sk_lookup.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 // Copyright (c) 2020 Cloudflare
3 /*
4  * Test BPF attach point for INET socket lookup (BPF_SK_LOOKUP).
5  *
6  * Tests exercise:
7  *  - attaching/detaching/querying programs to BPF_SK_LOOKUP hook,
8  *  - redirecting socket lookup to a socket selected by BPF program,
9  *  - failing a socket lookup on BPF program's request,
10  *  - error scenarios for selecting a socket from BPF program,
11  *  - accessing BPF program context,
12  *  - attaching and running multiple BPF programs.
13  *
14  * Tests run in a dedicated network namespace.
15  */
16 
17 #define _GNU_SOURCE
18 #include <arpa/inet.h>
19 #include <assert.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <sched.h>
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 
28 #include <bpf/libbpf.h>
29 #include <bpf/bpf.h>
30 
31 #include "test_progs.h"
32 #include "bpf_util.h"
33 #include "cgroup_helpers.h"
34 #include "network_helpers.h"
35 #include "testing_helpers.h"
36 #include "test_sk_lookup.skel.h"
37 
38 /* External (address, port) pairs the client sends packets to. */
39 #define EXT_IP4		"127.0.0.1"
40 #define EXT_IP6		"fd00::1"
41 #define EXT_PORT	7007
42 
43 /* Internal (address, port) pairs the server listens/receives at. */
44 #define INT_IP4		"127.0.0.2"
45 #define INT_IP4_V6	"::ffff:127.0.0.2"
46 #define INT_IP6		"fd00::2"
47 #define INT_PORT	8008
48 
49 enum server {
50 	SERVER_A = 0,
51 	SERVER_B = 1,
52 	MAX_SERVERS,
53 };
54 
55 enum {
56 	PROG1 = 0,
57 	PROG2,
58 };
59 
60 struct inet_addr {
61 	const char *ip;
62 	unsigned short port;
63 };
64 
65 struct test {
66 	const char *desc;
67 	struct bpf_program *lookup_prog;
68 	struct bpf_program *reuseport_prog;
69 	struct bpf_map *sock_map;
70 	int sotype;
71 	struct inet_addr connect_to;
72 	struct inet_addr listen_at;
73 	enum server accept_on;
74 	bool reuseport_has_conns; /* Add a connected socket to reuseport group */
75 };
76 
77 struct cb_opts {
78 	int family;
79 	int sotype;
80 	bool reuseport;
81 };
82 
83 static __u32 duration;		/* for CHECK macro */
84 
85 static bool is_ipv6(const char *ip)
86 {
87 	return !!strchr(ip, ':');
88 }
89 
90 static int attach_reuseport(int sock_fd, struct bpf_program *reuseport_prog)
91 {
92 	int err, prog_fd;
93 
94 	prog_fd = bpf_program__fd(reuseport_prog);
95 	if (prog_fd < 0) {
96 		errno = -prog_fd;
97 		return -1;
98 	}
99 
100 	err = setsockopt(sock_fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF,
101 			 &prog_fd, sizeof(prog_fd));
102 	if (err)
103 		return -1;
104 
105 	return 0;
106 }
107 
108 static int setsockopts(int fd, void *opts)
109 {
110 	struct cb_opts *co = (struct cb_opts *)opts;
111 	const int one = 1;
112 	int err = 0;
113 
114 	/* Enabled for UDPv6 sockets for IPv4-mapped IPv6 to work. */
115 	if (co->sotype == SOCK_DGRAM) {
116 		err = setsockopt(fd, SOL_IP, IP_RECVORIGDSTADDR, &one,
117 				 sizeof(one));
118 		if (CHECK(err, "setsockopt(IP_RECVORIGDSTADDR)", "failed\n")) {
119 			log_err("failed to enable IP_RECVORIGDSTADDR");
120 			goto fail;
121 		}
122 	}
123 
124 	if (co->sotype == SOCK_DGRAM && co->family == AF_INET6) {
125 		err = setsockopt(fd, SOL_IPV6, IPV6_RECVORIGDSTADDR, &one,
126 				 sizeof(one));
127 		if (CHECK(err, "setsockopt(IPV6_RECVORIGDSTADDR)", "failed\n")) {
128 			log_err("failed to enable IPV6_RECVORIGDSTADDR");
129 			goto fail;
130 		}
131 	}
132 
133 	if (co->sotype == SOCK_STREAM) {
134 		err = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one,
135 				 sizeof(one));
136 		if (CHECK(err, "setsockopt(SO_REUSEADDR)", "failed\n")) {
137 			log_err("failed to enable SO_REUSEADDR");
138 			goto fail;
139 		}
140 	}
141 
142 	if (co->reuseport) {
143 		err = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one,
144 				 sizeof(one));
145 		if (CHECK(err, "setsockopt(SO_REUSEPORT)", "failed\n")) {
146 			log_err("failed to enable SO_REUSEPORT");
147 			goto fail;
148 		}
149 	}
150 
151 fail:
152 	return err;
153 }
154 
155 static int make_server(int sotype, const char *ip, int port,
156 		       struct bpf_program *reuseport_prog)
157 {
158 	struct cb_opts cb_opts = {
159 		.family = is_ipv6(ip) ? AF_INET6 : AF_INET,
160 		.sotype = sotype,
161 		.reuseport = reuseport_prog,
162 	};
163 	struct network_helper_opts opts = {
164 		.backlog	= SOMAXCONN,
165 		.post_socket_cb = setsockopts,
166 		.cb_opts	= &cb_opts,
167 	};
168 	int err, fd;
169 
170 	fd = start_server_str(cb_opts.family, sotype, ip, port, &opts);
171 	if (!ASSERT_OK_FD(fd, "start_server_str"))
172 		return -1;
173 
174 	/* Late attach reuseport prog so we can have one init path */
175 	if (reuseport_prog) {
176 		err = attach_reuseport(fd, reuseport_prog);
177 		if (CHECK(err, "attach_reuseport", "failed\n")) {
178 			log_err("failed to attach reuseport prog");
179 			goto fail;
180 		}
181 	}
182 
183 	return fd;
184 fail:
185 	close(fd);
186 	return -1;
187 }
188 
189 static __u64 socket_cookie(int fd)
190 {
191 	__u64 cookie;
192 	socklen_t cookie_len = sizeof(cookie);
193 
194 	if (CHECK(getsockopt(fd, SOL_SOCKET, SO_COOKIE, &cookie, &cookie_len) < 0,
195 		  "getsockopt(SO_COOKIE)", "%s\n", strerror(errno)))
196 		return 0;
197 	return cookie;
198 }
199 
200 static int fill_sk_lookup_ctx(struct bpf_sk_lookup *ctx, const char *local_ip, __u16 local_port,
201 			      const char *remote_ip, __u16 remote_port)
202 {
203 	void *local, *remote;
204 	int err;
205 
206 	memset(ctx, 0, sizeof(*ctx));
207 	ctx->local_port = local_port;
208 	ctx->remote_port = htons(remote_port);
209 
210 	if (is_ipv6(local_ip)) {
211 		ctx->family = AF_INET6;
212 		local = &ctx->local_ip6[0];
213 		remote = &ctx->remote_ip6[0];
214 	} else {
215 		ctx->family = AF_INET;
216 		local = &ctx->local_ip4;
217 		remote = &ctx->remote_ip4;
218 	}
219 
220 	err = inet_pton(ctx->family, local_ip, local);
221 	if (CHECK(err != 1, "inet_pton", "local_ip failed\n"))
222 		return 1;
223 
224 	err = inet_pton(ctx->family, remote_ip, remote);
225 	if (CHECK(err != 1, "inet_pton", "remote_ip failed\n"))
226 		return 1;
227 
228 	return 0;
229 }
230 
231 static int send_byte(int fd)
232 {
233 	ssize_t n;
234 
235 	errno = 0;
236 	n = send(fd, "a", 1, 0);
237 	if (CHECK(n <= 0, "send_byte", "send")) {
238 		log_err("failed/partial send");
239 		return -1;
240 	}
241 	return 0;
242 }
243 
244 static int recv_byte(int fd)
245 {
246 	char buf[1];
247 	ssize_t n;
248 
249 	n = recv(fd, buf, sizeof(buf), 0);
250 	if (CHECK(n <= 0, "recv_byte", "recv")) {
251 		log_err("failed/partial recv");
252 		return -1;
253 	}
254 	return 0;
255 }
256 
257 static int tcp_recv_send(int server_fd)
258 {
259 	char buf[1];
260 	int ret, fd;
261 	ssize_t n;
262 
263 	fd = accept(server_fd, NULL, NULL);
264 	if (CHECK(fd < 0, "accept", "failed\n")) {
265 		log_err("failed to accept");
266 		return -1;
267 	}
268 
269 	n = recv(fd, buf, sizeof(buf), 0);
270 	if (CHECK(n <= 0, "recv", "failed\n")) {
271 		log_err("failed/partial recv");
272 		ret = -1;
273 		goto close;
274 	}
275 
276 	n = send(fd, buf, n, 0);
277 	if (CHECK(n <= 0, "send", "failed\n")) {
278 		log_err("failed/partial send");
279 		ret = -1;
280 		goto close;
281 	}
282 
283 	ret = 0;
284 close:
285 	close(fd);
286 	return ret;
287 }
288 
289 static void v4_to_v6(struct sockaddr_storage *ss)
290 {
291 	struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)ss;
292 	struct sockaddr_in v4 = *(struct sockaddr_in *)ss;
293 
294 	v6->sin6_family = AF_INET6;
295 	v6->sin6_port = v4.sin_port;
296 	v6->sin6_addr.s6_addr[10] = 0xff;
297 	v6->sin6_addr.s6_addr[11] = 0xff;
298 	memcpy(&v6->sin6_addr.s6_addr[12], &v4.sin_addr.s_addr, 4);
299 	memset(&v6->sin6_addr.s6_addr[0], 0, 10);
300 }
301 
302 static int udp_recv_send(int server_fd)
303 {
304 	char cmsg_buf[CMSG_SPACE(sizeof(struct sockaddr_storage))];
305 	struct sockaddr_storage _src_addr = { 0 };
306 	struct sockaddr_storage *src_addr = &_src_addr;
307 	struct sockaddr_storage *dst_addr = NULL;
308 	struct msghdr msg = { 0 };
309 	struct iovec iov = { 0 };
310 	struct cmsghdr *cm;
311 	char buf[1];
312 	int ret, fd;
313 	ssize_t n;
314 
315 	iov.iov_base = buf;
316 	iov.iov_len = sizeof(buf);
317 
318 	msg.msg_name = src_addr;
319 	msg.msg_namelen = sizeof(*src_addr);
320 	msg.msg_iov = &iov;
321 	msg.msg_iovlen = 1;
322 	msg.msg_control = cmsg_buf;
323 	msg.msg_controllen = sizeof(cmsg_buf);
324 
325 	errno = 0;
326 	n = recvmsg(server_fd, &msg, 0);
327 	if (CHECK(n <= 0, "recvmsg", "failed\n")) {
328 		log_err("failed to receive");
329 		return -1;
330 	}
331 	if (CHECK(msg.msg_flags & MSG_CTRUNC, "recvmsg", "truncated cmsg\n"))
332 		return -1;
333 
334 	for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) {
335 		if ((cm->cmsg_level == SOL_IP &&
336 		     cm->cmsg_type == IP_ORIGDSTADDR) ||
337 		    (cm->cmsg_level == SOL_IPV6 &&
338 		     cm->cmsg_type == IPV6_ORIGDSTADDR)) {
339 			dst_addr = (struct sockaddr_storage *)CMSG_DATA(cm);
340 			break;
341 		}
342 		log_err("warning: ignored cmsg at level %d type %d",
343 			cm->cmsg_level, cm->cmsg_type);
344 	}
345 	if (CHECK(!dst_addr, "recvmsg", "missing ORIGDSTADDR\n"))
346 		return -1;
347 
348 	/* Server socket bound to IPv4-mapped IPv6 address */
349 	if (src_addr->ss_family == AF_INET6 &&
350 	    dst_addr->ss_family == AF_INET) {
351 		v4_to_v6(dst_addr);
352 	}
353 
354 	/* Reply from original destination address. */
355 	fd = start_server_addr(SOCK_DGRAM, dst_addr, sizeof(*dst_addr), NULL);
356 	if (!ASSERT_OK_FD(fd, "start_server_addr")) {
357 		log_err("failed to create tx socket");
358 		return -1;
359 	}
360 
361 	msg.msg_control = NULL;
362 	msg.msg_controllen = 0;
363 	n = sendmsg(fd, &msg, 0);
364 	if (CHECK(n <= 0, "sendmsg", "failed\n")) {
365 		log_err("failed to send echo reply");
366 		ret = -1;
367 		goto out;
368 	}
369 
370 	ret = 0;
371 out:
372 	close(fd);
373 	return ret;
374 }
375 
376 static int tcp_echo_test(int client_fd, int server_fd)
377 {
378 	int err;
379 
380 	err = send_byte(client_fd);
381 	if (err)
382 		return -1;
383 	err = tcp_recv_send(server_fd);
384 	if (err)
385 		return -1;
386 	err = recv_byte(client_fd);
387 	if (err)
388 		return -1;
389 
390 	return 0;
391 }
392 
393 static int udp_echo_test(int client_fd, int server_fd)
394 {
395 	int err;
396 
397 	err = send_byte(client_fd);
398 	if (err)
399 		return -1;
400 	err = udp_recv_send(server_fd);
401 	if (err)
402 		return -1;
403 	err = recv_byte(client_fd);
404 	if (err)
405 		return -1;
406 
407 	return 0;
408 }
409 
410 static struct bpf_link *attach_lookup_prog(struct bpf_program *prog)
411 {
412 	struct bpf_link *link;
413 	int net_fd;
414 
415 	net_fd = open("/proc/self/ns/net", O_RDONLY);
416 	if (CHECK(net_fd < 0, "open", "failed\n")) {
417 		log_err("failed to open /proc/self/ns/net");
418 		return NULL;
419 	}
420 
421 	link = bpf_program__attach_netns(prog, net_fd);
422 	if (!ASSERT_OK_PTR(link, "bpf_program__attach_netns")) {
423 		errno = -PTR_ERR(link);
424 		log_err("failed to attach program '%s' to netns",
425 			bpf_program__name(prog));
426 		link = NULL;
427 	}
428 
429 	close(net_fd);
430 	return link;
431 }
432 
433 static int update_lookup_map(struct bpf_map *map, int index, int sock_fd)
434 {
435 	int err, map_fd;
436 	uint64_t value;
437 
438 	map_fd = bpf_map__fd(map);
439 	if (CHECK(map_fd < 0, "bpf_map__fd", "failed\n")) {
440 		errno = -map_fd;
441 		log_err("failed to get map FD");
442 		return -1;
443 	}
444 
445 	value = (uint64_t)sock_fd;
446 	err = bpf_map_update_elem(map_fd, &index, &value, BPF_NOEXIST);
447 	if (CHECK(err, "bpf_map_update_elem", "failed\n")) {
448 		log_err("failed to update redir_map @ %d", index);
449 		return -1;
450 	}
451 
452 	return 0;
453 }
454 
455 static void query_lookup_prog(struct test_sk_lookup *skel)
456 {
457 	struct bpf_link *link[3] = {};
458 	struct bpf_link_info info;
459 	__u32 attach_flags = 0;
460 	__u32 prog_ids[3] = {};
461 	__u32 prog_cnt = 3;
462 	__u32 prog_id;
463 	int net_fd;
464 	int err;
465 
466 	net_fd = open("/proc/self/ns/net", O_RDONLY);
467 	if (CHECK(net_fd < 0, "open", "failed\n")) {
468 		log_err("failed to open /proc/self/ns/net");
469 		return;
470 	}
471 
472 	link[0] = attach_lookup_prog(skel->progs.lookup_pass);
473 	if (!link[0])
474 		goto close;
475 	link[1] = attach_lookup_prog(skel->progs.lookup_pass);
476 	if (!link[1])
477 		goto detach;
478 	link[2] = attach_lookup_prog(skel->progs.lookup_drop);
479 	if (!link[2])
480 		goto detach;
481 
482 	err = bpf_prog_query(net_fd, BPF_SK_LOOKUP, 0 /* query flags */,
483 			     &attach_flags, prog_ids, &prog_cnt);
484 	if (CHECK(err, "bpf_prog_query", "failed\n")) {
485 		log_err("failed to query lookup prog");
486 		goto detach;
487 	}
488 
489 	errno = 0;
490 	if (CHECK(attach_flags != 0, "bpf_prog_query",
491 		  "wrong attach_flags on query: %u", attach_flags))
492 		goto detach;
493 	if (CHECK(prog_cnt != 3, "bpf_prog_query",
494 		  "wrong program count on query: %u", prog_cnt))
495 		goto detach;
496 	prog_id = link_info_prog_id(link[0], &info);
497 	CHECK(prog_ids[0] != prog_id, "bpf_prog_query",
498 	      "invalid program #0 id on query: %u != %u\n",
499 	      prog_ids[0], prog_id);
500 	CHECK(info.netns.netns_ino == 0, "netns_ino",
501 	      "unexpected netns_ino: %u\n", info.netns.netns_ino);
502 	prog_id = link_info_prog_id(link[1], &info);
503 	CHECK(prog_ids[1] != prog_id, "bpf_prog_query",
504 	      "invalid program #1 id on query: %u != %u\n",
505 	      prog_ids[1], prog_id);
506 	CHECK(info.netns.netns_ino == 0, "netns_ino",
507 	      "unexpected netns_ino: %u\n", info.netns.netns_ino);
508 	prog_id = link_info_prog_id(link[2], &info);
509 	CHECK(prog_ids[2] != prog_id, "bpf_prog_query",
510 	      "invalid program #2 id on query: %u != %u\n",
511 	      prog_ids[2], prog_id);
512 	CHECK(info.netns.netns_ino == 0, "netns_ino",
513 	      "unexpected netns_ino: %u\n", info.netns.netns_ino);
514 
515 	err = bpf_link__detach(link[0]);
516 	if (CHECK(err, "link_detach", "failed %d\n", err))
517 		goto detach;
518 
519 	/* prog id is still there, but netns_ino is zeroed out */
520 	prog_id = link_info_prog_id(link[0], &info);
521 	CHECK(prog_ids[0] != prog_id, "bpf_prog_query",
522 	      "invalid program #0 id on query: %u != %u\n",
523 	      prog_ids[0], prog_id);
524 	CHECK(info.netns.netns_ino != 0, "netns_ino",
525 	      "unexpected netns_ino: %u\n", info.netns.netns_ino);
526 
527 detach:
528 	if (link[2])
529 		bpf_link__destroy(link[2]);
530 	if (link[1])
531 		bpf_link__destroy(link[1]);
532 	if (link[0])
533 		bpf_link__destroy(link[0]);
534 close:
535 	close(net_fd);
536 }
537 
538 static void run_lookup_prog(const struct test *t)
539 {
540 	int server_fds[] = { [0 ... MAX_SERVERS - 1] = -1 };
541 	int client_fd, reuse_conn_fd = -1;
542 	struct bpf_link *lookup_link;
543 	int i, err;
544 
545 	lookup_link = attach_lookup_prog(t->lookup_prog);
546 	if (!lookup_link)
547 		return;
548 
549 	for (i = 0; i < ARRAY_SIZE(server_fds); i++) {
550 		server_fds[i] = make_server(t->sotype, t->listen_at.ip,
551 					    t->listen_at.port,
552 					    t->reuseport_prog);
553 		if (server_fds[i] < 0)
554 			goto close;
555 
556 		err = update_lookup_map(t->sock_map, i, server_fds[i]);
557 		if (err)
558 			goto close;
559 
560 		/* want just one server for non-reuseport test */
561 		if (!t->reuseport_prog)
562 			break;
563 	}
564 
565 	/* Regular UDP socket lookup with reuseport behaves
566 	 * differently when reuseport group contains connected
567 	 * sockets. Check that adding a connected UDP socket to the
568 	 * reuseport group does not affect how reuseport works with
569 	 * BPF socket lookup.
570 	 */
571 	if (t->reuseport_has_conns) {
572 		/* Add an extra socket to reuseport group */
573 		reuse_conn_fd = make_server(t->sotype, t->listen_at.ip,
574 					    t->listen_at.port,
575 					    t->reuseport_prog);
576 		if (reuse_conn_fd < 0)
577 			goto close;
578 
579 		 /* Connect the extra socket to itself */
580 		err = connect_fd_to_fd(reuse_conn_fd, reuse_conn_fd, 0);
581 		if (!ASSERT_OK(err, "connect_fd_to_fd"))
582 			goto close;
583 	}
584 
585 	client_fd = connect_to_addr_str(is_ipv6(t->connect_to.ip) ? AF_INET6 : AF_INET,
586 					t->sotype, t->connect_to.ip, t->connect_to.port, NULL);
587 	if (!ASSERT_OK_FD(client_fd, "connect_to_addr_str"))
588 		goto close;
589 
590 	if (t->sotype == SOCK_STREAM)
591 		tcp_echo_test(client_fd, server_fds[t->accept_on]);
592 	else
593 		udp_echo_test(client_fd, server_fds[t->accept_on]);
594 
595 	close(client_fd);
596 close:
597 	if (reuse_conn_fd != -1)
598 		close(reuse_conn_fd);
599 	for (i = 0; i < ARRAY_SIZE(server_fds); i++) {
600 		if (server_fds[i] != -1)
601 			close(server_fds[i]);
602 	}
603 	bpf_link__destroy(lookup_link);
604 }
605 
606 static void test_redirect_lookup(struct test_sk_lookup *skel)
607 {
608 	const struct test tests[] = {
609 		{
610 			.desc		= "TCP IPv4 redir port",
611 			.lookup_prog	= skel->progs.redir_port,
612 			.sock_map	= skel->maps.redir_map,
613 			.sotype		= SOCK_STREAM,
614 			.connect_to	= { EXT_IP4, EXT_PORT },
615 			.listen_at	= { EXT_IP4, INT_PORT },
616 		},
617 		{
618 			.desc		= "TCP IPv4 redir addr",
619 			.lookup_prog	= skel->progs.redir_ip4,
620 			.sock_map	= skel->maps.redir_map,
621 			.sotype		= SOCK_STREAM,
622 			.connect_to	= { EXT_IP4, EXT_PORT },
623 			.listen_at	= { INT_IP4, EXT_PORT },
624 		},
625 		{
626 			.desc		= "TCP IPv4 redir with reuseport",
627 			.lookup_prog	= skel->progs.select_sock_a,
628 			.reuseport_prog	= skel->progs.select_sock_b,
629 			.sock_map	= skel->maps.redir_map,
630 			.sotype		= SOCK_STREAM,
631 			.connect_to	= { EXT_IP4, EXT_PORT },
632 			.listen_at	= { INT_IP4, INT_PORT },
633 			.accept_on	= SERVER_B,
634 		},
635 		{
636 			.desc		= "TCP IPv4 redir skip reuseport",
637 			.lookup_prog	= skel->progs.select_sock_a_no_reuseport,
638 			.reuseport_prog	= skel->progs.select_sock_b,
639 			.sock_map	= skel->maps.redir_map,
640 			.sotype		= SOCK_STREAM,
641 			.connect_to	= { EXT_IP4, EXT_PORT },
642 			.listen_at	= { INT_IP4, INT_PORT },
643 			.accept_on	= SERVER_A,
644 		},
645 		{
646 			.desc		= "TCP IPv6 redir port",
647 			.lookup_prog	= skel->progs.redir_port,
648 			.sock_map	= skel->maps.redir_map,
649 			.sotype		= SOCK_STREAM,
650 			.connect_to	= { EXT_IP6, EXT_PORT },
651 			.listen_at	= { EXT_IP6, INT_PORT },
652 		},
653 		{
654 			.desc		= "TCP IPv6 redir addr",
655 			.lookup_prog	= skel->progs.redir_ip6,
656 			.sock_map	= skel->maps.redir_map,
657 			.sotype		= SOCK_STREAM,
658 			.connect_to	= { EXT_IP6, EXT_PORT },
659 			.listen_at	= { INT_IP6, EXT_PORT },
660 		},
661 		{
662 			.desc		= "TCP IPv4->IPv6 redir port",
663 			.lookup_prog	= skel->progs.redir_port,
664 			.sock_map	= skel->maps.redir_map,
665 			.sotype		= SOCK_STREAM,
666 			.connect_to	= { EXT_IP4, EXT_PORT },
667 			.listen_at	= { INT_IP4_V6, INT_PORT },
668 		},
669 		{
670 			.desc		= "TCP IPv6 redir with reuseport",
671 			.lookup_prog	= skel->progs.select_sock_a,
672 			.reuseport_prog	= skel->progs.select_sock_b,
673 			.sock_map	= skel->maps.redir_map,
674 			.sotype		= SOCK_STREAM,
675 			.connect_to	= { EXT_IP6, EXT_PORT },
676 			.listen_at	= { INT_IP6, INT_PORT },
677 			.accept_on	= SERVER_B,
678 		},
679 		{
680 			.desc		= "TCP IPv6 redir skip reuseport",
681 			.lookup_prog	= skel->progs.select_sock_a_no_reuseport,
682 			.reuseport_prog	= skel->progs.select_sock_b,
683 			.sock_map	= skel->maps.redir_map,
684 			.sotype		= SOCK_STREAM,
685 			.connect_to	= { EXT_IP6, EXT_PORT },
686 			.listen_at	= { INT_IP6, INT_PORT },
687 			.accept_on	= SERVER_A,
688 		},
689 		{
690 			.desc		= "UDP IPv4 redir port",
691 			.lookup_prog	= skel->progs.redir_port,
692 			.sock_map	= skel->maps.redir_map,
693 			.sotype		= SOCK_DGRAM,
694 			.connect_to	= { EXT_IP4, EXT_PORT },
695 			.listen_at	= { EXT_IP4, INT_PORT },
696 		},
697 		{
698 			.desc		= "UDP IPv4 redir addr",
699 			.lookup_prog	= skel->progs.redir_ip4,
700 			.sock_map	= skel->maps.redir_map,
701 			.sotype		= SOCK_DGRAM,
702 			.connect_to	= { EXT_IP4, EXT_PORT },
703 			.listen_at	= { INT_IP4, EXT_PORT },
704 		},
705 		{
706 			.desc		= "UDP IPv4 redir with reuseport",
707 			.lookup_prog	= skel->progs.select_sock_a,
708 			.reuseport_prog	= skel->progs.select_sock_b,
709 			.sock_map	= skel->maps.redir_map,
710 			.sotype		= SOCK_DGRAM,
711 			.connect_to	= { EXT_IP4, EXT_PORT },
712 			.listen_at	= { INT_IP4, INT_PORT },
713 			.accept_on	= SERVER_B,
714 		},
715 		{
716 			.desc		= "UDP IPv4 redir and reuseport with conns",
717 			.lookup_prog	= skel->progs.select_sock_a,
718 			.reuseport_prog	= skel->progs.select_sock_b,
719 			.sock_map	= skel->maps.redir_map,
720 			.sotype		= SOCK_DGRAM,
721 			.connect_to	= { EXT_IP4, EXT_PORT },
722 			.listen_at	= { INT_IP4, INT_PORT },
723 			.accept_on	= SERVER_B,
724 			.reuseport_has_conns = true,
725 		},
726 		{
727 			.desc		= "UDP IPv4 redir skip reuseport",
728 			.lookup_prog	= skel->progs.select_sock_a_no_reuseport,
729 			.reuseport_prog	= skel->progs.select_sock_b,
730 			.sock_map	= skel->maps.redir_map,
731 			.sotype		= SOCK_DGRAM,
732 			.connect_to	= { EXT_IP4, EXT_PORT },
733 			.listen_at	= { INT_IP4, INT_PORT },
734 			.accept_on	= SERVER_A,
735 		},
736 		{
737 			.desc		= "UDP IPv6 redir port",
738 			.lookup_prog	= skel->progs.redir_port,
739 			.sock_map	= skel->maps.redir_map,
740 			.sotype		= SOCK_DGRAM,
741 			.connect_to	= { EXT_IP6, EXT_PORT },
742 			.listen_at	= { EXT_IP6, INT_PORT },
743 		},
744 		{
745 			.desc		= "UDP IPv6 redir addr",
746 			.lookup_prog	= skel->progs.redir_ip6,
747 			.sock_map	= skel->maps.redir_map,
748 			.sotype		= SOCK_DGRAM,
749 			.connect_to	= { EXT_IP6, EXT_PORT },
750 			.listen_at	= { INT_IP6, EXT_PORT },
751 		},
752 		{
753 			.desc		= "UDP IPv4->IPv6 redir port",
754 			.lookup_prog	= skel->progs.redir_port,
755 			.sock_map	= skel->maps.redir_map,
756 			.sotype		= SOCK_DGRAM,
757 			.listen_at	= { INT_IP4_V6, INT_PORT },
758 			.connect_to	= { EXT_IP4, EXT_PORT },
759 		},
760 		{
761 			.desc		= "UDP IPv6 redir and reuseport",
762 			.lookup_prog	= skel->progs.select_sock_a,
763 			.reuseport_prog	= skel->progs.select_sock_b,
764 			.sock_map	= skel->maps.redir_map,
765 			.sotype		= SOCK_DGRAM,
766 			.connect_to	= { EXT_IP6, EXT_PORT },
767 			.listen_at	= { INT_IP6, INT_PORT },
768 			.accept_on	= SERVER_B,
769 		},
770 		{
771 			.desc		= "UDP IPv6 redir and reuseport with conns",
772 			.lookup_prog	= skel->progs.select_sock_a,
773 			.reuseport_prog	= skel->progs.select_sock_b,
774 			.sock_map	= skel->maps.redir_map,
775 			.sotype		= SOCK_DGRAM,
776 			.connect_to	= { EXT_IP6, EXT_PORT },
777 			.listen_at	= { INT_IP6, INT_PORT },
778 			.accept_on	= SERVER_B,
779 			.reuseport_has_conns = true,
780 		},
781 		{
782 			.desc		= "UDP IPv6 redir skip reuseport",
783 			.lookup_prog	= skel->progs.select_sock_a_no_reuseport,
784 			.reuseport_prog	= skel->progs.select_sock_b,
785 			.sock_map	= skel->maps.redir_map,
786 			.sotype		= SOCK_DGRAM,
787 			.connect_to	= { EXT_IP6, EXT_PORT },
788 			.listen_at	= { INT_IP6, INT_PORT },
789 			.accept_on	= SERVER_A,
790 		},
791 	};
792 	const struct test *t;
793 
794 	for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
795 		if (test__start_subtest(t->desc))
796 			run_lookup_prog(t);
797 	}
798 }
799 
800 static void drop_on_lookup(const struct test *t)
801 {
802 	int family = is_ipv6(t->connect_to.ip) ? AF_INET6 : AF_INET;
803 	struct sockaddr_storage dst = {};
804 	int client_fd, server_fd, err;
805 	struct bpf_link *lookup_link;
806 	socklen_t len;
807 	ssize_t n;
808 
809 	lookup_link = attach_lookup_prog(t->lookup_prog);
810 	if (!lookup_link)
811 		return;
812 
813 	server_fd = make_server(t->sotype, t->listen_at.ip, t->listen_at.port,
814 				t->reuseport_prog);
815 	if (server_fd < 0)
816 		goto detach;
817 
818 	client_fd = client_socket(family, t->sotype, NULL);
819 	if (!ASSERT_OK_FD(client_fd, "client_socket"))
820 		goto close_srv;
821 
822 	err = make_sockaddr(family, t->connect_to.ip, t->connect_to.port, &dst, &len);
823 	if (!ASSERT_OK(err, "make_sockaddr"))
824 		goto close_all;
825 	err = connect(client_fd, (void *)&dst, len);
826 	if (t->sotype == SOCK_DGRAM) {
827 		err = send_byte(client_fd);
828 		if (err)
829 			goto close_all;
830 
831 		/* Read out asynchronous error */
832 		n = recv(client_fd, NULL, 0, 0);
833 		err = n == -1;
834 	}
835 	if (CHECK(!err || errno != ECONNREFUSED, "connect",
836 		  "unexpected success or error\n"))
837 		log_err("expected ECONNREFUSED on connect");
838 
839 close_all:
840 	close(client_fd);
841 close_srv:
842 	close(server_fd);
843 detach:
844 	bpf_link__destroy(lookup_link);
845 }
846 
847 static void test_drop_on_lookup(struct test_sk_lookup *skel)
848 {
849 	const struct test tests[] = {
850 		{
851 			.desc		= "TCP IPv4 drop on lookup",
852 			.lookup_prog	= skel->progs.lookup_drop,
853 			.sotype		= SOCK_STREAM,
854 			.connect_to	= { EXT_IP4, EXT_PORT },
855 			.listen_at	= { EXT_IP4, EXT_PORT },
856 		},
857 		{
858 			.desc		= "TCP IPv6 drop on lookup",
859 			.lookup_prog	= skel->progs.lookup_drop,
860 			.sotype		= SOCK_STREAM,
861 			.connect_to	= { EXT_IP6, EXT_PORT },
862 			.listen_at	= { EXT_IP6, EXT_PORT },
863 		},
864 		{
865 			.desc		= "UDP IPv4 drop on lookup",
866 			.lookup_prog	= skel->progs.lookup_drop,
867 			.sotype		= SOCK_DGRAM,
868 			.connect_to	= { EXT_IP4, EXT_PORT },
869 			.listen_at	= { EXT_IP4, EXT_PORT },
870 		},
871 		{
872 			.desc		= "UDP IPv6 drop on lookup",
873 			.lookup_prog	= skel->progs.lookup_drop,
874 			.sotype		= SOCK_DGRAM,
875 			.connect_to	= { EXT_IP6, EXT_PORT },
876 			.listen_at	= { EXT_IP6, INT_PORT },
877 		},
878 		/* The program will drop on success, meaning that the ifindex
879 		 * was 1.
880 		 */
881 		{
882 			.desc		= "TCP IPv4 drop on valid ifindex",
883 			.lookup_prog	= skel->progs.check_ifindex,
884 			.sotype		= SOCK_STREAM,
885 			.connect_to	= { EXT_IP4, EXT_PORT },
886 			.listen_at	= { EXT_IP4, EXT_PORT },
887 		},
888 		{
889 			.desc		= "TCP IPv6 drop on valid ifindex",
890 			.lookup_prog	= skel->progs.check_ifindex,
891 			.sotype		= SOCK_STREAM,
892 			.connect_to	= { EXT_IP6, EXT_PORT },
893 			.listen_at	= { EXT_IP6, EXT_PORT },
894 		},
895 		{
896 			.desc		= "UDP IPv4 drop on valid ifindex",
897 			.lookup_prog	= skel->progs.check_ifindex,
898 			.sotype		= SOCK_DGRAM,
899 			.connect_to	= { EXT_IP4, EXT_PORT },
900 			.listen_at	= { EXT_IP4, EXT_PORT },
901 		},
902 		{
903 			.desc		= "UDP IPv6 drop on valid ifindex",
904 			.lookup_prog	= skel->progs.check_ifindex,
905 			.sotype		= SOCK_DGRAM,
906 			.connect_to	= { EXT_IP6, EXT_PORT },
907 			.listen_at	= { EXT_IP6, EXT_PORT },
908 		},
909 	};
910 	const struct test *t;
911 
912 	for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
913 		if (test__start_subtest(t->desc))
914 			drop_on_lookup(t);
915 	}
916 }
917 
918 static void drop_on_reuseport(const struct test *t)
919 {
920 	int family = is_ipv6(t->connect_to.ip) ? AF_INET6 : AF_INET;
921 	struct sockaddr_storage dst = { 0 };
922 	int client, server1, server2, err;
923 	struct bpf_link *lookup_link;
924 	socklen_t len;
925 	ssize_t n;
926 
927 	lookup_link = attach_lookup_prog(t->lookup_prog);
928 	if (!lookup_link)
929 		return;
930 
931 	server1 = make_server(t->sotype, t->listen_at.ip, t->listen_at.port,
932 			      t->reuseport_prog);
933 	if (server1 < 0)
934 		goto detach;
935 
936 	err = update_lookup_map(t->sock_map, SERVER_A, server1);
937 	if (err)
938 		goto close_srv1;
939 
940 	/* second server on destination address we should never reach */
941 	server2 = make_server(t->sotype, t->connect_to.ip, t->connect_to.port,
942 			      NULL /* reuseport prog */);
943 	if (server2 < 0)
944 		goto close_srv1;
945 
946 	client = client_socket(family, t->sotype, NULL);
947 	if (!ASSERT_OK_FD(client, "client_socket"))
948 		goto close_srv2;
949 
950 	err = make_sockaddr(family, t->connect_to.ip, t->connect_to.port, &dst, &len);
951 	if (!ASSERT_OK(err, "make_sockaddr"))
952 		goto close_all;
953 	err = connect(client, (void *)&dst, len);
954 	if (t->sotype == SOCK_DGRAM) {
955 		err = send_byte(client);
956 		if (err)
957 			goto close_all;
958 
959 		/* Read out asynchronous error */
960 		n = recv(client, NULL, 0, 0);
961 		err = n == -1;
962 	}
963 	if (CHECK(!err || errno != ECONNREFUSED, "connect",
964 		  "unexpected success or error\n"))
965 		log_err("expected ECONNREFUSED on connect");
966 
967 close_all:
968 	close(client);
969 close_srv2:
970 	close(server2);
971 close_srv1:
972 	close(server1);
973 detach:
974 	bpf_link__destroy(lookup_link);
975 }
976 
977 static void test_drop_on_reuseport(struct test_sk_lookup *skel)
978 {
979 	const struct test tests[] = {
980 		{
981 			.desc		= "TCP IPv4 drop on reuseport",
982 			.lookup_prog	= skel->progs.select_sock_a,
983 			.reuseport_prog	= skel->progs.reuseport_drop,
984 			.sock_map	= skel->maps.redir_map,
985 			.sotype		= SOCK_STREAM,
986 			.connect_to	= { EXT_IP4, EXT_PORT },
987 			.listen_at	= { INT_IP4, INT_PORT },
988 		},
989 		{
990 			.desc		= "TCP IPv6 drop on reuseport",
991 			.lookup_prog	= skel->progs.select_sock_a,
992 			.reuseport_prog	= skel->progs.reuseport_drop,
993 			.sock_map	= skel->maps.redir_map,
994 			.sotype		= SOCK_STREAM,
995 			.connect_to	= { EXT_IP6, EXT_PORT },
996 			.listen_at	= { INT_IP6, INT_PORT },
997 		},
998 		{
999 			.desc		= "UDP IPv4 drop on reuseport",
1000 			.lookup_prog	= skel->progs.select_sock_a,
1001 			.reuseport_prog	= skel->progs.reuseport_drop,
1002 			.sock_map	= skel->maps.redir_map,
1003 			.sotype		= SOCK_DGRAM,
1004 			.connect_to	= { EXT_IP4, EXT_PORT },
1005 			.listen_at	= { INT_IP4, INT_PORT },
1006 		},
1007 		{
1008 			.desc		= "TCP IPv6 drop on reuseport",
1009 			.lookup_prog	= skel->progs.select_sock_a,
1010 			.reuseport_prog	= skel->progs.reuseport_drop,
1011 			.sock_map	= skel->maps.redir_map,
1012 			.sotype		= SOCK_STREAM,
1013 			.connect_to	= { EXT_IP6, EXT_PORT },
1014 			.listen_at	= { INT_IP6, INT_PORT },
1015 		},
1016 	};
1017 	const struct test *t;
1018 
1019 	for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
1020 		if (test__start_subtest(t->desc))
1021 			drop_on_reuseport(t);
1022 	}
1023 }
1024 
1025 static void run_sk_assign(struct test_sk_lookup *skel,
1026 			  struct bpf_program *lookup_prog,
1027 			  const char *remote_ip, const char *local_ip)
1028 {
1029 	int server_fds[] = { [0 ... MAX_SERVERS - 1] = -1 };
1030 	struct bpf_sk_lookup ctx;
1031 	__u64 server_cookie;
1032 	int i, err;
1033 
1034 	DECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts,
1035 		.ctx_in = &ctx,
1036 		.ctx_size_in = sizeof(ctx),
1037 		.ctx_out = &ctx,
1038 		.ctx_size_out = sizeof(ctx),
1039 	);
1040 
1041 	if (fill_sk_lookup_ctx(&ctx, local_ip, EXT_PORT, remote_ip, INT_PORT))
1042 		return;
1043 
1044 	ctx.protocol = IPPROTO_TCP;
1045 
1046 	for (i = 0; i < ARRAY_SIZE(server_fds); i++) {
1047 		server_fds[i] = make_server(SOCK_STREAM, local_ip, 0, NULL);
1048 		if (server_fds[i] < 0)
1049 			goto close_servers;
1050 
1051 		err = update_lookup_map(skel->maps.redir_map, i,
1052 					server_fds[i]);
1053 		if (err)
1054 			goto close_servers;
1055 	}
1056 
1057 	server_cookie = socket_cookie(server_fds[SERVER_B]);
1058 	if (!server_cookie)
1059 		return;
1060 
1061 	err = bpf_prog_test_run_opts(bpf_program__fd(lookup_prog), &opts);
1062 	if (CHECK(err, "test_run", "failed with error %d\n", errno))
1063 		goto close_servers;
1064 
1065 	if (CHECK(ctx.cookie == 0, "ctx.cookie", "no socket selected\n"))
1066 		goto close_servers;
1067 
1068 	CHECK(ctx.cookie != server_cookie, "ctx.cookie",
1069 	      "selected sk %llu instead of %llu\n", ctx.cookie, server_cookie);
1070 
1071 close_servers:
1072 	for (i = 0; i < ARRAY_SIZE(server_fds); i++) {
1073 		if (server_fds[i] != -1)
1074 			close(server_fds[i]);
1075 	}
1076 }
1077 
1078 static void run_sk_assign_v4(struct test_sk_lookup *skel,
1079 			     struct bpf_program *lookup_prog)
1080 {
1081 	run_sk_assign(skel, lookup_prog, INT_IP4, EXT_IP4);
1082 }
1083 
1084 static void run_sk_assign_v6(struct test_sk_lookup *skel,
1085 			     struct bpf_program *lookup_prog)
1086 {
1087 	run_sk_assign(skel, lookup_prog, INT_IP6, EXT_IP6);
1088 }
1089 
1090 static void run_sk_assign_connected(struct test_sk_lookup *skel,
1091 				    int sotype)
1092 {
1093 	int err, client_fd, connected_fd, server_fd;
1094 	struct bpf_link *lookup_link;
1095 
1096 	server_fd = make_server(sotype, EXT_IP4, EXT_PORT, NULL);
1097 	if (server_fd < 0)
1098 		return;
1099 
1100 	connected_fd = connect_to_addr_str(AF_INET, sotype, EXT_IP4, EXT_PORT, NULL);
1101 	if (!ASSERT_OK_FD(connected_fd, "connect_to_addr_str"))
1102 		goto out_close_server;
1103 
1104 	/* Put a connected socket in redirect map */
1105 	err = update_lookup_map(skel->maps.redir_map, SERVER_A, connected_fd);
1106 	if (err)
1107 		goto out_close_connected;
1108 
1109 	lookup_link = attach_lookup_prog(skel->progs.sk_assign_esocknosupport);
1110 	if (!lookup_link)
1111 		goto out_close_connected;
1112 
1113 	/* Try to redirect TCP SYN / UDP packet to a connected socket */
1114 	client_fd = connect_to_addr_str(AF_INET, sotype, EXT_IP4, EXT_PORT, NULL);
1115 	if (!ASSERT_OK_FD(client_fd, "connect_to_addr_str"))
1116 		goto out_unlink_prog;
1117 	if (sotype == SOCK_DGRAM) {
1118 		send_byte(client_fd);
1119 		recv_byte(server_fd);
1120 	}
1121 
1122 	close(client_fd);
1123 out_unlink_prog:
1124 	bpf_link__destroy(lookup_link);
1125 out_close_connected:
1126 	close(connected_fd);
1127 out_close_server:
1128 	close(server_fd);
1129 }
1130 
1131 static void test_sk_assign_helper(struct test_sk_lookup *skel)
1132 {
1133 	if (test__start_subtest("sk_assign returns EEXIST"))
1134 		run_sk_assign_v4(skel, skel->progs.sk_assign_eexist);
1135 	if (test__start_subtest("sk_assign honors F_REPLACE"))
1136 		run_sk_assign_v4(skel, skel->progs.sk_assign_replace_flag);
1137 	if (test__start_subtest("sk_assign accepts NULL socket"))
1138 		run_sk_assign_v4(skel, skel->progs.sk_assign_null);
1139 	if (test__start_subtest("access ctx->sk"))
1140 		run_sk_assign_v4(skel, skel->progs.access_ctx_sk);
1141 	if (test__start_subtest("narrow access to ctx v4"))
1142 		run_sk_assign_v4(skel, skel->progs.ctx_narrow_access);
1143 	if (test__start_subtest("narrow access to ctx v6"))
1144 		run_sk_assign_v6(skel, skel->progs.ctx_narrow_access);
1145 	if (test__start_subtest("sk_assign rejects TCP established"))
1146 		run_sk_assign_connected(skel, SOCK_STREAM);
1147 	if (test__start_subtest("sk_assign rejects UDP connected"))
1148 		run_sk_assign_connected(skel, SOCK_DGRAM);
1149 }
1150 
1151 struct test_multi_prog {
1152 	const char *desc;
1153 	struct bpf_program *prog1;
1154 	struct bpf_program *prog2;
1155 	struct bpf_map *redir_map;
1156 	struct bpf_map *run_map;
1157 	int expect_errno;
1158 	struct inet_addr listen_at;
1159 };
1160 
1161 static void run_multi_prog_lookup(const struct test_multi_prog *t)
1162 {
1163 	struct sockaddr_storage dst = {};
1164 	int map_fd, server_fd, client_fd;
1165 	struct bpf_link *link1, *link2;
1166 	int prog_idx, done, err;
1167 	socklen_t len;
1168 
1169 	map_fd = bpf_map__fd(t->run_map);
1170 
1171 	done = 0;
1172 	prog_idx = PROG1;
1173 	err = bpf_map_update_elem(map_fd, &prog_idx, &done, BPF_ANY);
1174 	if (CHECK(err, "bpf_map_update_elem", "failed\n"))
1175 		return;
1176 	prog_idx = PROG2;
1177 	err = bpf_map_update_elem(map_fd, &prog_idx, &done, BPF_ANY);
1178 	if (CHECK(err, "bpf_map_update_elem", "failed\n"))
1179 		return;
1180 
1181 	link1 = attach_lookup_prog(t->prog1);
1182 	if (!link1)
1183 		return;
1184 	link2 = attach_lookup_prog(t->prog2);
1185 	if (!link2)
1186 		goto out_unlink1;
1187 
1188 	server_fd = make_server(SOCK_STREAM, t->listen_at.ip,
1189 				t->listen_at.port, NULL);
1190 	if (server_fd < 0)
1191 		goto out_unlink2;
1192 
1193 	err = update_lookup_map(t->redir_map, SERVER_A, server_fd);
1194 	if (err)
1195 		goto out_close_server;
1196 
1197 	client_fd = client_socket(AF_INET, SOCK_STREAM, NULL);
1198 	if (!ASSERT_OK_FD(client_fd, "client_socket"))
1199 		goto out_close_server;
1200 
1201 	err = make_sockaddr(AF_INET, EXT_IP4, EXT_PORT, &dst, &len);
1202 	if (!ASSERT_OK(err, "make_sockaddr"))
1203 		goto out_close_client;
1204 	err = connect(client_fd, (void *)&dst, len);
1205 	if (CHECK(err && !t->expect_errno, "connect",
1206 		  "unexpected error %d\n", errno))
1207 		goto out_close_client;
1208 	if (CHECK(err && t->expect_errno && errno != t->expect_errno,
1209 		  "connect", "unexpected error %d\n", errno))
1210 		goto out_close_client;
1211 
1212 	done = 0;
1213 	prog_idx = PROG1;
1214 	err = bpf_map_lookup_elem(map_fd, &prog_idx, &done);
1215 	CHECK(err, "bpf_map_lookup_elem", "failed\n");
1216 	CHECK(!done, "bpf_map_lookup_elem", "PROG1 !done\n");
1217 
1218 	done = 0;
1219 	prog_idx = PROG2;
1220 	err = bpf_map_lookup_elem(map_fd, &prog_idx, &done);
1221 	CHECK(err, "bpf_map_lookup_elem", "failed\n");
1222 	CHECK(!done, "bpf_map_lookup_elem", "PROG2 !done\n");
1223 
1224 out_close_client:
1225 	close(client_fd);
1226 out_close_server:
1227 	close(server_fd);
1228 out_unlink2:
1229 	bpf_link__destroy(link2);
1230 out_unlink1:
1231 	bpf_link__destroy(link1);
1232 }
1233 
1234 static void test_multi_prog_lookup(struct test_sk_lookup *skel)
1235 {
1236 	struct test_multi_prog tests[] = {
1237 		{
1238 			.desc		= "multi prog - pass, pass",
1239 			.prog1		= skel->progs.multi_prog_pass1,
1240 			.prog2		= skel->progs.multi_prog_pass2,
1241 			.listen_at	= { EXT_IP4, EXT_PORT },
1242 		},
1243 		{
1244 			.desc		= "multi prog - drop, drop",
1245 			.prog1		= skel->progs.multi_prog_drop1,
1246 			.prog2		= skel->progs.multi_prog_drop2,
1247 			.listen_at	= { EXT_IP4, EXT_PORT },
1248 			.expect_errno	= ECONNREFUSED,
1249 		},
1250 		{
1251 			.desc		= "multi prog - pass, drop",
1252 			.prog1		= skel->progs.multi_prog_pass1,
1253 			.prog2		= skel->progs.multi_prog_drop2,
1254 			.listen_at	= { EXT_IP4, EXT_PORT },
1255 			.expect_errno	= ECONNREFUSED,
1256 		},
1257 		{
1258 			.desc		= "multi prog - drop, pass",
1259 			.prog1		= skel->progs.multi_prog_drop1,
1260 			.prog2		= skel->progs.multi_prog_pass2,
1261 			.listen_at	= { EXT_IP4, EXT_PORT },
1262 			.expect_errno	= ECONNREFUSED,
1263 		},
1264 		{
1265 			.desc		= "multi prog - pass, redir",
1266 			.prog1		= skel->progs.multi_prog_pass1,
1267 			.prog2		= skel->progs.multi_prog_redir2,
1268 			.listen_at	= { INT_IP4, INT_PORT },
1269 		},
1270 		{
1271 			.desc		= "multi prog - redir, pass",
1272 			.prog1		= skel->progs.multi_prog_redir1,
1273 			.prog2		= skel->progs.multi_prog_pass2,
1274 			.listen_at	= { INT_IP4, INT_PORT },
1275 		},
1276 		{
1277 			.desc		= "multi prog - drop, redir",
1278 			.prog1		= skel->progs.multi_prog_drop1,
1279 			.prog2		= skel->progs.multi_prog_redir2,
1280 			.listen_at	= { INT_IP4, INT_PORT },
1281 		},
1282 		{
1283 			.desc		= "multi prog - redir, drop",
1284 			.prog1		= skel->progs.multi_prog_redir1,
1285 			.prog2		= skel->progs.multi_prog_drop2,
1286 			.listen_at	= { INT_IP4, INT_PORT },
1287 		},
1288 		{
1289 			.desc		= "multi prog - redir, redir",
1290 			.prog1		= skel->progs.multi_prog_redir1,
1291 			.prog2		= skel->progs.multi_prog_redir2,
1292 			.listen_at	= { INT_IP4, INT_PORT },
1293 		},
1294 	};
1295 	struct test_multi_prog *t;
1296 
1297 	for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
1298 		t->redir_map = skel->maps.redir_map;
1299 		t->run_map = skel->maps.run_map;
1300 		if (test__start_subtest(t->desc))
1301 			run_multi_prog_lookup(t);
1302 	}
1303 }
1304 
1305 static void run_tests(struct test_sk_lookup *skel)
1306 {
1307 	if (test__start_subtest("query lookup prog"))
1308 		query_lookup_prog(skel);
1309 	test_redirect_lookup(skel);
1310 	test_drop_on_lookup(skel);
1311 	test_drop_on_reuseport(skel);
1312 	test_sk_assign_helper(skel);
1313 	test_multi_prog_lookup(skel);
1314 }
1315 
1316 static int switch_netns(void)
1317 {
1318 	static const char * const setup_script[] = {
1319 		"ip -6 addr add dev lo " EXT_IP6 "/128",
1320 		"ip -6 addr add dev lo " INT_IP6 "/128",
1321 		"ip link set dev lo up",
1322 		NULL,
1323 	};
1324 	const char * const *cmd;
1325 	int err;
1326 
1327 	err = unshare(CLONE_NEWNET);
1328 	if (CHECK(err, "unshare", "failed\n")) {
1329 		log_err("unshare(CLONE_NEWNET)");
1330 		return -1;
1331 	}
1332 
1333 	for (cmd = setup_script; *cmd; cmd++) {
1334 		err = system(*cmd);
1335 		if (CHECK(err, "system", "failed\n")) {
1336 			log_err("system(%s)", *cmd);
1337 			return -1;
1338 		}
1339 	}
1340 
1341 	return 0;
1342 }
1343 
1344 void test_sk_lookup(void)
1345 {
1346 	struct test_sk_lookup *skel;
1347 	int err;
1348 
1349 	err = switch_netns();
1350 	if (err)
1351 		return;
1352 
1353 	skel = test_sk_lookup__open_and_load();
1354 	if (CHECK(!skel, "skel open_and_load", "failed\n"))
1355 		return;
1356 
1357 	run_tests(skel);
1358 
1359 	test_sk_lookup__destroy(skel);
1360 }
1361