Add a test using large chunks for zcrx memory area.

Signed-off-by: Pavel Begunkov <[email protected]>
---
 .../selftests/drivers/net/hw/iou-zcrx.c       | 72 +++++++++++++++----
 .../selftests/drivers/net/hw/iou-zcrx.py      | 37 ++++++++++
 2 files changed, 97 insertions(+), 12 deletions(-)

diff --git a/tools/testing/selftests/drivers/net/hw/iou-zcrx.c 
b/tools/testing/selftests/drivers/net/hw/iou-zcrx.c
index 62456df947bc..0a19b573f4f5 100644
--- a/tools/testing/selftests/drivers/net/hw/iou-zcrx.c
+++ b/tools/testing/selftests/drivers/net/hw/iou-zcrx.c
@@ -12,6 +12,7 @@
 #include <unistd.h>
 
 #include <arpa/inet.h>
+#include <linux/mman.h>
 #include <linux/errqueue.h>
 #include <linux/if_packet.h>
 #include <linux/ipv6.h>
@@ -37,6 +38,23 @@
 
 #include <liburing.h>
 
+#define SKIP_CODE      42
+
+struct t_io_uring_zcrx_ifq_reg {
+       __u32   if_idx;
+       __u32   if_rxq;
+       __u32   rq_entries;
+       __u32   flags;
+
+       __u64   area_ptr; /* pointer to struct io_uring_zcrx_area_reg */
+       __u64   region_ptr; /* struct io_uring_region_desc * */
+
+       struct io_uring_zcrx_offsets offsets;
+       __u32   zcrx_id;
+       __u32   rx_buf_len;
+       __u64   __resv[3];
+};
+
 static long page_size;
 #define AREA_SIZE (8192 * page_size)
 #define SEND_SIZE (512 * 4096)
@@ -65,6 +83,8 @@ static bool cfg_oneshot;
 static int cfg_oneshot_recvs;
 static int cfg_send_size = SEND_SIZE;
 static struct sockaddr_in6 cfg_addr;
+static unsigned cfg_rx_buf_len;
+static bool cfg_dry_run;
 
 static char *payload;
 static void *area_ptr;
@@ -128,14 +148,28 @@ static void setup_zcrx(struct io_uring *ring)
        if (!ifindex)
                error(1, 0, "bad interface name: %s", cfg_ifname);
 
-       area_ptr = mmap(NULL,
-                       AREA_SIZE,
-                       PROT_READ | PROT_WRITE,
-                       MAP_ANONYMOUS | MAP_PRIVATE,
-                       0,
-                       0);
-       if (area_ptr == MAP_FAILED)
-               error(1, 0, "mmap(): zero copy area");
+       if (cfg_rx_buf_len && cfg_rx_buf_len != page_size) {
+               area_ptr = mmap(NULL,
+                               AREA_SIZE,
+                               PROT_READ | PROT_WRITE,
+                               MAP_ANONYMOUS | MAP_PRIVATE |
+                               MAP_HUGETLB | MAP_HUGE_2MB,
+                               -1,
+                               0);
+               if (area_ptr == MAP_FAILED) {
+                       printf("Can't allocate huge pages\n");
+                       exit(SKIP_CODE);
+               }
+       } else {
+               area_ptr = mmap(NULL,
+                               AREA_SIZE,
+                               PROT_READ | PROT_WRITE,
+                               MAP_ANONYMOUS | MAP_PRIVATE,
+                               0,
+                               0);
+               if (area_ptr == MAP_FAILED)
+                       error(1, 0, "mmap(): zero copy area");
+       }
 
        ring_size = get_refill_ring_size(rq_entries);
        ring_ptr = mmap(NULL,
@@ -157,17 +191,23 @@ static void setup_zcrx(struct io_uring *ring)
                .flags = 0,
        };
 
