1212#include <unistd.h>
1313
1414#include <arpa/inet.h>
15+ #include <linux/mman.h>
1516#include <linux/errqueue.h>
1617#include <linux/if_packet.h>
1718#include <linux/ipv6.h>
3738
3839#include <liburing.h>
3940
41+ #define SKIP_CODE 42
42+
43+ struct t_io_uring_zcrx_ifq_reg {
44+ __u32 if_idx ;
45+ __u32 if_rxq ;
46+ __u32 rq_entries ;
47+ __u32 flags ;
48+
49+ __u64 area_ptr ; /* pointer to struct io_uring_zcrx_area_reg */
50+ __u64 region_ptr ; /* struct io_uring_region_desc * */
51+
52+ struct io_uring_zcrx_offsets offsets ;
53+ __u32 zcrx_id ;
54+ __u32 rx_buf_len ;
55+ __u64 __resv [3 ];
56+ };
57+
4058static long page_size ;
4159#define AREA_SIZE (8192 * page_size)
4260#define SEND_SIZE (512 * 4096)
@@ -65,6 +83,8 @@ static bool cfg_oneshot;
6583static int cfg_oneshot_recvs ;
6684static int cfg_send_size = SEND_SIZE ;
6785static struct sockaddr_in6 cfg_addr ;
86+ static unsigned int cfg_rx_buf_len ;
87+ static bool cfg_dry_run ;
6888
6989static char * payload ;
7090static void * area_ptr ;
@@ -128,14 +148,28 @@ static void setup_zcrx(struct io_uring *ring)
128148 if (!ifindex )
129149 error (1 , 0 , "bad interface name: %s" , cfg_ifname );
130150
131- area_ptr = mmap (NULL ,
132- AREA_SIZE ,
133- PROT_READ | PROT_WRITE ,
134- MAP_ANONYMOUS | MAP_PRIVATE ,
135- 0 ,
136- 0 );
137- if (area_ptr == MAP_FAILED )
138- error (1 , 0 , "mmap(): zero copy area" );
151+ if (cfg_rx_buf_len && cfg_rx_buf_len != page_size ) {
152+ area_ptr = mmap (NULL ,
153+ AREA_SIZE ,
154+ PROT_READ | PROT_WRITE ,
155+ MAP_ANONYMOUS | MAP_PRIVATE |
156+ MAP_HUGETLB | MAP_HUGE_2MB ,
157+ -1 ,
158+ 0 );
159+ if (area_ptr == MAP_FAILED ) {
160+ printf ("Can't allocate huge pages\n" );
161+ exit (SKIP_CODE );
162+ }
163+ } else {
164+ area_ptr = mmap (NULL ,
165+ AREA_SIZE ,
166+ PROT_READ | PROT_WRITE ,
167+ MAP_ANONYMOUS | MAP_PRIVATE ,
168+ 0 ,
169+ 0 );
170+ if (area_ptr == MAP_FAILED )
171+ error (1 , 0 , "mmap(): zero copy area" );
172+ }
139173
140174 ring_size = get_refill_ring_size (rq_entries );
141175 ring_ptr = mmap (NULL ,
@@ -157,17 +191,23 @@ static void setup_zcrx(struct io_uring *ring)
157191 .flags = 0 ,
158192 };
159193
160- struct io_uring_zcrx_ifq_reg reg = {
194+ struct t_io_uring_zcrx_ifq_reg reg = {
161195 .if_idx = ifindex ,
162196 .if_rxq = cfg_queue_id ,
163197 .rq_entries = rq_entries ,
164198 .area_ptr = (__u64 )(unsigned long )& area_reg ,
165199 .region_ptr = (__u64 )(unsigned long )& region_reg ,
200+ .rx_buf_len = cfg_rx_buf_len ,
166201 };
167202
168- ret = io_uring_register_ifq (ring , & reg );
169- if (ret )
203+ ret = io_uring_register_ifq (ring , (void * )& reg );
204+ if (cfg_rx_buf_len && (ret == - EINVAL || ret == - EOPNOTSUPP ||
205+ ret == - ERANGE )) {
206+ printf ("Large chunks are not supported %i\n" , ret );
207+ exit (SKIP_CODE );
208+ } else if (ret ) {
170209 error (1 , 0 , "io_uring_register_ifq(): %d" , ret );
210+ }
171211
172212 rq_ring .khead = (unsigned int * )((char * )ring_ptr + reg .offsets .head );
173213 rq_ring .ktail = (unsigned int * )((char * )ring_ptr + reg .offsets .tail );
@@ -323,6 +363,8 @@ static void run_server(void)
323363 io_uring_queue_init (512 , & ring , flags );
324364
325365 setup_zcrx (& ring );
366+ if (cfg_dry_run )
367+ return ;
326368
327369 add_accept (& ring , fd );
328370
@@ -383,7 +425,7 @@ static void parse_opts(int argc, char **argv)
383425 usage (argv [0 ]);
384426 cfg_payload_len = max_payload_len ;
385427
386- while ((c = getopt (argc , argv , "sch:p:l:i:q:o:z:" )) != -1 ) {
428+ while ((c = getopt (argc , argv , "sch:p:l:i:q:o:z:x:d " )) != -1 ) {
387429 switch (c ) {
388430 case 's' :
389431 if (cfg_client )
@@ -418,6 +460,12 @@ static void parse_opts(int argc, char **argv)
418460 case 'z' :
419461 cfg_send_size = strtoul (optarg , NULL , 0 );
420462 break ;
463+ case 'x' :
464+ cfg_rx_buf_len = page_size * strtoul (optarg , NULL , 0 );
465+ break ;
466+ case 'd' :
467+ cfg_dry_run = true;
468+ break ;
421469 }
422470 }
423471
0 commit comments