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