--- v16
+++ v9
@@ -1,58 +1,215 @@
-Rely on data_size_in in bpf_test_init routine signature. This is a
-preliminary patch to introduce xdp multi-buff selftest
-
+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 | 13 +++++++------
- 1 file changed, 7 insertions(+), 6 deletions(-)
-
-diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
-index 529608784aa8..89263bcb33b2 100644
---- a/net/bpf/test_run.c
-+++ b/net/bpf/test_run.c
-@@ -249,11 +249,10 @@ bool bpf_prog_test_check_kfunc_call(u32 kfunc_id, struct module *owner)
- return bpf_check_mod_kfunc_call(&prog_test_kfunc_list, kfunc_id, owner);
+ .../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);
}
--static void *bpf_test_init(const union bpf_attr *kattr, u32 size,
-- u32 headroom, u32 tailroom)
-+static void *bpf_test_init(const union bpf_attr *kattr, u32 user_size,
-+ u32 size, u32 headroom, u32 tailroom)
++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)
{
- void __user *data_in = u64_to_user_ptr(kattr->test.data_in);
-- u32 user_size = kattr->test.data_size_in;
- void *data;
-
- if (size < ETH_HLEN || size > PAGE_SIZE - headroom - tailroom)
-@@ -586,7 +585,8 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
- if (kattr->test.flags || kattr->test.cpu)
- return -EINVAL;
-
-- data = bpf_test_init(kattr, size, NET_SKB_PAD + NET_IP_ALIGN,
-+ data = bpf_test_init(kattr, kattr->test.data_size_in,
-+ size, NET_SKB_PAD + NET_IP_ALIGN,
- SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
- if (IS_ERR(data))
- return PTR_ERR(data);
-@@ -795,7 +795,8 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
- /* XDP have extra tailroom as (most) drivers use full page */
- max_data_sz = 4096 - headroom - tailroom;
-
-- data = bpf_test_init(kattr, max_data_sz, headroom, tailroom);
-+ data = bpf_test_init(kattr, kattr->test.data_size_in,
-+ max_data_sz, headroom, tailroom);
- if (IS_ERR(data)) {
- ret = PTR_ERR(data);
- goto free_ctx;
-@@ -881,7 +882,7 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
- if (size < ETH_HLEN)
- return -EINVAL;
-
-- data = bpf_test_init(kattr, size, 0, 0);
-+ data = bpf_test_init(kattr, kattr->test.data_size_in, size, 0, 0);
- if (IS_ERR(data))
- return PTR_ERR(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 */
+ }
+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;
++ }
++ break;
++ default:
+ offset = 20;
++ break;
++ }
+ if (bpf_xdp_adjust_tail(xdp, 0 - offset))
+ return XDP_DROP;
+ return XDP_TX;
--
2.31.1