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