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