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