aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincenzo Maffione <vmaffione@FreeBSD.org>2021-04-02 14:39:30 +0000
committerVincenzo Maffione <vmaffione@FreeBSD.org>2021-04-02 14:39:30 +0000
commit36d6e65722ea515bf2d122d6e69096a5ff620a92 (patch)
tree42151877db4d68455fc7ff4a372593594634ee73
parentab639bb2873034786cd2ec4d2d9c4489fbf6f424 (diff)
downloadsrc-36d6e65722ea515bf2d122d6e69096a5ff620a92.tar.gz
src-36d6e65722ea515bf2d122d6e69096a5ff620a92.zip
netmap: update unit tests with libnetmap tests
-rw-r--r--tests/sys/netmap/Makefile1
-rw-r--r--tests/sys/netmap/ctrl-api-test.c321
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@2", "eth0", "", 0, NR_REG_ALL_NIC, 0, 0 },
+ { "netmap:eth0@2/R", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_RX_RINGS_ONLY },
+ { "netmap:eth0@netmap:lo/R", "eth0", "@netmap:lo/R", 0, NR_REG_ALL_NIC, 0, 0 },
+ { "netmap:eth0/R@xxx", "eth0", "@xxx", 0, NR_REG_ALL_NIC, 0, NR_RX_RINGS_ONLY },
+ { "netmap:eth0@2/R@2", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_RX_RINGS_ONLY },
+ { "netmap:eth0@2/R@3", "eth0", "@2/R@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@opt", "vale0:0", "@opt", 0, NR_REG_ALL_NIC, 0, 0 },
+ { "vale0:0/Tx@opt", "vale0:0", "@opt", 0, NR_REG_ALL_NIC, 0, NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
+ { "vale0:0-3@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