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