netmap: update unit tests with libnetmap tests
This commit is contained in:
parent
ab639bb287
commit
36d6e65722
@ -10,5 +10,6 @@ PLAIN_TESTS_C+= ctrl-api-test
|
||||
|
||||
CFLAGS+= -I${SRCTOP}/tests
|
||||
LIBADD+= pthread
|
||||
LIBADD+= netmap
|
||||
|
||||
.include <bsd.test.mk>
|
||||
|
@ -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(®, 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, ®) < 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
|
||||
|
Loading…
Reference in New Issue
Block a user