test/napi-test: turn into a test case - Have napi-test.t invoke the shell script if no arguments are passed - Have napi-test.sh test with various queue flags - Add description - Remove some unneeded includes - Have connect retry if we get ECONNREFUSED, probably racing with receiver setting up. Timeout after 1 second. - Register napi instance - Test for root, can't work as a normal user - Test for ip and ethtool, and skip if not available Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/test/napi-test.c b/test/napi-test.c index eef2e1f..3512376 100644 --- a/test/napi-test.c +++ b/test/napi-test.c
@@ -1,46 +1,26 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Description: run NAPI receive test. Meant to be run from the associated + * script, napi-test.sh. That will invoke this test program + * as either a sender or receiver, with the queue flags passed + * in for testing. + * + */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <assert.h> #include <errno.h> -#include <limits.h> #include <fcntl.h> #include <unistd.h> -#include <stdbool.h> -#include <stdarg.h> #include <string.h> -#include <pthread.h> - -#include <poll.h> -#include <sched.h> #include <arpa/inet.h> #include <linux/if_packet.h> -#include <linux/ipv6.h> #include <linux/socket.h> -#include <linux/sockios.h> -#include <net/ethernet.h> -#include <net/if.h> -#include <netinet/ip.h> -#include <netinet/in.h> -#include <netinet/ip6.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> #include <sys/socket.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/un.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/mman.h> -#include <linux/mman.h> #include "liburing.h" - -#include <assert.h> +#include "helpers.h" static const char receiver_address[] = "10.10.10.20"; static const int port = 9999; @@ -56,7 +36,7 @@ assert(ret == 0); } -static void sender(void) +static int sender(void) { unsigned long long written = 0; struct sockaddr_in addr; @@ -71,14 +51,22 @@ fd = socket(PF_INET, SOCK_STREAM, 0); assert(fd >= 0); - printf("sender: connect\n"); - - if (connect(fd, (void *)&addr, sizeof(addr))) { - fprintf(stderr, "connect fail %i\n", errno); - exit(1); - } - - printf("sender: connected\n"); + /* don't race with receiver, give it 1 second to connect */ + i = 0; + do { + ret = connect(fd, (void *)&addr, sizeof(addr)); + if (!ret) + break; + if (ret == -1 && errno == ECONNREFUSED) { + if (i >= 10000) { + fprintf(stderr, "Gave up trying to connect\n"); + return 1; + } + usleep(100); + continue; + } + i++; + } while (1); while (written < 8 * 1024 * 1024) { for (i = 0; i < BUF_SIZE; i++) @@ -89,32 +77,37 @@ if (!ret || errno == ECONNRESET) break; fprintf(stderr, "write failed %i %i\n", ret, errno); - exit(1); + return 1; } written += ret; current_byte += ret; } close(fd); - printf("bytes sent %llu\n", written); + return 0; } -static void receiver(void) +static int receiver(int queue_flags) { struct io_uring_sqe *sqe; struct io_uring_cqe *cqe; struct io_uring ring; unsigned long long received = 0; + struct io_uring_napi napi = { }; struct sockaddr_in addr; int fd, listen_fd; int i, ret; - ret = io_uring_queue_init(8, &ring, 0); + ret = io_uring_queue_init(8, &ring, queue_flags); if (ret < 0) { fprintf(stderr, "queue_init: %s\n", strerror(-ret)); - return; + return 1; } + napi.prefer_busy_poll = 1; + napi.busy_poll_to = 50; + io_uring_register_napi(&ring, &napi); + memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); @@ -127,16 +120,12 @@ ret = bind(listen_fd, (void *)&addr, sizeof(addr)); if (ret) { fprintf(stderr, "bind failed %i %i\n", ret, errno); - exit(1); + return 1; } - printf("receiver: listen()\n"); - ret = listen(listen_fd, 8); assert(ret == 0); - printf("receiver: accept()\n"); - fd = accept(listen_fd, NULL, NULL); assert(fd >= 0); @@ -147,13 +136,13 @@ ret = io_uring_submit(&ring); if (ret != 1) { fprintf(stderr, "io_uring_submit: %i\n", ret); - return; + return 1; } ret = io_uring_wait_cqe(&ring, &cqe); if (ret < 0) { fprintf(stderr, "io_uring_wait_cqe: %i\n", ret); - return; + return 1; } ret = cqe->res; @@ -161,7 +150,7 @@ if (!ret) break; fprintf(stderr, "recv failed %i %i\n", ret, errno); - exit(1); + return 1; } for (i = 0; i < ret; i++) { @@ -170,7 +159,7 @@ if (buffer[i] != expected) { fprintf(stderr, "data mismatch: idx %i, %c vs %c\n", i, buffer[i], expected); - exit(1); + return 1; } } @@ -181,22 +170,37 @@ close(fd); io_uring_queue_exit(&ring); - printf("bytes received %llu\n", received); + return 0; } int main(int argc, char **argv) { + int queue_flags; int is_rx; - assert(argc == 2); - is_rx = strtoul(argv[1], NULL, 0); + if (geteuid()) { + fprintf(stdout, "NAPI test requires root\n"); + return T_EXIT_SKIP; + } - printf("%s: start\n", is_rx ? "receiver" : "sender"); + if (argc == 1) + return system("bash napi-test.sh"); + else if (argc == 2) + return T_EXIT_SKIP; + else if (argc != 3) + return T_EXIT_SKIP; + + if (!strcmp(argv[1], "receive")) + is_rx = 1; + else if (!strcmp(argv[1], "send")) + is_rx = 0; + else + return T_EXIT_FAIL; + + queue_flags = strtoul(argv[2], NULL, 16); if (is_rx) - receiver(); - else - sender(); + return receiver(queue_flags); - return 0; + return sender(); }
diff --git a/test/napi-test.sh b/test/napi-test.sh index f7248ed..6fe34d1 100644 --- a/test/napi-test.sh +++ b/test/napi-test.sh
@@ -1,10 +1,17 @@ #! /usr/bin/env bash +if [ ! -x "$(command -v ip)" ]; then + echo "Need ip installed" + exit 77 +fi +if [ ! -x "$(command -v ethtool)" ]; then + echo "Need ethool installed" + exit 77 +fi + function clean_namespaces { ip netns del nscl ip netns del nsserv - ip link del ptp-serv - echo 10 } trap clean_namespaces EXIT @@ -24,5 +31,18 @@ ip netns exec nsserv ethtool -K ptp-serv generic-receive-offload on ip netns exec nsserv ip link set dev ptp-serv up -ip netns exec nsserv ./prog 1 & -ip netns exec nscl ./prog 0 +# test basic init, defer_taskrun, and sqpoll +QUEUE_FLAGS="0x0 0x3000 0x2" +for flags in $QUEUE_FLAGS; do + if [ -f "napi-test.t" ]; then + NAPI_TEST="./napi-test.t" + elif [ -f "test/napi-test.t" ]; then + NAPI_TEST="test/napi-test.t" + else + echo "Can't find napi-test.t" + exit 77 + fi + ip netns exec nsserv $NAPI_TEST receive $flags & + ip netns exec nscl $NAPI_TEST send $flags + wait +done