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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'selftests-xsk-add-tests-for-xdp-tail-adjustment-in-af_xdp'

Tushar Vyavahare says:

====================
selftests/xsk: Add tests for XDP tail adjustment in AF_XDP

This patch series adds tests to validate the XDP tail adjustment
functionality, focusing on its use within the AF_XDP context. The tests
verify dynamic packet size manipulation using the bpf_xdp_adjust_tail()
helper function, covering both single and multi-buffer scenarios.

v1 -> v2:
1. Retain and extend stream replacement: Keep `pkt_stream_replace`
unchanged. Add `pkt_stream_replace_ifobject` for targeted ifobject
handling.

2. Consolidate patches: Merge patches 2 to 6 for tail adjustment tests and
check.

v2 -> v3:
1. Introduce `adjust_value` to replace `count` for clearer communication
with userspace.

v3 -> v4:
1. Remove `testapp_adjust_tail_common()`. [Maciej]

2. Add comments and modify code for buffer resizing logic in test cases
(shrink/grow by specific byte sizes for testing purposes). [Maciej]
====================

Link: https://patch.msgid.link/20250410033116.173617-1-tushar.vyavahare@intel.com
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>

+163 -8
+50
tools/testing/selftests/bpf/progs/xsk_xdp_progs.c
··· 4 4 #include <linux/bpf.h> 5 5 #include <bpf/bpf_helpers.h> 6 6 #include <linux/if_ether.h> 7 + #include <linux/ip.h> 8 + #include <linux/errno.h> 7 9 #include "xsk_xdp_common.h" 8 10 9 11 struct { ··· 16 14 } xsk SEC(".maps"); 17 15 18 16 static unsigned int idx; 17 + int adjust_value = 0; 19 18 int count = 0; 20 19 21 20 SEC("xdp.frags") int xsk_def_prog(struct xdp_md *xdp) ··· 71 68 return XDP_DROP; 72 69 73 70 return bpf_redirect_map(&xsk, idx, XDP_DROP); 71 + } 72 + 73 + SEC("xdp.frags") int xsk_xdp_adjust_tail(struct xdp_md *xdp) 74 + { 75 + __u32 buff_len, curr_buff_len; 76 + int ret; 77 + 78 + buff_len = bpf_xdp_get_buff_len(xdp); 79 + if (buff_len == 0) 80 + return XDP_DROP; 81 + 82 + ret = bpf_xdp_adjust_tail(xdp, adjust_value); 83 + if (ret < 0) { 84 + /* Handle unsupported cases */ 85 + if (ret == -EOPNOTSUPP) { 86 + /* Set adjust_value to -EOPNOTSUPP to indicate to userspace that this case 87 + * is unsupported 88 + */ 89 + adjust_value = -EOPNOTSUPP; 90 + return bpf_redirect_map(&xsk, 0, XDP_DROP); 91 + } 92 + 93 + return XDP_DROP; 94 + } 95 + 96 + curr_buff_len = bpf_xdp_get_buff_len(xdp); 97 + if (curr_buff_len != buff_len + adjust_value) 98 + return XDP_DROP; 99 + 100 + if (curr_buff_len > buff_len) { 101 + __u32 *pkt_data = (void *)(long)xdp->data; 102 + __u32 len, words_to_end, seq_num; 103 + 104 + len = curr_buff_len - PKT_HDR_ALIGN; 105 + words_to_end = len / sizeof(*pkt_data) - 1; 106 + seq_num = words_to_end; 107 + 108 + /* Convert sequence number to network byte order. Store this in the last 4 bytes of 109 + * the packet. Use 'adjust_value' to determine the position at the end of the 110 + * packet for storing the sequence number. 111 + */ 112 + seq_num = __constant_htonl(words_to_end); 113 + bpf_xdp_store_bytes(xdp, curr_buff_len - sizeof(seq_num), &seq_num, 114 + sizeof(seq_num)); 115 + } 116 + 117 + return bpf_redirect_map(&xsk, 0, XDP_DROP); 74 118 } 75 119 76 120 char _license[] SEC("license") = "GPL";
+1
tools/testing/selftests/bpf/xsk_xdp_common.h
··· 4 4 #define XSK_XDP_COMMON_H_ 5 5 6 6 #define MAX_SOCKETS 2 7 + #define PKT_HDR_ALIGN (sizeof(struct ethhdr) + 2) /* Just to align the data in the packet */ 7 8 8 9 struct xdp_info { 9 10 __u64 count;
+110 -8
tools/testing/selftests/bpf/xskxceiver.c
··· 524 524 test->nb_sockets = 1; 525 525 test->fail = false; 526 526 test->set_ring = false; 527 + test->adjust_tail = false; 528 + test->adjust_tail_support = false; 527 529 test->mtu = MAX_ETH_PKT_SIZE; 528 530 test->xdp_prog_rx = ifobj_rx->xdp_progs->progs.xsk_def_prog; 529 531 test->xskmap_rx = ifobj_rx->xdp_progs->maps.xsk; ··· 759 757 return pkt_stream_generate(pkt_stream->nb_pkts, pkt_stream->pkts[0].len); 760 758 } 761 759 760 + static void pkt_stream_replace_ifobject(struct ifobject *ifobj, u32 nb_pkts, u32 pkt_len) 761 + { 762 + ifobj->xsk->pkt_stream = pkt_stream_generate(nb_pkts, pkt_len); 763 + } 764 + 762 765 static void pkt_stream_replace(struct test_spec *test, u32 nb_pkts, u32 pkt_len) 763 766 { 764 - struct pkt_stream *pkt_stream; 765 - 766 - pkt_stream = pkt_stream_generate(nb_pkts, pkt_len); 767 - test->ifobj_tx->xsk->pkt_stream = pkt_stream; 768 - pkt_stream = pkt_stream_generate(nb_pkts, pkt_len); 769 - test->ifobj_rx->xsk->pkt_stream = pkt_stream; 767 + pkt_stream_replace_ifobject(test->ifobj_tx, nb_pkts, pkt_len); 768 + pkt_stream_replace_ifobject(test->ifobj_rx, nb_pkts, pkt_len); 770 769 } 771 770 772 771 static void __pkt_stream_replace_half(struct ifobject *ifobj, u32 pkt_len, ··· 992 989 } 993 990 994 991 return true; 992 + } 993 + 994 + static bool is_adjust_tail_supported(struct xsk_xdp_progs *skel_rx) 995 + { 996 + struct bpf_map *data_map; 997 + int adjust_value = 0; 998 + int key = 0; 999 + int ret; 1000 + 1001 + data_map = bpf_object__find_map_by_name(skel_rx->obj, "xsk_xdp_.bss"); 1002 + if (!data_map || !bpf_map__is_internal(data_map)) { 1003 + ksft_print_msg("Error: could not find bss section of XDP program\n"); 1004 + exit_with_error(errno); 1005 + } 1006 + 1007 + ret = bpf_map_lookup_elem(bpf_map__fd(data_map), &key, &adjust_value); 1008 + if (ret) { 1009 + ksft_print_msg("Error: bpf_map_lookup_elem failed with error %d\n", ret); 1010 + exit_with_error(errno); 1011 + } 1012 + 1013 + /* Set the 'adjust_value' variable to -EOPNOTSUPP in the XDP program if the adjust_tail 1014 + * helper is not supported. Skip the adjust_tail test case in this scenario. 1015 + */ 1016 + return adjust_value != -EOPNOTSUPP; 995 1017 } 996 1018 997 1019 static bool is_frag_valid(struct xsk_umem_info *umem, u64 addr, u32 len, u32 expected_pkt_nb, ··· 1795 1767 1796 1768 if (!err && ifobject->validation_func) 1797 1769 err = ifobject->validation_func(ifobject); 1798 - if (err) 1799 - report_failure(test); 1770 + 1771 + if (err) { 1772 + if (test->adjust_tail && !is_adjust_tail_supported(ifobject->xdp_progs)) 1773 + test->adjust_tail_support = false; 1774 + else 1775 + report_failure(test); 1776 + } 1800 1777 1801 1778 pthread_exit(NULL); 1802 1779 } ··· 2548 2515 return testapp_validate_traffic(test); 2549 2516 } 2550 2517 2518 + static int testapp_xdp_adjust_tail(struct test_spec *test, int adjust_value) 2519 + { 2520 + struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs; 2521 + struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs; 2522 + 2523 + test_spec_set_xdp_prog(test, skel_rx->progs.xsk_xdp_adjust_tail, 2524 + skel_tx->progs.xsk_xdp_adjust_tail, 2525 + skel_rx->maps.xsk, skel_tx->maps.xsk); 2526 + 2527 + skel_rx->bss->adjust_value = adjust_value; 2528 + 2529 + return testapp_validate_traffic(test); 2530 + } 2531 + 2532 + static int testapp_adjust_tail(struct test_spec *test, u32 value, u32 pkt_len) 2533 + { 2534 + int ret; 2535 + 2536 + test->adjust_tail_support = true; 2537 + test->adjust_tail = true; 2538 + test->total_steps = 1; 2539 + 2540 + pkt_stream_replace_ifobject(test->ifobj_tx, DEFAULT_BATCH_SIZE, pkt_len); 2541 + pkt_stream_replace_ifobject(test->ifobj_rx, DEFAULT_BATCH_SIZE, pkt_len + value); 2542 + 2543 + ret = testapp_xdp_adjust_tail(test, value); 2544 + if (ret) 2545 + return ret; 2546 + 2547 + if (!test->adjust_tail_support) { 2548 + ksft_test_result_skip("%s %sResize pkt with bpf_xdp_adjust_tail() not supported\n", 2549 + mode_string(test), busy_poll_string(test)); 2550 + return TEST_SKIP; 2551 + } 2552 + 2553 + return 0; 2554 + } 2555 + 2556 + static int testapp_adjust_tail_shrink(struct test_spec *test) 2557 + { 2558 + /* Shrink by 4 bytes for testing purpose */ 2559 + return testapp_adjust_tail(test, -4, MIN_PKT_SIZE * 2); 2560 + } 2561 + 2562 + static int testapp_adjust_tail_shrink_mb(struct test_spec *test) 2563 + { 2564 + test->mtu = MAX_ETH_JUMBO_SIZE; 2565 + /* Shrink by the frag size */ 2566 + return testapp_adjust_tail(test, -XSK_UMEM__MAX_FRAME_SIZE, XSK_UMEM__LARGE_FRAME_SIZE * 2); 2567 + } 2568 + 2569 + static int testapp_adjust_tail_grow(struct test_spec *test) 2570 + { 2571 + /* Grow by 4 bytes for testing purpose */ 2572 + return testapp_adjust_tail(test, 4, MIN_PKT_SIZE * 2); 2573 + } 2574 + 2575 + static int testapp_adjust_tail_grow_mb(struct test_spec *test) 2576 + { 2577 + test->mtu = MAX_ETH_JUMBO_SIZE; 2578 + /* Grow by (frag_size - last_frag_Size) - 1 to stay inside the last fragment */ 2579 + return testapp_adjust_tail(test, (XSK_UMEM__MAX_FRAME_SIZE / 2) - 1, 2580 + XSK_UMEM__LARGE_FRAME_SIZE * 2); 2581 + } 2582 + 2551 2583 static void run_pkt_test(struct test_spec *test) 2552 2584 { 2553 2585 int ret; ··· 2719 2621 {.name = "TOO_MANY_FRAGS", .test_func = testapp_too_many_frags}, 2720 2622 {.name = "HW_SW_MIN_RING_SIZE", .test_func = testapp_hw_sw_min_ring_size}, 2721 2623 {.name = "HW_SW_MAX_RING_SIZE", .test_func = testapp_hw_sw_max_ring_size}, 2624 + {.name = "XDP_ADJUST_TAIL_SHRINK", .test_func = testapp_adjust_tail_shrink}, 2625 + {.name = "XDP_ADJUST_TAIL_SHRINK_MULTI_BUFF", .test_func = testapp_adjust_tail_shrink_mb}, 2626 + {.name = "XDP_ADJUST_TAIL_GROW", .test_func = testapp_adjust_tail_grow}, 2627 + {.name = "XDP_ADJUST_TAIL_GROW_MULTI_BUFF", .test_func = testapp_adjust_tail_grow_mb}, 2722 2628 }; 2723 2629 2724 2630 static void print_tests(void)
+2
tools/testing/selftests/bpf/xskxceiver.h
··· 173 173 u16 nb_sockets; 174 174 bool fail; 175 175 bool set_ring; 176 + bool adjust_tail; 177 + bool adjust_tail_support; 176 178 enum test_mode mode; 177 179 char name[MAX_TEST_NAME_SIZE]; 178 180 };