1 // SPDX-License-Identifier: GPL-2.0 2 3 #define _GNU_SOURCE 4 #include <stdbool.h> 5 #include <stdlib.h> 6 #include <stdio.h> 7 #include <bpf/bpf.h> 8 #include <linux/bpf.h> 9 #include <bpf/libbpf.h> 10 #include <arpa/inet.h> 11 #include <asm/byteorder.h> 12 #include <netinet/udp.h> 13 #include <poll.h> 14 #include <string.h> 15 #include <sys/ioctl.h> 16 #include <sys/socket.h> 17 #include <sys/time.h> 18 #include <unistd.h> 19 #include "test_progs.h" 20 #include "network_helpers.h" 21 #include "bpf_util.h" 22 #include "bpf_flow.skel.h" 23 24 #define CFG_PORT_INNER 8000 25 #define CFG_PORT_GUE 6080 26 #define SUBTEST_NAME_MAX_LEN 32 27 #define TEST_NAME_MAX_LEN (32 + SUBTEST_NAME_MAX_LEN) 28 #define MAX_SOURCE_PORTS 3 29 #define TEST_PACKETS_COUNT 10 30 #define TEST_PACKET_LEN 100 31 #define TEST_PACKET_PATTERN 'a' 32 #define TEST_IPV4 "192.168.0.1/32" 33 #define TEST_IPV6 "100::a/128" 34 #define TEST_TUNNEL_REMOTE "127.0.0.2" 35 #define TEST_TUNNEL_LOCAL "127.0.0.1" 36 37 #define INIT_ADDR4(addr4, port) \ 38 { \ 39 .sin_family = AF_INET, \ 40 .sin_port = __constant_htons(port), \ 41 .sin_addr.s_addr = __constant_htonl(addr4), \ 42 } 43 44 #define INIT_ADDR6(addr6, port) \ 45 { \ 46 .sin6_family = AF_INET6, \ 47 .sin6_port = __constant_htons(port), \ 48 .sin6_addr = addr6, \ 49 } 50 #define TEST_IN4_SRC_ADDR_DEFAULT INIT_ADDR4(INADDR_LOOPBACK + 2, 0) 51 #define TEST_IN4_DST_ADDR_DEFAULT INIT_ADDR4(INADDR_LOOPBACK, CFG_PORT_INNER) 52 #define TEST_OUT4_SRC_ADDR_DEFAULT INIT_ADDR4(INADDR_LOOPBACK + 1, 0) 53 #define TEST_OUT4_DST_ADDR_DEFAULT INIT_ADDR4(INADDR_LOOPBACK, 0) 54 55 #define TEST_IN6_SRC_ADDR_DEFAULT INIT_ADDR6(IN6ADDR_LOOPBACK_INIT, 0) 56 #define TEST_IN6_DST_ADDR_DEFAULT \ 57 INIT_ADDR6(IN6ADDR_LOOPBACK_INIT, CFG_PORT_INNER) 58 #define TEST_OUT6_SRC_ADDR_DEFAULT INIT_ADDR6(IN6ADDR_LOOPBACK_INIT, 0) 59 #define TEST_OUT6_DST_ADDR_DEFAULT INIT_ADDR6(IN6ADDR_LOOPBACK_INIT, 0) 60 61 #define TEST_IN4_SRC_ADDR_DISSECT_CONTINUE INIT_ADDR4(INADDR_LOOPBACK + 126, 0) 62 #define TEST_IN4_SRC_ADDR_IPIP INIT_ADDR4((in_addr_t)0x01010101, 0) 63 #define TEST_IN4_DST_ADDR_IPIP INIT_ADDR4((in_addr_t)0xC0A80001, CFG_PORT_INNER) 64 65 struct grehdr { 66 uint16_t unused; 67 uint16_t protocol; 68 } __packed; 69 70 struct guehdr { 71 union { 72 struct { 73 #if defined(__LITTLE_ENDIAN_BITFIELD) 74 __u8 hlen : 5, control : 1, version : 2; 75 #elif defined(__BIG_ENDIAN_BITFIELD) 76 __u8 version : 2, control : 1, hlen : 5; 77 #else 78 #error "Please fix <asm/byteorder.h>" 79 #endif 80 __u8 proto_ctype; 81 __be16 flags; 82 }; 83 __be32 word; 84 }; 85 }; 86 87 static char buf[ETH_DATA_LEN]; 88 89 struct test_configuration { 90 char name[SUBTEST_NAME_MAX_LEN]; 91 int (*test_setup)(void); 92 void (*test_teardown)(void); 93 int source_ports[MAX_SOURCE_PORTS]; 94 int cfg_l3_inner; 95 struct sockaddr_in in_saddr4; 96 struct sockaddr_in in_daddr4; 97 struct sockaddr_in6 in_saddr6; 98 struct sockaddr_in6 in_daddr6; 99 int cfg_l3_outer; 100 struct sockaddr_in out_saddr4; 101 struct sockaddr_in out_daddr4; 102 struct sockaddr_in6 out_saddr6; 103 struct sockaddr_in6 out_daddr6; 104 int cfg_encap_proto; 105 uint8_t cfg_dsfield_inner; 106 uint8_t cfg_dsfield_outer; 107 int cfg_l3_extra; 108 struct sockaddr_in extra_saddr4; 109 struct sockaddr_in extra_daddr4; 110 struct sockaddr_in6 extra_saddr6; 111 struct sockaddr_in6 extra_daddr6; 112 }; 113 114 static unsigned long util_gettime(void) 115 { 116 struct timeval tv; 117 118 gettimeofday(&tv, NULL); 119 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); 120 } 121 122 static void build_ipv4_header(void *header, uint8_t proto, uint32_t src, 123 uint32_t dst, int payload_len, uint8_t tos) 124 { 125 struct iphdr *iph = header; 126 127 iph->ihl = 5; 128 iph->version = 4; 129 iph->tos = tos; 130 iph->ttl = 8; 131 iph->tot_len = htons(sizeof(*iph) + payload_len); 132 iph->id = htons(1337); 133 iph->protocol = proto; 134 iph->saddr = src; 135 iph->daddr = dst; 136 iph->check = build_ip_csum((void *)iph); 137 } 138 139 static void ipv6_set_dsfield(struct ipv6hdr *ip6h, uint8_t dsfield) 140 { 141 uint16_t val, *ptr = (uint16_t *)ip6h; 142 143 val = ntohs(*ptr); 144 val &= 0xF00F; 145 val |= ((uint16_t)dsfield) << 4; 146 *ptr = htons(val); 147 } 148 149 static void build_ipv6_header(void *header, uint8_t proto, 150 const struct sockaddr_in6 *src, 151 const struct sockaddr_in6 *dst, int payload_len, 152 uint8_t dsfield) 153 { 154 struct ipv6hdr *ip6h = header; 155 156 ip6h->version = 6; 157 ip6h->payload_len = htons(payload_len); 158 ip6h->nexthdr = proto; 159 ip6h->hop_limit = 8; 160 ipv6_set_dsfield(ip6h, dsfield); 161 162 memcpy(&ip6h->saddr, &src->sin6_addr, sizeof(ip6h->saddr)); 163 memcpy(&ip6h->daddr, &dst->sin6_addr, sizeof(ip6h->daddr)); 164 } 165 166 static void build_udp_header(void *header, int payload_len, uint16_t sport, 167 uint16_t dport, int family) 168 { 169 struct udphdr *udph = header; 170 int len = sizeof(*udph) + payload_len; 171 172 udph->source = htons(sport); 173 udph->dest = htons(dport); 174 udph->len = htons(len); 175 udph->check = 0; 176 if (family == AF_INET) 177 udph->check = build_udp_v4_csum(header - sizeof(struct iphdr), 178 udph); 179 else 180 udph->check = build_udp_v6_csum(header - sizeof(struct ipv6hdr), 181 udph); 182 } 183 184 static void build_gue_header(void *header, uint8_t proto) 185 { 186 struct guehdr *gueh = header; 187 188 gueh->proto_ctype = proto; 189 } 190 191 static void build_gre_header(void *header, uint16_t proto) 192 { 193 struct grehdr *greh = header; 194 195 greh->protocol = htons(proto); 196 } 197 198 static int l3_length(int family) 199 { 200 if (family == AF_INET) 201 return sizeof(struct iphdr); 202 else 203 return sizeof(struct ipv6hdr); 204 } 205 206 static int build_packet(const struct test_configuration *test, uint16_t sport) 207 { 208 int ol3_len = 0, ol4_len = 0, il3_len = 0, il4_len = 0; 209 int el3_len = 0, packet_len; 210 211 memset(buf, 0, ETH_DATA_LEN); 212 213 if (test->cfg_l3_extra) 214 el3_len = l3_length(test->cfg_l3_extra); 215 216 /* calculate header offsets */ 217 if (test->cfg_encap_proto) { 218 ol3_len = l3_length(test->cfg_l3_outer); 219 220 if (test->cfg_encap_proto == IPPROTO_GRE) 221 ol4_len = sizeof(struct grehdr); 222 else if (test->cfg_encap_proto == IPPROTO_UDP) 223 ol4_len = sizeof(struct udphdr) + sizeof(struct guehdr); 224 } 225 226 il3_len = l3_length(test->cfg_l3_inner); 227 il4_len = sizeof(struct udphdr); 228 229 packet_len = el3_len + ol3_len + ol4_len + il3_len + il4_len + 230 TEST_PACKET_LEN; 231 if (!ASSERT_LE(packet_len, sizeof(buf), "check packet size")) 232 return -1; 233 234 /* 235 * Fill packet from inside out, to calculate correct checksums. 236 * But create ip before udp headers, as udp uses ip for pseudo-sum. 237 */ 238 memset(buf + el3_len + ol3_len + ol4_len + il3_len + il4_len, 239 TEST_PACKET_PATTERN, TEST_PACKET_LEN); 240 241 /* add zero byte for udp csum padding */ 242 buf[el3_len + ol3_len + ol4_len + il3_len + il4_len + TEST_PACKET_LEN] = 243 0; 244 245 switch (test->cfg_l3_inner) { 246 case PF_INET: 247 build_ipv4_header(buf + el3_len + ol3_len + ol4_len, 248 IPPROTO_UDP, test->in_saddr4.sin_addr.s_addr, 249 test->in_daddr4.sin_addr.s_addr, 250 il4_len + TEST_PACKET_LEN, 251 test->cfg_dsfield_inner); 252 break; 253 case PF_INET6: 254 build_ipv6_header(buf + el3_len + ol3_len + ol4_len, 255 IPPROTO_UDP, &test->in_saddr6, 256 &test->in_daddr6, il4_len + TEST_PACKET_LEN, 257 test->cfg_dsfield_inner); 258 break; 259 } 260 261 build_udp_header(buf + el3_len + ol3_len + ol4_len + il3_len, 262 TEST_PACKET_LEN, sport, CFG_PORT_INNER, 263 test->cfg_l3_inner); 264 265 if (!test->cfg_encap_proto) 266 return il3_len + il4_len + TEST_PACKET_LEN; 267 268 switch (test->cfg_l3_outer) { 269 case PF_INET: 270 build_ipv4_header(buf + el3_len, test->cfg_encap_proto, 271 test->out_saddr4.sin_addr.s_addr, 272 test->out_daddr4.sin_addr.s_addr, 273 ol4_len + il3_len + il4_len + TEST_PACKET_LEN, 274 test->cfg_dsfield_outer); 275 break; 276 case PF_INET6: 277 build_ipv6_header(buf + el3_len, test->cfg_encap_proto, 278 &test->out_saddr6, &test->out_daddr6, 279 ol4_len + il3_len + il4_len + TEST_PACKET_LEN, 280 test->cfg_dsfield_outer); 281 break; 282 } 283 284 switch (test->cfg_encap_proto) { 285 case IPPROTO_UDP: 286 build_gue_header(buf + el3_len + ol3_len + ol4_len - 287 sizeof(struct guehdr), 288 test->cfg_l3_inner == PF_INET ? IPPROTO_IPIP : 289 IPPROTO_IPV6); 290 build_udp_header(buf + el3_len + ol3_len, 291 sizeof(struct guehdr) + il3_len + il4_len + 292 TEST_PACKET_LEN, 293 sport, CFG_PORT_GUE, test->cfg_l3_outer); 294 break; 295 case IPPROTO_GRE: 296 build_gre_header(buf + el3_len + ol3_len, 297 test->cfg_l3_inner == PF_INET ? ETH_P_IP : 298 ETH_P_IPV6); 299 break; 300 } 301 302 switch (test->cfg_l3_extra) { 303 case PF_INET: 304 build_ipv4_header(buf, 305 test->cfg_l3_outer == PF_INET ? IPPROTO_IPIP : 306 IPPROTO_IPV6, 307 test->extra_saddr4.sin_addr.s_addr, 308 test->extra_daddr4.sin_addr.s_addr, 309 ol3_len + ol4_len + il3_len + il4_len + 310 TEST_PACKET_LEN, 311 0); 312 break; 313 case PF_INET6: 314 build_ipv6_header(buf, 315 test->cfg_l3_outer == PF_INET ? IPPROTO_IPIP : 316 IPPROTO_IPV6, 317 &test->extra_saddr6, &test->extra_daddr6, 318 ol3_len + ol4_len + il3_len + il4_len + 319 TEST_PACKET_LEN, 320 0); 321 break; 322 } 323 324 return el3_len + ol3_len + ol4_len + il3_len + il4_len + 325 TEST_PACKET_LEN; 326 } 327 328 /* sender transmits encapsulated over RAW or unencap'd over UDP */ 329 static int setup_tx(const struct test_configuration *test) 330 { 331 int family, fd, ret; 332 333 if (test->cfg_l3_extra) 334 family = test->cfg_l3_extra; 335 else if (test->cfg_l3_outer) 336 family = test->cfg_l3_outer; 337 else 338 family = test->cfg_l3_inner; 339 340 fd = socket(family, SOCK_RAW, IPPROTO_RAW); 341 if (!ASSERT_OK_FD(fd, "setup tx socket")) 342 return fd; 343 344 if (test->cfg_l3_extra) { 345 if (test->cfg_l3_extra == PF_INET) 346 ret = connect(fd, (void *)&test->extra_daddr4, 347 sizeof(test->extra_daddr4)); 348 else 349 ret = connect(fd, (void *)&test->extra_daddr6, 350 sizeof(test->extra_daddr6)); 351 if (!ASSERT_OK(ret, "connect")) { 352 close(fd); 353 return ret; 354 } 355 } else if (test->cfg_l3_outer) { 356 /* connect to destination if not encapsulated */ 357 if (test->cfg_l3_outer == PF_INET) 358 ret = connect(fd, (void *)&test->out_daddr4, 359 sizeof(test->out_daddr4)); 360 else 361 ret = connect(fd, (void *)&test->out_daddr6, 362 sizeof(test->out_daddr6)); 363 if (!ASSERT_OK(ret, "connect")) { 364 close(fd); 365 return ret; 366 } 367 } else { 368 /* otherwise using loopback */ 369 if (test->cfg_l3_inner == PF_INET) 370 ret = connect(fd, (void *)&test->in_daddr4, 371 sizeof(test->in_daddr4)); 372 else 373 ret = connect(fd, (void *)&test->in_daddr6, 374 sizeof(test->in_daddr6)); 375 if (!ASSERT_OK(ret, "connect")) { 376 close(fd); 377 return ret; 378 } 379 } 380 381 return fd; 382 } 383 384 /* receiver reads unencapsulated UDP */ 385 static int setup_rx(const struct test_configuration *test) 386 { 387 int fd, ret; 388 389 fd = socket(test->cfg_l3_inner, SOCK_DGRAM, 0); 390 if (!ASSERT_OK_FD(fd, "socket rx")) 391 return fd; 392 393 if (test->cfg_l3_inner == PF_INET) 394 ret = bind(fd, (void *)&test->in_daddr4, 395 sizeof(test->in_daddr4)); 396 else 397 ret = bind(fd, (void *)&test->in_daddr6, 398 sizeof(test->in_daddr6)); 399 if (!ASSERT_OK(ret, "bind rx")) { 400 close(fd); 401 return ret; 402 } 403 404 return fd; 405 } 406 407 static int do_tx(int fd, const char *pkt, int len) 408 { 409 int ret; 410 411 ret = write(fd, pkt, len); 412 return ret != len; 413 } 414 415 static int do_poll(int fd, short events, int timeout) 416 { 417 struct pollfd pfd; 418 int ret; 419 420 pfd.fd = fd; 421 pfd.events = events; 422 423 ret = poll(&pfd, 1, timeout); 424 return ret; 425 } 426 427 static int do_rx(int fd) 428 { 429 char rbuf; 430 int ret, num = 0; 431 432 while (1) { 433 ret = recv(fd, &rbuf, 1, MSG_DONTWAIT); 434 if (ret == -1 && errno == EAGAIN) 435 break; 436 if (ret < 0) 437 return -1; 438 if (!ASSERT_EQ(rbuf, TEST_PACKET_PATTERN, "check pkt pattern")) 439 return -1; 440 num++; 441 } 442 443 return num; 444 } 445 446 static int run_test(const struct test_configuration *test, 447 int source_port_index) 448 { 449 int fdt = -1, fdr = -1, len, tx = 0, rx = 0, err; 450 unsigned long tstop, tcur; 451 452 fdr = setup_rx(test); 453 fdt = setup_tx(test); 454 if (!ASSERT_OK_FD(fdr, "setup rx") || !ASSERT_OK_FD(fdt, "setup tx")) { 455 err = -1; 456 goto out_close_sockets; 457 } 458 459 len = build_packet(test, 460 (uint16_t)test->source_ports[source_port_index]); 461 if (!ASSERT_GT(len, 0, "build test packet")) 462 return -1; 463 464 tcur = util_gettime(); 465 tstop = tcur; 466 467 while (tx < TEST_PACKETS_COUNT) { 468 if (!ASSERT_OK(do_tx(fdt, buf, len), "do_tx")) 469 break; 470 tx++; 471 err = do_rx(fdr); 472 if (!ASSERT_GE(err, 0, "do_rx")) 473 break; 474 rx += err; 475 } 476 477 /* read straggler packets, if any */ 478 if (rx < tx) { 479 tstop = util_gettime() + 100; 480 while (rx < tx) { 481 tcur = util_gettime(); 482 if (tcur >= tstop) 483 break; 484 485 err = do_poll(fdr, POLLIN, tstop - tcur); 486 if (err < 0) 487 break; 488 err = do_rx(fdr); 489 if (err >= 0) 490 rx += err; 491 } 492 } 493 494 out_close_sockets: 495 close(fdt); 496 close(fdr); 497 return rx; 498 } 499 500 static int attach_and_configure_program(struct bpf_flow *skel) 501 { 502 struct bpf_map *prog_array = skel->maps.jmp_table; 503 int main_prog_fd, sub_prog_fd, map_fd, i, err; 504 struct bpf_program *prog; 505 char prog_name[32]; 506 507 main_prog_fd = bpf_program__fd(skel->progs._dissect); 508 if (main_prog_fd < 0) 509 return main_prog_fd; 510 511 err = bpf_prog_attach(main_prog_fd, 0, BPF_FLOW_DISSECTOR, 0); 512 if (err) 513 return err; 514 515 map_fd = bpf_map__fd(prog_array); 516 if (map_fd < 0) 517 return map_fd; 518 519 for (i = 0; i < bpf_map__max_entries(prog_array); i++) { 520 snprintf(prog_name, sizeof(prog_name), "flow_dissector_%d", i); 521 522 prog = bpf_object__find_program_by_name(skel->obj, prog_name); 523 if (!prog) 524 return -1; 525 526 sub_prog_fd = bpf_program__fd(prog); 527 if (sub_prog_fd < 0) 528 return -1; 529 530 err = bpf_map_update_elem(map_fd, &i, &sub_prog_fd, BPF_ANY); 531 if (err) 532 return -1; 533 } 534 535 return main_prog_fd; 536 } 537 538 static void detach_program(struct bpf_flow *skel, int prog_fd) 539 { 540 bpf_prog_detach2(prog_fd, 0, BPF_FLOW_DISSECTOR); 541 } 542 543 static int set_port_drop(int pf, bool multi_port) 544 { 545 SYS(fail, "tc qdisc add dev lo ingress"); 546 SYS(fail_delete_qdisc, "tc filter add %s %s %s %s %s %s %s %s %s %s", 547 "dev lo", 548 "parent FFFF:", 549 "protocol", pf == PF_INET6 ? "ipv6" : "ip", 550 "pref 1337", 551 "flower", 552 "ip_proto udp", 553 "src_port", multi_port ? "8-10" : "9", 554 "action drop"); 555 return 0; 556 557 fail_delete_qdisc: 558 SYS_NOFAIL("tc qdisc del dev lo ingress"); 559 fail: 560 return 1; 561 } 562 563 static void remove_filter(void) 564 { 565 SYS_NOFAIL("tc filter del dev lo ingress"); 566 SYS_NOFAIL("tc qdisc del dev lo ingress"); 567 } 568 569 static int ipv4_setup(void) 570 { 571 return set_port_drop(PF_INET, false); 572 } 573 574 static int ipv6_setup(void) 575 { 576 return set_port_drop(PF_INET6, false); 577 } 578 579 static int port_range_setup(void) 580 { 581 return set_port_drop(PF_INET, true); 582 } 583 584 static int set_addresses(void) 585 { 586 SYS(out, "ip -4 addr add %s dev lo", TEST_IPV4); 587 SYS(out_remove_ipv4, "ip -6 addr add %s dev lo", TEST_IPV6); 588 return 0; 589 out_remove_ipv4: 590 SYS_NOFAIL("ip -4 addr del %s dev lo", TEST_IPV4); 591 out: 592 return -1; 593 } 594 595 static void unset_addresses(void) 596 { 597 SYS_NOFAIL("ip -4 addr del %s dev lo", TEST_IPV4); 598 SYS_NOFAIL("ip -6 addr del %s dev lo", TEST_IPV6); 599 } 600 601 static int ipip_setup(void) 602 { 603 if (!ASSERT_OK(set_addresses(), "configure addresses")) 604 return -1; 605 if (!ASSERT_OK(set_port_drop(PF_INET, false), "set filter")) 606 goto out_unset_addresses; 607 SYS(out_remove_filter, 608 "ip link add ipip_test type ipip remote %s local %s dev lo", 609 TEST_TUNNEL_REMOTE, TEST_TUNNEL_LOCAL); 610 SYS(out_clean_netif, "ip link set ipip_test up"); 611 return 0; 612 613 out_clean_netif: 614 SYS_NOFAIL("ip link del ipip_test"); 615 out_remove_filter: 616 remove_filter(); 617 out_unset_addresses: 618 unset_addresses(); 619 return -1; 620 } 621 622 static void ipip_shutdown(void) 623 { 624 SYS_NOFAIL("ip link del ipip_test"); 625 remove_filter(); 626 unset_addresses(); 627 } 628 629 static int gre_setup(void) 630 { 631 if (!ASSERT_OK(set_addresses(), "configure addresses")) 632 return -1; 633 if (!ASSERT_OK(set_port_drop(PF_INET, false), "set filter")) 634 goto out_unset_addresses; 635 SYS(out_remove_filter, 636 "ip link add gre_test type gre remote %s local %s dev lo", 637 TEST_TUNNEL_REMOTE, TEST_TUNNEL_LOCAL); 638 SYS(out_clean_netif, "ip link set gre_test up"); 639 return 0; 640 641 out_clean_netif: 642 SYS_NOFAIL("ip link del ipip_test"); 643 out_remove_filter: 644 remove_filter(); 645 out_unset_addresses: 646 unset_addresses(); 647 return -1; 648 } 649 650 static void gre_shutdown(void) 651 { 652 SYS_NOFAIL("ip link del gre_test"); 653 remove_filter(); 654 unset_addresses(); 655 } 656 657 static const struct test_configuration tests_input[] = { 658 { 659 .name = "ipv4", 660 .test_setup = ipv4_setup, 661 .test_teardown = remove_filter, 662 .source_ports = { 8, 9, 10 }, 663 .cfg_l3_inner = PF_INET, 664 .in_saddr4 = TEST_IN4_SRC_ADDR_DEFAULT, 665 .in_daddr4 = TEST_IN4_DST_ADDR_DEFAULT 666 }, 667 { 668 .name = "ipv4_continue_dissect", 669 .test_setup = ipv4_setup, 670 .test_teardown = remove_filter, 671 .source_ports = { 8, 9, 10 }, 672 .cfg_l3_inner = PF_INET, 673 .in_saddr4 = TEST_IN4_SRC_ADDR_DISSECT_CONTINUE, 674 .in_daddr4 = TEST_IN4_DST_ADDR_DEFAULT }, 675 { 676 .name = "ipip", 677 .test_setup = ipip_setup, 678 .test_teardown = ipip_shutdown, 679 .source_ports = { 8, 9, 10 }, 680 .cfg_l3_inner = PF_INET, 681 .in_saddr4 = TEST_IN4_SRC_ADDR_IPIP, 682 .in_daddr4 = TEST_IN4_DST_ADDR_IPIP, 683 .out_saddr4 = TEST_OUT4_SRC_ADDR_DEFAULT, 684 .out_daddr4 = TEST_OUT4_DST_ADDR_DEFAULT, 685 .cfg_l3_outer = PF_INET, 686 .cfg_encap_proto = IPPROTO_IPIP, 687 688 }, 689 { 690 .name = "gre", 691 .test_setup = gre_setup, 692 .test_teardown = gre_shutdown, 693 .source_ports = { 8, 9, 10 }, 694 .cfg_l3_inner = PF_INET, 695 .in_saddr4 = TEST_IN4_SRC_ADDR_IPIP, 696 .in_daddr4 = TEST_IN4_DST_ADDR_IPIP, 697 .out_saddr4 = TEST_OUT4_SRC_ADDR_DEFAULT, 698 .out_daddr4 = TEST_OUT4_DST_ADDR_DEFAULT, 699 .cfg_l3_outer = PF_INET, 700 .cfg_encap_proto = IPPROTO_GRE, 701 }, 702 { 703 .name = "port_range", 704 .test_setup = port_range_setup, 705 .test_teardown = remove_filter, 706 .source_ports = { 7, 9, 11 }, 707 .cfg_l3_inner = PF_INET, 708 .in_saddr4 = TEST_IN4_SRC_ADDR_DEFAULT, 709 .in_daddr4 = TEST_IN4_DST_ADDR_DEFAULT }, 710 { 711 .name = "ipv6", 712 .test_setup = ipv6_setup, 713 .test_teardown = remove_filter, 714 .source_ports = { 8, 9, 10 }, 715 .cfg_l3_inner = PF_INET6, 716 .in_saddr6 = TEST_IN6_SRC_ADDR_DEFAULT, 717 .in_daddr6 = TEST_IN6_DST_ADDR_DEFAULT 718 }, 719 }; 720 721 struct test_ctx { 722 struct bpf_flow *skel; 723 struct netns_obj *ns; 724 int prog_fd; 725 }; 726 727 static int test_global_init(struct test_ctx *ctx) 728 { 729 int err; 730 731 ctx->skel = bpf_flow__open_and_load(); 732 if (!ASSERT_OK_PTR(ctx->skel, "open and load flow_dissector")) 733 return -1; 734 735 ctx->ns = netns_new("flow_dissector_classification", true); 736 if (!ASSERT_OK_PTR(ctx->ns, "switch ns")) 737 goto out_destroy_skel; 738 739 err = write_sysctl("/proc/sys/net/ipv4/conf/default/rp_filter", "0"); 740 err |= write_sysctl("/proc/sys/net/ipv4/conf/all/rp_filter", "0"); 741 err |= write_sysctl("/proc/sys/net/ipv4/conf/lo/rp_filter", "0"); 742 if (!ASSERT_OK(err, "configure net tunables")) 743 goto out_clean_ns; 744 745 ctx->prog_fd = attach_and_configure_program(ctx->skel); 746 if (!ASSERT_OK_FD(ctx->prog_fd, "attach and configure program")) 747 goto out_clean_ns; 748 return 0; 749 out_clean_ns: 750 netns_free(ctx->ns); 751 out_destroy_skel: 752 bpf_flow__destroy(ctx->skel); 753 return -1; 754 } 755 756 static void test_global_shutdown(struct test_ctx *ctx) 757 { 758 detach_program(ctx->skel, ctx->prog_fd); 759 netns_free(ctx->ns); 760 bpf_flow__destroy(ctx->skel); 761 } 762 763 void test_flow_dissector_classification(void) 764 { 765 struct test_ctx ctx; 766 const struct test_configuration *test; 767 int i; 768 769 if (test_global_init(&ctx)) 770 return; 771 772 for (i = 0; i < ARRAY_SIZE(tests_input); i++) { 773 if (!test__start_subtest(tests_input[i].name)) 774 continue; 775 test = &tests_input[i]; 776 /* All tests are expected to have one rx-ok port first, 777 * then a non-working rx port, and finally a rx-ok port 778 */ 779 if (test->test_setup && 780 !ASSERT_OK(test->test_setup(), "init filter")) 781 continue; 782 783 ASSERT_EQ(run_test(test, 0), TEST_PACKETS_COUNT, 784 "test first port"); 785 ASSERT_EQ(run_test(test, 1), 0, "test second port"); 786 ASSERT_EQ(run_test(test, 2), TEST_PACKETS_COUNT, 787 "test third port"); 788 if (test->test_teardown) 789 test->test_teardown(); 790 } 791 test_global_shutdown(&ctx); 792 } 793