Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'selftests-bpf-migrate-test_flow_dissector-sh-to-test_progs'

Alexis Lothoré says:

====================
This is the revision 3 of test_flow_dissector_migration.sh into
test_progs. This revision addresses comments from Stanislas, especially
about proper reuse of pseudo-header checksuming in new network helpers.

There are 2 "main" parts in test_flow_dissector.sh:
- a set of tests checking flow_dissector programs attachment to either
root namespace or non-root namespace
- dissection test

The first set is integrated in flow_dissector.c, which already contains
some existing tests for flow_dissector programs. This series uses the
opportunity to update a bit this file (use new assert, re-split tests,
etc)
The second part is migrated into a new file under test_progs,
flow_dissector_classification.c. It uses the same eBPF programs as
flow_dissector.c, but the difference is rather about how those program
are executed:
- flow_dissector.c manually runs programs with BPF_PROG_RUN
- flow_dissector_classification.c sends real packets to be dissected, and
so it also executes kernel code related to eBPF flow dissector (eg:
__skb_flow_bpf_to_target)

---
Changes in v3:
- Keep new helpers name in sync with kernel ones
- Document some existing network helpers
- Properly reuse pseudo-header csum helper in transport layer csum
helper
- Drop duplicate assert
- Use const for test structure in the migrated test
- Simplify shutdown callchain for basic test
- collect Acked-by
- Link to v2: https://lore.kernel.org/r/20241114-flow_dissector-v2-0-ee4a3be3de65@bootlin.com

