--- v11
+++ v9
@@ -1,118 +1,215 @@
-Introduce the capability to allocate a xdp multi-buff in
-bpf_prog_test_run_xdp routine. This is a preliminary patch to introduce
-the selftests for new xdp multi-buff ebpf helpers
-
+From: Eelco Chaudron <echaudro@redhat.com>
+
+This change adds test cases for the multi-buffer scenarios when shrinking
+and growing.
+
+Signed-off-by: Eelco Chaudron <echaudro@redhat.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
- net/bpf/test_run.c | 54 ++++++++++++++++++++++++++++++++++++----------
- 1 file changed, 43 insertions(+), 11 deletions(-)
-
-diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
-index 362e020631b3..1833b863c185 100644
---- a/net/bpf/test_run.c
-+++ b/net/bpf/test_run.c
-@@ -749,16 +749,16 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
- union bpf_attr __user *uattr)
+ .../bpf/prog_tests/xdp_adjust_tail.c | 105 ++++++++++++++++++
+ .../bpf/progs/test_xdp_adjust_tail_grow.c | 10 +-
+ .../bpf/progs/test_xdp_adjust_tail_shrink.c | 32 +++++-
+ 3 files changed, 140 insertions(+), 7 deletions(-)
+
+diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c b/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c
+index d5c98f2cb12f..b936beaba797 100644
+--- a/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c
++++ b/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c
+@@ -130,6 +130,107 @@ void test_xdp_adjust_tail_grow2(void)
+ bpf_object__close(obj);
+ }
+
++void test_xdp_adjust_mb_tail_shrink(void)
++{
++ const char *file = "./test_xdp_adjust_tail_shrink.o";
++ __u32 duration, retval, size, exp_size;
++ struct bpf_object *obj;
++ static char buf[9000];
++ int err, prog_fd;
++
++ /* For the individual test cases, the first byte in the packet
++ * indicates which test will be run.
++ */
++
++ err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
++ if (CHECK_FAIL(err))
++ return;
++
++ /* Test case removing 10 bytes from last frag, NOT freeing it */
++ buf[0] = 0;
++ exp_size = sizeof(buf) - 10;
++ err = bpf_prog_test_run(prog_fd, 1, buf, sizeof(buf),
++ buf, &size, &retval, &duration);
++
++ CHECK(err || retval != XDP_TX || size != exp_size,
++ "9k-10b", "err %d errno %d retval %d[%d] size %d[%u]\n",
++ err, errno, retval, XDP_TX, size, exp_size);
++
++ /* Test case removing one of two pages, assuming 4K pages */
++ buf[0] = 1;
++ exp_size = sizeof(buf) - 4100;
++ err = bpf_prog_test_run(prog_fd, 1, buf, sizeof(buf),
++ buf, &size, &retval, &duration);
++
++ CHECK(err || retval != XDP_TX || size != exp_size,
++ "9k-1p", "err %d errno %d retval %d[%d] size %d[%u]\n",
++ err, errno, retval, XDP_TX, size, exp_size);
++
++ /* Test case removing two pages resulting in a non mb xdp_buff */
++ buf[0] = 2;
++ exp_size = sizeof(buf) - 8200;
++ err = bpf_prog_test_run(prog_fd, 1, buf, sizeof(buf),
++ buf, &size, &retval, &duration);
++
++ CHECK(err || retval != XDP_TX || size != exp_size,
++ "9k-2p", "err %d errno %d retval %d[%d] size %d[%u]\n",
++ err, errno, retval, XDP_TX, size, exp_size);
++
++ bpf_object__close(obj);
++}
++
++void test_xdp_adjust_mb_tail_grow(void)
++{
++ const char *file = "./test_xdp_adjust_tail_grow.o";
++ __u32 duration, retval, size, exp_size;
++ static char buf[16384];
++ struct bpf_object *obj;
++ int err, i, prog_fd;
++
++ err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
++ if (CHECK_FAIL(err))
++ return;
++
++ /* Test case add 10 bytes to last frag */
++ memset(buf, 1, sizeof(buf));
++ size = 9000;
++ exp_size = size + 10;
++ err = bpf_prog_test_run(prog_fd, 1, buf, size,
++ buf, &size, &retval, &duration);
++
++ CHECK(err || retval != XDP_TX || size != exp_size,
++ "9k+10b", "err %d retval %d[%d] size %d[%u]\n",
++ err, retval, XDP_TX, size, exp_size);
++
++ for (i = 0; i < 9000; i++)
++ CHECK(buf[i] != 1, "9k+10b-old",
++ "Old data not all ok, offset %i is failing [%u]!\n",
++ i, buf[i]);
++
++ for (i = 9000; i < 9010; i++)
++ CHECK(buf[i] != 0, "9k+10b-new",
++ "New data not all ok, offset %i is failing [%u]!\n",
++ i, buf[i]);
++
++ for (i = 9010; i < sizeof(buf); i++)
++ CHECK(buf[i] != 1, "9k+10b-untouched",
++ "Unused data not all ok, offset %i is failing [%u]!\n",
++ i, buf[i]);
++
++ /* Test a too large grow */
++ memset(buf, 1, sizeof(buf));
++ size = 9001;
++ exp_size = size;
++ err = bpf_prog_test_run(prog_fd, 1, buf, size,
++ buf, &size, &retval, &duration);
++
++ CHECK(err || retval != XDP_DROP || size != exp_size,
++ "9k+10b", "err %d retval %d[%d] size %d[%u]\n",
++ err, retval, XDP_TX, size, exp_size);
++
++ bpf_object__close(obj);
++}
++
+ void test_xdp_adjust_tail(void)
{
- u32 tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
-- u32 headroom = XDP_PACKET_HEADROOM;
- u32 size = kattr->test.data_size_in;
-+ u32 headroom = XDP_PACKET_HEADROOM;
-+ u32 retval, duration, max_data_sz;
- u32 repeat = kattr->test.repeat;
- struct netdev_rx_queue *rxqueue;
-+ struct skb_shared_info *sinfo;
- struct xdp_buff xdp = {};
-- u32 retval, duration;
-+ int i, ret = -EINVAL;
- struct xdp_md *ctx;
-- u32 max_data_sz;
- void *data;
-- int ret = -EINVAL;
-
- if (prog->expected_attach_type == BPF_XDP_DEVMAP ||
- prog->expected_attach_type == BPF_XDP_CPUMAP)
-@@ -778,11 +778,10 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
- headroom -= ctx->data;
+ if (test__start_subtest("xdp_adjust_tail_shrink"))
+@@ -138,4 +239,8 @@ void test_xdp_adjust_tail(void)
+ test_xdp_adjust_tail_grow();
+ if (test__start_subtest("xdp_adjust_tail_grow2"))
+ test_xdp_adjust_tail_grow2();
++ if (test__start_subtest("xdp_adjust_mb_tail_shrink"))
++ test_xdp_adjust_mb_tail_shrink();
++ if (test__start_subtest("xdp_adjust_mb_tail_grow"))
++ test_xdp_adjust_mb_tail_grow();
+ }
+diff --git a/tools/testing/selftests/bpf/progs/test_xdp_adjust_tail_grow.c b/tools/testing/selftests/bpf/progs/test_xdp_adjust_tail_grow.c
+index 3d66599eee2e..3d43defb0e00 100644
+--- a/tools/testing/selftests/bpf/progs/test_xdp_adjust_tail_grow.c
++++ b/tools/testing/selftests/bpf/progs/test_xdp_adjust_tail_grow.c
+@@ -7,11 +7,10 @@ int _xdp_adjust_tail_grow(struct xdp_md *xdp)
+ {
+ void *data_end = (void *)(long)xdp->data_end;
+ void *data = (void *)(long)xdp->data;
+- unsigned int data_len;
++ int data_len = bpf_xdp_get_buff_len(xdp);
+ int offset = 0;
+
+ /* Data length determine test case */
+- data_len = data_end - data;
+
+ if (data_len == 54) { /* sizeof(pkt_v4) */
+ offset = 4096; /* test too large offset */
+@@ -20,7 +19,12 @@ int _xdp_adjust_tail_grow(struct xdp_md *xdp)
+ } else if (data_len == 64) {
+ offset = 128;
+ } else if (data_len == 128) {
+- offset = 4096 - 256 - 320 - data_len; /* Max tail grow 3520 */
++ /* Max tail grow 3520 */
++ offset = 4096 - 256 - 320 - data_len;
++ } else if (data_len == 9000) {
++ offset = 10;
++ } else if (data_len == 9001) {
++ offset = 4096;
+ } else {
+ return XDP_ABORTED; /* No matching test */
}
-
-- /* XDP have extra tailroom as (most) drivers use full page */
- max_data_sz = 4096 - headroom - tailroom;
-+ size = min_t(u32, size, max_data_sz);
-
-- data = bpf_test_init(kattr, kattr->test.data_size_in,
-- max_data_sz, headroom, tailroom);
-+ data = bpf_test_init(kattr, size, max_data_sz, headroom, tailroom);
- if (IS_ERR(data)) {
- ret = PTR_ERR(data);
- goto free_ctx;
-@@ -792,11 +791,45 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
- xdp_init_buff(&xdp, headroom + max_data_sz + tailroom,
- &rxqueue->xdp_rxq);
- xdp_prepare_buff(&xdp, data, headroom, size, true);
-+ sinfo = xdp_get_shared_info_from_buff(&xdp);
-
- ret = xdp_convert_md_to_buff(ctx, &xdp);
- if (ret)
- goto free_data;
-
-+ if (unlikely(kattr->test.data_size_in > size)) {
-+ void __user *data_in = u64_to_user_ptr(kattr->test.data_in);
-+
-+ while (size < kattr->test.data_size_in) {
-+ struct page *page;
-+ skb_frag_t *frag;
-+ int data_len;
-+
-+ page = alloc_page(GFP_KERNEL);
-+ if (!page) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ frag = &sinfo->frags[sinfo->nr_frags++];
-+ __skb_frag_set_page(frag, page);
-+
-+ data_len = min_t(int, kattr->test.data_size_in - size,
-+ PAGE_SIZE);
-+ skb_frag_size_set(frag, data_len);
-+
-+ if (copy_from_user(page_address(page), data_in + size,
-+ data_len)) {
-+ ret = -EFAULT;
-+ goto out;
-+ }
-+ sinfo->xdp_frags_tsize += PAGE_SIZE;
-+ sinfo->xdp_frags_size += data_len;
-+ size += data_len;
+diff --git a/tools/testing/selftests/bpf/progs/test_xdp_adjust_tail_shrink.c b/tools/testing/selftests/bpf/progs/test_xdp_adjust_tail_shrink.c
+index 22065a9cfb25..64177597ac29 100644
+--- a/tools/testing/selftests/bpf/progs/test_xdp_adjust_tail_shrink.c
++++ b/tools/testing/selftests/bpf/progs/test_xdp_adjust_tail_shrink.c
+@@ -14,14 +14,38 @@ int _version SEC("version") = 1;
+ SEC("xdp_adjust_tail_shrink")
+ int _xdp_adjust_tail_shrink(struct xdp_md *xdp)
+ {
+- void *data_end = (void *)(long)xdp->data_end;
+- void *data = (void *)(long)xdp->data;
++ __u8 *data_end = (void *)(long)xdp->data_end;
++ __u8 *data = (void *)(long)xdp->data;
+ int offset = 0;
+
+- if (data_end - data == 54) /* sizeof(pkt_v4) */
++ switch (bpf_xdp_get_buff_len(xdp)) {
++ case 54:
++ /* sizeof(pkt_v4) */
+ offset = 256; /* shrink too much */
+- else
++ break;
++ case 9000:
++ /* Multi-buffer test cases */
++ if (data + 1 > data_end)
++ return XDP_DROP;
++
++ switch (data[0]) {
++ case 0:
++ offset = 10;
++ break;
++ case 1:
++ offset = 4100;
++ break;
++ case 2:
++ offset = 8200;
++ break;
++ default:
++ return XDP_DROP;
+ }
-+ xdp_buff_set_mb(&xdp);
++ break;
++ default:
+ offset = 20;
++ break;
+ }
-+
- bpf_prog_change_xdp(NULL, prog);
- ret = bpf_test_run(prog, &xdp, repeat, &retval, &duration, true);
- /* We convert the xdp_buff back to an xdp_md before checking the return
-@@ -807,10 +840,7 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
- if (ret)
- goto out;
-
-- if (xdp.data_meta != data + headroom ||
-- xdp.data_end != xdp.data_meta + size)
-- size = xdp.data_end - xdp.data_meta;
--
-+ size = xdp.data_end - xdp.data_meta + sinfo->xdp_frags_size;
- ret = bpf_test_finish(kattr, uattr, xdp.data_meta, size, retval,
- duration);
- if (!ret)
-@@ -820,6 +850,8 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
- out:
- bpf_prog_change_xdp(prog, NULL);
- free_data:
-+ for (i = 0; i < sinfo->nr_frags; i++)
-+ __free_page(skb_frag_page(&sinfo->frags[i]));
- kfree(data);
- free_ctx:
- kfree(ctx);
+ if (bpf_xdp_adjust_tail(xdp, 0 - offset))
+ return XDP_DROP;
+ return XDP_TX;
--
2.31.1