-       struct io_uring_zcrx_ifq_reg reg = {
+       struct t_io_uring_zcrx_ifq_reg reg = {
                .if_idx = ifindex,
                .if_rxq = cfg_queue_id,
                .rq_entries = rq_entries,
                .area_ptr = (__u64)(unsigned long)&area_reg,
                .region_ptr = (__u64)(unsigned long)&region_reg,
+               .rx_buf_len = cfg_rx_buf_len,
        };
 
-       ret = io_uring_register_ifq(ring, &reg);
-       if (ret)
+       ret = io_uring_register_ifq(ring, (void *)&reg);
+       if (cfg_rx_buf_len && (ret == -EINVAL || ret == -EOPNOTSUPP ||
+                              ret == -ERANGE)) {
+               printf("Large chunks are not supported %i\n", ret);
+               exit(SKIP_CODE);
+       } else if (ret) {
                error(1, 0, "io_uring_register_ifq(): %d", ret);
+       }
 
        rq_ring.khead = (unsigned int *)((char *)ring_ptr + reg.offsets.head);
        rq_ring.ktail = (unsigned int *)((char *)ring_ptr + reg.offsets.tail);
@@ -323,6 +363,8 @@ static void run_server(void)
        io_uring_queue_init(512, &ring, flags);
 
        setup_zcrx(&ring);
+       if (cfg_dry_run)
+               return;
 
        add_accept(&ring, fd);
 
@@ -383,7 +425,7 @@ static void parse_opts(int argc, char **argv)
                usage(argv[0]);
        cfg_payload_len = max_payload_len;
 
-       while ((c = getopt(argc, argv, "sch:p:l:i:q:o:z:")) != -1) {
+       while ((c = getopt(argc, argv, "sch:p:l:i:q:o:z:x:d")) != -1) {
                switch (c) {
                case 's':
                        if (cfg_client)
@@ -418,6 +460,12 @@ static void parse_opts(int argc, char **argv)
                case 'z':
                        cfg_send_size = strtoul(optarg, NULL, 0);
                        break;
+               case 'x':
+                       cfg_rx_buf_len = page_size * strtoul(optarg, NULL, 0);
+                       break;
+               case 'd':
+                       cfg_dry_run = true;
+                       break;
                }
        }
 
diff --git a/tools/testing/selftests/drivers/net/hw/iou-zcrx.py 
b/tools/testing/selftests/drivers/net/hw/iou-zcrx.py
index 712c806508b5..83061b27f2f2 100755
--- a/tools/testing/selftests/drivers/net/hw/iou-zcrx.py
+++ b/tools/testing/selftests/drivers/net/hw/iou-zcrx.py
@@ -7,6 +7,7 @@ from lib.py import ksft_run, ksft_exit, KsftSkipEx
 from lib.py import NetDrvEpEnv
 from lib.py import bkg, cmd, defer, ethtool, rand_port, wait_port_listen
 
+SKIP_CODE = 42
 
 def _get_current_settings(cfg):
     output = ethtool(f"-g {cfg.ifname}", json=True)[0]
@@ -132,6 +133,42 @@ def test_zcrx_rss(cfg) -> None:
         cmd(tx_cmd, host=cfg.remote)
 
 
+def test_zcrx_large_chunks(cfg) -> None:
+    cfg.require_ipver('6')
+
+    combined_chans = _get_combined_channels(cfg)
+    if combined_chans < 2:
+        raise KsftSkipEx('at least 2 combined channels required')
+    (rx_ring, hds_thresh) = _get_current_settings(cfg)
+    port = rand_port()
+
+    ethtool(f"-G {cfg.ifname} tcp-data-split on")
+    defer(ethtool, f"-G {cfg.ifname} tcp-data-split auto")
+
+    ethtool(f"-G {cfg.ifname} hds-thresh 0")
+    defer(ethtool, f"-G {cfg.ifname} hds-thresh {hds_thresh}")
+
+    ethtool(f"-G {cfg.ifname} rx 64")
+    defer(ethtool, f"-G {cfg.ifname} rx {rx_ring}")
+
+    ethtool(f"-X {cfg.ifname} equal {combined_chans - 1}")
+    defer(ethtool, f"-X {cfg.ifname} default")
+
+    flow_rule_id = _set_flow_rule(cfg, port, combined_chans - 1)
+    defer(ethtool, f"-N {cfg.ifname} delete {flow_rule_id}")
+
+    rx_cmd = f"{cfg.bin_local} -s -p {port} -i {cfg.ifname} -q {combined_chans 
- 1} -x 2"
+    tx_cmd = f"{cfg.bin_remote} -c -h {cfg.addr_v['6']} -p {port} -l 12840"
+
+    probe = cmd(rx_cmd + " -d", fail=False)
+    if probe.ret == SKIP_CODE:
+        raise KsftSkipEx(probe.stdout)
+
+    with bkg(rx_cmd, exit_wait=True):
+        wait_port_listen(port, proto="tcp")
+        cmd(tx_cmd, host=cfg.remote)
+
+
 def main() -> None:
     with NetDrvEpEnv(__file__) as cfg:
         cfg.bin_local = path.abspath(path.dirname(__file__) + 
"/../../../drivers/net/hw/iou-zcrx")
-- 
2.52.0


Reply via email to