Changes in v2:
- allow tests to run in parallel
- move some generic helpers to network_helpers.h
- define proper function for ASSERT_MEMEQ
- fetch acked-by tags
- Link to v1: https://lore.kernel.org/r/20241113-flow_dissector-v1-0-27c4df0592dc@bootlin.com
====================

Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+1175 -1067
-1
tools/testing/selftests/bpf/.gitignore
··· 19 19 urandom_read 20 20 test_sockmap 21 21 test_lirc_mode2_user 22 - test_flow_dissector 23 22 flow_dissector_load 24 23 test_tcpnotify_user 25 24 test_libbpf
-2
tools/testing/selftests/bpf/Makefile
··· 133 133 test_tunnel.sh \ 134 134 test_lwt_seg6local.sh \ 135 135 test_lirc_mode2.sh \ 136 - test_flow_dissector.sh \ 137 136 test_xdp_vlan_mode_generic.sh \ 138 137 test_xdp_vlan_mode_native.sh \ 139 138 test_lwt_ip_encap.sh \ ··· 160 161 flow_dissector_load \ 161 162 runqslower \ 162 163 test_cpp \ 163 - test_flow_dissector \ 164 164 test_lirc_mode2_user \ 165 165 veristat \ 166 166 xdp_features \
+1
tools/testing/selftests/bpf/config
··· 58 58 CONFIG_MPLS_IPTUNNEL=y 59 59 CONFIG_MPLS_ROUTING=y 60 60 CONFIG_MPTCP=y 61 + CONFIG_NET_ACT_GACT=y 61 62 CONFIG_NET_ACT_SKBMOD=y 62 63 CONFIG_NET_CLS=y 63 64 CONFIG_NET_CLS_ACT=y
+1 -1
tools/testing/selftests/bpf/network_helpers.c
··· 21 21 #include <linux/limits.h> 22 22 23 23 #include <linux/ip.h> 24 - #include <linux/udp.h> 24 + #include <netinet/udp.h> 25 25 #include <netinet/tcp.h> 26 26 #include <net/if.h> 27 27
+96
tools/testing/selftests/bpf/network_helpers.h
··· 14 14 #include <linux/sockios.h> 15 15 #include <linux/err.h> 16 16 #include <netinet/tcp.h> 17 + #include <netinet/udp.h> 17 18 #include <bpf/bpf_endian.h> 18 19 #include <net/if.h> 19 20 ··· 106 105 return (__u16)~csum; 107 106 } 108 107 108 + static __wsum csum_partial(const void *buf, int len, __wsum sum) 109 + { 110 + __u16 *p = (__u16 *)buf; 111 + int num_u16 = len >> 1; 112 + int i; 113 + 114 + for (i = 0; i < num_u16; i++) 115 + sum += p[i]; 116 + 117 + return sum; 118 + } 119 + 120 + static inline __sum16 build_ip_csum(struct iphdr *iph) 121 + { 122 + __u32 sum = 0; 123 + __u16 *p; 124 + 125 + iph->check = 0; 126 + p = (void *)iph; 127 + sum = csum_partial(p, iph->ihl << 2, 0); 128 + 129 + return csum_fold(sum); 130 + } 131 + 132 + /** 133 + * csum_tcpudp_magic - compute IP pseudo-header checksum 134 + * 135 + * Compute the IPv4 pseudo header checksum. The helper can take a 136 + * accumulated sum from the transport layer to accumulate it and directly 137 + * return the transport layer 138 + * 139 + * @saddr: IP source address 140 + * @daddr: IP dest address 141 + * @len: IP data size 142 + * @proto: transport layer protocol 143 + * @csum: The accumulated partial sum to add to the computation 144 + * 145 + * Returns the folded sum 146 + */ 109 147 static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, 110 148 __u32 len, __u8 proto, 111 149 __wsum csum) ··· 160 120 return csum_fold((__u32)s); 161 121 } 162 122 123 + /** 124 + * csum_ipv6_magic - compute IPv6 pseudo-header checksum 125 + * 126 + * Compute the ipv6 pseudo header checksum. The helper can take a 127 + * accumulated sum from the transport layer to accumulate it and directly 128 + * return the transport layer 129 + * 130 + * @saddr: IPv6 source address 131 + * @daddr: IPv6 dest address 132 + * @len: IPv6 data size 133 + * @proto: transport layer protocol 134 + * @csum: The accumulated partial sum to add to the computation 135 + * 136 + * Returns the folded sum 137 + */ 163 138 static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr, 164 139 const struct in6_addr *daddr, 165 140 __u32 len, __u8 proto, ··· 192 137 s = (s & 0xffffffff) + (s >> 32); 193 138 194 139 return csum_fold((__u32)s); 140 + } 141 + 142 + /** 143 + * build_udp_v4_csum - compute UDP checksum for UDP over IPv4 144 + * 145 + * Compute the checksum to embed in UDP header, composed of the sum of IP 146 + * pseudo-header checksum, UDP header checksum and UDP data checksum 147 + * @iph IP header 148 + * @udph UDP header, which must be immediately followed by UDP data 149 + * 150 + * Returns the total checksum 151 + */ 152 + 153 + static inline __sum16 build_udp_v4_csum(const struct iphdr *iph, 154 + const struct udphdr *udph) 155 + { 156 + unsigned long sum; 157 + 158 + sum = csum_partial(udph, ntohs(udph->len), 0); 159 + return csum_tcpudp_magic(iph->saddr, iph->daddr, ntohs(udph->len), 160 + IPPROTO_UDP, sum); 161 + } 162 + 163 + /** 164 + * build_udp_v6_csum - compute UDP checksum for UDP over IPv6 165 + * 166 + * Compute the checksum to embed in UDP header, composed of the sum of IPv6 167 + * pseudo-header checksum, UDP header checksum and UDP data checksum 168 + * @ip6h IPv6 header 169 + * @udph UDP header, which must be immediately followed by UDP data 170 + * 171 + * Returns the total checksum 172 + */ 173 + static inline __sum16 build_udp_v6_csum(const struct ipv6hdr *ip6h, 174 + const struct udphdr *udph) 175 + { 176 + unsigned long sum; 177 + 178 + sum = csum_partial(udph, ntohs(udph->len), 0); 179 + return csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, ntohs(udph->len), 180 + IPPROTO_UDP, sum); 195 181 } 196 182 197 183 struct tmonitor_ctx;
+245 -78
tools/testing/selftests/bpf/prog_tests/flow_dissector.c
··· 7 7 8 8 #include "bpf_flow.skel.h" 9 9 10 + #define TEST_NS "flow_dissector_ns" 10 11 #define FLOW_CONTINUE_SADDR 0x7f00007f /* 127.0.0.127 */ 12 + #define TEST_NAME_MAX_LEN 64 11 13 12 14 #ifndef IP_MF 13 15 #define IP_MF 0x2000 14 16 #endif 15 - 16 - #define CHECK_FLOW_KEYS(desc, got, expected) \ 17 - _CHECK(memcmp(&got, &expected, sizeof(got)) != 0, \ 18 - desc, \ 19 - topts.duration, \ 20 - "nhoff=%u/%u " \ 21 - "thoff=%u/%u " \ 22 - "addr_proto=0x%x/0x%x " \ 23 - "is_frag=%u/%u " \ 24 - "is_first_frag=%u/%u " \ 25 - "is_encap=%u/%u " \ 26 - "ip_proto=0x%x/0x%x " \ 27 - "n_proto=0x%x/0x%x " \ 28 - "flow_label=0x%x/0x%x " \ 29 - "sport=%u/%u " \ 30 - "dport=%u/%u\n", \ 31 - got.nhoff, expected.nhoff, \ 32 - got.thoff, expected.thoff, \ 33 - got.addr_proto, expected.addr_proto, \ 34 - got.is_frag, expected.is_frag, \ 35 - got.is_first_frag, expected.is_first_frag, \ 36 - got.is_encap, expected.is_encap, \ 37 - got.ip_proto, expected.ip_proto, \ 38 - got.n_proto, expected.n_proto, \ 39 - got.flow_label, expected.flow_label, \ 40 - got.sport, expected.sport, \ 41 - got.dport, expected.dport) 42 17 43 18 struct ipv4_pkt { 44 19 struct ethhdr eth; ··· 64 89 struct tcphdr tcp; 65 90 } __packed; 66 91 92 + struct gre_base_hdr { 93 + __be16 flags; 94 + __be16 protocol; 95 + } gre_base_hdr; 96 + 97 + struct gre_minimal_pkt { 98 + struct ethhdr eth; 99 + struct iphdr iph; 100 + struct gre_base_hdr gre_hdr; 101 + struct iphdr iph_inner; 102 + struct tcphdr tcp; 103 + } __packed; 104 + 67 105 struct test { 68 106 const char *name; 69 107 union { ··· 86 98 struct ipv6_pkt ipv6; 87 99 struct ipv6_frag_pkt ipv6_frag; 88 100 struct dvlan_ipv6_pkt dvlan_ipv6; 101 + struct gre_minimal_pkt gre_minimal; 89 102 } pkt; 90 103 struct bpf_flow_keys keys; 91 104 __u32 flags; ··· 95 106 96 107 #define VLAN_HLEN 4 97 108 98 - static __u32 duration; 99 109 struct test tests[] = { 100 110 { 101 111 .name = "ipv4", ··· 432 444 }, 433 445 .retval = BPF_FLOW_DISSECTOR_CONTINUE, 434 446 }, 447 + { 448 + .name = "ip-gre", 449 + .pkt.gre_minimal = { 450 + .eth.h_proto = __bpf_constant_htons(ETH_P_IP), 451 + .iph.ihl = 5, 452 + .iph.protocol = IPPROTO_GRE, 453 + .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES), 454 + .gre_hdr = { 455 + .flags = 0, 456 + .protocol = __bpf_constant_htons(ETH_P_IP), 457 + }, 458 + .iph_inner.ihl = 5, 459 + .iph_inner.protocol = IPPROTO_TCP, 460 + .iph_inner.tot_len = 461 + __bpf_constant_htons(MAGIC_BYTES - 462 + sizeof(struct iphdr)), 463 + .tcp.doff = 5, 464 + .tcp.source = 80, 465 + .tcp.dest = 8080, 466 + }, 467 + .keys = { 468 + .nhoff = ETH_HLEN, 469 + .thoff = ETH_HLEN + sizeof(struct iphdr) * 2 + 470 + sizeof(struct gre_base_hdr), 471 + .addr_proto = ETH_P_IP, 472 + .ip_proto = IPPROTO_TCP, 473 + .n_proto = __bpf_constant_htons(ETH_P_IP), 474 + .is_encap = true, 475 + .sport = 80, 476 + .dport = 8080, 477 + }, 478 + .retval = BPF_OK, 479 + }, 480 + { 481 + .name = "ip-gre-no-encap", 482 + .pkt.ipip = { 483 + .eth.h_proto = __bpf_constant_htons(ETH_P_IP), 484 + .iph.ihl = 5, 485 + .iph.protocol = IPPROTO_GRE, 486 + .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES), 487 + .iph_inner.ihl = 5, 488 + .iph_inner.protocol = IPPROTO_TCP, 489 + .iph_inner.tot_len = 490 + __bpf_constant_htons(MAGIC_BYTES - 491 + sizeof(struct iphdr)), 492 + .tcp.doff = 5, 493 + .tcp.source = 80, 494 + .tcp.dest = 8080, 495 + }, 496 + .keys = { 497 + .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP, 498 + .nhoff = ETH_HLEN, 499 + .thoff = ETH_HLEN + sizeof(struct iphdr) 500 + + sizeof(struct gre_base_hdr), 501 + .addr_proto = ETH_P_IP, 502 + .ip_proto = IPPROTO_GRE, 503 + .n_proto = __bpf_constant_htons(ETH_P_IP), 504 + .is_encap = true, 505 + }, 506 + .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP, 507 + .retval = BPF_OK, 508 + }, 435 509 }; 510 + 511 + void serial_test_flow_dissector_namespace(void) 512 + { 513 + struct bpf_flow *skel; 514 + struct nstoken *ns; 515 + int err, prog_fd; 516 + 517 + skel = bpf_flow__open_and_load(); 518 + if (!ASSERT_OK_PTR(skel, "open/load skeleton")) 519 + return; 520 + 521 + prog_fd = bpf_program__fd(skel->progs._dissect); 522 + if (!ASSERT_OK_FD(prog_fd, "get dissector fd")) 523 + goto out_destroy_skel; 524 + 525 + /* We must be able to attach a flow dissector to root namespace */ 526 + err = bpf_prog_attach(prog_fd, 0, BPF_FLOW_DISSECTOR, 0); 527 + if (!ASSERT_OK(err, "attach on root namespace ok")) 528 + goto out_destroy_skel; 529 + 530 + err = make_netns(TEST_NS); 531 + if (!ASSERT_OK(err, "create non-root net namespace")) 532 + goto out_destroy_skel; 533 + 534 + /* We must not be able to additionally attach a flow dissector to a 535 + * non-root net namespace 536 + */ 537 + ns = open_netns(TEST_NS); 538 + if (!ASSERT_OK_PTR(ns, "enter non-root net namespace")) 539 + goto out_clean_ns; 540 + 541 + err = bpf_prog_attach(prog_fd, 0, BPF_FLOW_DISSECTOR, 0); 542 + close_netns(ns); 543 + ASSERT_ERR(err, "refuse new flow dissector in non-root net namespace"); 544 + ASSERT_EQ(errno, EEXIST, "refused because of already attached prog"); 545 + 546 + /* If no flow dissector is attached to the root namespace, we must 547 + * be able to attach one to a non-root net namespace 548 + */ 549 + bpf_prog_detach2(prog_fd, 0, BPF_FLOW_DISSECTOR); 550 + ns = open_netns(TEST_NS); 551 + ASSERT_OK_PTR(ns, "enter non-root net namespace"); 552 + err = bpf_prog_attach(prog_fd, 0, BPF_FLOW_DISSECTOR, 0); 553 + close_netns(ns); 554 + ASSERT_OK(err, "accept new flow dissector in non-root net namespace"); 555 + 556 + /* If a flow dissector is attached to non-root net namespace, attaching 557 + * a flow dissector to root namespace must fail 558 + */ 559 + err = bpf_prog_attach(prog_fd, 0, BPF_FLOW_DISSECTOR, 0); 560 + ASSERT_ERR(err, "refuse new flow dissector on root namespace"); 561 + ASSERT_EQ(errno, EEXIST, "refused because of already attached prog"); 562 + 563 + ns = open_netns(TEST_NS); 564 + bpf_prog_detach2(prog_fd, 0, BPF_FLOW_DISSECTOR); 565 + close_netns(ns); 566 + out_clean_ns: 567 + remove_netns(TEST_NS); 568 + out_destroy_skel: 569 + bpf_flow__destroy(skel); 570 + } 436 571 437 572 static int create_tap(const char *ifname) 438 573 { ··· 644 533 return 0; 645 534 } 646 535 647 - static void run_tests_skb_less(int tap_fd, struct bpf_map *keys) 536 + static void run_tests_skb_less(int tap_fd, struct bpf_map *keys, 537 + char *test_suffix) 648 538 { 539 + char test_name[TEST_NAME_MAX_LEN]; 649 540 int i, err, keys_fd; 650 541 651 542 keys_fd = bpf_map__fd(keys); 652 - if (CHECK(keys_fd < 0, "bpf_map__fd", "err %d\n", keys_fd)) 543 + if (!ASSERT_OK_FD(keys_fd, "bpf_map__fd")) 653 544 return; 654 545 655 546 for (i = 0; i < ARRAY_SIZE(tests); i++) { 656 547 /* Keep in sync with 'flags' from eth_get_headlen. */ 657 548 __u32 eth_get_headlen_flags = 658 549 BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG; 659 - LIBBPF_OPTS(bpf_test_run_opts, topts); 660 550 struct bpf_flow_keys flow_keys = {}; 661 551 __u32 key = (__u32)(tests[i].keys.sport) << 16 | 662 552 tests[i].keys.dport; 553 + snprintf(test_name, TEST_NAME_MAX_LEN, "%s-%s", tests[i].name, 554 + test_suffix); 555 + if (!test__start_subtest(test_name)) 556 + continue; 663 557 664 558 /* For skb-less case we can't pass input flags; run 665 559 * only the tests that have a matching set of flags. ··· 674 558 continue; 675 559 676 560 err = tx_tap(tap_fd, &tests[i].pkt, sizeof(tests[i].pkt)); 677 - CHECK(err < 0, "tx_tap", "err %d errno %d\n", err, errno); 561 + if (!ASSERT_EQ(err, sizeof(tests[i].pkt), "tx_tap")) 562 + continue; 678 563 679 564 /* check the stored flow_keys only if BPF_OK expected */ 680 565 if (tests[i].retval != BPF_OK) 681 566 continue; 682 567 683 568 err = bpf_map_lookup_elem(keys_fd, &key, &flow_keys); 684 - ASSERT_OK(err, "bpf_map_lookup_elem"); 569 + if (!ASSERT_OK(err, "bpf_map_lookup_elem")) 570 + continue; 685 571 686 - CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys); 572 + ASSERT_MEMEQ(&flow_keys, &tests[i].keys, 573 + sizeof(struct bpf_flow_keys), 574 + "returned flow keys"); 687 575 688 576 err = bpf_map_delete_elem(keys_fd, &key); 689 577 ASSERT_OK(err, "bpf_map_delete_elem"); 690 578 } 691 579 } 692 580 693 - static void test_skb_less_prog_attach(struct bpf_flow *skel, int tap_fd) 581 + void test_flow_dissector_skb_less_direct_attach(void) 694 582 { 695 - int err, prog_fd; 583 + int err, prog_fd, tap_fd; 584 + struct bpf_flow *skel; 585 + struct netns_obj *ns; 586 + 587 + ns = netns_new("flow_dissector_skb_less_indirect_attach_ns", true); 588 + if (!ASSERT_OK_PTR(ns, "create and open netns")) 589 + return; 590 + 591 + skel = bpf_flow__open_and_load(); 592 + if (!ASSERT_OK_PTR(skel, "open/load skeleton")) 593 + goto out_clean_ns; 594 + 595 + err = init_prog_array(skel->obj, skel->maps.jmp_table); 596 + if (!ASSERT_OK(err, "init_prog_array")) 597 + goto out_destroy_skel; 696 598 697 599 prog_fd = bpf_program__fd(skel->progs._dissect); 698 - if (CHECK(prog_fd < 0, "bpf_program__fd", "err %d\n", prog_fd)) 699 - return; 600 + if (!ASSERT_OK_FD(prog_fd, "bpf_program__fd")) 601 + goto out_destroy_skel; 700 602 701 603 err = bpf_prog_attach(prog_fd, 0, BPF_FLOW_DISSECTOR, 0); 702 - if (CHECK(err, "bpf_prog_attach", "err %d errno %d\n", err, errno)) 703 - return; 604 + if (!ASSERT_OK(err, "bpf_prog_attach")) 605 + goto out_destroy_skel; 704 606 705 - run_tests_skb_less(tap_fd, skel->maps.last_dissection); 607 + tap_fd = create_tap("tap0"); 608 + if (!ASSERT_OK_FD(tap_fd, "create_tap")) 609 + goto out_destroy_skel; 610 + err = ifup("tap0"); 611 + if (!ASSERT_OK(err, "ifup")) 612 + goto out_close_tap; 613 + 614 + run_tests_skb_less(tap_fd, skel->maps.last_dissection, 615 + "non-skb-direct-attach"); 706 616 707 617 err = bpf_prog_detach2(prog_fd, 0, BPF_FLOW_DISSECTOR); 708 - CHECK(err, "bpf_prog_detach2", "err %d errno %d\n", err, errno); 618 + ASSERT_OK(err, "bpf_prog_detach2"); 619 + 620 + out_close_tap: 621 + close(tap_fd); 622 + out_destroy_skel: 623 + bpf_flow__destroy(skel); 624 + out_clean_ns: 625 + netns_free(ns); 709 626 } 710 627 711 - static void test_skb_less_link_create(struct bpf_flow *skel, int tap_fd) 628 + void test_flow_dissector_skb_less_indirect_attach(void) 712 629 { 630 + int err, net_fd, tap_fd; 631 + struct bpf_flow *skel; 713 632 struct bpf_link *link; 714 - int err, net_fd; 633 + struct netns_obj *ns; 634 + 635 + ns = netns_new("flow_dissector_skb_less_indirect_attach_ns", true); 636 + if (!ASSERT_OK_PTR(ns, "create and open netns")) 637 + return; 638 + 639 + skel = bpf_flow__open_and_load(); 640 + if (!ASSERT_OK_PTR(skel, "open/load skeleton")) 641 + goto out_clean_ns; 715 642 716 643 net_fd = open("/proc/self/ns/net", O_RDONLY); 717 - if (CHECK(net_fd < 0, "open(/proc/self/ns/net)", "err %d\n", errno)) 718 - return; 644 + if (!ASSERT_OK_FD(net_fd, "open(/proc/self/ns/net")) 645 + goto out_destroy_skel; 646 + 647 + err = init_prog_array(skel->obj, skel->maps.jmp_table); 648 + if (!ASSERT_OK(err, "init_prog_array")) 649 + goto out_destroy_skel; 650 + 651 + tap_fd = create_tap("tap0"); 652 + if (!ASSERT_OK_FD(tap_fd, "create_tap")) 653 + goto out_close_ns; 654 + err = ifup("tap0"); 655 + if (!ASSERT_OK(err, "ifup")) 656 + goto out_close_tap; 719 657 720 658 link = bpf_program__attach_netns(skel->progs._dissect, net_fd); 721 659 if (!ASSERT_OK_PTR(link, "attach_netns")) 722 - goto out_close; 660 + goto out_close_tap; 723 661 724 - run_tests_skb_less(tap_fd, skel->maps.last_dissection); 662 + run_tests_skb_less(tap_fd, skel->maps.last_dissection, 663 + "non-skb-indirect-attach"); 725 664 726 665 err = bpf_link__destroy(link); 727 - CHECK(err, "bpf_link__destroy", "err %d\n", err); 728 - out_close: 666 + ASSERT_OK(err, "bpf_link__destroy"); 667 + 668 + out_close_tap: 669 + close(tap_fd); 670 + out_close_ns: 729 671 close(net_fd); 672 + out_destroy_skel: 673 + bpf_flow__destroy(skel); 674 + out_clean_ns: 675 + netns_free(ns); 730 676 } 731 677 732 - void test_flow_dissector(void) 678 + void test_flow_dissector_skb(void) 733 679 { 734 - int i, err, prog_fd, keys_fd = -1, tap_fd; 680 + char test_name[TEST_NAME_MAX_LEN]; 735 681 struct bpf_flow *skel; 682 + int i, err, prog_fd; 736 683 737 684 skel = bpf_flow__open_and_load(); 738 - if (CHECK(!skel, "skel", "failed to open/load skeleton\n")) 685 + if (!ASSERT_OK_PTR(skel, "open/load skeleton")) 739 686 return; 740 687 741 - prog_fd = bpf_program__fd(skel->progs._dissect); 742 - if (CHECK(prog_fd < 0, "bpf_program__fd", "err %d\n", prog_fd)) 743 - goto out_destroy_skel; 744 - keys_fd = bpf_map__fd(skel->maps.last_dissection); 745 - if (CHECK(keys_fd < 0, "bpf_map__fd", "err %d\n", keys_fd)) 746 - goto out_destroy_skel; 747 688 err = init_prog_array(skel->obj, skel->maps.jmp_table); 748 - if (CHECK(err, "init_prog_array", "err %d\n", err)) 689 + if (!ASSERT_OK(err, "init_prog_array")) 690 + goto out_destroy_skel; 691 + 692 + prog_fd = bpf_program__fd(skel->progs._dissect); 693 + if (!ASSERT_OK_FD(prog_fd, "bpf_program__fd")) 749 694 goto out_destroy_skel; 750 695 751 696 for (i = 0; i < ARRAY_SIZE(tests); i++) { ··· 817 640 .data_out = &flow_keys, 818 641 ); 819 642 static struct bpf_flow_keys ctx = {}; 643 + 644 + snprintf(test_name, TEST_NAME_MAX_LEN, "%s-skb", tests[i].name); 645 + if (!test__start_subtest(test_name)) 646 + continue; 820 647 821 648 if (tests[i].flags) { 822 649 topts.ctx_in = &ctx; ··· 837 656 continue; 838 657 ASSERT_EQ(topts.data_size_out, sizeof(flow_keys), 839 658 "test_run data_size_out"); 840 - CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys); 659 + ASSERT_MEMEQ(&flow_keys, &tests[i].keys, 660 + sizeof(struct bpf_flow_keys), 661 + "returned flow keys"); 841 662 } 842 663 843 - /* Do the same tests but for skb-less flow dissector. 844 - * We use a known path in the net/tun driver that calls 845 - * eth_get_headlen and we manually export bpf_flow_keys 846 - * via BPF map in this case. 847 - */ 848 - 849 - tap_fd = create_tap("tap0"); 850 - CHECK(tap_fd < 0, "create_tap", "tap_fd %d errno %d\n", tap_fd, errno); 851 - err = ifup("tap0"); 852 - CHECK(err, "ifup", "err %d errno %d\n", err, errno); 853 - 854 - /* Test direct prog attachment */ 855 - test_skb_less_prog_attach(skel, tap_fd); 856 - /* Test indirect prog attachment via link */ 857 - test_skb_less_link_create(skel, tap_fd); 858 - 859 - close(tap_fd); 860 664 out_destroy_skel: 861 665 bpf_flow__destroy(skel); 862 666 } 667 +
+792
tools/testing/selftests/bpf/prog_tests/flow_dissector_classification.c
··· 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 + }
+1 -1
tools/testing/selftests/bpf/prog_tests/sockopt_sk.c
··· 2 2 #include <test_progs.h> 3 3 #include "cgroup_helpers.h" 4 4 5 - #include <linux/tcp.h> 5 + #include <netinet/tcp.h> 6 6 #include <linux/netlink.h> 7 7 #include "sockopt_sk.skel.h" 8 8
+1 -1
tools/testing/selftests/bpf/prog_tests/xdp_bonding.c
··· 17 17 #include "network_helpers.h" 18 18 #include <linux/if_bonding.h> 19 19 #include <linux/limits.h> 20 - #include <linux/udp.h> 20 + #include <netinet/udp.h> 21 21 #include <uapi/linux/netdev.h> 22 22 23 23 #include "xdp_dummy.skel.h"
+1 -1
tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c
··· 7 7 #include <linux/if_link.h> 8 8 #include <linux/ipv6.h> 9 9 #include <linux/in6.h> 10 - #include <linux/udp.h> 10 + #include <netinet/udp.h> 11 11 #include <bpf/bpf_endian.h> 12 12 #include <uapi/linux/netdev.h> 13 13 #include "test_xdp_do_redirect.skel.h"
+1 -1
tools/testing/selftests/bpf/prog_tests/xdp_flowtable.c
··· 3 3 #include <network_helpers.h> 4 4 #include <bpf/btf.h> 5 5 #include <linux/if_link.h> 6 - #include <linux/udp.h> 6 + #include <netinet/udp.h> 7 7 #include <net/if.h> 8 8 #include <unistd.h> 9 9
+2 -19
tools/testing/selftests/bpf/prog_tests/xdp_metadata.c
··· 10 10 #include <linux/errqueue.h> 11 11 #include <linux/if_link.h> 12 12 #include <linux/net_tstamp.h> 13 - #include <linux/udp.h> 13 + #include <netinet/udp.h> 14 14 #include <sys/mman.h> 15 15 #include <net/if.h> 16 16 #include <poll.h> ··· 133 133 munmap(xsk->umem_area, UMEM_SIZE); 134 134 } 135 135 136 - static void ip_csum(struct iphdr *iph) 137 - { 138 - __u32 sum = 0; 139 - __u16 *p; 140 - int i; 141 - 142 - iph->check = 0; 143 - p = (void *)iph; 144 - for (i = 0; i < sizeof(*iph) / sizeof(*p); i++) 145 - sum += p[i]; 146 - 147 - while (sum >> 16) 148 - sum = (sum & 0xffff) + (sum >> 16); 149 - 150 - iph->check = ~sum; 151 - } 152 - 153 136 static int generate_packet(struct xsk *xsk, __u16 dst_port) 154 137 { 155 138 struct xsk_tx_metadata *meta; ··· 175 192 iph->protocol = IPPROTO_UDP; 176 193 ASSERT_EQ(inet_pton(FAMILY, TX_ADDR, &iph->saddr), 1, "inet_pton(TX_ADDR)"); 177 194 ASSERT_EQ(inet_pton(FAMILY, RX_ADDR, &iph->daddr), 1, "inet_pton(RX_ADDR)"); 178 - ip_csum(iph); 195 + iph->check = build_ip_csum(iph); 179 196 180 197 udph->source = htons(UDP_SOURCE_PORT); 181 198 udph->dest = htons(dst_port);
+1 -1
tools/testing/selftests/bpf/progs/test_cls_redirect.c
··· 15 15 #include <linux/ipv6.h> 16 16 #include <linux/pkt_cls.h> 17 17 #include <linux/tcp.h> 18 - #include <linux/udp.h> 18 + #include <netinet/udp.h> 19 19 20 20 #include <bpf/bpf_helpers.h> 21 21 #include <bpf/bpf_endian.h>
+1 -1
tools/testing/selftests/bpf/progs/test_cls_redirect.h
··· 10 10 #include <linux/in.h> 11 11 #include <linux/ip.h> 12 12 #include <linux/ipv6.h> 13 - #include <linux/udp.h> 13 + #include <netinet/udp.h> 14 14 15 15 /* offsetof() is used in static asserts, and the libbpf-redefined CO-RE 16 16 * friendly version breaks compilation for older clang versions <= 15
+1 -1
tools/testing/selftests/bpf/progs/test_cls_redirect_dynptr.c
··· 15 15 #include <linux/ipv6.h> 16 16 #include <linux/pkt_cls.h> 17 17 #include <linux/tcp.h> 18 - #include <linux/udp.h> 18 + #include <netinet/udp.h> 19 19 20 20 #include <bpf/bpf_helpers.h> 21 21 #include <bpf/bpf_endian.h>
-780
tools/testing/selftests/bpf/test_flow_dissector.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * Inject packets with all sorts of encapsulation into the kernel. 4 - * 5 - * IPv4/IPv6 outer layer 3 6 - * GRE/GUE/BARE outer layer 4, where bare is IPIP/SIT/IPv4-in-IPv6/.. 7 - * IPv4/IPv6 inner layer 3 8 - */ 9 - 10 - #define _GNU_SOURCE 11 - 12 - #include <stddef.h> 13 - #include <arpa/inet.h> 14 - #include <asm/byteorder.h> 15 - #include <error.h> 16 - #include <errno.h> 17 - #include <linux/if_packet.h> 18 - #include <linux/if_ether.h> 19 - #include <linux/ipv6.h> 20 - #include <netinet/ip.h> 21 - #include <netinet/in.h> 22 - #include <netinet/udp.h> 23 - #include <poll.h> 24 - #include <stdbool.h> 25 - #include <stdlib.h> 26 - #include <stdio.h> 27 - #include <string.h> 28 - #include <sys/ioctl.h> 29 - #include <sys/socket.h> 30 - #include <sys/stat.h> 31 - #include <sys/time.h> 32 - #include <sys/types.h> 33 - #include <unistd.h> 34 - 35 - #define CFG_PORT_INNER 8000 36 - 37 - /* Add some protocol definitions that do not exist in userspace */ 38 - 39 - struct grehdr { 40 - uint16_t unused; 41 - uint16_t protocol; 42 - } __attribute__((packed)); 43 - 44 - struct guehdr { 45 - union { 46 - struct { 47 - #if defined(__LITTLE_ENDIAN_BITFIELD) 48 - __u8 hlen:5, 49 - control:1, 50 - version:2; 51 - #elif defined (__BIG_ENDIAN_BITFIELD) 52 - __u8 version:2, 53 - control:1, 54 - hlen:5; 55 - #else 56 - #error "Please fix <asm/byteorder.h>" 57 - #endif 58 - __u8 proto_ctype; 59 - __be16 flags; 60 - }; 61 - __be32 word; 62 - }; 63 - }; 64 - 65 - static uint8_t cfg_dsfield_inner; 66 - static uint8_t cfg_dsfield_outer; 67 - static uint8_t cfg_encap_proto; 68 - static bool cfg_expect_failure = false; 69 - static int cfg_l3_extra = AF_UNSPEC; /* optional SIT prefix */ 70 - static int cfg_l3_inner = AF_UNSPEC; 71 - static int cfg_l3_outer = AF_UNSPEC; 72 - static int cfg_num_pkt = 10; 73 - static int cfg_num_secs = 0; 74 - static char cfg_payload_char = 'a'; 75 - static int cfg_payload_len = 100; 76 - static int cfg_port_gue = 6080; 77 - static bool cfg_only_rx; 78 - static bool cfg_only_tx; 79 - static int cfg_src_port = 9; 80 - 81 - static char buf[ETH_DATA_LEN]; 82 - 83 - #define INIT_ADDR4(name, addr4, port) \ 84 - static struct sockaddr_in name = { \ 85 - .sin_family = AF_INET, \ 86 - .sin_port = __constant_htons(port), \ 87 - .sin_addr.s_addr = __constant_htonl(addr4), \ 88 - }; 89 - 90 - #define INIT_ADDR6(name, addr6, port) \ 91 - static struct sockaddr_in6 name = { \ 92 - .sin6_family = AF_INET6, \ 93 - .sin6_port = __constant_htons(port), \ 94 - .sin6_addr = addr6, \ 95 - }; 96 - 97 - INIT_ADDR4(in_daddr4, INADDR_LOOPBACK, CFG_PORT_INNER) 98 - INIT_ADDR4(in_saddr4, INADDR_LOOPBACK + 2, 0) 99 - INIT_ADDR4(out_daddr4, INADDR_LOOPBACK, 0) 100 - INIT_ADDR4(out_saddr4, INADDR_LOOPBACK + 1, 0) 101 - INIT_ADDR4(extra_daddr4, INADDR_LOOPBACK, 0) 102 - INIT_ADDR4(extra_saddr4, INADDR_LOOPBACK + 1, 0) 103 - 104 - INIT_ADDR6(in_daddr6, IN6ADDR_LOOPBACK_INIT, CFG_PORT_INNER) 105 - INIT_ADDR6(in_saddr6, IN6ADDR_LOOPBACK_INIT, 0) 106 - INIT_ADDR6(out_daddr6, IN6ADDR_LOOPBACK_INIT, 0) 107 - INIT_ADDR6(out_saddr6, IN6ADDR_LOOPBACK_INIT, 0) 108 - INIT_ADDR6(extra_daddr6, IN6ADDR_LOOPBACK_INIT, 0) 109 - INIT_ADDR6(extra_saddr6, IN6ADDR_LOOPBACK_INIT, 0) 110 - 111 - static unsigned long util_gettime(void) 112 - { 113 - struct timeval tv; 114 - 115 - gettimeofday(&tv, NULL); 116 - return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); 117 - } 118 - 119 - static void util_printaddr(const char *msg, struct sockaddr *addr) 120 - { 121 - unsigned long off = 0; 122 - char nbuf[INET6_ADDRSTRLEN]; 123 - 124 - switch (addr->sa_family) { 125 - case PF_INET: 126 - off = __builtin_offsetof(struct sockaddr_in, sin_addr); 127 - break; 128 - case PF_INET6: 129 - off = __builtin_offsetof(struct sockaddr_in6, sin6_addr); 130 - break; 131 - default: 132 - error(1, 0, "printaddr: unsupported family %u\n", 133 - addr->sa_family); 134 - } 135 - 136 - if (!inet_ntop(addr->sa_family, ((void *) addr) + off, nbuf, 137 - sizeof(nbuf))) 138 - error(1, errno, "inet_ntop"); 139 - 140 - fprintf(stderr, "%s: %s\n", msg, nbuf); 141 - } 142 - 143 - static unsigned long add_csum_hword(const uint16_t *start, int num_u16) 144 - { 145 - unsigned long sum = 0; 146 - int i; 147 - 148 - for (i = 0; i < num_u16; i++) 149 - sum += start[i]; 150 - 151 - return sum; 152 - } 153 - 154 - static uint16_t build_ip_csum(const uint16_t *start, int num_u16, 155 - unsigned long sum) 156 - { 157 - sum += add_csum_hword(start, num_u16); 158 - 159 - while (sum >> 16) 160 - sum = (sum & 0xffff) + (sum >> 16); 161 - 162 - return ~sum; 163 - } 164 - 165 - static void build_ipv4_header(void *header, uint8_t proto, 166 - uint32_t src, uint32_t dst, 167 - int payload_len, uint8_t tos) 168 - { 169 - struct iphdr *iph = header; 170 - 171 - iph->ihl = 5; 172 - iph->version = 4; 173 - iph->tos = tos; 174 - iph->ttl = 8; 175 - iph->tot_len = htons(sizeof(*iph) + payload_len); 176 - iph->id = htons(1337); 177 - iph->protocol = proto; 178 - iph->saddr = src; 179 - iph->daddr = dst; 180 - iph->check = build_ip_csum((void *) iph, iph->ihl << 1, 0); 181 - } 182 - 183 - static void ipv6_set_dsfield(struct ipv6hdr *ip6h, uint8_t dsfield) 184 - { 185 - uint16_t val, *ptr = (uint16_t *)ip6h; 186 - 187 - val = ntohs(*ptr); 188 - val &= 0xF00F; 189 - val |= ((uint16_t) dsfield) << 4; 190 - *ptr = htons(val); 191 - } 192 - 193 - static void build_ipv6_header(void *header, uint8_t proto, 194 - struct sockaddr_in6 *src, 195 - struct sockaddr_in6 *dst, 196 - int payload_len, uint8_t dsfield) 197 - { 198 - struct ipv6hdr *ip6h = header; 199 - 200 - ip6h->version = 6; 201 - ip6h->payload_len = htons(payload_len); 202 - ip6h->nexthdr = proto; 203 - ip6h->hop_limit = 8; 204 - ipv6_set_dsfield(ip6h, dsfield); 205 - 206 - memcpy(&ip6h->saddr, &src->sin6_addr, sizeof(ip6h->saddr)); 207 - memcpy(&ip6h->daddr, &dst->sin6_addr, sizeof(ip6h->daddr)); 208 - } 209 - 210 - static uint16_t build_udp_v4_csum(const struct iphdr *iph, 211 - const struct udphdr *udph, 212 - int num_words) 213 - { 214 - unsigned long pseudo_sum; 215 - int num_u16 = sizeof(iph->saddr); /* halfwords: twice byte len */ 216 - 217 - pseudo_sum = add_csum_hword((void *) &iph->saddr, num_u16); 218 - pseudo_sum += htons(IPPROTO_UDP); 219 - pseudo_sum += udph->len; 220 - return build_ip_csum((void *) udph, num_words, pseudo_sum); 221 - } 222 - 223 - static uint16_t build_udp_v6_csum(const struct ipv6hdr *ip6h, 224 - const struct udphdr *udph, 225 - int num_words) 226 - { 227 - unsigned long pseudo_sum; 228 - int num_u16 = sizeof(ip6h->saddr); /* halfwords: twice byte len */ 229 - 230 - pseudo_sum = add_csum_hword((void *) &ip6h->saddr, num_u16); 231 - pseudo_sum += htons(ip6h->nexthdr); 232 - pseudo_sum += ip6h->payload_len; 233 - return build_ip_csum((void *) udph, num_words, pseudo_sum); 234 - } 235 - 236 - static void build_udp_header(void *header, int payload_len, 237 - uint16_t dport, int family) 238 - { 239 - struct udphdr *udph = header; 240 - int len = sizeof(*udph) + payload_len; 241 - 242 - udph->source = htons(cfg_src_port); 243 - udph->dest = htons(dport); 244 - udph->len = htons(len); 245 - udph->check = 0; 246 - if (family == AF_INET) 247 - udph->check = build_udp_v4_csum(header - sizeof(struct iphdr), 248 - udph, len >> 1); 249 - else 250 - udph->check = build_udp_v6_csum(header - sizeof(struct ipv6hdr), 251 - udph, len >> 1); 252 - } 253 - 254 - static void build_gue_header(void *header, uint8_t proto) 255 - { 256 - struct guehdr *gueh = header; 257 - 258 - gueh->proto_ctype = proto; 259 - } 260 - 261 - static void build_gre_header(void *header, uint16_t proto) 262 - { 263 - struct grehdr *greh = header; 264 - 265 - greh->protocol = htons(proto); 266 - } 267 - 268 - static int l3_length(int family) 269 - { 270 - if (family == AF_INET) 271 - return sizeof(struct iphdr); 272 - else 273 - return sizeof(struct ipv6hdr); 274 - } 275 - 276 - static int build_packet(void) 277 - { 278 - int ol3_len = 0, ol4_len = 0, il3_len = 0, il4_len = 0; 279 - int el3_len = 0; 280 - 281 - if (cfg_l3_extra) 282 - el3_len = l3_length(cfg_l3_extra); 283 - 284 - /* calculate header offsets */ 285 - if (cfg_encap_proto) { 286 - ol3_len = l3_length(cfg_l3_outer); 287 - 288 - if (cfg_encap_proto == IPPROTO_GRE) 289 - ol4_len = sizeof(struct grehdr); 290 - else if (cfg_encap_proto == IPPROTO_UDP) 291 - ol4_len = sizeof(struct udphdr) + sizeof(struct guehdr); 292 - } 293 - 294 - il3_len = l3_length(cfg_l3_inner); 295 - il4_len = sizeof(struct udphdr); 296 - 297 - if (el3_len + ol3_len + ol4_len + il3_len + il4_len + cfg_payload_len >= 298 - sizeof(buf)) 299 - error(1, 0, "packet too large\n"); 300 - 301 - /* 302 - * Fill packet from inside out, to calculate correct checksums. 303 - * But create ip before udp headers, as udp uses ip for pseudo-sum. 304 - */ 305 - memset(buf + el3_len + ol3_len + ol4_len + il3_len + il4_len, 306 - cfg_payload_char, cfg_payload_len); 307 - 308 - /* add zero byte for udp csum padding */ 309 - buf[el3_len + ol3_len + ol4_len + il3_len + il4_len + cfg_payload_len] = 0; 310 - 311 - switch (cfg_l3_inner) { 312 - case PF_INET: 313 - build_ipv4_header(buf + el3_len + ol3_len + ol4_len, 314 - IPPROTO_UDP, 315 - in_saddr4.sin_addr.s_addr, 316 - in_daddr4.sin_addr.s_addr, 317 - il4_len + cfg_payload_len, 318 - cfg_dsfield_inner); 319 - break; 320 - case PF_INET6: 321 - build_ipv6_header(buf + el3_len + ol3_len + ol4_len, 322 - IPPROTO_UDP, 323 - &in_saddr6, &in_daddr6, 324 - il4_len + cfg_payload_len, 325 - cfg_dsfield_inner); 326 - break; 327 - } 328 - 329 - build_udp_header(buf + el3_len + ol3_len + ol4_len + il3_len, 330 - cfg_payload_len, CFG_PORT_INNER, cfg_l3_inner); 331 - 332 - if (!cfg_encap_proto) 333 - return il3_len + il4_len + cfg_payload_len; 334 - 335 - switch (cfg_l3_outer) { 336 - case PF_INET: 337 - build_ipv4_header(buf + el3_len, cfg_encap_proto, 338 - out_saddr4.sin_addr.s_addr, 339 - out_daddr4.sin_addr.s_addr, 340 - ol4_len + il3_len + il4_len + cfg_payload_len, 341 - cfg_dsfield_outer); 342 - break; 343 - case PF_INET6: 344 - build_ipv6_header(buf + el3_len, cfg_encap_proto, 345 - &out_saddr6, &out_daddr6, 346 - ol4_len + il3_len + il4_len + cfg_payload_len, 347 - cfg_dsfield_outer); 348 - break; 349 - } 350 - 351 - switch (cfg_encap_proto) { 352 - case IPPROTO_UDP: 353 - build_gue_header(buf + el3_len + ol3_len + ol4_len - 354 - sizeof(struct guehdr), 355 - cfg_l3_inner == PF_INET ? IPPROTO_IPIP 356 - : IPPROTO_IPV6); 357 - build_udp_header(buf + el3_len + ol3_len, 358 - sizeof(struct guehdr) + il3_len + il4_len + 359 - cfg_payload_len, 360 - cfg_port_gue, cfg_l3_outer); 361 - break; 362 - case IPPROTO_GRE: 363 - build_gre_header(buf + el3_len + ol3_len, 364 - cfg_l3_inner == PF_INET ? ETH_P_IP 365 - : ETH_P_IPV6); 366 - break; 367 - } 368 - 369 - switch (cfg_l3_extra) { 370 - case PF_INET: 371 - build_ipv4_header(buf, 372 - cfg_l3_outer == PF_INET ? IPPROTO_IPIP 373 - : IPPROTO_IPV6, 374 - extra_saddr4.sin_addr.s_addr, 375 - extra_daddr4.sin_addr.s_addr, 376 - ol3_len + ol4_len + il3_len + il4_len + 377 - cfg_payload_len, 0); 378 - break; 379 - case PF_INET6: 380 - build_ipv6_header(buf, 381 - cfg_l3_outer == PF_INET ? IPPROTO_IPIP 382 - : IPPROTO_IPV6, 383 - &extra_saddr6, &extra_daddr6, 384 - ol3_len + ol4_len + il3_len + il4_len + 385 - cfg_payload_len, 0); 386 - break; 387 - } 388 - 389 - return el3_len + ol3_len + ol4_len + il3_len + il4_len + 390 - cfg_payload_len; 391 - } 392 - 393 - /* sender transmits encapsulated over RAW or unencap'd over UDP */ 394 - static int setup_tx(void) 395 - { 396 - int family, fd, ret; 397 - 398 - if (cfg_l3_extra) 399 - family = cfg_l3_extra; 400 - else if (cfg_l3_outer) 401 - family = cfg_l3_outer; 402 - else 403 - family = cfg_l3_inner; 404 - 405 - fd = socket(family, SOCK_RAW, IPPROTO_RAW); 406 - if (fd == -1) 407 - error(1, errno, "socket tx"); 408 - 409 - if (cfg_l3_extra) { 410 - if (cfg_l3_extra == PF_INET) 411 - ret = connect(fd, (void *) &extra_daddr4, 412 - sizeof(extra_daddr4)); 413 - else 414 - ret = connect(fd, (void *) &extra_daddr6, 415 - sizeof(extra_daddr6)); 416 - if (ret) 417 - error(1, errno, "connect tx"); 418 - } else if (cfg_l3_outer) { 419 - /* connect to destination if not encapsulated */ 420 - if (cfg_l3_outer == PF_INET) 421 - ret = connect(fd, (void *) &out_daddr4, 422 - sizeof(out_daddr4)); 423 - else 424 - ret = connect(fd, (void *) &out_daddr6, 425 - sizeof(out_daddr6)); 426 - if (ret) 427 - error(1, errno, "connect tx"); 428 - } else { 429 - /* otherwise using loopback */ 430 - if (cfg_l3_inner == PF_INET) 431 - ret = connect(fd, (void *) &in_daddr4, 432 - sizeof(in_daddr4)); 433 - else 434 - ret = connect(fd, (void *) &in_daddr6, 435 - sizeof(in_daddr6)); 436 - if (ret) 437 - error(1, errno, "connect tx"); 438 - } 439 - 440 - return fd; 441 - } 442 - 443 - /* receiver reads unencapsulated UDP */ 444 - static int setup_rx(void) 445 - { 446 - int fd, ret; 447 - 448 - fd = socket(cfg_l3_inner, SOCK_DGRAM, 0); 449 - if (fd == -1) 450 - error(1, errno, "socket rx"); 451 - 452 - if (cfg_l3_inner == PF_INET) 453 - ret = bind(fd, (void *) &in_daddr4, sizeof(in_daddr4)); 454 - else 455 - ret = bind(fd, (void *) &in_daddr6, sizeof(in_daddr6)); 456 - if (ret) 457 - error(1, errno, "bind rx"); 458 - 459 - return fd; 460 - } 461 - 462 - static int do_tx(int fd, const char *pkt, int len) 463 - { 464 - int ret; 465 - 466 - ret = write(fd, pkt, len); 467 - if (ret == -1) 468 - error(1, errno, "send"); 469 - if (ret != len) 470 - error(1, errno, "send: len (%d < %d)\n", ret, len); 471 - 472 - return 1; 473 - } 474 - 475 - static int do_poll(int fd, short events, int timeout) 476 - { 477 - struct pollfd pfd; 478 - int ret; 479 - 480 - pfd.fd = fd; 481 - pfd.events = events; 482 - 483 - ret = poll(&pfd, 1, timeout); 484 - if (ret == -1) 485 - error(1, errno, "poll"); 486 - if (ret && !(pfd.revents & POLLIN)) 487 - error(1, errno, "poll: unexpected event 0x%x\n", pfd.revents); 488 - 489 - return ret; 490 - } 491 - 492 - static int do_rx(int fd) 493 - { 494 - char rbuf; 495 - int ret, num = 0; 496 - 497 - while (1) { 498 - ret = recv(fd, &rbuf, 1, MSG_DONTWAIT); 499 - if (ret == -1 && errno == EAGAIN) 500 - break; 501 - if (ret == -1) 502 - error(1, errno, "recv"); 503 - if (rbuf != cfg_payload_char) 504 - error(1, 0, "recv: payload mismatch"); 505 - num++; 506 - } 507 - 508 - return num; 509 - } 510 - 511 - static int do_main(void) 512 - { 513 - unsigned long tstop, treport, tcur; 514 - int fdt = -1, fdr = -1, len, tx = 0, rx = 0; 515 - 516 - if (!cfg_only_tx) 517 - fdr = setup_rx(); 518 - if (!cfg_only_rx) 519 - fdt = setup_tx(); 520 - 521 - len = build_packet(); 522 - 523 - tcur = util_gettime(); 524 - treport = tcur + 1000; 525 - tstop = tcur + (cfg_num_secs * 1000); 526 - 527 - while (1) { 528 - if (!cfg_only_rx) 529 - tx += do_tx(fdt, buf, len); 530 - 531 - if (!cfg_only_tx) 532 - rx += do_rx(fdr); 533 - 534 - if (cfg_num_secs) { 535 - tcur = util_gettime(); 536 - if (tcur >= tstop) 537 - break; 538 - if (tcur >= treport) { 539 - fprintf(stderr, "pkts: tx=%u rx=%u\n", tx, rx); 540 - tx = 0; 541 - rx = 0; 542 - treport = tcur + 1000; 543 - } 544 - } else { 545 - if (tx == cfg_num_pkt) 546 - break; 547 - } 548 - } 549 - 550 - /* read straggler packets, if any */ 551 - if (rx < tx) { 552 - tstop = util_gettime() + 100; 553 - while (rx < tx) { 554 - tcur = util_gettime(); 555 - if (tcur >= tstop) 556 - break; 557 - 558 - do_poll(fdr, POLLIN, tstop - tcur); 559 - rx += do_rx(fdr); 560 - } 561 - } 562 - 563 - fprintf(stderr, "pkts: tx=%u rx=%u\n", tx, rx); 564 - 565 - if (fdr != -1 && close(fdr)) 566 - error(1, errno, "close rx"); 567 - if (fdt != -1 && close(fdt)) 568 - error(1, errno, "close tx"); 569 - 570 - /* 571 - * success (== 0) only if received all packets 572 - * unless failure is expected, in which case none must arrive. 573 - */ 574 - if (cfg_expect_failure) 575 - return rx != 0; 576 - else 577 - return rx != tx; 578 - } 579 - 580 - 581 - static void __attribute__((noreturn)) usage(const char *filepath) 582 - { 583 - fprintf(stderr, "Usage: %s [-e gre|gue|bare|none] [-i 4|6] [-l len] " 584 - "[-O 4|6] [-o 4|6] [-n num] [-t secs] [-R] [-T] " 585 - "[-s <osrc> [-d <odst>] [-S <isrc>] [-D <idst>] " 586 - "[-x <otos>] [-X <itos>] [-f <isport>] [-F]\n", 587 - filepath); 588 - exit(1); 589 - } 590 - 591 - static void parse_addr(int family, void *addr, const char *optarg) 592 - { 593 - int ret; 594 - 595 - ret = inet_pton(family, optarg, addr); 596 - if (ret == -1) 597 - error(1, errno, "inet_pton"); 598 - if (ret == 0) 599 - error(1, 0, "inet_pton: bad string"); 600 - } 601 - 602 - static void parse_addr4(struct sockaddr_in *addr, const char *optarg) 603 - { 604 - parse_addr(AF_INET, &addr->sin_addr, optarg); 605 - } 606 - 607 - static void parse_addr6(struct sockaddr_in6 *addr, const char *optarg) 608 - { 609 - parse_addr(AF_INET6, &addr->sin6_addr, optarg); 610 - } 611 - 612 - static int parse_protocol_family(const char *filepath, const char *optarg) 613 - { 614 - if (!strcmp(optarg, "4")) 615 - return PF_INET; 616 - if (!strcmp(optarg, "6")) 617 - return PF_INET6; 618 - 619 - usage(filepath); 620 - } 621 - 622 - static void parse_opts(int argc, char **argv) 623 - { 624 - int c; 625 - 626 - while ((c = getopt(argc, argv, "d:D:e:f:Fhi:l:n:o:O:Rs:S:t:Tx:X:")) != -1) { 627 - switch (c) { 628 - case 'd': 629 - if (cfg_l3_outer == AF_UNSPEC) 630 - error(1, 0, "-d must be preceded by -o"); 631 - if (cfg_l3_outer == AF_INET) 632 - parse_addr4(&out_daddr4, optarg); 633 - else 634 - parse_addr6(&out_daddr6, optarg); 635 - break; 636 - case 'D': 637 - if (cfg_l3_inner == AF_UNSPEC) 638 - error(1, 0, "-D must be preceded by -i"); 639 - if (cfg_l3_inner == AF_INET) 640 - parse_addr4(&in_daddr4, optarg); 641 - else 642 - parse_addr6(&in_daddr6, optarg); 643 - break; 644 - case 'e': 645 - if (!strcmp(optarg, "gre")) 646 - cfg_encap_proto = IPPROTO_GRE; 647 - else if (!strcmp(optarg, "gue")) 648 - cfg_encap_proto = IPPROTO_UDP; 649 - else if (!strcmp(optarg, "bare")) 650 - cfg_encap_proto = IPPROTO_IPIP; 651 - else if (!strcmp(optarg, "none")) 652 - cfg_encap_proto = IPPROTO_IP; /* == 0 */ 653 - else 654 - usage(argv[0]); 655 - break; 656 - case 'f': 657 - cfg_src_port = strtol(optarg, NULL, 0); 658 - break; 659 - case 'F': 660 - cfg_expect_failure = true; 661 - break; 662 - case 'h': 663 - usage(argv[0]); 664 - break; 665 - case 'i': 666 - if (!strcmp(optarg, "4")) 667 - cfg_l3_inner = PF_INET; 668 - else if (!strcmp(optarg, "6")) 669 - cfg_l3_inner = PF_INET6; 670 - else 671 - usage(argv[0]); 672 - break; 673 - case 'l': 674 - cfg_payload_len = strtol(optarg, NULL, 0); 675 - break; 676 - case 'n': 677 - cfg_num_pkt = strtol(optarg, NULL, 0); 678 - break; 679 - case 'o': 680 - cfg_l3_outer = parse_protocol_family(argv[0], optarg); 681 - break; 682 - case 'O': 683 - cfg_l3_extra = parse_protocol_family(argv[0], optarg); 684 - break; 685 - case 'R': 686 - cfg_only_rx = true; 687 - break; 688 - case 's': 689 - if (cfg_l3_outer == AF_INET) 690 - parse_addr4(&out_saddr4, optarg); 691 - else 692 - parse_addr6(&out_saddr6, optarg); 693 - break; 694 - case 'S': 695 - if (cfg_l3_inner == AF_INET) 696 - parse_addr4(&in_saddr4, optarg); 697 - else 698 - parse_addr6(&in_saddr6, optarg); 699 - break; 700 - case 't': 701 - cfg_num_secs = strtol(optarg, NULL, 0); 702 - break; 703 - case 'T': 704 - cfg_only_tx = true; 705 - break; 706 - case 'x': 707 - cfg_dsfield_outer = strtol(optarg, NULL, 0); 708 - break; 709 - case 'X': 710 - cfg_dsfield_inner = strtol(optarg, NULL, 0); 711 - break; 712 - } 713 - } 714 - 715 - if (cfg_only_rx && cfg_only_tx) 716 - error(1, 0, "options: cannot combine rx-only and tx-only"); 717 - 718 - if (cfg_encap_proto && cfg_l3_outer == AF_UNSPEC) 719 - error(1, 0, "options: must specify outer with encap"); 720 - else if ((!cfg_encap_proto) && cfg_l3_outer != AF_UNSPEC) 721 - error(1, 0, "options: cannot combine no-encap and outer"); 722 - else if ((!cfg_encap_proto) && cfg_l3_extra != AF_UNSPEC) 723 - error(1, 0, "options: cannot combine no-encap and extra"); 724 - 725 - if (cfg_l3_inner == AF_UNSPEC) 726 - cfg_l3_inner = AF_INET6; 727 - if (cfg_l3_inner == AF_INET6 && cfg_encap_proto == IPPROTO_IPIP) 728 - cfg_encap_proto = IPPROTO_IPV6; 729 - 730 - /* RFC 6040 4.2: 731 - * on decap, if outer encountered congestion (CE == 0x3), 732 - * but inner cannot encode ECN (NoECT == 0x0), then drop packet. 733 - */ 734 - if (((cfg_dsfield_outer & 0x3) == 0x3) && 735 - ((cfg_dsfield_inner & 0x3) == 0x0)) 736 - cfg_expect_failure = true; 737 - } 738 - 739 - static void print_opts(void) 740 - { 741 - if (cfg_l3_inner == PF_INET6) { 742 - util_printaddr("inner.dest6", (void *) &in_daddr6); 743 - util_printaddr("inner.source6", (void *) &in_saddr6); 744 - } else { 745 - util_printaddr("inner.dest4", (void *) &in_daddr4); 746 - util_printaddr("inner.source4", (void *) &in_saddr4); 747 - } 748 - 749 - if (!cfg_l3_outer) 750 - return; 751 - 752 - fprintf(stderr, "encap proto: %u\n", cfg_encap_proto); 753 - 754 - if (cfg_l3_outer == PF_INET6) { 755 - util_printaddr("outer.dest6", (void *) &out_daddr6); 756 - util_printaddr("outer.source6", (void *) &out_saddr6); 757 - } else { 758 - util_printaddr("outer.dest4", (void *) &out_daddr4); 759 - util_printaddr("outer.source4", (void *) &out_saddr4); 760 - } 761 - 762 - if (!cfg_l3_extra) 763 - return; 764 - 765 - if (cfg_l3_outer == PF_INET6) { 766 - util_printaddr("extra.dest6", (void *) &extra_daddr6); 767 - util_printaddr("extra.source6", (void *) &extra_saddr6); 768 - } else { 769 - util_printaddr("extra.dest4", (void *) &extra_daddr4); 770 - util_printaddr("extra.source4", (void *) &extra_saddr4); 771 - } 772 - 773 - } 774 - 775 - int main(int argc, char **argv) 776 - { 777 - parse_opts(argc, argv); 778 - print_opts(); 779 - return do_main(); 780 - }
-178
tools/testing/selftests/bpf/test_flow_dissector.sh
··· 1 - #!/bin/bash 2 - # SPDX-License-Identifier: GPL-2.0 3 - # 4 - # Load BPF flow dissector and verify it correctly dissects traffic 5 - 6 - BPF_FILE="bpf_flow.bpf.o" 7 - export TESTNAME=test_flow_dissector 8 - unmount=0 9 - 10 - # Kselftest framework requirement - SKIP code is 4. 11 - ksft_skip=4 12 - 13 - msg="skip all tests:" 14 - if [ $UID != 0 ]; then 15 - echo $msg please run this as root >&2 16 - exit $ksft_skip 17 - fi 18 - 19 - # This test needs to be run in a network namespace with in_netns.sh. Check if 20 - # this is the case and run it with in_netns.sh if it is being run in the root 21 - # namespace. 22 - if [[ -z $(ip netns identify $$) ]]; then 23 - err=0 24 - if bpftool="$(which bpftool)"; then 25 - echo "Testing global flow dissector..." 26 - 27 - $bpftool prog loadall $BPF_FILE /sys/fs/bpf/flow \ 28 - type flow_dissector 29 - 30 - if ! unshare --net $bpftool prog attach pinned \ 31 - /sys/fs/bpf/flow/_dissect flow_dissector; then 32 - echo "Unexpected unsuccessful attach in namespace" >&2 33 - err=1 34 - fi 35 - 36 - $bpftool prog attach pinned /sys/fs/bpf/flow/_dissect \ 37 - flow_dissector 38 - 39 - if unshare --net $bpftool prog attach pinned \ 40 - /sys/fs/bpf/flow/_dissect flow_dissector; then 41 - echo "Unexpected successful attach in namespace" >&2 42 - err=1 43 - fi 44 - 45 - if ! $bpftool prog detach pinned \ 46 - /sys/fs/bpf/flow/_dissect flow_dissector; then 47 - echo "Failed to detach flow dissector" >&2 48 - err=1 49 - fi 50 - 51 - rm -rf /sys/fs/bpf/flow 52 - else 53 - echo "Skipping root flow dissector test, bpftool not found" >&2 54 - fi 55 - 56 - # Run the rest of the tests in a net namespace. 57 - ../net/in_netns.sh "$0" "$@" 58 - err=$(( $err + $? )) 59 - 60 - if (( $err == 0 )); then 61 - echo "selftests: $TESTNAME [PASS]"; 62 - else 63 - echo "selftests: $TESTNAME [FAILED]"; 64 - fi 65 - 66 - exit $err 67 - fi 68 - 69 - # Determine selftest success via shell exit code 70 - exit_handler() 71 - { 72 - set +e 73 - 74 - # Cleanup 75 - tc filter del dev lo ingress pref 1337 2> /dev/null 76 - tc qdisc del dev lo ingress 2> /dev/null 77 - ./flow_dissector_load -d 2> /dev/null 78 - if [ $unmount -ne 0 ]; then 79 - umount bpffs 2> /dev/null 80 - fi 81 - } 82 - 83 - # Exit script immediately (well catched by trap handler) if any 84 - # program/thing exits with a non-zero status. 85 - set -e 86 - 87 - # (Use 'trap -l' to list meaning of numbers) 88 - trap exit_handler 0 2 3 6 9 89 - 90 - # Mount BPF file system 91 - if /bin/mount | grep /sys/fs/bpf > /dev/null; then 92 - echo "bpffs already mounted" 93 - else 94 - echo "bpffs not mounted. Mounting..." 95 - unmount=1 96 - /bin/mount bpffs /sys/fs/bpf -t bpf 97 - fi 98 - 99 - # Attach BPF program 100 - ./flow_dissector_load -p $BPF_FILE -s _dissect 101 - 102 - # Setup 103 - tc qdisc add dev lo ingress 104 - echo 0 > /proc/sys/net/ipv4/conf/default/rp_filter 105 - echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter 106 - echo 0 > /proc/sys/net/ipv4/conf/lo/rp_filter 107 - 108 - echo "Testing IPv4..." 109 - # Drops all IP/UDP packets coming from port 9 110 - tc filter add dev lo parent ffff: protocol ip pref 1337 flower ip_proto \ 111 - udp src_port 9 action drop 112 - 113 - # Send 10 IPv4/UDP packets from port 8. Filter should not drop any. 114 - ./test_flow_dissector -i 4 -f 8 115 - # Send 10 IPv4/UDP packets from port 9. Filter should drop all. 116 - ./test_flow_dissector -i 4 -f 9 -F 117 - # Send 10 IPv4/UDP packets from port 10. Filter should not drop any. 118 - ./test_flow_dissector -i 4 -f 10 119 - 120 - echo "Testing IPv4 from 127.0.0.127 (fallback to generic dissector)..." 121 - # Send 10 IPv4/UDP packets from port 8. Filter should not drop any. 122 - ./test_flow_dissector -i 4 -S 127.0.0.127 -f 8 123 - # Send 10 IPv4/UDP packets from port 9. Filter should drop all. 124 - ./test_flow_dissector -i 4 -S 127.0.0.127 -f 9 -F 125 - # Send 10 IPv4/UDP packets from port 10. Filter should not drop any. 126 - ./test_flow_dissector -i 4 -S 127.0.0.127 -f 10 127 - 128 - echo "Testing IPIP..." 129 - # Send 10 IPv4/IPv4/UDP packets from port 8. Filter should not drop any. 130 - ./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e bare -i 4 \ 131 - -D 192.168.0.1 -S 1.1.1.1 -f 8 132 - # Send 10 IPv4/IPv4/UDP packets from port 9. Filter should drop all. 133 - ./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e bare -i 4 \ 134 - -D 192.168.0.1 -S 1.1.1.1 -f 9 -F 135 - # Send 10 IPv4/IPv4/UDP packets from port 10. Filter should not drop any. 136 - ./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e bare -i 4 \ 137 - -D 192.168.0.1 -S 1.1.1.1 -f 10 138 - 139 - echo "Testing IPv4 + GRE..." 140 - # Send 10 IPv4/GRE/IPv4/UDP packets from port 8. Filter should not drop any. 141 - ./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e gre -i 4 \ 142 - -D 192.168.0.1 -S 1.1.1.1 -f 8 143 - # Send 10 IPv4/GRE/IPv4/UDP packets from port 9. Filter should drop all. 144 - ./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e gre -i 4 \ 145 - -D 192.168.0.1 -S 1.1.1.1 -f 9 -F 146 - # Send 10 IPv4/GRE/IPv4/UDP packets from port 10. Filter should not drop any. 147 - ./with_addr.sh ./with_tunnels.sh ./test_flow_dissector -o 4 -e gre -i 4 \ 148 - -D 192.168.0.1 -S 1.1.1.1 -f 10 149 - 150 - tc filter del dev lo ingress pref 1337 151 - 152 - echo "Testing port range..." 153 - # Drops all IP/UDP packets coming from port 8-10 154 - tc filter add dev lo parent ffff: protocol ip pref 1337 flower ip_proto \ 155 - udp src_port 8-10 action drop 156 - 157 - # Send 10 IPv4/UDP packets from port 7. Filter should not drop any. 158 - ./test_flow_dissector -i 4 -f 7 159 - # Send 10 IPv4/UDP packets from port 9. Filter should drop all. 160 - ./test_flow_dissector -i 4 -f 9 -F 161 - # Send 10 IPv4/UDP packets from port 11. Filter should not drop any. 162 - ./test_flow_dissector -i 4 -f 11 163 - 164 - tc filter del dev lo ingress pref 1337 165 - 166 - echo "Testing IPv6..." 167 - # Drops all IPv6/UDP packets coming from port 9 168 - tc filter add dev lo parent ffff: protocol ipv6 pref 1337 flower ip_proto \ 169 - udp src_port 9 action drop 170 - 171 - # Send 10 IPv6/UDP packets from port 8. Filter should not drop any. 172 - ./test_flow_dissector -i 6 -f 8 173 - # Send 10 IPv6/UDP packets from port 9. Filter should drop all. 174 - ./test_flow_dissector -i 6 -f 9 -F 175 - # Send 10 IPv6/UDP packets from port 10. Filter should not drop any. 176 - ./test_flow_dissector -i 6 -f 10 177 - 178 - exit 0
+15
tools/testing/selftests/bpf/test_progs.c
··· 1282 1282 backtrace_symbols_fd(bt, sz, STDERR_FILENO); 1283 1283 } 1284 1284 1285 + void hexdump(const char *prefix, const void *buf, size_t len) 1286 + { 1287 + for (int i = 0; i < len; i++) { 1288 + if (!(i % 16)) { 1289 + if (i) 1290 + fprintf(stdout, "\n"); 1291 + fprintf(stdout, "%s", prefix); 1292 + } 1293 + if (i && !(i % 8) && (i % 16)) 1294 + fprintf(stdout, "\t"); 1295 + fprintf(stdout, "%02X ", ((uint8_t *)(buf))[i]); 1296 + } 1297 + fprintf(stdout, "\n"); 1298 + } 1299 + 1285 1300 static void sigint_handler(int signum) 1286 1301 { 1287 1302 int i;
+15
tools/testing/selftests/bpf/test_progs.h
··· 185 185 void test__skip(void); 186 186 void test__fail(void); 187 187 int test__join_cgroup(const char *path); 188 + void hexdump(const char *prefix, const void *buf, size_t len); 188 189 189 190 #define PRINT_FAIL(format...) \ 190 191 ({ \ ··· 342 341 CHECK(!___ok, (name), \ 343 342 "unexpected %s: '%s' is not a substring of '%s'\n", \ 344 343 (name), ___substr, ___str); \ 344 + ___ok; \ 345 + }) 346 + 347 + #define ASSERT_MEMEQ(actual, expected, len, name) ({ \ 348 + static int duration = 0; \ 349 + const void *__act = actual; \ 350 + const void *__exp = expected; \ 351 + int __len = len; \ 352 + bool ___ok = memcmp(__act, __exp, __len) == 0; \ 353 + CHECK(!___ok, (name), "unexpected memory mismatch\n"); \ 354 + fprintf(stdout, "actual:\n"); \ 355 + hexdump("\t", __act, __len); \ 356 + fprintf(stdout, "expected:\n"); \ 357 + hexdump("\t", __exp, __len); \ 345 358 ___ok; \ 346 359 }) 347 360
+1 -1
tools/testing/selftests/bpf/xdp_hw_metadata.c
··· 27 27 #include <linux/errqueue.h> 28 28 #include <linux/if_link.h> 29 29 #include <linux/net_tstamp.h> 30 - #include <linux/udp.h> 30 + #include <netinet/udp.h> 31 31 #include <linux/sockios.h> 32 32 #include <linux/if_xdp.h> 33 33 #include <sys/mman.h>