git: 36d6e65722ea - main - netmap: update unit tests with libnetmap tests

Vincenzo Maffione vmaffione at FreeBSD.org
Fri Apr 2 14:39:44 UTC 2021


The branch main has been updated by vmaffione:

URL: https://cgit.FreeBSD.org/src/commit/?id=36d6e65722ea515bf2d122d6e69096a5ff620a92

commit 36d6e65722ea515bf2d122d6e69096a5ff620a92
Author:     Vincenzo Maffione <vmaffione at FreeBSD.org>
AuthorDate: 2021-04-02 14:39:30 +0000
Commit:     Vincenzo Maffione <vmaffione at FreeBSD.org>
CommitDate: 2021-04-02 14:39:30 +0000

    netmap: update unit tests with libnetmap tests
---
 tests/sys/netmap/Makefile        |   1 +
 tests/sys/netmap/ctrl-api-test.c | 321 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 309 insertions(+), 13 deletions(-)

diff --git a/tests/sys/netmap/Makefile b/tests/sys/netmap/Makefile
index 0228271dd668..a7891f583b3b 100644
--- a/tests/sys/netmap/Makefile
+++ b/tests/sys/netmap/Makefile
@@ -10,5 +10,6 @@ PLAIN_TESTS_C+=	ctrl-api-test
 
 CFLAGS+=	-I${SRCTOP}/tests
 LIBADD+= 	pthread
+LIBADD+= 	netmap
 
 .include <bsd.test.mk>
diff --git a/tests/sys/netmap/ctrl-api-test.c b/tests/sys/netmap/ctrl-api-test.c
index cea78141fbe4..7cd4d6ac6d9b 100644
--- a/tests/sys/netmap/ctrl-api-test.c
+++ b/tests/sys/netmap/ctrl-api-test.c
@@ -46,6 +46,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <libnetmap.h>
 #include <net/if.h>
 #include <net/netmap.h>
 #include <pthread.h>
@@ -57,6 +58,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <signal.h>
+#include <stddef.h>
 
 #ifdef __FreeBSD__
 #include "freebsd_test_suite/macros.h"
@@ -71,6 +73,8 @@ eventfd(int x __unused, int y __unused)
 #include <sys/eventfd.h>
 #endif
 
+#define NM_IFNAMSZ 64
+
 static int
 exec_command(int argc, const char *const argv[])
 {
@@ -143,9 +147,9 @@ exec_command(int argc, const char *const argv[])
 #define THRET_FAILURE	((void *)0)
 
 struct TestContext {
-	char ifname[64];
-	char ifname_ext[128];
-	char bdgname[64];
+	char ifname[NM_IFNAMSZ];
+	char ifname_ext[NM_IFNAMSZ];
+	char bdgname[NM_IFNAMSZ];
 	uint32_t nr_tx_slots;   /* slots in tx rings */
 	uint32_t nr_rx_slots;   /* slots in rx rings */
 	uint16_t nr_tx_rings;   /* number of tx rings */
@@ -166,6 +170,10 @@ struct TestContext {
 	void *csb;                    /* CSB entries (atok and ktoa) */
 	struct nmreq_option *nr_opt;  /* list of options */
 	sem_t *sem;	/* for thread synchronization */
+
+	struct nmctx *nmctx;
+	const char *ifparse;
+	struct nmport_d *nmport;      /* nmport descriptor from libnetmap */
 };
 
 static struct TestContext ctx_;
@@ -177,7 +185,8 @@ nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
 {
 	memset(hdr, 0, sizeof(*hdr));
 	hdr->nr_version = NETMAP_API;
-	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name) - 1);
+	assert(strlen(ifname) < NM_IFNAMSZ);
+	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name));
 }
 
 /* Single NETMAP_REQ_PORT_INFO_GET. */
@@ -522,16 +531,30 @@ port_register_hwall_rx(struct TestContext *ctx)
 	return port_register(ctx);
 }
 
