xref: /linux/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c (revision fab183d632628381b466a41479489541ac0e29a0)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020 Cloudflare
3 /*
4  * Test suite for SOCKMAP/SOCKHASH holding listening sockets.
5  * Covers:
6  *  1. BPF map operations - bpf_map_{update,lookup delete}_elem
7  *  2. BPF redirect helpers - bpf_{sk,msg}_redirect_map
8  *  3. BPF reuseport helper - bpf_sk_select_reuseport
9  */
10 
11 #include <linux/compiler.h>
12 #include <errno.h>
13 #include <error.h>
14 #include <limits.h>
15 #include <netinet/in.h>
16 #include <pthread.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/select.h>
20 #include <unistd.h>
21 #include <linux/vm_sockets.h>
22 
23 #include <bpf/bpf.h>
24 #include <bpf/libbpf.h>
25 
26 #include "bpf_util.h"
27 #include "test_progs.h"
28 #include "test_sockmap_listen.skel.h"
29 
30 #include "sockmap_helpers.h"
31 
32 #define NO_FLAGS 0
33 
test_insert_invalid(struct test_sockmap_listen * skel __always_unused,int family,int sotype,int mapfd)34 static void test_insert_invalid(struct test_sockmap_listen *skel __always_unused,
35 				int family, int sotype, int mapfd)
36 {
37 	u32 key = 0;
38 	u64 value;
39 	int err;
40 
41 	value = -1;
42 	err = bpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
43 	if (!err || errno != EINVAL)
44 		FAIL_ERRNO("map_update: expected EINVAL");
45 
46 	value = INT_MAX;
47 	err = bpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
48 	if (!err || errno != EBADF)
49 		FAIL_ERRNO("map_update: expected EBADF");
50 }
51 
test_insert_opened(struct test_sockmap_listen * skel __always_unused,int family,int sotype,int mapfd)52 static void test_insert_opened(struct test_sockmap_listen *skel __always_unused,
53 			       int family, int sotype, int mapfd)
54 {
55 	u32 key = 0;
56 	int err, s;
57 	u64 value;
58 
59 	s = xsocket(family, sotype, 0);
60 	if (s == -1)
61 		return;
62 
63 	errno = 0;
64 	value = s;
65 	err = bpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
66 	ASSERT_ERR(err, "map_update");
67 	ASSERT_EQ(errno, EOPNOTSUPP, "errno");
68 	xclose(s);
69 }
70 
test_insert_bound(struct test_sockmap_listen * skel __always_unused,int family,int sotype,int mapfd)71 static void test_insert_bound(struct test_sockmap_listen *skel __always_unused,
72 			      int family, int sotype, int mapfd)
73 {
74 	struct sockaddr_storage addr;
75 	socklen_t len = 0;
76 	u32 key = 0;
77 	int err, s;
78 	u64 value;
79 
80 	init_addr_loopback(family, &addr, &len);
81 
82 	s = xsocket(family, sotype, 0);
83 	if (s == -1)
84 		return;
85 
86 	err = xbind(s, sockaddr(&addr), len);
87 	if (err)
88 		goto close;
89 
90 	errno = 0;
91 	value = s;
92 	err = bpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
93 	if (sotype == SOCK_STREAM) {
94 		ASSERT_ERR(err, "map_update");
95 		ASSERT_EQ(errno, EOPNOTSUPP, "errno");
96 	} else {
97 		ASSERT_OK(err, "map_update");
98 	}
99 close:
100 	xclose(s);
101 }
102 
test_insert(struct test_sockmap_listen * skel __always_unused,int family,int sotype,int mapfd)103 static void test_insert(struct test_sockmap_listen *skel __always_unused,
104 			int family, int sotype, int mapfd)
105 {
106 	u64 value;
107 	u32 key;
108 	int s;
109 
110 	s = socket_loopback(family, sotype);
111 	if (s < 0)
112 		return;
113 
114 	key = 0;
115 	value = s;
116 	xbpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
117 	xclose(s);
118 }
119 
test_delete_after_insert(struct test_sockmap_listen * skel __always_unused,int family,int sotype,int mapfd)120 static void test_delete_after_insert(struct test_sockmap_listen *skel __always_unused,
121 				     int family, int sotype, int mapfd)
122 {
123 	u64 value;
124 	u32 key;
125 	int s;
126 
127 	s = socket_loopback(family, sotype);
128 	if (s < 0)
129 		return;
130 
131 	key = 0;
132 	value = s;
133 	xbpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
134 	xbpf_map_delete_elem(mapfd, &key);
135 	xclose(s);
136 }
137 
test_delete_after_close(struct test_sockmap_listen * skel __always_unused,int family,int sotype,int mapfd)138 static void test_delete_after_close(struct test_sockmap_listen *skel __always_unused,
139 				    int family, int sotype, int mapfd)
140 {
141 	int err, s;
142 	u64 value;
143 	u32 key;
144 
145 	s = socket_loopback(family, sotype);
146 	if (s < 0)
147 		return;
148 
149 	key = 0;
150 	value = s;
151 	xbpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
152 
153 	xclose(s);
154 
155 	errno = 0;
156 	err = bpf_map_delete_elem(mapfd, &key);
157 	if (!err || (errno != EINVAL && errno != ENOENT))
158 		/* SOCKMAP and SOCKHASH return different error codes */
159 		FAIL_ERRNO("map_delete: expected EINVAL/EINVAL");
160 }
161 
test_lookup_after_insert(struct test_sockmap_listen * skel __always_unused,int family,int sotype,int mapfd)162 static void test_lookup_after_insert(struct test_sockmap_listen *skel __always_unused,
163 				     int family, int sotype, int mapfd)
164 {
165 	u64 cookie, value;
166 	socklen_t len;
167 	u32 key;
168 	int s;
169 
170 	s = socket_loopback(family, sotype);
171 	if (s < 0)
172 		return;
173 
174 	key = 0;
175 	value = s;
176 	xbpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
177 
178 	len = sizeof(cookie);
179 	xgetsockopt(s, SOL_SOCKET, SO_COOKIE, &cookie, &len);
180 
181 	xbpf_map_lookup_elem(mapfd, &key, &value);
182 
183 	if (value != cookie) {
184 		FAIL("map_lookup: have %#llx, want %#llx",
185 		     (unsigned long long)value, (unsigned long long)cookie);
186 	}
187 
188 	xclose(s);
189 }
190 
test_lookup_after_delete(struct test_sockmap_listen * skel __always_unused,int family,int sotype,int mapfd)191 static void test_lookup_after_delete(struct test_sockmap_listen *skel __always_unused,
192 				     int family, int sotype, int mapfd)
193 {
194 	int err, s;
195 	u64 value;
196 	u32 key;
197 
198 	s = socket_loopback(family, sotype);
199 	if (s < 0)
200 		return;
201 
202 	key = 0;
203 	value = s;
204 	xbpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
205 	xbpf_map_delete_elem(mapfd, &key);
206 
207 	errno = 0;
208 	err = bpf_map_lookup_elem(mapfd, &key, &value);
209 	if (!err || errno != ENOENT)
210 		FAIL_ERRNO("map_lookup: expected ENOENT");
211 
212 	xclose(s);
213 }
214 
test_lookup_32_bit_value(struct test_sockmap_listen * skel __always_unused,int family,int sotype,int mapfd)215 static void test_lookup_32_bit_value(struct test_sockmap_listen *skel __always_unused,
216 				     int family, int sotype, int mapfd)
217 {
218 	u32 key, value32;
219 	int err, s;
220 
221 	s = socket_loopback(family, sotype);
222 	if (s < 0)
223 		return;
224 
225 	mapfd = bpf_map_create(BPF_MAP_TYPE_SOCKMAP, NULL, sizeof(key),
226 			       sizeof(value32), 1, NULL);
227 	if (mapfd < 0) {
228 		FAIL_ERRNO("map_create");
229 		goto close;
230 	}
231 
232 	key = 0;
233 	value32 = s;
234 	xbpf_map_update_elem(mapfd, &key, &value32, BPF_NOEXIST);
235 
236 	errno = 0;
237 	err = bpf_map_lookup_elem(mapfd, &key, &value32);
238 	if (!err || errno != ENOSPC)
239 		FAIL_ERRNO("map_lookup: expected ENOSPC");
240 
241 	xclose(mapfd);
242 close:
243 	xclose(s);
244 }
245 
test_update_existing(struct test_sockmap_listen * skel __always_unused,int family,int sotype,int mapfd)246 static void test_update_existing(struct test_sockmap_listen *skel __always_unused,
247 				 int family, int sotype, int mapfd)
248 {
249 	int s1, s2;
250 	u64 value;
251 	u32 key;
252 
253 	s1 = socket_loopback(family, sotype);
254 	if (s1 < 0)
255 		return;
256 
257 	s2 = socket_loopback(family, sotype);
258 	if (s2 < 0)
259 		goto close_s1;
260 
261 	key = 0;
262 	value = s1;
263 	xbpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
264 
265 	value = s2;
266 	xbpf_map_update_elem(mapfd, &key, &value, BPF_EXIST);
267 	xclose(s2);
268 close_s1:
269 	xclose(s1);
270 }
271 
272 /* Exercise the code path where we destroy child sockets that never
273  * got accept()'ed, aka orphans, when parent socket gets closed.
274  */
do_destroy_orphan_child(int family,int sotype,int mapfd)275 static void do_destroy_orphan_child(int family, int sotype, int mapfd)
276 {
277 	struct sockaddr_storage addr;
278 	socklen_t len;
279 	int err, s, c;
280 	u64 value;
281 	u32 key;
282 
283 	s = socket_loopback(family, sotype);
284 	if (s < 0)
285 		return;
286 
287 	len = sizeof(addr);
288 	err = xgetsockname(s, sockaddr(&addr), &len);
289 	if (err)
290 		goto close_srv;
291 
292 	key = 0;
293 	value = s;
294 	xbpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
295 
296 	c = xsocket(family, sotype, 0);
297 	if (c == -1)
298 		goto close_srv;
299 
300 	xconnect(c, sockaddr(&addr), len);
301 	xclose(c);
302 close_srv:
303 	xclose(s);
304 }
305 
test_destroy_orphan_child(struct test_sockmap_listen * skel,int family,int sotype,int mapfd)306 static void test_destroy_orphan_child(struct test_sockmap_listen *skel,
307 				      int family, int sotype, int mapfd)
308 {
309 	int msg_verdict = bpf_program__fd(skel->progs.prog_msg_verdict);
310 	int skb_verdict = bpf_program__fd(skel->progs.prog_skb_verdict);
311 	const struct test {
312 		int progfd;
313 		enum bpf_attach_type atype;
314 	} tests[] = {
315 		{ -1, -1 },
316 		{ msg_verdict, BPF_SK_MSG_VERDICT },
317 		{ skb_verdict, BPF_SK_SKB_VERDICT },
318 	};
319 	const struct test *t;
320 
321 	for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
322 		if (t->progfd != -1 &&
323 		    xbpf_prog_attach(t->progfd, mapfd, t->atype, 0) != 0)
324 			return;
325 
326 		do_destroy_orphan_child(family, sotype, mapfd);
327 
328 		if (t->progfd != -1)
329 			xbpf_prog_detach2(t->progfd, mapfd, t->atype);
330 	}
331 }
332 
333 /* Perform a passive open after removing listening socket from SOCKMAP
334  * to ensure that callbacks get restored properly.
335  */
test_clone_after_delete(struct test_sockmap_listen * skel __always_unused,int family,int sotype,int mapfd)336 static void test_clone_after_delete(struct test_sockmap_listen *skel __always_unused,
337 				    int family, int sotype, int mapfd)
338 {
339 	struct sockaddr_storage addr;
340 	socklen_t len;
341 	int err, s, c;
342 	u64 value;
343 	u32 key;
344 
345 	s = socket_loopback(family, sotype);
346 	if (s < 0)
347 		return;
348 
349 	len = sizeof(addr);
350 	err = xgetsockname(s, sockaddr(&addr), &len);
351 	if (err)
352 		goto close_srv;
353 
354 	key = 0;
355 	value = s;
356 	xbpf_map_update_elem(mapfd, &key, &value, BPF_NOEXIST);
357 	xbpf_map_delete_elem(mapfd, &key);
358 
359 	c = xsocket(family, sotype, 0);
360 	if (c < 0)
361 		goto close_srv;
362 
363 	xconnect(c, sockaddr(&addr), len);
364 	xclose(c);
365 close_srv:
366 	xclose(s);
367 }
368 
369 /* Check that child socket that got created while parent was in a
370  * SOCKMAP, but got accept()'ed only after the parent has been removed
371  * from SOCKMAP, gets cloned without parent psock state or callbacks.
372  */
test_accept_after_delete(struct test_sockmap_listen * skel __always_unused,int family,int sotype,int mapfd)373 static void test_accept_after_delete(struct test_sockmap_listen *skel __always_unused,
374 				     int family, int sotype, int mapfd)
375 {
376 	struct sockaddr_storage addr;
377 	const u32 zero = 0;
378 	int err, s, c, p;
379 	socklen_t len;
380 	u64 value;
381 
382 	s = socket_loopback(family, sotype | SOCK_NONBLOCK);
383 	if (s == -1)
384 		return;
385 
386 	len = sizeof(addr);
387 	err = xgetsockname(s, sockaddr(&addr), &len);
388 	if (err)
389 		goto close_srv;
390 
391 	value = s;
392 	err = xbpf_map_update_elem(mapfd, &zero, &value, BPF_NOEXIST);
393 	if (err)
394 		goto close_srv;
395 
396 	c = xsocket(family, sotype, 0);
397 	if (c == -1)
398 		goto close_srv;
399 
400 	/* Create child while parent is in sockmap */
401 	err = xconnect(c, sockaddr(&addr), len);
402 	if (err)
403 		goto close_cli;
404 
405 	/* Remove parent from sockmap */
406 	err = xbpf_map_delete_elem(mapfd, &zero);
407 	if (err)
408 		goto close_cli;
409 
410 	p = xaccept_nonblock(s, NULL, NULL);
411 	if (p == -1)
412 		goto close_cli;
413 
414 	/* Check that child sk_user_data is not set */
415 	value = p;
416 	xbpf_map_update_elem(mapfd, &zero, &value, BPF_NOEXIST);
417 
418 	xclose(p);
419 close_cli:
420 	xclose(c);
421 close_srv:
422 	xclose(s);
423 }
424 
425 /* Check that child socket that got created and accepted while parent
426  * was in a SOCKMAP is cloned without parent psock state or callbacks.
427  */
test_accept_before_delete(struct test_sockmap_listen * skel __always_unused,int family,int sotype,int mapfd)428 static void test_accept_before_delete(struct test_sockmap_listen *skel __always_unused,
429 				      int family, int sotype, int mapfd)
430 {
431 	struct sockaddr_storage addr;
432 	const u32 zero = 0, one = 1;
433 	int err, s, c, p;
434 	socklen_t len;
435 	u64 value;
436 
437 	s = socket_loopback(family, sotype | SOCK_NONBLOCK);
438 	if (s == -1)
439 		return;
440 
441 	len = sizeof(addr);
442 	err = xgetsockname(s, sockaddr(&addr), &len);
443 	if (err)
444 		goto close_srv;
445 
446 	value = s;
447 	err = xbpf_map_update_elem(mapfd, &zero, &value, BPF_NOEXIST);
448 	if (err)
449 		goto close_srv;
450 
451 	c = xsocket(family, sotype, 0);
452 	if (c == -1)
453 		goto close_srv;
454 
455 	/* Create & accept child while parent is in sockmap */
456 	err = xconnect(c, sockaddr(&addr), len);
457 	if (err)
458 		goto close_cli;
459 
460 	p = xaccept_nonblock(s, NULL, NULL);
461 	if (p == -1)
462 		goto close_cli;
463 
464 	/* Check that child sk_user_data is not set */
465 	value = p;
466 	xbpf_map_update_elem(mapfd, &one, &value, BPF_NOEXIST);
467 
468 	xclose(p);
469 close_cli:
470 	xclose(c);
471 close_srv:
472 	xclose(s);
473 }
474 
475 struct connect_accept_ctx {
476 	int sockfd;
477 	unsigned int done;
478 	unsigned int nr_iter;
479 };
480 
is_thread_done(struct connect_accept_ctx * ctx)481 static bool is_thread_done(struct connect_accept_ctx *ctx)
482 {
483 	return READ_ONCE(ctx->done);
484 }
485 
connect_accept_thread(void * arg)486 static void *connect_accept_thread(void *arg)
487 {
488 	struct connect_accept_ctx *ctx = arg;
489 	struct sockaddr_storage addr;
490 	int family, socktype;
491 	socklen_t len;
492 	int err, i, s;
493 
494 	s = ctx->sockfd;
495 
496 	len = sizeof(addr);
497 	err = xgetsockname(s, sockaddr(&addr), &len);
498 	if (err)
499 		goto done;
500 
501 	len = sizeof(family);
502 	err = xgetsockopt(s, SOL_SOCKET, SO_DOMAIN, &family, &len);
503 	if (err)
504 		goto done;
505 
506 	len = sizeof(socktype);
507 	err = xgetsockopt(s, SOL_SOCKET, SO_TYPE, &socktype, &len);
508 	if (err)
509 		goto done;
510 
511 	for (i = 0; i < ctx->nr_iter; i++) {
512 		int c, p;
513 
514 		c = xsocket(family, socktype, 0);
515 		if (c < 0)
516 			break;
517 
518 		err = xconnect(c, (struct sockaddr *)&addr, sizeof(addr));
519 		if (err) {
520 			xclose(c);
521 			break;
522 		}
523 
524 		p = xaccept_nonblock(s, NULL, NULL);
525 		if (p < 0) {
526 			xclose(c);
527 			break;
528 		}
529 
530 		xclose(p);
531 		xclose(c);
532 	}
533 done:
534 	WRITE_ONCE(ctx->done, 1);
535 	return NULL;
536 }
537 
test_syn_recv_insert_delete(struct test_sockmap_listen * skel __always_unused,int family,int sotype,int mapfd)538 static void test_syn_recv_insert_delete(struct test_sockmap_listen *skel __always_unused,
539 					int family, int sotype, int mapfd)
540 {
541 	struct connect_accept_ctx ctx = { 0 };
542 	struct sockaddr_storage addr;
543 	socklen_t len;
544 	u32 zero = 0;
545 	pthread_t t;
546 	int err, s;
547 	u64 value;
548 
549 	s = socket_loopback(family, sotype | SOCK_NONBLOCK);
550 	if (s < 0)
551 		return;
552 
553 	len = sizeof(addr);
554 	err = xgetsockname(s, sockaddr(&addr), &len);
555 	if (err)
556 		goto close;
557 
558 	ctx.sockfd = s;
559 	ctx.nr_iter = 1000;
560 
561 	err = xpthread_create(&t, NULL, connect_accept_thread, &ctx);
562 	if (err)
563 		goto close;
564 
565 	value = s;
566 	while (!is_thread_done(&ctx)) {
567 		err = xbpf_map_update_elem(mapfd, &zero, &value, BPF_NOEXIST);
568 		if (err)
569 			break;
570 
571 		err = xbpf_map_delete_elem(mapfd, &zero);
572 		if (err)
573 			break;
574 	}
575 
576 	xpthread_join(t, NULL);
577 close:
578 	xclose(s);
579 }
580 
listen_thread(void * arg)581 static void *listen_thread(void *arg)
582 {
583 	struct sockaddr unspec = { AF_UNSPEC };
584 	struct connect_accept_ctx *ctx = arg;
585 	int err, i, s;
586 
587 	s = ctx->sockfd;
588 
589 	for (i = 0; i < ctx->nr_iter; i++) {
590 		err = xlisten(s, 1);
591 		if (err)
592 			break;
593 		err = xconnect(s, &unspec, sizeof(unspec));
594 		if (err)
595 			break;
596 	}
597 
598 	WRITE_ONCE(ctx->done, 1);
599 	return NULL;
600 }
601 
test_race_insert_listen(struct test_sockmap_listen * skel __always_unused,int family,int socktype,int mapfd)602 static void test_race_insert_listen(struct test_sockmap_listen *skel __always_unused,
603 				    int family, int socktype, int mapfd)
604 {
605 	struct connect_accept_ctx ctx = { 0 };
606 	const u32 zero = 0;
607 	const int one = 1;
608 	pthread_t t;
609 	int err, s;
610 	u64 value;
611 
612 	s = xsocket(family, socktype, 0);
613 	if (s < 0)
614 		return;
615 
616 	err = xsetsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
617 	if (err)
618 		goto close;
619 
620 	ctx.sockfd = s;
621 	ctx.nr_iter = 10000;
622 
623 	err = pthread_create(&t, NULL, listen_thread, &ctx);
624 	if (err)
625 		goto close;
626 
627 	value = s;
628 	while (!is_thread_done(&ctx)) {
629 		err = bpf_map_update_elem(mapfd, &zero, &value, BPF_NOEXIST);
630 		/* Expecting EOPNOTSUPP before listen() */
631 		if (err && errno != EOPNOTSUPP) {
632 			FAIL_ERRNO("map_update");
633 			break;
634 		}
635 
636 		err = bpf_map_delete_elem(mapfd, &zero);
637 		/* Expecting no entry after unhash on connect(AF_UNSPEC) */
638 		if (err && errno != EINVAL && errno != ENOENT) {
639 			FAIL_ERRNO("map_delete");
640 			break;
641 		}
642 	}
643 
644 	xpthread_join(t, NULL);
645 close:
646 	xclose(s);
647 }
648 
zero_verdict_count(int mapfd)649 static void zero_verdict_count(int mapfd)
650 {
651 	unsigned int zero = 0;
652 	int key;
653 
654 	key = SK_DROP;
655 	xbpf_map_update_elem(mapfd, &key, &zero, BPF_ANY);
656 	key = SK_PASS;
657 	xbpf_map_update_elem(mapfd, &key, &zero, BPF_ANY);
658 }
659 
660 enum redir_mode {
661 	REDIR_INGRESS,
662 	REDIR_EGRESS,
663 };
664 
redir_mode_str(enum redir_mode mode)665 static const char *redir_mode_str(enum redir_mode mode)
666 {
667 	switch (mode) {
668 	case REDIR_INGRESS:
669 		return "ingress";
670 	case REDIR_EGRESS:
671 		return "egress";
672 	default:
673 		return "unknown";
674 	}
675 }
676 
redir_to_connected(int family,int sotype,int sock_mapfd,int verd_mapfd,enum redir_mode mode)677 static void redir_to_connected(int family, int sotype, int sock_mapfd,
678 			       int verd_mapfd, enum redir_mode mode)
679 {
680 	const char *log_prefix = redir_mode_str(mode);
681 	int c0, c1, p0, p1;
682 	unsigned int pass;
683 	int err, n;
684 	u32 key;
685 	char b;
686 
687 	zero_verdict_count(verd_mapfd);
688 
689 	err = create_socket_pairs(family, sotype | SOCK_NONBLOCK, &c0, &c1,
690 				  &p0, &p1);
691 	if (err)
692 		return;
693 
694 	err = add_to_sockmap(sock_mapfd, p0, p1);
695 	if (err)
696 		goto close;
697 
698 	n = write(mode == REDIR_INGRESS ? c1 : p1, "a", 1);
699 	if (n < 0)
700 		FAIL_ERRNO("%s: write", log_prefix);
701 	if (n == 0)
702 		FAIL("%s: incomplete write", log_prefix);
703 	if (n < 1)
704 		goto close;
705 
706 	key = SK_PASS;
707 	err = xbpf_map_lookup_elem(verd_mapfd, &key, &pass);
708 	if (err)
709 		goto close;
710 	if (pass != 1)
711 		FAIL("%s: want pass count 1, have %d", log_prefix, pass);
712 	n = recv_timeout(c0, &b, 1, 0, IO_TIMEOUT_SEC);
713 	if (n < 0)
714 		FAIL_ERRNO("%s: recv_timeout", log_prefix);
715 	if (n == 0)
716 		FAIL("%s: incomplete recv", log_prefix);
717 
718 close:
719 	xclose(p1);
720 	xclose(c1);
721 	xclose(p0);
722 	xclose(c0);
723 }
724 
test_skb_redir_to_connected(struct test_sockmap_listen * skel,struct bpf_map * inner_map,int family,int sotype)725 static void test_skb_redir_to_connected(struct test_sockmap_listen *skel,
726 					struct bpf_map *inner_map, int family,
727 					int sotype)
728 {
729 	int verdict = bpf_program__fd(skel->progs.prog_stream_verdict);
730 	int parser = bpf_program__fd(skel->progs.prog_stream_parser);
731 	int verdict_map = bpf_map__fd(skel->maps.verdict_map);
732 	int sock_map = bpf_map__fd(inner_map);
733 	int err;
734 
735 	err = xbpf_prog_attach(parser, sock_map, BPF_SK_SKB_STREAM_PARSER, 0);
736 	if (err)
737 		return;
738 	err = xbpf_prog_attach(verdict, sock_map, BPF_SK_SKB_STREAM_VERDICT, 0);
739 	if (err)
740 		goto detach;
741 
742 	redir_to_connected(family, sotype, sock_map, verdict_map,
743 			   REDIR_INGRESS);
744 
745 	xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_STREAM_VERDICT);
746 detach:
747 	xbpf_prog_detach2(parser, sock_map, BPF_SK_SKB_STREAM_PARSER);
748 }
749 
test_msg_redir_to_connected(struct test_sockmap_listen * skel,struct bpf_map * inner_map,int family,int sotype)750 static void test_msg_redir_to_connected(struct test_sockmap_listen *skel,
751 					struct bpf_map *inner_map, int family,
752 					int sotype)
753 {
754 	int verdict = bpf_program__fd(skel->progs.prog_msg_verdict);
755 	int verdict_map = bpf_map__fd(skel->maps.verdict_map);
756 	int sock_map = bpf_map__fd(inner_map);
757 	int err;
758 
759 	err = xbpf_prog_attach(verdict, sock_map, BPF_SK_MSG_VERDICT, 0);
760 	if (err)
761 		return;
762 
763 	redir_to_connected(family, sotype, sock_map, verdict_map, REDIR_EGRESS);
764 
765 	xbpf_prog_detach2(verdict, sock_map, BPF_SK_MSG_VERDICT);
766 }
767 
test_msg_redir_to_connected_with_link(struct test_sockmap_listen * skel,struct bpf_map * inner_map,int family,int sotype)768 static void test_msg_redir_to_connected_with_link(struct test_sockmap_listen *skel,
769 						  struct bpf_map *inner_map, int family,
770 						  int sotype)
771 {
772 	int prog_msg_verdict = bpf_program__fd(skel->progs.prog_msg_verdict);
773 	int verdict_map = bpf_map__fd(skel->maps.verdict_map);
774 	int sock_map = bpf_map__fd(inner_map);
775 	int link_fd;
776 
777 	link_fd = bpf_link_create(prog_msg_verdict, sock_map, BPF_SK_MSG_VERDICT, NULL);
778 	if (!ASSERT_GE(link_fd, 0, "bpf_link_create"))
779 		return;
780 
781 	redir_to_connected(family, sotype, sock_map, verdict_map, REDIR_EGRESS);
782 
783 	close(link_fd);
784 }
785 
redir_to_listening(int family,int sotype,int sock_mapfd,int verd_mapfd,enum redir_mode mode)786 static void redir_to_listening(int family, int sotype, int sock_mapfd,
787 			       int verd_mapfd, enum redir_mode mode)
788 {
789 	const char *log_prefix = redir_mode_str(mode);
790 	struct sockaddr_storage addr;
791 	int s, c, p, err, n;
792 	unsigned int drop;
793 	socklen_t len;
794 	u32 key;
795 
796 	zero_verdict_count(verd_mapfd);
797 
798 	s = socket_loopback(family, sotype | SOCK_NONBLOCK);
799 	if (s < 0)
800 		return;
801 
802 	len = sizeof(addr);
803 	err = xgetsockname(s, sockaddr(&addr), &len);
804 	if (err)
805 		goto close_srv;
806 
807 	c = xsocket(family, sotype, 0);
808 	if (c < 0)
809 		goto close_srv;
810 	err = xconnect(c, sockaddr(&addr), len);
811 	if (err)
812 		goto close_cli;
813 
814 	p = xaccept_nonblock(s, NULL, NULL);
815 	if (p < 0)
816 		goto close_cli;
817 
818 	err = add_to_sockmap(sock_mapfd, s, p);
819 	if (err)
820 		goto close_peer;
821 
822 	n = write(mode == REDIR_INGRESS ? c : p, "a", 1);
823 	if (n < 0 && errno != EACCES)
824 		FAIL_ERRNO("%s: write", log_prefix);
825 	if (n == 0)
826 		FAIL("%s: incomplete write", log_prefix);
827 	if (n < 1)
828 		goto close_peer;
829 
830 	key = SK_DROP;
831 	err = xbpf_map_lookup_elem(verd_mapfd, &key, &drop);
832 	if (err)
833 		goto close_peer;
834 	if (drop != 1)
835 		FAIL("%s: want drop count 1, have %d", log_prefix, drop);
836 
837 close_peer:
838 	xclose(p);
839 close_cli:
840 	xclose(c);
841 close_srv:
842 	xclose(s);
843 }
844 
test_skb_redir_to_listening(struct test_sockmap_listen * skel,struct bpf_map * inner_map,int family,int sotype)845 static void test_skb_redir_to_listening(struct test_sockmap_listen *skel,
846 					struct bpf_map *inner_map, int family,
847 					int sotype)
848 {
849 	int verdict = bpf_program__fd(skel->progs.prog_stream_verdict);
850 	int parser = bpf_program__fd(skel->progs.prog_stream_parser);
851 	int verdict_map = bpf_map__fd(skel->maps.verdict_map);
852 	int sock_map = bpf_map__fd(inner_map);
853 	int err;
854 
855 	err = xbpf_prog_attach(parser, sock_map, BPF_SK_SKB_STREAM_PARSER, 0);
856 	if (err)
857 		return;
858 	err = xbpf_prog_attach(verdict, sock_map, BPF_SK_SKB_STREAM_VERDICT, 0);
859 	if (err)
860 		goto detach;
861 
862 	redir_to_listening(family, sotype, sock_map, verdict_map,
863 			   REDIR_INGRESS);
864 
865 	xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_STREAM_VERDICT);
866 detach:
867 	xbpf_prog_detach2(parser, sock_map, BPF_SK_SKB_STREAM_PARSER);
868 }
869 
test_msg_redir_to_listening(struct test_sockmap_listen * skel,struct bpf_map * inner_map,int family,int sotype)870 static void test_msg_redir_to_listening(struct test_sockmap_listen *skel,
871 					struct bpf_map *inner_map, int family,
872 					int sotype)
873 {
874 	int verdict = bpf_program__fd(skel->progs.prog_msg_verdict);
875 	int verdict_map = bpf_map__fd(skel->maps.verdict_map);
876 	int sock_map = bpf_map__fd(inner_map);
877 	int err;
878 
879 	err = xbpf_prog_attach(verdict, sock_map, BPF_SK_MSG_VERDICT, 0);
880 	if (err)
881 		return;
882 
883 	redir_to_listening(family, sotype, sock_map, verdict_map, REDIR_EGRESS);
884 
885 	xbpf_prog_detach2(verdict, sock_map, BPF_SK_MSG_VERDICT);
886 }
887 
test_msg_redir_to_listening_with_link(struct test_sockmap_listen * skel,struct bpf_map * inner_map,int family,int sotype)888 static void test_msg_redir_to_listening_with_link(struct test_sockmap_listen *skel,
889 						  struct bpf_map *inner_map, int family,
890 						  int sotype)
891 {
892 	struct bpf_program *verdict = skel->progs.prog_msg_verdict;
893 	int verdict_map = bpf_map__fd(skel->maps.verdict_map);
894 	int sock_map = bpf_map__fd(inner_map);
895 	struct bpf_link *link;
896 
897 	link = bpf_program__attach_sockmap(verdict, sock_map);
898 	if (!ASSERT_OK_PTR(link, "bpf_program__attach_sockmap"))
899 		return;
900 
901 	redir_to_listening(family, sotype, sock_map, verdict_map, REDIR_EGRESS);
902 
903 	bpf_link__destroy(link);
904 }
905 
redir_partial(int family,int sotype,int sock_map,int parser_map)906 static void redir_partial(int family, int sotype, int sock_map, int parser_map)
907 {
908 	int c0 = -1, c1 = -1, p0 = -1, p1 = -1;
909 	int err, n, key, value;
910 	char buf[] = "abc";
911 
912 	key = 0;
913 	value = sizeof(buf) - 1;
914 	err = xbpf_map_update_elem(parser_map, &key, &value, 0);
915 	if (err)
916 		return;
917 
918 	err = create_socket_pairs(family, sotype | SOCK_NONBLOCK, &c0, &c1,
919 				  &p0, &p1);
920 	if (err)
921 		goto clean_parser_map;
922 
923 	err = add_to_sockmap(sock_map, p0, p1);
924 	if (err)
925 		goto close;
926 
927 	n = xsend(c1, buf, sizeof(buf), 0);
928 	if (n == -1)
929 		goto close;
930 	if (n < sizeof(buf))
931 		FAIL("incomplete write");
932 
933 	n = xrecv_nonblock(c0, buf, sizeof(buf), 0);
934 	if (n != sizeof(buf) - 1)
935 		FAIL("expect %zu, received %d", sizeof(buf) - 1, n);
936 
937 close:
938 	xclose(c0);
939 	xclose(p0);
940 	xclose(c1);
941 	xclose(p1);
942 
943 clean_parser_map:
944 	key = 0;
945 	value = 0;
946 	xbpf_map_update_elem(parser_map, &key, &value, 0);
947 }
948 
test_skb_redir_partial(struct test_sockmap_listen * skel,struct bpf_map * inner_map,int family,int sotype)949 static void test_skb_redir_partial(struct test_sockmap_listen *skel,
950 				   struct bpf_map *inner_map, int family,
951 				   int sotype)
952 {
953 	int verdict = bpf_program__fd(skel->progs.prog_stream_verdict);
954 	int parser = bpf_program__fd(skel->progs.prog_stream_parser);
955 	int parser_map = bpf_map__fd(skel->maps.parser_map);
956 	int sock_map = bpf_map__fd(inner_map);
957 	int err;
958 
959 	err = xbpf_prog_attach(parser, sock_map, BPF_SK_SKB_STREAM_PARSER, 0);
960 	if (err)
961 		return;
962 
963 	err = xbpf_prog_attach(verdict, sock_map, BPF_SK_SKB_STREAM_VERDICT, 0);
964 	if (err)
965 		goto detach;
966 
967 	redir_partial(family, sotype, sock_map, parser_map);
968 
969 	xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_STREAM_VERDICT);
970 detach:
971 	xbpf_prog_detach2(parser, sock_map, BPF_SK_SKB_STREAM_PARSER);
972 }
973 
test_reuseport_select_listening(int family,int sotype,int sock_map,int verd_map,int reuseport_prog)974 static void test_reuseport_select_listening(int family, int sotype,
975 					    int sock_map, int verd_map,
976 					    int reuseport_prog)
977 {
978 	struct sockaddr_storage addr;
979 	unsigned int pass;
980 	int s, c, err;
981 	socklen_t len;
982 	u64 value;
983 	u32 key;
984 
985 	zero_verdict_count(verd_map);
986 
987 	s = socket_loopback_reuseport(family, sotype | SOCK_NONBLOCK,
988 				      reuseport_prog);
989 	if (s < 0)
990 		return;
991 
992 	len = sizeof(addr);
993 	err = xgetsockname(s, sockaddr(&addr), &len);
994 	if (err)
995 		goto close_srv;
996 
997 	key = 0;
998 	value = s;
999 	err = xbpf_map_update_elem(sock_map, &key, &value, BPF_NOEXIST);
1000 	if (err)
1001 		goto close_srv;
1002 
1003 	c = xsocket(family, sotype, 0);
1004 	if (c < 0)
1005 		goto close_srv;
1006 	err = xconnect(c, sockaddr(&addr), len);
1007 	if (err)
1008 		goto close_cli;
1009 
1010 	if (sotype == SOCK_STREAM) {
1011 		int p;
1012 
1013 		p = xaccept_nonblock(s, NULL, NULL);
1014 		if (p < 0)
1015 			goto close_cli;
1016 		xclose(p);
1017 	} else {
1018 		char b = 'a';
1019 		ssize_t n;
1020 
1021 		n = xsend(c, &b, sizeof(b), 0);
1022 		if (n == -1)
1023 			goto close_cli;
1024 
1025 		n = xrecv_nonblock(s, &b, sizeof(b), 0);
1026 		if (n == -1)
1027 			goto close_cli;
1028 	}
1029 
1030 	key = SK_PASS;
1031 	err = xbpf_map_lookup_elem(verd_map, &key, &pass);
1032 	if (err)
1033 		goto close_cli;
1034 	if (pass != 1)
1035 		FAIL("want pass count 1, have %d", pass);
1036 
1037 close_cli:
1038 	xclose(c);
1039 close_srv:
1040 	xclose(s);
1041 }
1042 
test_reuseport_select_connected(int family,int sotype,int sock_map,int verd_map,int reuseport_prog)1043 static void test_reuseport_select_connected(int family, int sotype,
1044 					    int sock_map, int verd_map,
1045 					    int reuseport_prog)
1046 {
1047 	struct sockaddr_storage addr;
1048 	int s, c0, c1, p0, err;
1049 	unsigned int drop;
1050 	socklen_t len;
1051 	u64 value;
1052 	u32 key;
1053 
1054 	zero_verdict_count(verd_map);
1055 
1056 	s = socket_loopback_reuseport(family, sotype, reuseport_prog);
1057 	if (s < 0)
1058 		return;
1059 
1060 	/* Populate sock_map[0] to avoid ENOENT on first connection */
1061 	key = 0;
1062 	value = s;
1063 	err = xbpf_map_update_elem(sock_map, &key, &value, BPF_NOEXIST);
1064 	if (err)
1065 		goto close_srv;
1066 
1067 	len = sizeof(addr);
1068 	err = xgetsockname(s, sockaddr(&addr), &len);
1069 	if (err)
1070 		goto close_srv;
1071 
1072 	c0 = xsocket(family, sotype, 0);
1073 	if (c0 < 0)
1074 		goto close_srv;
1075 
1076 	err = xconnect(c0, sockaddr(&addr), len);
1077 	if (err)
1078 		goto close_cli0;
1079 
1080 	if (sotype == SOCK_STREAM) {
1081 		p0 = xaccept_nonblock(s, NULL, NULL);
1082 		if (p0 < 0)
1083 			goto close_cli0;
1084 	} else {
1085 		p0 = xsocket(family, sotype, 0);
1086 		if (p0 < 0)
1087 			goto close_cli0;
1088 
1089 		len = sizeof(addr);
1090 		err = xgetsockname(c0, sockaddr(&addr), &len);
1091 		if (err)
1092 			goto close_cli0;
1093 
1094 		err = xconnect(p0, sockaddr(&addr), len);
1095 		if (err)
1096 			goto close_cli0;
1097 	}
1098 
1099 	/* Update sock_map[0] to redirect to a connected socket */
1100 	key = 0;
1101 	value = p0;
1102 	err = xbpf_map_update_elem(sock_map, &key, &value, BPF_EXIST);
1103 	if (err)
1104 		goto close_peer0;
1105 
1106 	c1 = xsocket(family, sotype, 0);
1107 	if (c1 < 0)
1108 		goto close_peer0;
1109 
1110 	len = sizeof(addr);
1111 	err = xgetsockname(s, sockaddr(&addr), &len);
1112 	if (err)
1113 		goto close_srv;
1114 
1115 	errno = 0;
1116 	err = connect(c1, sockaddr(&addr), len);
1117 	if (sotype == SOCK_DGRAM) {
1118 		char b = 'a';
1119 		ssize_t n;
1120 
1121 		n = xsend(c1, &b, sizeof(b), 0);
1122 		if (n == -1)
1123 			goto close_cli1;
1124 
1125 		n = recv_timeout(c1, &b, sizeof(b), 0, IO_TIMEOUT_SEC);
1126 		err = n == -1;
1127 	}
1128 	if (!err || errno != ECONNREFUSED)
1129 		FAIL_ERRNO("connect: expected ECONNREFUSED");
1130 
1131 	key = SK_DROP;
1132 	err = xbpf_map_lookup_elem(verd_map, &key, &drop);
1133 	if (err)
1134 		goto close_cli1;
1135 	if (drop != 1)
1136 		FAIL("want drop count 1, have %d", drop);
1137 
1138 close_cli1:
1139 	xclose(c1);
1140 close_peer0:
1141 	xclose(p0);
1142 close_cli0:
1143 	xclose(c0);
1144 close_srv:
1145 	xclose(s);
1146 }
1147 
1148 /* Check that redirecting across reuseport groups is not allowed. */
test_reuseport_mixed_groups(int family,int sotype,int sock_map,int verd_map,int reuseport_prog)1149 static void test_reuseport_mixed_groups(int family, int sotype, int sock_map,
1150 					int verd_map, int reuseport_prog)
1151 {
1152 	struct sockaddr_storage addr;
1153 	int s1, s2, c, err;
1154 	unsigned int drop;
1155 	socklen_t len;
1156 	u32 key;
1157 
1158 	zero_verdict_count(verd_map);
1159 
1160 	/* Create two listeners, each in its own reuseport group */
1161 	s1 = socket_loopback_reuseport(family, sotype, reuseport_prog);
1162 	if (s1 < 0)
1163 		return;
1164 
1165 	s2 = socket_loopback_reuseport(family, sotype, reuseport_prog);
1166 	if (s2 < 0)
1167 		goto close_srv1;
1168 
1169 	err = add_to_sockmap(sock_map, s1, s2);
1170 	if (err)
1171 		goto close_srv2;
1172 
1173 	/* Connect to s2, reuseport BPF selects s1 via sock_map[0] */
1174 	len = sizeof(addr);
1175 	err = xgetsockname(s2, sockaddr(&addr), &len);
1176 	if (err)
1177 		goto close_srv2;
1178 
1179 	c = xsocket(family, sotype, 0);
1180 	if (c < 0)
1181 		goto close_srv2;
1182 
1183 	err = connect(c, sockaddr(&addr), len);
1184 	if (sotype == SOCK_DGRAM) {
1185 		char b = 'a';
1186 		ssize_t n;
1187 
1188 		n = xsend(c, &b, sizeof(b), 0);
1189 		if (n == -1)
1190 			goto close_cli;
1191 
1192 		n = recv_timeout(c, &b, sizeof(b), 0, IO_TIMEOUT_SEC);
1193 		err = n == -1;
1194 	}
1195 	if (!err || errno != ECONNREFUSED) {
1196 		FAIL_ERRNO("connect: expected ECONNREFUSED");
1197 		goto close_cli;
1198 	}
1199 
1200 	/* Expect drop, can't redirect outside of reuseport group */
1201 	key = SK_DROP;
1202 	err = xbpf_map_lookup_elem(verd_map, &key, &drop);
1203 	if (err)
1204 		goto close_cli;
1205 	if (drop != 1)
1206 		FAIL("want drop count 1, have %d", drop);
1207 
1208 close_cli:
1209 	xclose(c);
1210 close_srv2:
1211 	xclose(s2);
1212 close_srv1:
1213 	xclose(s1);
1214 }
1215 
1216 #define TEST(fn, ...)                                                          \
1217 	{                                                                      \
1218 		fn, #fn, __VA_ARGS__                                           \
1219 	}
1220 
test_ops_cleanup(const struct bpf_map * map)1221 static void test_ops_cleanup(const struct bpf_map *map)
1222 {
1223 	int err, mapfd;
1224 	u32 key;
1225 
1226 	mapfd = bpf_map__fd(map);
1227 
1228 	for (key = 0; key < bpf_map__max_entries(map); key++) {
1229 		err = bpf_map_delete_elem(mapfd, &key);
1230 		if (err && errno != EINVAL && errno != ENOENT)
1231 			FAIL_ERRNO("map_delete: expected EINVAL/ENOENT");
1232 	}
1233 }
1234 
family_str(sa_family_t family)1235 static const char *family_str(sa_family_t family)
1236 {
1237 	switch (family) {
1238 	case AF_INET:
1239 		return "IPv4";
1240 	case AF_INET6:
1241 		return "IPv6";
1242 	case AF_UNIX:
1243 		return "Unix";
1244 	case AF_VSOCK:
1245 		return "VSOCK";
1246 	default:
1247 		return "unknown";
1248 	}
1249 }
1250 
map_type_str(const struct bpf_map * map)1251 static const char *map_type_str(const struct bpf_map *map)
1252 {
1253 	int type;
1254 
1255 	if (!map)
1256 		return "invalid";
1257 	type = bpf_map__type(map);
1258 
1259 	switch (type) {
1260 	case BPF_MAP_TYPE_SOCKMAP:
1261 		return "sockmap";
1262 	case BPF_MAP_TYPE_SOCKHASH:
1263 		return "sockhash";
1264 	default:
1265 		return "unknown";
1266 	}
1267 }
1268 
sotype_str(int sotype)1269 static const char *sotype_str(int sotype)
1270 {
1271 	switch (sotype) {
1272 	case SOCK_DGRAM:
1273 		return "UDP";
1274 	case SOCK_STREAM:
1275 		return "TCP";
1276 	default:
1277 		return "unknown";
1278 	}
1279 }
1280 
test_ops(struct test_sockmap_listen * skel,struct bpf_map * map,int family,int sotype)1281 static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,
1282 		     int family, int sotype)
1283 {
1284 	const struct op_test {
1285 		void (*fn)(struct test_sockmap_listen *skel,
1286 			   int family, int sotype, int mapfd);
1287 		const char *name;
1288 		int sotype;
1289 	} tests[] = {
1290 		/* insert */
1291 		TEST(test_insert_invalid),
1292 		TEST(test_insert_opened),
1293 		TEST(test_insert_bound),
1294 		TEST(test_insert),
1295 		/* delete */
1296 		TEST(test_delete_after_insert),
1297 		TEST(test_delete_after_close),
1298 		/* lookup */
1299 		TEST(test_lookup_after_insert),
1300 		TEST(test_lookup_after_delete),
1301 		TEST(test_lookup_32_bit_value),
1302 		/* update */
1303 		TEST(test_update_existing),
1304 		/* races with insert/delete */
1305 		TEST(test_destroy_orphan_child, SOCK_STREAM),
1306 		TEST(test_syn_recv_insert_delete, SOCK_STREAM),
1307 		TEST(test_race_insert_listen, SOCK_STREAM),
1308 		/* child clone */
1309 		TEST(test_clone_after_delete, SOCK_STREAM),
1310 		TEST(test_accept_after_delete, SOCK_STREAM),
1311 		TEST(test_accept_before_delete, SOCK_STREAM),
1312 	};
1313 	const char *family_name, *map_name, *sotype_name;
1314 	const struct op_test *t;
1315 	char s[MAX_TEST_NAME];
1316 	int map_fd;
1317 
1318 	family_name = family_str(family);
1319 	map_name = map_type_str(map);
1320 	sotype_name = sotype_str(sotype);
1321 	map_fd = bpf_map__fd(map);
1322 
1323 	for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
1324 		snprintf(s, sizeof(s), "%s %s %s %s", map_name, family_name,
1325 			 sotype_name, t->name);
1326 
1327 		if (t->sotype != 0 && t->sotype != sotype)
1328 			continue;
1329 
1330 		if (!test__start_subtest(s))
1331 			continue;
1332 
1333 		t->fn(skel, family, sotype, map_fd);
1334 		test_ops_cleanup(map);
1335 	}
1336 }
1337 
test_redir(struct test_sockmap_listen * skel,struct bpf_map * map,int family,int sotype)1338 static void test_redir(struct test_sockmap_listen *skel, struct bpf_map *map,
1339 		       int family, int sotype)
1340 {
1341 	const struct redir_test {
1342 		void (*fn)(struct test_sockmap_listen *skel,
1343 			   struct bpf_map *map, int family, int sotype);
1344 		const char *name;
1345 	} tests[] = {
1346 		TEST(test_skb_redir_to_connected),
1347 		TEST(test_skb_redir_to_listening),
1348 		TEST(test_skb_redir_partial),
1349 		TEST(test_msg_redir_to_connected),
1350 		TEST(test_msg_redir_to_connected_with_link),
1351 		TEST(test_msg_redir_to_listening),
1352 		TEST(test_msg_redir_to_listening_with_link),
1353 	};
1354 	const char *family_name, *map_name;
1355 	const struct redir_test *t;
1356 	char s[MAX_TEST_NAME];
1357 
1358 	family_name = family_str(family);
1359 	map_name = map_type_str(map);
1360 
1361 	for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
1362 		snprintf(s, sizeof(s), "%s %s %s", map_name, family_name,
1363 			 t->name);
1364 
1365 		if (!test__start_subtest(s))
1366 			continue;
1367 
1368 		t->fn(skel, map, family, sotype);
1369 	}
1370 }
1371 
test_reuseport(struct test_sockmap_listen * skel,struct bpf_map * map,int family,int sotype)1372 static void test_reuseport(struct test_sockmap_listen *skel,
1373 			   struct bpf_map *map, int family, int sotype)
1374 {
1375 	const struct reuseport_test {
1376 		void (*fn)(int family, int sotype, int socket_map,
1377 			   int verdict_map, int reuseport_prog);
1378 		const char *name;
1379 		int sotype;
1380 	} tests[] = {
1381 		TEST(test_reuseport_select_listening),
1382 		TEST(test_reuseport_select_connected),
1383 		TEST(test_reuseport_mixed_groups),
1384 	};
1385 	int socket_map, verdict_map, reuseport_prog;
1386 	const char *family_name, *map_name, *sotype_name;
1387 	const struct reuseport_test *t;
1388 	char s[MAX_TEST_NAME];
1389 
1390 	family_name = family_str(family);
1391 	map_name = map_type_str(map);
1392 	sotype_name = sotype_str(sotype);
1393 
1394 	socket_map = bpf_map__fd(map);
1395 	verdict_map = bpf_map__fd(skel->maps.verdict_map);
1396 	reuseport_prog = bpf_program__fd(skel->progs.prog_reuseport);
1397 
1398 	for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
1399 		snprintf(s, sizeof(s), "%s %s %s %s", map_name, family_name,
1400 			 sotype_name, t->name);
1401 
1402 		if (t->sotype != 0 && t->sotype != sotype)
1403 			continue;
1404 
1405 		if (!test__start_subtest(s))
1406 			continue;
1407 
1408 		t->fn(family, sotype, socket_map, verdict_map, reuseport_prog);
1409 	}
1410 }
1411 
run_tests(struct test_sockmap_listen * skel,struct bpf_map * map,int family)1412 static void run_tests(struct test_sockmap_listen *skel, struct bpf_map *map,
1413 		      int family)
1414 {
1415 	test_ops(skel, map, family, SOCK_STREAM);
1416 	test_ops(skel, map, family, SOCK_DGRAM);
1417 	test_redir(skel, map, family, SOCK_STREAM);
1418 	test_reuseport(skel, map, family, SOCK_STREAM);
1419 	test_reuseport(skel, map, family, SOCK_DGRAM);
1420 }
1421 
serial_test_sockmap_listen(void)1422 void serial_test_sockmap_listen(void)
1423 {
1424 	struct test_sockmap_listen *skel;
1425 
1426 	skel = test_sockmap_listen__open_and_load();
1427 	if (!skel) {
1428 		FAIL("skeleton open/load failed");
1429 		return;
1430 	}
1431 
1432 	skel->bss->test_sockmap = true;
1433 	run_tests(skel, skel->maps.sock_map, AF_INET);
1434 	run_tests(skel, skel->maps.sock_map, AF_INET6);
1435 
1436 	skel->bss->test_sockmap = false;
1437 	run_tests(skel, skel->maps.sock_hash, AF_INET);
1438 	run_tests(skel, skel->maps.sock_hash, AF_INET6);
1439 
1440 	test_sockmap_listen__destroy(skel);
1441 }
1442