uringmachine 0.8.2 → 0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/TODO.md +0 -1
- data/examples/bm_side_running.rb +83 -0
- data/examples/bm_sqlite.rb +1 -1
- data/ext/um/um.c +66 -4
- data/ext/um/um.h +36 -0
- data/ext/um/um_class.c +6 -0
- data/ext/um/um_const.c +36 -0
- data/ext/um/um_ext.c +2 -0
- data/ext/um/um_stream.c +344 -0
- data/ext/um/um_stream_class.c +140 -0
- data/ext/um/um_utils.c +4 -0
- data/lib/uringmachine/actor.rb +1 -1
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +35 -17
- data/test/test_fiber.rb +23 -3
- data/test/test_stream.rb +133 -0
- data/test/test_um.rb +109 -2
- data/uringmachine.gemspec +0 -2
- data/vendor/liburing/.github/workflows/{build.yml → ci.yml} +107 -42
- data/vendor/liburing/.gitignore +1 -0
- data/vendor/liburing/CHANGELOG +10 -0
- data/vendor/liburing/README +5 -0
- data/vendor/liburing/configure +1 -1
- data/vendor/liburing/examples/Makefile +1 -0
- data/vendor/liburing/examples/helpers.c +25 -0
- data/vendor/liburing/examples/helpers.h +13 -0
- data/vendor/liburing/examples/io_uring-test.c +3 -0
- data/vendor/liburing/examples/proxy.c +1 -1
- data/vendor/liburing/examples/reg-wait.c +41 -6
- data/vendor/liburing/examples/send-zerocopy.c +79 -32
- data/vendor/liburing/examples/zcrx.c +436 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/src/Makefile +0 -1
- data/vendor/liburing/src/arch/generic/syscall.h +2 -2
- data/vendor/liburing/src/arch/syscall-defs.h +2 -2
- data/vendor/liburing/src/include/liburing/io_uring.h +101 -17
- data/vendor/liburing/src/include/liburing.h +179 -59
- data/vendor/liburing/src/int_flags.h +4 -1
- data/vendor/liburing/src/liburing-ffi.map +14 -2
- data/vendor/liburing/src/liburing.map +9 -2
- data/vendor/liburing/src/queue.c +35 -30
- data/vendor/liburing/src/register.c +46 -15
- data/vendor/liburing/src/sanitize.c +6 -9
- data/vendor/liburing/src/setup.c +37 -71
- data/vendor/liburing/src/syscall.c +2 -2
- data/vendor/liburing/test/232c93d07b74.c +1 -0
- data/vendor/liburing/test/Makefile +9 -0
- data/vendor/liburing/test/accept-test.c +1 -0
- data/vendor/liburing/test/cmd-discard.c +16 -8
- data/vendor/liburing/test/connect.c +11 -7
- data/vendor/liburing/test/epwait.c +420 -0
- data/vendor/liburing/test/eventfd-ring.c +30 -5
- data/vendor/liburing/test/fallocate.c +1 -1
- data/vendor/liburing/test/fixed-hugepage.c +10 -7
- data/vendor/liburing/test/fixed-seg.c +187 -0
- data/vendor/liburing/test/helpers.c +121 -0
- data/vendor/liburing/test/helpers.h +13 -0
- data/vendor/liburing/test/init-mem.c +2 -0
- data/vendor/liburing/test/io_uring_passthrough.c +78 -62
- data/vendor/liburing/test/iopoll-overflow.c +5 -4
- data/vendor/liburing/test/iopoll.c +20 -10
- data/vendor/liburing/test/iowait.c +141 -0
- data/vendor/liburing/test/nvme.h +2 -0
- data/vendor/liburing/test/pipe-bug.c +11 -5
- data/vendor/liburing/test/pipe-eof.c +11 -1
- data/vendor/liburing/test/read-inc-file.c +150 -0
- data/vendor/liburing/test/read-write.c +21 -14
- data/vendor/liburing/test/recv-bundle-short-ooo.c +435 -0
- data/vendor/liburing/test/recv-multishot.c +2 -2
- data/vendor/liburing/test/reg-wait.c +449 -120
- data/vendor/liburing/test/regbuf-clone.c +53 -0
- data/vendor/liburing/test/resize-rings.c +25 -2
- data/vendor/liburing/test/rsrc_tags.c +67 -14
- data/vendor/liburing/test/send-zerocopy.c +52 -130
- data/vendor/liburing/test/sendmsg_iov_clean.c +216 -0
- data/vendor/liburing/test/socket-nb.c +158 -0
- data/vendor/liburing/test/sqwait.c +9 -11
- data/vendor/liburing/test/timeout.c +198 -0
- data/vendor/liburing/test/vec-regbuf.c +609 -0
- data/vendor/liburing/test/wait-timeout.c +1 -1
- data/vendor/liburing/test/wq-aff.c +5 -1
- data/vendor/liburing/test/zcrx.c +928 -0
- metadata +16 -32
- data/vendor/liburing/.github/workflows/codespell.yml +0 -25
- data/vendor/liburing/.github/workflows/shellcheck.yml +0 -20
@@ -43,6 +43,8 @@
|
|
43
43
|
|
44
44
|
#include "liburing.h"
|
45
45
|
|
46
|
+
#define PATTERN_SIZE 26
|
47
|
+
|
46
48
|
#define ZC_TAG 0xfffffffULL
|
47
49
|
#define MAX_SUBMIT_NR 512
|
48
50
|
#define MAX_THREADS 100
|
@@ -68,6 +70,7 @@ static bool cfg_defer_taskrun = 0;
|
|
68
70
|
static int cfg_cpu = -1;
|
69
71
|
static bool cfg_rx = 0;
|
70
72
|
static unsigned cfg_nr_threads = 1;
|
73
|
+
static const char *cfg_ifname;
|
71
74
|
|
72
75
|
static int cfg_family = PF_UNSPEC;
|
73
76
|
static int cfg_type = 0;
|
@@ -75,11 +78,12 @@ static int cfg_payload_len;
|
|
75
78
|
static int cfg_port = 8000;
|
76
79
|
static int cfg_runtime_ms = 4200;
|
77
80
|
static bool cfg_rx_poll = false;
|
81
|
+
static bool cfg_verify;
|
78
82
|
|
79
83
|
static socklen_t cfg_alen;
|
80
84
|
static char *str_addr = NULL;
|
81
85
|
|
82
|
-
static char payload_buf[IP_MAXPACKET] __attribute__((aligned(4096)));
|
86
|
+
static char payload_buf[IP_MAXPACKET + PATTERN_SIZE] __attribute__((aligned(4096)));
|
83
87
|
static char *payload;
|
84
88
|
static struct thread_data threads[MAX_THREADS];
|
85
89
|
static pthread_barrier_t barrier;
|
@@ -343,6 +347,16 @@ static void do_tx(struct thread_data *td, int domain, int type, int protocol)
|
|
343
347
|
if (fd == -1)
|
344
348
|
t_error(1, errno, "socket t");
|
345
349
|
|
350
|
+
if (cfg_ifname) {
|
351
|
+
struct ifreq ifr;
|
352
|
+
|
353
|
+
memset(&ifr, 0, sizeof(ifr));
|
354
|
+
strncpy(ifr.ifr_name, cfg_ifname, sizeof(ifr.ifr_name));
|
355
|
+
|
356
|
+
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0)
|
357
|
+
t_error(1, errno, "Binding to device failed\n");
|
358
|
+
}
|
359
|
+
|
346
360
|
if (connect(fd, (void *)&td->dst_addr, cfg_alen))
|
347
361
|
t_error(1, errno, "connect, idx %i", td->idx);
|
348
362
|
|
@@ -365,7 +379,7 @@ static void do_tx(struct thread_data *td, int domain, int type, int protocol)
|
|
365
379
|
}
|
366
380
|
|
367
381
|
iov.iov_base = payload;
|
368
|
-
iov.iov_len = cfg_payload_len;
|
382
|
+
iov.iov_len = cfg_payload_len + PATTERN_SIZE;
|
369
383
|
|
370
384
|
ret = io_uring_register_buffers(&ring, &iov, 1);
|
371
385
|
if (ret)
|
@@ -392,13 +406,18 @@ static void do_tx(struct thread_data *td, int domain, int type, int protocol)
|
|
392
406
|
unsigned msg_flags = MSG_WAITALL;
|
393
407
|
|
394
408
|
for (i = 0; i < cfg_nr_reqs; i++) {
|
409
|
+
char *buf = payload;
|
410
|
+
|
411
|
+
if (cfg_verify && cfg_type == SOCK_STREAM)
|
412
|
+
buf += td->bytes % PATTERN_SIZE;
|
413
|
+
|
395
414
|
sqe = io_uring_get_sqe(&ring);
|
396
415
|
|
397
416
|
if (!cfg_zc)
|
398
|
-
io_uring_prep_send(sqe, fd,
|
417
|
+
io_uring_prep_send(sqe, fd, buf,
|
399
418
|
cfg_payload_len, 0);
|
400
419
|
else {
|
401
|
-
io_uring_prep_send_zc(sqe, fd,
|
420
|
+
io_uring_prep_send_zc(sqe, fd, buf,
|
402
421
|
cfg_payload_len, msg_flags, 0);
|
403
422
|
if (cfg_fixed_buf) {
|
404
423
|
sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
|
@@ -439,7 +458,7 @@ static void do_tx(struct thread_data *td, int domain, int type, int protocol)
|
|
439
458
|
td->bytes += cqe->res;
|
440
459
|
} else if (cqe->res == -ECONNREFUSED || cqe->res == -EPIPE ||
|
441
460
|
cqe->res == -ECONNRESET) {
|
442
|
-
|
461
|
+
printf("Connection failure %i\n", cqe->res);
|
443
462
|
goto out_fail;
|
444
463
|
} else if (cqe->res != -EAGAIN) {
|
445
464
|
t_error(1, cqe->res, "send failed");
|
@@ -450,9 +469,9 @@ static void do_tx(struct thread_data *td, int domain, int type, int protocol)
|
|
450
469
|
break;
|
451
470
|
} while ((++loop % 16 != 0) || gettimeofday_ms() < tstart + cfg_runtime_ms);
|
452
471
|
|
472
|
+
out_fail:
|
453
473
|
td->dt_ms = gettimeofday_ms() - tstart;
|
454
474
|
|
455
|
-
out_fail:
|
456
475
|
shutdown(fd, SHUT_RDWR);
|
457
476
|
if (close(fd))
|
458
477
|
t_error(1, errno, "close");
|
@@ -488,7 +507,6 @@ static void usage(const char *filepath)
|
|
488
507
|
printf(" -D <address>\tDestination address\n");
|
489
508
|
printf(" -p <port>\tServer port to listen on/connect to\n");
|
490
509
|
printf(" -s <size>\tBytes per request\n");
|
491
|
-
printf(" -s <size>\tBytes per request\n");
|
492
510
|
printf(" -n <nr>\tNumber of parallel requests\n");
|
493
511
|
printf(" -z <mode>\tZerocopy mode, 0 to disable, enabled otherwise\n");
|
494
512
|
printf(" -b <mode>\tUse registered buffers\n");
|
@@ -502,6 +520,7 @@ static void usage(const char *filepath)
|
|
502
520
|
|
503
521
|
static void parse_opts(int argc, char **argv)
|
504
522
|
{
|
523
|
+
const char *cfg_test;
|
505
524
|
const int max_payload_len = IP_MAXPACKET -
|
506
525
|
sizeof(struct ipv6hdr) -
|
507
526
|
sizeof(struct tcphdr) -
|
@@ -516,7 +535,7 @@ static void parse_opts(int argc, char **argv)
|
|
516
535
|
|
517
536
|
cfg_payload_len = max_payload_len;
|
518
537
|
|
519
|
-
while ((c = getopt(argc, argv, "46D:p:s:t:n:z:b:l:dC:T:
|
538
|
+
while ((c = getopt(argc, argv, "46D:p:s:t:n:z:I:b:l:dC:T:Ryv")) != -1) {
|
520
539
|
switch (c) {
|
521
540
|
case '4':
|
522
541
|
if (cfg_family != PF_UNSPEC)
|
@@ -530,6 +549,9 @@ static void parse_opts(int argc, char **argv)
|
|
530
549
|
cfg_family = PF_INET6;
|
531
550
|
cfg_alen = sizeof(struct sockaddr_in6);
|
532
551
|
break;
|
552
|
+
case 'I':
|
553
|
+
cfg_ifname = optarg;
|
554
|
+
break;
|
533
555
|
case 'D':
|
534
556
|
daddr = optarg;
|
535
557
|
break;
|
@@ -568,16 +590,38 @@ static void parse_opts(int argc, char **argv)
|
|
568
590
|
case 'R':
|
569
591
|
cfg_rx = 1;
|
570
592
|
break;
|
593
|
+
case 'v':
|
594
|
+
cfg_verify = true;
|
595
|
+
break;
|
571
596
|
case 'y':
|
572
597
|
cfg_rx_poll = 1;
|
573
598
|
break;
|
574
599
|
}
|
575
600
|
}
|
576
601
|
|
602
|
+
cfg_test = argv[argc - 1];
|
603
|
+
if (!strcmp(cfg_test, "tcp"))
|
604
|
+
cfg_type = SOCK_STREAM;
|
605
|
+
else if (!strcmp(cfg_test, "udp"))
|
606
|
+
cfg_type = SOCK_DGRAM;
|
607
|
+
else
|
608
|
+
t_error(1, 0, "unknown cfg_test %s", cfg_test);
|
609
|
+
|
577
610
|
if (cfg_nr_reqs > MAX_SUBMIT_NR)
|
578
611
|
t_error(1, 0, "-n: submit batch nr exceeds max (%d)", MAX_SUBMIT_NR);
|
579
612
|
if (cfg_payload_len > max_payload_len)
|
580
613
|
t_error(1, 0, "-s: payload exceeds max (%d)", max_payload_len);
|
614
|
+
if (!cfg_nr_reqs)
|
615
|
+
t_error(1, 0, "-n: submit batch can't be zero");
|
616
|
+
if (cfg_ifname && cfg_rx)
|
617
|
+
t_error(1, 0, "Interface can only be specified for tx");
|
618
|
+
if (cfg_nr_reqs > 1 && cfg_type == SOCK_STREAM) {
|
619
|
+
printf("warning: submit batching >1 with TCP sockets will cause data reordering");
|
620
|
+
if (cfg_verify)
|
621
|
+
t_error(1, 0, "can't verify data because of reordering");
|
622
|
+
}
|
623
|
+
if (cfg_rx && cfg_verify)
|
624
|
+
t_error(1, 0, "Server mode doesn't support data verification");
|
581
625
|
|
582
626
|
str_addr = daddr;
|
583
627
|
|
@@ -585,42 +629,45 @@ static void parse_opts(int argc, char **argv)
|
|
585
629
|
usage(argv[0]);
|
586
630
|
}
|
587
631
|
|
632
|
+
static void init_buffers(void)
|
633
|
+
{
|
634
|
+
size_t size;
|
635
|
+
int i;
|
636
|
+
|
637
|
+
payload = payload_buf;
|
638
|
+
size = sizeof(payload_buf);
|
639
|
+
|
640
|
+
if (cfg_hugetlb) {
|
641
|
+
size = 1 << 21;
|
642
|
+
payload = mmap(NULL, size, PROT_READ | PROT_WRITE,
|
643
|
+
MAP_PRIVATE | MAP_HUGETLB | MAP_HUGE_2MB | MAP_ANONYMOUS,
|
644
|
+
-1, 0);
|
645
|
+
if (payload == MAP_FAILED)
|
646
|
+
t_error(0, 1, "huge pages alloc failed");
|
647
|
+
}
|
648
|
+
|
649
|
+
if (cfg_payload_len + PATTERN_SIZE > size)
|
650
|
+
t_error(1, 0, "Buffers are too small");
|
651
|
+
|
652
|
+
if (cfg_verify) {
|
653
|
+
for (i = 0; i < size; i++)
|
654
|
+
payload[i] = 'a' + (i % PATTERN_SIZE);
|
655
|
+
}
|
656
|
+
}
|
657
|
+
|
588
658
|
int main(int argc, char **argv)
|
589
659
|
{
|
590
660
|
unsigned long long tsum = 0;
|
591
661
|
unsigned long long packets = 0, bytes = 0;
|
592
662
|
struct thread_data *td;
|
593
|
-
const char *cfg_test;
|
594
663
|
unsigned int i;
|
595
664
|
void *res;
|
596
665
|
|
597
666
|
parse_opts(argc, argv);
|
667
|
+
init_buffers();
|
598
668
|
set_cpu_affinity();
|
599
669
|
|
600
|
-
payload = payload_buf;
|
601
|
-
if (cfg_hugetlb) {
|
602
|
-
payload = mmap(NULL, 2*1024*1024, PROT_READ | PROT_WRITE,
|
603
|
-
MAP_PRIVATE | MAP_HUGETLB | MAP_HUGE_2MB | MAP_ANONYMOUS,
|
604
|
-
-1, 0);
|
605
|
-
if (payload == MAP_FAILED) {
|
606
|
-
fprintf(stderr, "hugetlb alloc failed\n");
|
607
|
-
return 1;
|
608
|
-
}
|
609
|
-
}
|
610
|
-
|
611
|
-
cfg_test = argv[argc - 1];
|
612
|
-
if (!strcmp(cfg_test, "tcp"))
|
613
|
-
cfg_type = SOCK_STREAM;
|
614
|
-
else if (!strcmp(cfg_test, "udp"))
|
615
|
-
cfg_type = SOCK_DGRAM;
|
616
|
-
else
|
617
|
-
t_error(1, 0, "unknown cfg_test %s", cfg_test);
|
618
|
-
|
619
670
|
pthread_barrier_init(&barrier, NULL, cfg_nr_threads);
|
620
|
-
|
621
|
-
for (i = 0; i < IP_MAXPACKET; i++)
|
622
|
-
payload[i] = 'a' + (i % 26);
|
623
|
-
|
624
671
|
for (i = 0; i < cfg_nr_threads; i++) {
|
625
672
|
td = &threads[i];
|
626
673
|
td->idx = i;
|
@@ -0,0 +1,436 @@
|
|
1
|
+
// SPDX-License-Identifier: GPL-2.0
|
2
|
+
#include <assert.h>
|
3
|
+
#include <errno.h>
|
4
|
+
#include <error.h>
|
5
|
+
#include <fcntl.h>
|
6
|
+
#include <limits.h>
|
7
|
+
#include <stdbool.h>
|
8
|
+
#include <stdint.h>
|
9
|
+
#include <stdio.h>
|
10
|
+
#include <stdlib.h>
|
11
|
+
#include <string.h>
|
12
|
+
#include <unistd.h>
|
13
|
+
#include <stdarg.h>
|
14
|
+
|
15
|
+
#include <arpa/inet.h>
|
16
|
+
#include <linux/errqueue.h>
|
17
|
+
#include <linux/if_packet.h>
|
18
|
+
#include <linux/ipv6.h>
|
19
|
+
#include <linux/socket.h>
|
20
|
+
#include <linux/sockios.h>
|
21
|
+
#include <net/ethernet.h>
|
22
|
+
#include <net/if.h>
|
23
|
+
#include <netinet/in.h>
|
24
|
+
#include <netinet/ip.h>
|
25
|
+
#include <netinet/ip6.h>
|
26
|
+
#include <netinet/tcp.h>
|
27
|
+
#include <netinet/udp.h>
|
28
|
+
#include <sys/epoll.h>
|
29
|
+
#include <sys/ioctl.h>
|
30
|
+
#include <sys/mman.h>
|
31
|
+
#include <sys/resource.h>
|
32
|
+
#include <sys/socket.h>
|
33
|
+
#include <sys/stat.h>
|
34
|
+
#include <sys/time.h>
|
35
|
+
#include <sys/types.h>
|
36
|
+
#include <sys/un.h>
|
37
|
+
#include <sys/wait.h>
|
38
|
+
#include <linux/mman.h>
|
39
|
+
|
40
|
+
#include <linux/memfd.h>
|
41
|
+
#include <linux/dma-buf.h>
|
42
|
+
#include <linux/udmabuf.h>
|
43
|
+
|
44
|
+
#include "liburing.h"
|
45
|
+
#include "helpers.h"
|
46
|
+
|
47
|
+
enum {
|
48
|
+
RQ_ALLOC_USER,
|
49
|
+
RQ_ALLOC_KERNEL,
|
50
|
+
|
51
|
+
__RQ_ALLOC_MAX,
|
52
|
+
};
|
53
|
+
|
54
|
+
static long page_size;
|
55
|
+
#define AREA_SIZE (8192 * page_size)
|
56
|
+
|
57
|
+
#define REQ_TYPE_SHIFT 3
|
58
|
+
#define REQ_TYPE_MASK ((1UL << REQ_TYPE_SHIFT) - 1)
|
59
|
+
|
60
|
+
enum {
|
61
|
+
AREA_TYPE_NORMAL,
|
62
|
+
AREA_TYPE_HUGE_PAGES,
|
63
|
+
AREA_TYPE_DMABUF,
|
64
|
+
__AREA_TYPE_MAX,
|
65
|
+
};
|
66
|
+
|
67
|
+
enum {
|
68
|
+
REQ_TYPE_ACCEPT = 1,
|
69
|
+
REQ_TYPE_RX = 2,
|
70
|
+
};
|
71
|
+
|
72
|
+
static int cfg_port = 8000;
|
73
|
+
static const char *cfg_ifname;
|
74
|
+
static int cfg_queue_id = -1;
|
75
|
+
static bool cfg_verify_data = false;
|
76
|
+
static size_t cfg_size = 0;
|
77
|
+
static unsigned cfg_rq_alloc_mode = RQ_ALLOC_USER;
|
78
|
+
static unsigned cfg_area_type = AREA_TYPE_NORMAL;
|
79
|
+
static struct sockaddr_in6 cfg_addr;
|
80
|
+
|
81
|
+
static void *area_ptr;
|
82
|
+
static void *ring_ptr;
|
83
|
+
static size_t ring_size;
|
84
|
+
static struct io_uring_zcrx_rq rq_ring;
|
85
|
+
static unsigned long area_token;
|
86
|
+
static int connfd;
|
87
|
+
static bool stop;
|
88
|
+
static size_t received;
|
89
|
+
static __u32 zcrx_id;
|
90
|
+
|
91
|
+
static int dmabuf_fd;
|
92
|
+
static int memfd;
|
93
|
+
|
94
|
+
static inline size_t get_refill_ring_size(unsigned int rq_entries)
|
95
|
+
{
|
96
|
+
ring_size = rq_entries * sizeof(struct io_uring_zcrx_rqe);
|
97
|
+
/* add space for the header (head/tail/etc.) */
|
98
|
+
ring_size += page_size;
|
99
|
+
return T_ALIGN_UP(ring_size, page_size);
|
100
|
+
}
|
101
|
+
|
102
|
+
static void zcrx_populate_area_udmabuf(struct io_uring_zcrx_area_reg *area_reg)
|
103
|
+
{
|
104
|
+
struct udmabuf_create create;
|
105
|
+
int ret, devfd;
|
106
|
+
|
107
|
+
devfd = open("/dev/udmabuf", O_RDWR);
|
108
|
+
if (devfd < 0)
|
109
|
+
t_error(1, devfd, "Failed to open udmabuf dev");
|
110
|
+
|
111
|
+
memfd = memfd_create("udmabuf-test", MFD_ALLOW_SEALING);
|
112
|
+
if (memfd < 0)
|
113
|
+
t_error(1, memfd, "Failed to open udmabuf dev");
|
114
|
+
|
115
|
+
ret = fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK);
|
116
|
+
if (ret < 0)
|
117
|
+
t_error(1, 0, "Failed to set seals");
|
118
|
+
|
119
|
+
ret = ftruncate(memfd, AREA_SIZE);
|
120
|
+
if (ret == -1)
|
121
|
+
t_error(1, 0, "Failed to resize udmabuf");
|
122
|
+
|
123
|
+
memset(&create, 0, sizeof(create));
|
124
|
+
create.memfd = memfd;
|
125
|
+
create.offset = 0;
|
126
|
+
create.size = AREA_SIZE;
|
127
|
+
dmabuf_fd = ioctl(devfd, UDMABUF_CREATE, &create);
|
128
|
+
if (dmabuf_fd < 0)
|
129
|
+
t_error(1, dmabuf_fd, "Failed to create udmabuf");
|
130
|
+
|
131
|
+
area_ptr = mmap(NULL, AREA_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
|
132
|
+
dmabuf_fd, 0);
|
133
|
+
if (area_ptr == MAP_FAILED)
|
134
|
+
t_error(1, 0, "Failed to mmap udmabuf");
|
135
|
+
|
136
|
+
memset(area_reg, 0, sizeof(*area_reg));
|
137
|
+
area_reg->addr = 0; /* offset into dmabuf */
|
138
|
+
area_reg->len = AREA_SIZE;
|
139
|
+
area_reg->flags |= IORING_ZCRX_AREA_DMABUF;
|
140
|
+
area_reg->dmabuf_fd = dmabuf_fd;
|
141
|
+
|
142
|
+
close(devfd);
|
143
|
+
}
|
144
|
+
|
145
|
+
static void zcrx_populate_area(struct io_uring_zcrx_area_reg *area_reg)
|
146
|
+
{
|
147
|
+
unsigned flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
148
|
+
unsigned prot = PROT_READ | PROT_WRITE;
|
149
|
+
|
150
|
+
if (cfg_area_type == AREA_TYPE_DMABUF) {
|
151
|
+
zcrx_populate_area_udmabuf(area_reg);
|
152
|
+
return;
|
153
|
+
}
|
154
|
+
if (cfg_area_type == AREA_TYPE_NORMAL) {
|
155
|
+
area_ptr = mmap(NULL, AREA_SIZE, prot,
|
156
|
+
flags, 0, 0);
|
157
|
+
} else if (cfg_area_type == AREA_TYPE_HUGE_PAGES) {
|
158
|
+
area_ptr = mmap(NULL, AREA_SIZE, prot,
|
159
|
+
flags | MAP_HUGETLB | MAP_HUGE_2MB, -1, 0);
|
160
|
+
}
|
161
|
+
|
162
|
+
if (area_ptr == MAP_FAILED)
|
163
|
+
t_error(1, 0, "mmap(): area allocation failed");
|
164
|
+
|
165
|
+
memset(area_reg, 0, sizeof(*area_reg));
|
166
|
+
area_reg->addr = (__u64)(unsigned long)area_ptr;
|
167
|
+
area_reg->len = AREA_SIZE;
|
168
|
+
area_reg->flags = 0;
|
169
|
+
}
|
170
|
+
|
171
|
+
static void setup_zcrx(struct io_uring *ring)
|
172
|
+
{
|
173
|
+
struct io_uring_zcrx_area_reg area_reg;
|
174
|
+
unsigned int ifindex;
|
175
|
+
unsigned int rq_entries = 4096;
|
176
|
+
unsigned rq_flags = 0;
|
177
|
+
int ret;
|
178
|
+
|
179
|
+
ifindex = if_nametoindex(cfg_ifname);
|
180
|
+
if (!ifindex)
|
181
|
+
t_error(1, 0, "bad interface name: %s", cfg_ifname);
|
182
|
+
|
183
|
+
ring_size = get_refill_ring_size(rq_entries);
|
184
|
+
ring_ptr = NULL;
|
185
|
+
if (cfg_rq_alloc_mode == RQ_ALLOC_USER) {
|
186
|
+
ring_ptr = mmap(NULL, ring_size,
|
187
|
+
PROT_READ | PROT_WRITE,
|
188
|
+
MAP_ANONYMOUS | MAP_PRIVATE,
|
189
|
+
0, 0);
|
190
|
+
if (ring_ptr == MAP_FAILED)
|
191
|
+
t_error(1, 0, "mmap(): refill ring");
|
192
|
+
rq_flags |= IORING_MEM_REGION_TYPE_USER;
|
193
|
+
}
|
194
|
+
|
195
|
+
struct io_uring_region_desc region_reg = {
|
196
|
+
.size = ring_size,
|
197
|
+
.user_addr = (__u64)(unsigned long)ring_ptr,
|
198
|
+
.flags = rq_flags,
|
199
|
+
};
|
200
|
+
|
201
|
+
zcrx_populate_area(&area_reg);
|
202
|
+
|
203
|
+
struct io_uring_zcrx_ifq_reg reg = {
|
204
|
+
.if_idx = ifindex,
|
205
|
+
.if_rxq = cfg_queue_id,
|
206
|
+
.rq_entries = rq_entries,
|
207
|
+
.area_ptr = (__u64)(unsigned long)&area_reg,
|
208
|
+
.region_ptr = (__u64)(unsigned long)®ion_reg,
|
209
|
+
};
|
210
|
+
|
211
|
+
ret = io_uring_register_ifq(ring, ®);
|
212
|
+
if (ret)
|
213
|
+
t_error(1, 0, "io_uring_register_ifq(): %d", ret);
|
214
|
+
|
215
|
+
if (cfg_rq_alloc_mode == RQ_ALLOC_KERNEL) {
|
216
|
+
ring_ptr = mmap(NULL, ring_size,
|
217
|
+
PROT_READ | PROT_WRITE,
|
218
|
+
MAP_SHARED | MAP_POPULATE,
|
219
|
+
ring->ring_fd, region_reg.mmap_offset);
|
220
|
+
if (ring_ptr == MAP_FAILED)
|
221
|
+
t_error(1, 0, "mmap(): refill ring");
|
222
|
+
}
|
223
|
+
|
224
|
+
rq_ring.khead = (unsigned int *)((char *)ring_ptr + reg.offsets.head);
|
225
|
+
rq_ring.ktail = (unsigned int *)((char *)ring_ptr + reg.offsets.tail);
|
226
|
+
rq_ring.rqes = (struct io_uring_zcrx_rqe *)((char *)ring_ptr + reg.offsets.rqes);
|
227
|
+
rq_ring.rq_tail = 0;
|
228
|
+
rq_ring.ring_entries = reg.rq_entries;
|
229
|
+
|
230
|
+
zcrx_id = reg.zcrx_id;
|
231
|
+
area_token = area_reg.rq_area_token;
|
232
|
+
}
|
233
|
+
|
234
|
+
static void add_accept(struct io_uring *ring, int sockfd)
|
235
|
+
{
|
236
|
+
struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
|
237
|
+
|
238
|
+
io_uring_prep_accept(sqe, sockfd, NULL, NULL, 0);
|
239
|
+
sqe->user_data = REQ_TYPE_ACCEPT;
|
240
|
+
}
|
241
|
+
|
242
|
+
static void add_recvzc(struct io_uring *ring, int sockfd, size_t len)
|
243
|
+
{
|
244
|
+
struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
|
245
|
+
|
246
|
+
io_uring_prep_rw(IORING_OP_RECV_ZC, sqe, sockfd, NULL, len, 0);
|
247
|
+
sqe->ioprio |= IORING_RECV_MULTISHOT;
|
248
|
+
sqe->zcrx_ifq_idx = zcrx_id;
|
249
|
+
sqe->user_data = REQ_TYPE_RX;
|
250
|
+
}
|
251
|
+
|
252
|
+
static void process_accept(struct io_uring *ring, struct io_uring_cqe *cqe)
|
253
|
+
{
|
254
|
+
if (cqe->res < 0)
|
255
|
+
t_error(1, 0, "accept()");
|
256
|
+
if (connfd)
|
257
|
+
t_error(1, 0, "Unexpected second connection");
|
258
|
+
|
259
|
+
connfd = cqe->res;
|
260
|
+
add_recvzc(ring, connfd, cfg_size);
|
261
|
+
}
|
262
|
+
|
263
|
+
static void verify_data(char *data, size_t size, unsigned long seq)
|
264
|
+
{
|
265
|
+
int i;
|
266
|
+
|
267
|
+
if (!cfg_verify_data)
|
268
|
+
return;
|
269
|
+
|
270
|
+
for (i = 0; i < size; i++) {
|
271
|
+
char expected = 'a' + (seq + i) % 26;
|
272
|
+
|
273
|
+
if (data[i] != expected)
|
274
|
+
t_error(1, 0, "payload mismatch at %i: expected %i vs got %i, seq %li",
|
275
|
+
i, expected, data[i], seq);
|
276
|
+
}
|
277
|
+
}
|
278
|
+
|
279
|
+
static void process_recvzc(struct io_uring __attribute__((unused)) *ring,
|
280
|
+
struct io_uring_cqe *cqe)
|
281
|
+
{
|
282
|
+
unsigned rq_mask = rq_ring.ring_entries - 1;
|
283
|
+
struct io_uring_zcrx_cqe *rcqe;
|
284
|
+
struct io_uring_zcrx_rqe *rqe;
|
285
|
+
uint64_t mask;
|
286
|
+
char *data;
|
287
|
+
|
288
|
+
if (!(cqe->flags & IORING_CQE_F_MORE)) {
|
289
|
+
if (!cfg_size || cqe->res != 0)
|
290
|
+
t_error(1, 0, "invalid final recvzc ret %i", cqe->res);
|
291
|
+
if (received != cfg_size)
|
292
|
+
t_error(1, 0, "total receive size mismatch %lu / %lu",
|
293
|
+
received, cfg_size);
|
294
|
+
stop = true;
|
295
|
+
return;
|
296
|
+
}
|
297
|
+
if (cqe->res < 0)
|
298
|
+
t_error(1, 0, "recvzc(): %d", cqe->res);
|
299
|
+
|
300
|
+
rcqe = (struct io_uring_zcrx_cqe *)(cqe + 1);
|
301
|
+
mask = (1ULL << IORING_ZCRX_AREA_SHIFT) - 1;
|
302
|
+
data = (char *)area_ptr + (rcqe->off & mask);
|
303
|
+
|
304
|
+
verify_data(data, cqe->res, received);
|
305
|
+
received += cqe->res;
|
306
|
+
|
307
|
+
/* processed, return back to the kernel */
|
308
|
+
rqe = &rq_ring.rqes[rq_ring.rq_tail & rq_mask];
|
309
|
+
rqe->off = (rcqe->off & ~IORING_ZCRX_AREA_MASK) | area_token;
|
310
|
+
rqe->len = cqe->res;
|
311
|
+
io_uring_smp_store_release(rq_ring.ktail, ++rq_ring.rq_tail);
|
312
|
+
}
|
313
|
+
|
314
|
+
static void server_loop(struct io_uring *ring)
|
315
|
+
{
|
316
|
+
struct io_uring_cqe *cqe;
|
317
|
+
unsigned int head, count = 0;
|
318
|
+
|
319
|
+
io_uring_submit_and_wait(ring, 1);
|
320
|
+
|
321
|
+
io_uring_for_each_cqe(ring, head, cqe) {
|
322
|
+
switch (cqe->user_data & REQ_TYPE_MASK) {
|
323
|
+
case REQ_TYPE_ACCEPT:
|
324
|
+
process_accept(ring, cqe);
|
325
|
+
break;
|
326
|
+
case REQ_TYPE_RX:
|
327
|
+
process_recvzc(ring, cqe);
|
328
|
+
break;
|
329
|
+
default:
|
330
|
+
t_error(1, 0, "unknown cqe");
|
331
|
+
}
|
332
|
+
count++;
|
333
|
+
}
|
334
|
+
io_uring_cq_advance(ring, count);
|
335
|
+
}
|
336
|
+
|
337
|
+
static void run_server(void)
|
338
|
+
{
|
339
|
+
unsigned int flags = 0;
|
340
|
+
struct io_uring ring;
|
341
|
+
int fd, enable, ret;
|
342
|
+
|
343
|
+
fd = socket(AF_INET6, SOCK_STREAM, 0);
|
344
|
+
if (fd == -1)
|
345
|
+
t_error(1, 0, "socket()");
|
346
|
+
|
347
|
+
enable = 1;
|
348
|
+
ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
|
349
|
+
if (ret < 0)
|
350
|
+
t_error(1, 0, "setsockopt(SO_REUSEADDR)");
|
351
|
+
|
352
|
+
ret = bind(fd, (struct sockaddr *)&cfg_addr, sizeof(cfg_addr));
|
353
|
+
if (ret < 0)
|
354
|
+
t_error(1, 0, "bind()");
|
355
|
+
|
356
|
+
if (listen(fd, 1024) < 0)
|
357
|
+
t_error(1, 0, "listen()");
|
358
|
+
|
359
|
+
flags |= IORING_SETUP_COOP_TASKRUN;
|
360
|
+
flags |= IORING_SETUP_SINGLE_ISSUER;
|
361
|
+
flags |= IORING_SETUP_DEFER_TASKRUN;
|
362
|
+
flags |= IORING_SETUP_SUBMIT_ALL;
|
363
|
+
flags |= IORING_SETUP_CQE32;
|
364
|
+
|
365
|
+
ret = io_uring_queue_init(512, &ring, flags);
|
366
|
+
if (ret)
|
367
|
+
t_error(1, ret, "ring init failed");
|
368
|
+
|
369
|
+
setup_zcrx(&ring);
|
370
|
+
add_accept(&ring, fd);
|
371
|
+
|
372
|
+
while (!stop)
|
373
|
+
server_loop(&ring);
|
374
|
+
}
|
375
|
+
|
376
|
+
static void usage(const char *filepath)
|
377
|
+
{
|
378
|
+
t_error(1, 0, "Usage: %s (-4|-6) -p<port> -i<ifname> -q<rxq_id>", filepath);
|
379
|
+
}
|
380
|
+
|
381
|
+
static void parse_opts(int argc, char **argv)
|
382
|
+
{
|
383
|
+
struct sockaddr_in6 *addr6 = (void *) &cfg_addr;
|
384
|
+
int c;
|
385
|
+
|
386
|
+
if (argc <= 1)
|
387
|
+
usage(argv[0]);
|
388
|
+
|
389
|
+
while ((c = getopt(argc, argv, "vp:i:q:s:r:A:")) != -1) {
|
390
|
+
switch (c) {
|
391
|
+
case 'p':
|
392
|
+
cfg_port = strtoul(optarg, NULL, 0);
|
393
|
+
break;
|
394
|
+
case 'i':
|
395
|
+
cfg_ifname = optarg;
|
396
|
+
break;
|
397
|
+
case 's':
|
398
|
+
cfg_size = strtoul(optarg, NULL, 0);
|
399
|
+
break;
|
400
|
+
case 'q':
|
401
|
+
cfg_queue_id = strtoul(optarg, NULL, 0);
|
402
|
+
break;
|
403
|
+
case 'v':
|
404
|
+
cfg_verify_data = true;
|
405
|
+
break;
|
406
|
+
case 'r':
|
407
|
+
cfg_rq_alloc_mode = strtoul(optarg, NULL, 0);
|
408
|
+
if (cfg_rq_alloc_mode >= __RQ_ALLOC_MAX)
|
409
|
+
t_error(1, 0, "invalid RQ allocation mode");
|
410
|
+
break;
|
411
|
+
case 'A':
|
412
|
+
cfg_area_type = strtoul(optarg, NULL, 0);
|
413
|
+
if (cfg_area_type >= __AREA_TYPE_MAX)
|
414
|
+
t_error(1, 0, "Invalid area type");
|
415
|
+
break;
|
416
|
+
}
|
417
|
+
}
|
418
|
+
|
419
|
+
memset(addr6, 0, sizeof(*addr6));
|
420
|
+
addr6->sin6_family = AF_INET6;
|
421
|
+
addr6->sin6_port = htons(cfg_port);
|
422
|
+
addr6->sin6_addr = in6addr_any;
|
423
|
+
}
|
424
|
+
|
425
|
+
int main(int argc, char **argv)
|
426
|
+
{
|
427
|
+
page_size = sysconf(_SC_PAGESIZE);
|
428
|
+
if (page_size < 0) {
|
429
|
+
perror("sysconf(_SC_PAGESIZE)");
|
430
|
+
return 1;
|
431
|
+
}
|
432
|
+
|
433
|
+
parse_opts(argc, argv);
|
434
|
+
run_server();
|
435
|
+
return 0;
|
436
|
+
}
|
@@ -101,7 +101,6 @@ install: $(all_targets)
|
|
101
101
|
install -D -m 644 include/liburing.h $(includedir)/liburing.h
|
102
102
|
install -D -m 644 include/liburing/compat.h $(includedir)/liburing/compat.h
|
103
103
|
install -D -m 644 include/liburing/barrier.h $(includedir)/liburing/barrier.h
|
104
|
-
install -D -m 644 include/liburing/sanitize.h $(includedir)/liburing/sanitize.h
|
105
104
|
install -D -m 644 include/liburing/io_uring_version.h $(includedir)/liburing/io_uring_version.h
|
106
105
|
install -D -m 644 liburing.a $(libdevdir)/liburing.a
|
107
106
|
install -D -m 644 liburing-ffi.a $(libdevdir)/liburing-ffi.a
|
@@ -23,12 +23,12 @@ static inline int __sys_io_uring_setup(unsigned int entries,
|
|
23
23
|
|
24
24
|
static inline int __sys_io_uring_enter2(unsigned int fd, unsigned int to_submit,
|
25
25
|
unsigned int min_complete,
|
26
|
-
unsigned int flags,
|
26
|
+
unsigned int flags, void *arg,
|
27
27
|
size_t sz)
|
28
28
|
{
|
29
29
|
int ret;
|
30
30
|
ret = syscall(__NR_io_uring_enter, fd, to_submit, min_complete, flags,
|
31
|
-
|
31
|
+
arg, sz);
|
32
32
|
return (ret < 0) ? -errno : ret;
|
33
33
|
}
|
34
34
|
|