+
+static int
+vale_mkname(char *vpname, struct TestContext *ctx)
+{
+	if (snprintf(vpname, NM_IFNAMSZ, "%s:%s", ctx->bdgname, ctx->ifname_ext) >= NM_IFNAMSZ) {
+		fprintf(stderr, "%s:%s too long (max %d chars)\n", ctx->bdgname, ctx->ifname_ext,
+				NM_IFNAMSZ - 1);
+		return -1;
+	}
+	return 0;
+}
+
+
 /* NETMAP_REQ_VALE_ATTACH */
 static int
 vale_attach(struct TestContext *ctx)
 {
 	struct nmreq_vale_attach req;
 	struct nmreq_header hdr;
-	char vpname[sizeof(ctx->bdgname) + 1 + sizeof(ctx->ifname_ext)];
+	char vpname[NM_IFNAMSZ];
 	int ret;
 
-	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
+	if (vale_mkname(vpname, ctx) < 0)
+		return -1;
 
 	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
 	nmreq_hdr_init(&hdr, vpname);
@@ -563,10 +586,11 @@ vale_detach(struct TestContext *ctx)
 {
 	struct nmreq_header hdr;
 	struct nmreq_vale_detach req;
-	char vpname[256];
+	char vpname[NM_IFNAMSZ];
 	int ret;
 
-	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
+	if (vale_mkname(vpname, ctx) < 0)
+		return -1;
 
 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
 	nmreq_hdr_init(&hdr, vpname);
@@ -818,7 +842,7 @@ pipe_slave(struct TestContext *ctx)
 }
 
 /* Test PORT_INFO_GET and POOLS_INFO_GET on a pipe. This is useful to test the
- * registration request used internall by netmap. */
+ * registration request used internally by netmap. */
 static int
 pipe_port_info_get(struct TestContext *ctx)
 {
@@ -841,10 +865,12 @@ vale_polling_enable(struct TestContext *ctx)
 {
 	struct nmreq_vale_polling req;
 	struct nmreq_header hdr;
-	char vpname[256];
+	char vpname[NM_IFNAMSZ];
 	int ret;
 
-	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
+	if (vale_mkname(vpname, ctx) < 0)
+		return -1;
+
 	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
 
 	nmreq_hdr_init(&hdr, vpname);
@@ -873,10 +899,12 @@ vale_polling_disable(struct TestContext *ctx)
 {
 	struct nmreq_vale_polling req;
 	struct nmreq_header hdr;
-	char vpname[256];
+	char vpname[NM_IFNAMSZ];
 	int ret;
 
-	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
+	if (vale_mkname(vpname, ctx) < 0)
+		return -1;
+
 	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
 
 	nmreq_hdr_init(&hdr, vpname);
@@ -1715,6 +1743,271 @@ null_port_sync(struct TestContext *ctx)
 	return 0;
 }
 
+struct nmreq_parse_test {
+	const char *ifname;
+	const char *exp_port;
+	const char *exp_suff;
+	int exp_error;
+	uint32_t exp_mode;
+	uint16_t exp_ringid;
+	uint64_t exp_flags;
+};
+
+static struct nmreq_parse_test nmreq_parse_tests[] = {
+	/* port spec is the input. The expected results are as follows:
+	 * - port: what should go into hdr.nr_name
+	 * - suff: the trailing part of the input after parsing (NULL means equal to port spec)
+	 * - err: the expected return value, interpreted as follows
+	 *       err > 0 => nmreq_header_parse should fail with the given error
+	 *       err < 0 => nrmeq_header_parse should succeed, but nmreq_register_decode should
+	 *       		   fail with error |err|
+	 *       err = 0 => should succeed
+	 * - mode, ringid flags: what should go into the corresponding nr_* fields in the
+	 *   	nmreq_register struct in case of success
+	 */
+
+	/*port spec*/			/*port*/	/*suff*/    /*err*/	/*mode*/    /*ringid*/ /*flags*/
+	{ "netmap:eth0",		"eth0",		"",		0, 	NR_REG_ALL_NIC,	0,	0 },
+	{ "netmap:eth0-1",		"eth0",		"",		0, 	NR_REG_ONE_NIC, 1,	0 },
+	{ "netmap:eth0-",		"eth0",		"-",		-EINVAL,0,		0,	0 },
+	{ "netmap:eth0/x",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_EXCLUSIVE },
+	{ "netmap:eth0/z",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_ZCOPY_MON },
+	{ "netmap:eth0/r",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_MONITOR_RX },
+	{ "netmap:eth0/t",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_MONITOR_TX },
+	{ "netmap:eth0-2/Tx",		"eth0",		"",		0, 	NR_REG_ONE_NIC, 2,	NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
+	{ "netmap:eth0*",		"eth0",		"",		0, 	NR_REG_NIC_SW,  0,	0 },
+	{ "netmap:eth0^",		"eth0",		"",		0, 	NR_REG_SW,	0,	0 },
+	{ "netmap:eth0 at 2",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "netmap:eth0 at 2/R",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	NR_RX_RINGS_ONLY },
+	{ "netmap:eth0 at netmap:lo/R",	"eth0",	        "@netmap:lo/R",	0,	NR_REG_ALL_NIC,	0,	0 },
+	{ "netmap:eth0/R at xxx",		"eth0",	        "@xxx",		0,	NR_REG_ALL_NIC,	0,	NR_RX_RINGS_ONLY },
+	{ "netmap:eth0 at 2/R at 2",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	NR_RX_RINGS_ONLY },
+	{ "netmap:eth0 at 2/R at 3",		"eth0",	        "@2/R at 3",	-EINVAL,0,		0,	0 },
+	{ "netmap:eth0@",		"eth0",	        "@",		-EINVAL,0,		0,	0 },
+	{ "netmap:",			"",		NULL,		EINVAL, 0,		0,	0 },
+	{ "netmap:^",			"",		NULL,		EINVAL,	0,		0,	0 },
+	{ "netmap:{",			"",		NULL,		EINVAL,	0,		0,	0 },
+	{ "netmap:vale0:0",		NULL,		NULL,		EINVAL,	0,		0,	0 },
+	{ "eth0",			NULL,		NULL,		EINVAL, 0,		0,	0 },
+	{ "vale0:0",			"vale0:0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "vale:0",			"vale:0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "valeXXX:YYY",		"valeXXX:YYY",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "valeXXX:YYY-4",		"valeXXX:YYY",	"",		0,	NR_REG_ONE_NIC, 4,	0 },
+	{ "netmapXXX:eth0",		NULL,		NULL,		EINVAL,	0,		0,	0 },
+	{ "netmap:14",			"14",		"",		0, 	NR_REG_ALL_NIC,	0,	0 },
+	{ "netmap:eth0&",		NULL,		NULL,		EINVAL, 0,		0,	0 },
+	{ "netmap:pipe{0",		"pipe{0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "netmap:pipe{in",		"pipe{in",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "netmap:pipe{in-7",		"pipe{in",	"",		0,	NR_REG_ONE_NIC, 7,	0 },
+	{ "vale0:0{0",			"vale0:0{0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "netmap:pipe{1}2",		NULL,		NULL,		EINVAL, 0,		0,	0 },
+	{ "vale0:0 at opt", 		"vale0:0",	"@opt",		0,	NR_REG_ALL_NIC, 0,	0 },
+	{ "vale0:0/Tx at opt", 		"vale0:0",	"@opt",		0,	NR_REG_ALL_NIC, 0,	NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
+	{ "vale0:0-3 at opt", 		"vale0:0",	"@opt",		0,	NR_REG_ONE_NIC, 3,	0 },
+	{ "vale0:0@", 			"vale0:0",	"@",		-EINVAL,0,	        0,	0 },
+	{ "",				NULL,		NULL,		EINVAL, 0,		0,	0 },
+	{ NULL,				NULL,		NULL,		0, 	0,		0,	0 },
+};
+
+static void
+randomize(void *dst, size_t n)
+{
+	size_t i;
+	char *dst_ = dst;
+
+	for (i = 0; i < n; i++)
+		dst_[i] = (char)random();
+}
+
+static int
+nmreq_hdr_parsing(struct TestContext *ctx,
+		struct nmreq_parse_test *t,
+		struct nmreq_header *hdr)
+{
+	const char *save;
+	struct nmreq_header orig_hdr;
+
+	save = ctx->ifparse = t->ifname;
+	orig_hdr = *hdr;
+
+	printf("nmreq_header: \"%s\"\n", ctx->ifparse);
+	if (nmreq_header_decode(&ctx->ifparse, hdr, ctx->nmctx) < 0) {
+		if (t->exp_error > 0) {
+			if (errno != t->exp_error) {
+				printf("!!! got errno=%d, want %d\n",
+						errno, t->exp_error);
+				return -1;
+			}
+			if (ctx->ifparse != save) {
+				printf("!!! parse error, but first arg changed\n");
+				return -1;
+			}
+			if (memcmp(&orig_hdr, hdr, sizeof(*hdr))) {
+				printf("!!! parse error, but header changed\n");
+				return -1;
+			}
+			return 0;
+		}
+		printf ("!!! nmreq_header_decode was expected to succeed, but it failed with error %d\n", errno);
+		return -1;
+	}
+	if (t->exp_error > 0) {
+		printf("!!! nmreq_header_decode returns 0, but error %d was expected\n", t->exp_error);
+		return -1;
+	}
+	if (strcmp(t->exp_port, hdr->nr_name) != 0) {
+		printf("!!! got '%s', want '%s'\n", hdr->nr_name, t->exp_port);
+		return -1;
+	}
+	if (hdr->nr_reqtype != orig_hdr.nr_reqtype ||
+	    hdr->nr_options != orig_hdr.nr_options ||
+	    hdr->nr_body    != orig_hdr.nr_body) {
+		printf("!!! some fields of the nmreq_header where changed unexpectedly\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+nmreq_reg_parsing(struct TestContext *ctx,
+		struct nmreq_parse_test *t,
+		struct nmreq_register *reg)
+{
+	const char *save;
+	struct nmreq_register orig_reg;
+
+
+	save = ctx->ifparse;
+	orig_reg = *reg;
+
+	printf("nmreq_register: \"%s\"\n", ctx->ifparse);
+	if (nmreq_register_decode(&ctx->ifparse, reg, ctx->nmctx) < 0) {
+		if (t->exp_error < 0) {
+			if (errno != -t->exp_error) {
+				printf("!!! got errno=%d, want %d\n",
+						errno, -t->exp_error);
+				return -1;
+			}
+			if (ctx->ifparse != save) {
+				printf("!!! parse error, but first arg changed\n");
+				return -1;
+			}
+			if (memcmp(&orig_reg, reg, sizeof(*reg))) {
+				printf("!!! parse error, but nmreq_register changed\n");
+				return -1;
+			}
+			return 0;
+		}
+		printf ("!!! parse failed but it should have succeeded\n");
+		return -1;
+	}
+	if (t->exp_error < 0) {
+		printf("!!! nmreq_register_decode returns 0, but error %d was expected\n", -t->exp_error);
+		return -1;
+	}
+	if (reg->nr_mode != t->exp_mode) {
+		printf("!!! got nr_mode '%d', want '%d'\n", reg->nr_mode, t->exp_mode);
+		return -1;
+	}
+	if (reg->nr_ringid != t->exp_ringid) {
+		printf("!!! got nr_ringid '%d', want '%d'\n", reg->nr_ringid, t->exp_ringid);
+		return -1;
+	}
+	if (reg->nr_flags != t->exp_flags) {
+		printf("!!! got nm_flags '%llx', want '%llx\n", (unsigned long long)reg->nr_flags,
+				(unsigned long long)t->exp_flags);
+		return -1;
+	}
+	if (reg->nr_offset     != orig_reg.nr_offset     ||
+	    reg->nr_memsize    != orig_reg.nr_memsize    ||
+	    reg->nr_tx_slots   != orig_reg.nr_tx_slots   ||
+	    reg->nr_rx_slots   != orig_reg.nr_rx_slots   ||
+	    reg->nr_tx_rings   != orig_reg.nr_tx_rings   ||
+	    reg->nr_rx_rings   != orig_reg.nr_rx_rings   ||
+	    reg->nr_extra_bufs != orig_reg.nr_extra_bufs)
+	{
+		printf("!!! some fields of the nmreq_register where changed unexpectedly\n");
+		return -1;
+	}
+	return 0;
+}
+
+static void
+nmctx_parsing_error(struct nmctx *ctx, const char *msg)
+{
+	(void)ctx;
+	printf("    got message: %s\n", msg);
+}
+
+static int
+nmreq_parsing(struct TestContext *ctx)
+{
+	struct nmreq_parse_test *t;
+	struct nmreq_header hdr;
+	struct nmreq_register reg;
+	struct nmctx test_nmctx, *nmctx;
+	int ret = 0;
+
+	nmctx = nmctx_get();
+	if (nmctx == NULL) {
+		printf("Failed to acquire nmctx: %s", strerror(errno));
+		return -1;
+	}
+	test_nmctx = *nmctx;
+	test_nmctx.error = nmctx_parsing_error;
+	ctx->nmctx = &test_nmctx;
+	for (t = nmreq_parse_tests; t->ifname != NULL; t++) {
+		const char *exp_suff = t->exp_suff != NULL ?
+			t->exp_suff : t->ifname;
+
+		randomize(&hdr, sizeof(hdr));
+		randomize(&reg, sizeof(reg));
+		reg.nr_mem_id = 0;
+		if (nmreq_hdr_parsing(ctx, t, &hdr) < 0) {
+			ret = -1;
+		} else if (t->exp_error <= 0 && nmreq_reg_parsing(ctx, t, &reg) < 0) {
+			ret = -1;
+		}
+		if (strcmp(ctx->ifparse, exp_suff) != 0) {
+			printf("!!! string suffix after parse is '%s', but it should be '%s'\n",
+					ctx->ifparse, exp_suff);
+			ret = -1;
+		}
+	}
+	return ret;
+}
+
+static int
+binarycomp(struct TestContext *ctx)
+{
+#define ckroff(f, o) do {\
+	if (offsetof(struct netmap_ring, f) != (o)) {\
+		printf("offset of netmap_ring.%s is %zd, but it should be %d",\
+				#f, offsetof(struct netmap_ring, f), (o));\
+		return -1;\
+	}\
+} while (0)
+
+	(void)ctx;
+
+	ckroff(buf_ofs, 0);
+	ckroff(num_slots, 8);
+	ckroff(nr_buf_size, 12);
+	ckroff(ringid, 16);
+	ckroff(dir, 18);
+	ckroff(head, 20);
+	ckroff(cur, 24);
+	ckroff(tail, 28);
+	ckroff(flags, 32);
+	ckroff(ts, 40);
+	ckroff(offset_mask, 56);
+	ckroff(buf_align, 64);
+	ckroff(sem, 128);
+	ckroff(slot, 256);
+
+	return 0;
+}
+
 static void
 usage(const char *prog)
 {
@@ -1783,6 +2076,8 @@ static struct mytest tests[] = {
 	decltest(legacy_regif_extra_bufs),
 	decltest(legacy_regif_extra_bufs_pipe),
 	decltest(legacy_regif_extra_bufs_pipe_vale),
+	decltest(nmreq_parsing),
+	decltest(binarycomp),
 };
 
 static void


More information about the dev-commits-src-all mailing list