xref: /freebsd-src/tests/sys/netmap/ctrl-api-test.c (revision ee5804da116f2107451c8b4376b69b3a64a630e8)
12a8682a8SVincenzo Maffione /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
32a8682a8SVincenzo Maffione  *
42a8682a8SVincenzo Maffione  * Copyright (C) 2018 Vincenzo Maffione
52a8682a8SVincenzo Maffione  *
62a8682a8SVincenzo Maffione  * Redistribution and use in source and binary forms, with or without
72a8682a8SVincenzo Maffione  * modification, are permitted provided that the following conditions
82a8682a8SVincenzo Maffione  * are met:
92a8682a8SVincenzo Maffione  *   1. Redistributions of source code must retain the above copyright
102a8682a8SVincenzo Maffione  *      notice, this list of conditions and the following disclaimer.
112a8682a8SVincenzo Maffione  *   2. Redistributions in binary form must reproduce the above copyright
122a8682a8SVincenzo Maffione  *      notice, this list of conditions and the following disclaimer in the
132a8682a8SVincenzo Maffione  *      documentation and/or other materials provided with the distribution.
142a8682a8SVincenzo Maffione  *
152a8682a8SVincenzo Maffione  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
162a8682a8SVincenzo Maffione  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
172a8682a8SVincenzo Maffione  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
182a8682a8SVincenzo Maffione  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
192a8682a8SVincenzo Maffione  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
202a8682a8SVincenzo Maffione  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
212a8682a8SVincenzo Maffione  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
222a8682a8SVincenzo Maffione  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
232a8682a8SVincenzo Maffione  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
242a8682a8SVincenzo Maffione  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
252a8682a8SVincenzo Maffione  * SUCH DAMAGE.
262a8682a8SVincenzo Maffione  */
272a8682a8SVincenzo Maffione 
2845c67e8fSVincenzo Maffione /*
2945c67e8fSVincenzo Maffione  * This program contains a suite of unit tests for the netmap control device.
3045c67e8fSVincenzo Maffione  *
3145c67e8fSVincenzo Maffione  * On FreeBSD, you can run these tests with Kyua once installed in the system:
3245c67e8fSVincenzo Maffione  *     # kyua test -k /usr/tests/sys/netmap/Kyuafile
3345c67e8fSVincenzo Maffione  *
3445c67e8fSVincenzo Maffione  * On Linux, you can run them directly:
3545c67e8fSVincenzo Maffione  *     # ./ctrl-api-test
3645c67e8fSVincenzo Maffione  */
3745c67e8fSVincenzo Maffione 
382a8682a8SVincenzo Maffione #include <sys/ioctl.h>
392a8682a8SVincenzo Maffione #include <sys/mman.h>
402a8682a8SVincenzo Maffione #include <sys/wait.h>
412a8682a8SVincenzo Maffione 
422a8682a8SVincenzo Maffione #include <assert.h>
432a8682a8SVincenzo Maffione #include <ctype.h>
442a8682a8SVincenzo Maffione #include <errno.h>
452a8682a8SVincenzo Maffione #include <fcntl.h>
462a8682a8SVincenzo Maffione #include <inttypes.h>
4736d6e657SVincenzo Maffione #include <libnetmap.h>
482a8682a8SVincenzo Maffione #include <net/if.h>
492a8682a8SVincenzo Maffione #include <net/netmap.h>
502a8682a8SVincenzo Maffione #include <pthread.h>
512a8682a8SVincenzo Maffione #include <semaphore.h>
522a8682a8SVincenzo Maffione #include <stdint.h>
532a8682a8SVincenzo Maffione #include <stdio.h>
542a8682a8SVincenzo Maffione #include <stdlib.h>
552a8682a8SVincenzo Maffione #include <string.h>
562a8682a8SVincenzo Maffione #include <time.h>
572a8682a8SVincenzo Maffione #include <unistd.h>
582a8682a8SVincenzo Maffione #include <signal.h>
5936d6e657SVincenzo Maffione #include <stddef.h>
602a8682a8SVincenzo Maffione 
617d757b71SOlivier Cochard #ifdef __FreeBSD__
627d757b71SOlivier Cochard #include "freebsd_test_suite/macros.h"
637d757b71SOlivier Cochard 
642a8682a8SVincenzo Maffione static int
eventfd(int x __unused,int y __unused)652a8682a8SVincenzo Maffione eventfd(int x __unused, int y __unused)
662a8682a8SVincenzo Maffione {
672a8682a8SVincenzo Maffione 	errno = ENODEV;
682a8682a8SVincenzo Maffione 	return -1;
692a8682a8SVincenzo Maffione }
704f6858e8SVincenzo Maffione #else /* __linux__ */
714f6858e8SVincenzo Maffione #include <sys/eventfd.h>
724f6858e8SVincenzo Maffione #endif
732a8682a8SVincenzo Maffione 
7436d6e657SVincenzo Maffione #define NM_IFNAMSZ 64
7536d6e657SVincenzo Maffione 
762a8682a8SVincenzo Maffione static int
exec_command(int argc,const char * const argv[])772a8682a8SVincenzo Maffione exec_command(int argc, const char *const argv[])
782a8682a8SVincenzo Maffione {
792a8682a8SVincenzo Maffione 	pid_t child_pid;
802a8682a8SVincenzo Maffione 	pid_t wret;
812a8682a8SVincenzo Maffione 	int child_status;
822a8682a8SVincenzo Maffione 	int i;
832a8682a8SVincenzo Maffione 
842a8682a8SVincenzo Maffione 	printf("Executing command: ");
852a8682a8SVincenzo Maffione 	for (i = 0; i < argc - 1; i++) {
862a8682a8SVincenzo Maffione 		if (!argv[i]) {
872a8682a8SVincenzo Maffione 			/* Invalid argument. */
882a8682a8SVincenzo Maffione 			return -1;
892a8682a8SVincenzo Maffione 		}
902a8682a8SVincenzo Maffione 		if (i > 0) {
912a8682a8SVincenzo Maffione 			putchar(' ');
922a8682a8SVincenzo Maffione 		}
932a8682a8SVincenzo Maffione 		printf("%s", argv[i]);
942a8682a8SVincenzo Maffione 	}
952a8682a8SVincenzo Maffione 	putchar('\n');
962a8682a8SVincenzo Maffione 
972a8682a8SVincenzo Maffione 	child_pid = fork();
982a8682a8SVincenzo Maffione 	if (child_pid == 0) {
992a8682a8SVincenzo Maffione 		char **av;
10008f34ad9SVincenzo Maffione 		int fds[3];
1012a8682a8SVincenzo Maffione 
1022a8682a8SVincenzo Maffione 		/* Child process. Redirect stdin, stdout
1032a8682a8SVincenzo Maffione 		 * and stderr. */
10408f34ad9SVincenzo Maffione 		for (i = 0; i < 3; i++) {
10508f34ad9SVincenzo Maffione 			close(i);
10608f34ad9SVincenzo Maffione 			fds[i] = open("/dev/null", O_RDONLY);
10708f34ad9SVincenzo Maffione 			if (fds[i] < 0) {
10808f34ad9SVincenzo Maffione 				for (i--; i >= 0; i--) {
10908f34ad9SVincenzo Maffione 					close(fds[i]);
11008f34ad9SVincenzo Maffione 				}
1112a8682a8SVincenzo Maffione 				return -1;
1122a8682a8SVincenzo Maffione 			}
11308f34ad9SVincenzo Maffione 		}
1142a8682a8SVincenzo Maffione 
1152a8682a8SVincenzo Maffione 		/* Make a copy of the arguments, passing them to execvp. */
1162a8682a8SVincenzo Maffione 		av = calloc(argc, sizeof(av[0]));
1172a8682a8SVincenzo Maffione 		if (!av) {
1182a8682a8SVincenzo Maffione 			exit(EXIT_FAILURE);
1192a8682a8SVincenzo Maffione 		}
1202a8682a8SVincenzo Maffione 		for (i = 0; i < argc - 1; i++) {
1212a8682a8SVincenzo Maffione 			av[i] = strdup(argv[i]);
1222a8682a8SVincenzo Maffione 			if (!av[i]) {
1232a8682a8SVincenzo Maffione 				exit(EXIT_FAILURE);
1242a8682a8SVincenzo Maffione 			}
1252a8682a8SVincenzo Maffione 		}
1262a8682a8SVincenzo Maffione 		execvp(av[0], av);
1272a8682a8SVincenzo Maffione 		perror("execvp()");
1282a8682a8SVincenzo Maffione 		exit(EXIT_FAILURE);
1292a8682a8SVincenzo Maffione 	}
1302a8682a8SVincenzo Maffione 
1312a8682a8SVincenzo Maffione 	wret = waitpid(child_pid, &child_status, 0);
1322a8682a8SVincenzo Maffione 	if (wret < 0) {
1332a8682a8SVincenzo Maffione 		fprintf(stderr, "waitpid() failed: %s\n", strerror(errno));
1342a8682a8SVincenzo Maffione 		return wret;
1352a8682a8SVincenzo Maffione 	}
1362a8682a8SVincenzo Maffione 	if (WIFEXITED(child_status)) {
1372a8682a8SVincenzo Maffione 		return WEXITSTATUS(child_status);
1382a8682a8SVincenzo Maffione 	}
1392a8682a8SVincenzo Maffione 
1402a8682a8SVincenzo Maffione 	return -1;
1412a8682a8SVincenzo Maffione }
1422a8682a8SVincenzo Maffione 
1432a8682a8SVincenzo Maffione 
1442a8682a8SVincenzo Maffione #define THRET_SUCCESS	((void *)128)
1452a8682a8SVincenzo Maffione #define THRET_FAILURE	((void *)0)
1462a8682a8SVincenzo Maffione 
1472a8682a8SVincenzo Maffione struct TestContext {
14836d6e657SVincenzo Maffione 	char ifname[NM_IFNAMSZ];
14936d6e657SVincenzo Maffione 	char ifname_ext[NM_IFNAMSZ];
15036d6e657SVincenzo Maffione 	char bdgname[NM_IFNAMSZ];
1512a8682a8SVincenzo Maffione 	uint32_t nr_tx_slots;   /* slots in tx rings */
1522a8682a8SVincenzo Maffione 	uint32_t nr_rx_slots;   /* slots in rx rings */
1532a8682a8SVincenzo Maffione 	uint16_t nr_tx_rings;   /* number of tx rings */
1542a8682a8SVincenzo Maffione 	uint16_t nr_rx_rings;   /* number of rx rings */
1554f6858e8SVincenzo Maffione 	uint16_t nr_host_tx_rings;   /* number of host tx rings */
1564f6858e8SVincenzo Maffione 	uint16_t nr_host_rx_rings;   /* number of host rx rings */
1572a8682a8SVincenzo Maffione 	uint16_t nr_mem_id;     /* id of the memory allocator */
1582a8682a8SVincenzo Maffione 	uint16_t nr_ringid;     /* ring(s) we care about */
1592a8682a8SVincenzo Maffione 	uint32_t nr_mode;       /* specify NR_REG_* modes */
1602a8682a8SVincenzo Maffione 	uint32_t nr_extra_bufs; /* number of requested extra buffers */
1612a8682a8SVincenzo Maffione 	uint64_t nr_flags;      /* additional flags (see below) */
1622a8682a8SVincenzo Maffione 	uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
1632a8682a8SVincenzo Maffione 	uint32_t nr_first_cpu_id;     /* vale polling */
1642a8682a8SVincenzo Maffione 	uint32_t nr_num_polling_cpus; /* vale polling */
1655e874d26SVincenzo Maffione 	uint32_t sync_kloop_mode; /* sync-kloop */
1662a8682a8SVincenzo Maffione 	int fd; /* netmap file descriptor */
1672a8682a8SVincenzo Maffione 
1682a8682a8SVincenzo Maffione 	void *csb;                    /* CSB entries (atok and ktoa) */
1692a8682a8SVincenzo Maffione 	struct nmreq_option *nr_opt;  /* list of options */
1702a8682a8SVincenzo Maffione 	sem_t *sem;	/* for thread synchronization */
17136d6e657SVincenzo Maffione 
17236d6e657SVincenzo Maffione 	struct nmctx *nmctx;
17336d6e657SVincenzo Maffione 	const char *ifparse;
17436d6e657SVincenzo Maffione 	struct nmport_d *nmport;      /* nmport descriptor from libnetmap */
1752a8682a8SVincenzo Maffione };
1762a8682a8SVincenzo Maffione 
1772a8682a8SVincenzo Maffione static struct TestContext ctx_;
1782a8682a8SVincenzo Maffione 
1792a8682a8SVincenzo Maffione typedef int (*testfunc_t)(struct TestContext *ctx);
1802a8682a8SVincenzo Maffione 
1812a8682a8SVincenzo Maffione static void
nmreq_hdr_init(struct nmreq_header * hdr,const char * ifname)1822a8682a8SVincenzo Maffione nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
1832a8682a8SVincenzo Maffione {
1842a8682a8SVincenzo Maffione 	memset(hdr, 0, sizeof(*hdr));
1852a8682a8SVincenzo Maffione 	hdr->nr_version = NETMAP_API;
18636d6e657SVincenzo Maffione 	assert(strlen(ifname) < NM_IFNAMSZ);
18736d6e657SVincenzo Maffione 	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name));
1882a8682a8SVincenzo Maffione }
1892a8682a8SVincenzo Maffione 
1902a8682a8SVincenzo Maffione /* Single NETMAP_REQ_PORT_INFO_GET. */
1912a8682a8SVincenzo Maffione static int
port_info_get(struct TestContext * ctx)1922a8682a8SVincenzo Maffione port_info_get(struct TestContext *ctx)
1932a8682a8SVincenzo Maffione {
1942a8682a8SVincenzo Maffione 	struct nmreq_port_info_get req;
1952a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
1962a8682a8SVincenzo Maffione 	int success;
1972a8682a8SVincenzo Maffione 	int ret;
1982a8682a8SVincenzo Maffione 
19908f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname_ext);
2002a8682a8SVincenzo Maffione 
20108f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
2022a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
2032a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
2042a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
2052a8682a8SVincenzo Maffione 	req.nr_mem_id = ctx->nr_mem_id;
2062a8682a8SVincenzo Maffione 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
2072a8682a8SVincenzo Maffione 	if (ret != 0) {
2082a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
2092a8682a8SVincenzo Maffione 		return ret;
2102a8682a8SVincenzo Maffione 	}
2115854d718SVincenzo Maffione 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
2122a8682a8SVincenzo Maffione 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
2132a8682a8SVincenzo Maffione 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
2142a8682a8SVincenzo Maffione 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
2152a8682a8SVincenzo Maffione 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
2162a8682a8SVincenzo Maffione 	printf("nr_mem_id %u\n", req.nr_mem_id);
2172a8682a8SVincenzo Maffione 
2182a8682a8SVincenzo Maffione 	success = req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
2192a8682a8SVincenzo Maffione 	          req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings;
2202a8682a8SVincenzo Maffione 	if (!success) {
2212a8682a8SVincenzo Maffione 		return -1;
2222a8682a8SVincenzo Maffione 	}
2232a8682a8SVincenzo Maffione 
2242a8682a8SVincenzo Maffione 	/* Write back results to the context structure. */
2252a8682a8SVincenzo Maffione 	ctx->nr_tx_slots = req.nr_tx_slots;
2262a8682a8SVincenzo Maffione 	ctx->nr_rx_slots = req.nr_rx_slots;
2272a8682a8SVincenzo Maffione 	ctx->nr_tx_rings = req.nr_tx_rings;
2282a8682a8SVincenzo Maffione 	ctx->nr_rx_rings = req.nr_rx_rings;
2292a8682a8SVincenzo Maffione 	ctx->nr_mem_id   = req.nr_mem_id;
2302a8682a8SVincenzo Maffione 
2312a8682a8SVincenzo Maffione 	return 0;
2322a8682a8SVincenzo Maffione }
2332a8682a8SVincenzo Maffione 
2342a8682a8SVincenzo Maffione /* Single NETMAP_REQ_REGISTER, no use. */
2352a8682a8SVincenzo Maffione static int
port_register(struct TestContext * ctx)2362a8682a8SVincenzo Maffione port_register(struct TestContext *ctx)
2372a8682a8SVincenzo Maffione {
2382a8682a8SVincenzo Maffione 	struct nmreq_register req;
2392a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
2402a8682a8SVincenzo Maffione 	int success;
2412a8682a8SVincenzo Maffione 	int ret;
2422a8682a8SVincenzo Maffione 
2432a8682a8SVincenzo Maffione 	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
2445854d718SVincenzo Maffione 	       "flags=0x%llx) on '%s'\n",
2455854d718SVincenzo Maffione 	       ctx->nr_mode, ctx->nr_ringid, (unsigned long long)ctx->nr_flags,
24608f34ad9SVincenzo Maffione 	       ctx->ifname_ext);
2472a8682a8SVincenzo Maffione 
24808f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
2492a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
2502a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
2512a8682a8SVincenzo Maffione 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
2522a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
2532a8682a8SVincenzo Maffione 	req.nr_mem_id     = ctx->nr_mem_id;
2542a8682a8SVincenzo Maffione 	req.nr_mode       = ctx->nr_mode;
2552a8682a8SVincenzo Maffione 	req.nr_ringid     = ctx->nr_ringid;
2562a8682a8SVincenzo Maffione 	req.nr_flags      = ctx->nr_flags;
2572a8682a8SVincenzo Maffione 	req.nr_tx_slots   = ctx->nr_tx_slots;
2582a8682a8SVincenzo Maffione 	req.nr_rx_slots   = ctx->nr_rx_slots;
2592a8682a8SVincenzo Maffione 	req.nr_tx_rings   = ctx->nr_tx_rings;
2604f6858e8SVincenzo Maffione 	req.nr_host_tx_rings = ctx->nr_host_tx_rings;
2614f6858e8SVincenzo Maffione 	req.nr_host_rx_rings = ctx->nr_host_rx_rings;
2622a8682a8SVincenzo Maffione 	req.nr_rx_rings   = ctx->nr_rx_rings;
2632a8682a8SVincenzo Maffione 	req.nr_extra_bufs = ctx->nr_extra_bufs;
2642a8682a8SVincenzo Maffione 	ret               = ioctl(ctx->fd, NIOCCTRL, &hdr);
2652a8682a8SVincenzo Maffione 	if (ret != 0) {
2662a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
2672a8682a8SVincenzo Maffione 		return ret;
2682a8682a8SVincenzo Maffione 	}
2695854d718SVincenzo Maffione 	printf("nr_offset 0x%llx\n", (unsigned long long)req.nr_offset);
2705854d718SVincenzo Maffione 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
2712a8682a8SVincenzo Maffione 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
2722a8682a8SVincenzo Maffione 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
2732a8682a8SVincenzo Maffione 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
2742a8682a8SVincenzo Maffione 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
2754f6858e8SVincenzo Maffione 	printf("nr_host_tx_rings %u\n", req.nr_host_tx_rings);
2764f6858e8SVincenzo Maffione 	printf("nr_host_rx_rings %u\n", req.nr_host_rx_rings);
2772a8682a8SVincenzo Maffione 	printf("nr_mem_id %u\n", req.nr_mem_id);
2782a8682a8SVincenzo Maffione 	printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
2792a8682a8SVincenzo Maffione 
2802a8682a8SVincenzo Maffione 	success = req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
2812a8682a8SVincenzo Maffione 		       (ctx->nr_ringid == req.nr_ringid) &&
2822a8682a8SVincenzo Maffione 		       (ctx->nr_flags == req.nr_flags) &&
2832a8682a8SVincenzo Maffione 		       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
2842a8682a8SVincenzo Maffione 			(ctx->nr_tx_slots == req.nr_tx_slots)) &&
2852a8682a8SVincenzo Maffione 		       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
2862a8682a8SVincenzo Maffione 			(ctx->nr_rx_slots == req.nr_rx_slots)) &&
2872a8682a8SVincenzo Maffione 		       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
2882a8682a8SVincenzo Maffione 			(ctx->nr_tx_rings == req.nr_tx_rings)) &&
2892a8682a8SVincenzo Maffione 		       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
2902a8682a8SVincenzo Maffione 			(ctx->nr_rx_rings == req.nr_rx_rings)) &&
2914f6858e8SVincenzo Maffione 		       ((!ctx->nr_host_tx_rings && req.nr_host_tx_rings) ||
2924f6858e8SVincenzo Maffione 			(ctx->nr_host_tx_rings == req.nr_host_tx_rings)) &&
2934f6858e8SVincenzo Maffione 		       ((!ctx->nr_host_rx_rings && req.nr_host_rx_rings) ||
2944f6858e8SVincenzo Maffione 			(ctx->nr_host_rx_rings == req.nr_host_rx_rings)) &&
2952a8682a8SVincenzo Maffione 		       ((!ctx->nr_mem_id && req.nr_mem_id) ||
2962a8682a8SVincenzo Maffione 			(ctx->nr_mem_id == req.nr_mem_id)) &&
2972a8682a8SVincenzo Maffione 		       (ctx->nr_extra_bufs == req.nr_extra_bufs);
2982a8682a8SVincenzo Maffione 	if (!success) {
2992a8682a8SVincenzo Maffione 		return -1;
3002a8682a8SVincenzo Maffione 	}
3012a8682a8SVincenzo Maffione 
3022a8682a8SVincenzo Maffione 	/* Write back results to the context structure.*/
3032a8682a8SVincenzo Maffione 	ctx->nr_tx_slots   = req.nr_tx_slots;
3042a8682a8SVincenzo Maffione 	ctx->nr_rx_slots   = req.nr_rx_slots;
3052a8682a8SVincenzo Maffione 	ctx->nr_tx_rings   = req.nr_tx_rings;
3062a8682a8SVincenzo Maffione 	ctx->nr_rx_rings   = req.nr_rx_rings;
3074f6858e8SVincenzo Maffione 	ctx->nr_host_tx_rings = req.nr_host_tx_rings;
3084f6858e8SVincenzo Maffione 	ctx->nr_host_rx_rings = req.nr_host_rx_rings;
3092a8682a8SVincenzo Maffione 	ctx->nr_mem_id     = req.nr_mem_id;
3102a8682a8SVincenzo Maffione 	ctx->nr_extra_bufs = req.nr_extra_bufs;
3112a8682a8SVincenzo Maffione 
3122a8682a8SVincenzo Maffione 	return 0;
3132a8682a8SVincenzo Maffione }
3142a8682a8SVincenzo Maffione 
3152a8682a8SVincenzo Maffione static int
niocregif(struct TestContext * ctx,int netmap_api)3162a8682a8SVincenzo Maffione niocregif(struct TestContext *ctx, int netmap_api)
3172a8682a8SVincenzo Maffione {
3182a8682a8SVincenzo Maffione 	struct nmreq req;
3192a8682a8SVincenzo Maffione 	int success;
3202a8682a8SVincenzo Maffione 	int ret;
3212a8682a8SVincenzo Maffione 
32208f34ad9SVincenzo Maffione 	printf("Testing legacy NIOCREGIF on '%s'\n", ctx->ifname_ext);
3232a8682a8SVincenzo Maffione 
3242a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
32508f34ad9SVincenzo Maffione 	memcpy(req.nr_name, ctx->ifname_ext, sizeof(req.nr_name));
3262a8682a8SVincenzo Maffione 	req.nr_name[sizeof(req.nr_name) - 1] = '\0';
3272a8682a8SVincenzo Maffione 	req.nr_version = netmap_api;
3282a8682a8SVincenzo Maffione 	req.nr_ringid     = ctx->nr_ringid;
3292a8682a8SVincenzo Maffione 	req.nr_flags      = ctx->nr_mode | ctx->nr_flags;
3302a8682a8SVincenzo Maffione 	req.nr_tx_slots   = ctx->nr_tx_slots;
3312a8682a8SVincenzo Maffione 	req.nr_rx_slots   = ctx->nr_rx_slots;
3322a8682a8SVincenzo Maffione 	req.nr_tx_rings   = ctx->nr_tx_rings;
3332a8682a8SVincenzo Maffione 	req.nr_rx_rings   = ctx->nr_rx_rings;
3342a8682a8SVincenzo Maffione 	req.nr_arg2     = ctx->nr_mem_id;
3352a8682a8SVincenzo Maffione 	req.nr_arg3 = ctx->nr_extra_bufs;
3362a8682a8SVincenzo Maffione 
3372a8682a8SVincenzo Maffione 	ret = ioctl(ctx->fd, NIOCREGIF, &req);
3382a8682a8SVincenzo Maffione 	if (ret != 0) {
3392a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCREGIF)");
3402a8682a8SVincenzo Maffione 		return ret;
3412a8682a8SVincenzo Maffione 	}
3422a8682a8SVincenzo Maffione 
3432a8682a8SVincenzo Maffione 	printf("nr_offset 0x%x\n", req.nr_offset);
3442a8682a8SVincenzo Maffione 	printf("nr_memsize  %u\n", req.nr_memsize);
3452a8682a8SVincenzo Maffione 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
3462a8682a8SVincenzo Maffione 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
3472a8682a8SVincenzo Maffione 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
3482a8682a8SVincenzo Maffione 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
3492a8682a8SVincenzo Maffione 	printf("nr_version  %d\n", req.nr_version);
3502a8682a8SVincenzo Maffione 	printf("nr_ringid   %x\n", req.nr_ringid);
3512a8682a8SVincenzo Maffione 	printf("nr_flags    %x\n", req.nr_flags);
3522a8682a8SVincenzo Maffione 	printf("nr_arg2     %u\n", req.nr_arg2);
3532a8682a8SVincenzo Maffione 	printf("nr_arg3     %u\n", req.nr_arg3);
3542a8682a8SVincenzo Maffione 
3552a8682a8SVincenzo Maffione 	success = req.nr_memsize &&
3562a8682a8SVincenzo Maffione 	       (ctx->nr_ringid == req.nr_ringid) &&
3572a8682a8SVincenzo Maffione 	       ((ctx->nr_mode | ctx->nr_flags) == req.nr_flags) &&
3582a8682a8SVincenzo Maffione 	       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
3592a8682a8SVincenzo Maffione 		(ctx->nr_tx_slots == req.nr_tx_slots)) &&
3602a8682a8SVincenzo Maffione 	       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
3612a8682a8SVincenzo Maffione 		(ctx->nr_rx_slots == req.nr_rx_slots)) &&
3622a8682a8SVincenzo Maffione 	       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
3632a8682a8SVincenzo Maffione 		(ctx->nr_tx_rings == req.nr_tx_rings)) &&
3642a8682a8SVincenzo Maffione 	       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
3652a8682a8SVincenzo Maffione 		(ctx->nr_rx_rings == req.nr_rx_rings)) &&
3662a8682a8SVincenzo Maffione 	       ((!ctx->nr_mem_id && req.nr_arg2) ||
3672a8682a8SVincenzo Maffione 		(ctx->nr_mem_id == req.nr_arg2)) &&
3682a8682a8SVincenzo Maffione 	       (ctx->nr_extra_bufs == req.nr_arg3);
3692a8682a8SVincenzo Maffione 	if (!success) {
3702a8682a8SVincenzo Maffione 		return -1;
3712a8682a8SVincenzo Maffione 	}
3722a8682a8SVincenzo Maffione 
3732a8682a8SVincenzo Maffione 	/* Write back results to the context structure.*/
3742a8682a8SVincenzo Maffione 	ctx->nr_tx_slots   = req.nr_tx_slots;
3752a8682a8SVincenzo Maffione 	ctx->nr_rx_slots   = req.nr_rx_slots;
3762a8682a8SVincenzo Maffione 	ctx->nr_tx_rings   = req.nr_tx_rings;
3772a8682a8SVincenzo Maffione 	ctx->nr_rx_rings   = req.nr_rx_rings;
3782a8682a8SVincenzo Maffione 	ctx->nr_mem_id     = req.nr_arg2;
3792a8682a8SVincenzo Maffione 	ctx->nr_extra_bufs = req.nr_arg3;
3802a8682a8SVincenzo Maffione 
3812a8682a8SVincenzo Maffione 	return ret;
3822a8682a8SVincenzo Maffione }
3832a8682a8SVincenzo Maffione 
3842a8682a8SVincenzo Maffione /* The 11 ABI is the one right before the introduction of the new NIOCCTRL
3852a8682a8SVincenzo Maffione  * ABI. The 11 ABI is useful to perform tests with legacy applications
3865e874d26SVincenzo Maffione  * (which use the 11 ABI) and new kernel (which uses 12, or higher).
3875e874d26SVincenzo Maffione  * However, version 14 introduced a change in the layout of struct netmap_if,
3885e874d26SVincenzo Maffione  * so that binary backward compatibility to 11 is not supported anymore.
3895e874d26SVincenzo Maffione  */
3905e874d26SVincenzo Maffione #define NETMAP_API_NIOCREGIF	14
3912a8682a8SVincenzo Maffione 
3922a8682a8SVincenzo Maffione static int
legacy_regif_default(struct TestContext * ctx)3932a8682a8SVincenzo Maffione legacy_regif_default(struct TestContext *ctx)
3942a8682a8SVincenzo Maffione {
3952a8682a8SVincenzo Maffione 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
3962a8682a8SVincenzo Maffione }
3972a8682a8SVincenzo Maffione 
3982a8682a8SVincenzo Maffione static int
legacy_regif_all_nic(struct TestContext * ctx)3992a8682a8SVincenzo Maffione legacy_regif_all_nic(struct TestContext *ctx)
4002a8682a8SVincenzo Maffione {
4012a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
4022a8682a8SVincenzo Maffione 	return niocregif(ctx, NETMAP_API);
4032a8682a8SVincenzo Maffione }
4042a8682a8SVincenzo Maffione 
4052a8682a8SVincenzo Maffione static int
legacy_regif_12(struct TestContext * ctx)4062a8682a8SVincenzo Maffione legacy_regif_12(struct TestContext *ctx)
4072a8682a8SVincenzo Maffione {
4082a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
4092a8682a8SVincenzo Maffione 	return niocregif(ctx, NETMAP_API_NIOCREGIF+1);
4102a8682a8SVincenzo Maffione }
4112a8682a8SVincenzo Maffione 
4122a8682a8SVincenzo Maffione static int
legacy_regif_sw(struct TestContext * ctx)4132a8682a8SVincenzo Maffione legacy_regif_sw(struct TestContext *ctx)
4142a8682a8SVincenzo Maffione {
4152a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_SW;
4162a8682a8SVincenzo Maffione 	return niocregif(ctx,  NETMAP_API_NIOCREGIF);
4172a8682a8SVincenzo Maffione }
4182a8682a8SVincenzo Maffione 
4192a8682a8SVincenzo Maffione static int
legacy_regif_future(struct TestContext * ctx)4202a8682a8SVincenzo Maffione legacy_regif_future(struct TestContext *ctx)
4212a8682a8SVincenzo Maffione {
4222a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_NIC_SW;
4232a8682a8SVincenzo Maffione 	/* Test forward compatibility for the legacy ABI. This means
4242a8682a8SVincenzo Maffione 	 * using an older kernel (with ABI 12 or higher) and a newer
4252a8682a8SVincenzo Maffione 	 * application (with ABI greater than NETMAP_API). */
4262a8682a8SVincenzo Maffione 	return niocregif(ctx, NETMAP_API+2);
4272a8682a8SVincenzo Maffione }
4282a8682a8SVincenzo Maffione 
4292a8682a8SVincenzo Maffione static int
legacy_regif_extra_bufs(struct TestContext * ctx)4302a8682a8SVincenzo Maffione legacy_regif_extra_bufs(struct TestContext *ctx)
4312a8682a8SVincenzo Maffione {
4322a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
4332a8682a8SVincenzo Maffione 	ctx->nr_extra_bufs = 20;	/* arbitrary number of extra bufs */
4342a8682a8SVincenzo Maffione 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
4352a8682a8SVincenzo Maffione }
4362a8682a8SVincenzo Maffione 
4372a8682a8SVincenzo Maffione static int
legacy_regif_extra_bufs_pipe(struct TestContext * ctx)4382a8682a8SVincenzo Maffione legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
4392a8682a8SVincenzo Maffione {
44008f34ad9SVincenzo Maffione 	strncat(ctx->ifname_ext, "{pipeexbuf", sizeof(ctx->ifname_ext));
4412a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
4422a8682a8SVincenzo Maffione 	ctx->nr_extra_bufs = 58;	/* arbitrary number of extra bufs */
4432a8682a8SVincenzo Maffione 
4442a8682a8SVincenzo Maffione 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
4452a8682a8SVincenzo Maffione }
4462a8682a8SVincenzo Maffione 
4472a8682a8SVincenzo Maffione static int
legacy_regif_extra_bufs_pipe_vale(struct TestContext * ctx)4482a8682a8SVincenzo Maffione legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
4492a8682a8SVincenzo Maffione {
45008f34ad9SVincenzo Maffione 	strncpy(ctx->ifname_ext, "valeX1:Y4", sizeof(ctx->ifname_ext));
4512a8682a8SVincenzo Maffione 	return legacy_regif_extra_bufs_pipe(ctx);
4522a8682a8SVincenzo Maffione }
4532a8682a8SVincenzo Maffione 
4542a8682a8SVincenzo Maffione /* Only valid after a successful port_register(). */
4552a8682a8SVincenzo Maffione static int
num_registered_rings(struct TestContext * ctx)4562a8682a8SVincenzo Maffione num_registered_rings(struct TestContext *ctx)
4572a8682a8SVincenzo Maffione {
4582a8682a8SVincenzo Maffione 	if (ctx->nr_flags & NR_TX_RINGS_ONLY) {
4592a8682a8SVincenzo Maffione 		return ctx->nr_tx_rings;
4602a8682a8SVincenzo Maffione 	}
4612a8682a8SVincenzo Maffione 	if (ctx->nr_flags & NR_RX_RINGS_ONLY) {
4622a8682a8SVincenzo Maffione 		return ctx->nr_rx_rings;
4632a8682a8SVincenzo Maffione 	}
4642a8682a8SVincenzo Maffione 
4652a8682a8SVincenzo Maffione 	return ctx->nr_tx_rings + ctx->nr_rx_rings;
4662a8682a8SVincenzo Maffione }
4672a8682a8SVincenzo Maffione 
4682a8682a8SVincenzo Maffione static int
port_register_hwall_host(struct TestContext * ctx)4692a8682a8SVincenzo Maffione port_register_hwall_host(struct TestContext *ctx)
4702a8682a8SVincenzo Maffione {
4712a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_NIC_SW;
4722a8682a8SVincenzo Maffione 	return port_register(ctx);
4732a8682a8SVincenzo Maffione }
4742a8682a8SVincenzo Maffione 
4752a8682a8SVincenzo Maffione static int
port_register_hostall(struct TestContext * ctx)4764f6858e8SVincenzo Maffione port_register_hostall(struct TestContext *ctx)
4772a8682a8SVincenzo Maffione {
4782a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_SW;
4792a8682a8SVincenzo Maffione 	return port_register(ctx);
4802a8682a8SVincenzo Maffione }
4812a8682a8SVincenzo Maffione 
4822a8682a8SVincenzo Maffione static int
port_register_hwall(struct TestContext * ctx)4832a8682a8SVincenzo Maffione port_register_hwall(struct TestContext *ctx)
4842a8682a8SVincenzo Maffione {
4852a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
4862a8682a8SVincenzo Maffione 	return port_register(ctx);
4872a8682a8SVincenzo Maffione }
4882a8682a8SVincenzo Maffione 
4892a8682a8SVincenzo Maffione static int
port_register_single_hw_pair(struct TestContext * ctx)4904f6858e8SVincenzo Maffione port_register_single_hw_pair(struct TestContext *ctx)
4912a8682a8SVincenzo Maffione {
4922a8682a8SVincenzo Maffione 	ctx->nr_mode   = NR_REG_ONE_NIC;
4932a8682a8SVincenzo Maffione 	ctx->nr_ringid = 0;
4942a8682a8SVincenzo Maffione 	return port_register(ctx);
4952a8682a8SVincenzo Maffione }
4962a8682a8SVincenzo Maffione 
4972a8682a8SVincenzo Maffione static int
port_register_single_host_pair(struct TestContext * ctx)4984f6858e8SVincenzo Maffione port_register_single_host_pair(struct TestContext *ctx)
4994f6858e8SVincenzo Maffione {
5004f6858e8SVincenzo Maffione 	ctx->nr_mode   = NR_REG_ONE_SW;
5014f6858e8SVincenzo Maffione 	ctx->nr_host_tx_rings = 2;
5024f6858e8SVincenzo Maffione 	ctx->nr_host_rx_rings = 2;
5034f6858e8SVincenzo Maffione 	ctx->nr_ringid = 1;
5044f6858e8SVincenzo Maffione 	return port_register(ctx);
5054f6858e8SVincenzo Maffione }
5064f6858e8SVincenzo Maffione 
5074f6858e8SVincenzo Maffione static int
port_register_hostall_many(struct TestContext * ctx)5084f6858e8SVincenzo Maffione port_register_hostall_many(struct TestContext *ctx)
5094f6858e8SVincenzo Maffione {
5104f6858e8SVincenzo Maffione 	ctx->nr_mode   = NR_REG_SW;
5114f6858e8SVincenzo Maffione 	ctx->nr_host_tx_rings = 5;
5124f6858e8SVincenzo Maffione 	ctx->nr_host_rx_rings = 4;
5134f6858e8SVincenzo Maffione 	return port_register(ctx);
5144f6858e8SVincenzo Maffione }
5154f6858e8SVincenzo Maffione 
5164f6858e8SVincenzo Maffione static int
port_register_hwall_tx(struct TestContext * ctx)5172a8682a8SVincenzo Maffione port_register_hwall_tx(struct TestContext *ctx)
5182a8682a8SVincenzo Maffione {
5192a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
5202a8682a8SVincenzo Maffione 	ctx->nr_flags |= NR_TX_RINGS_ONLY;
5212a8682a8SVincenzo Maffione 	return port_register(ctx);
5222a8682a8SVincenzo Maffione }
5232a8682a8SVincenzo Maffione 
5242a8682a8SVincenzo Maffione static int
port_register_hwall_rx(struct TestContext * ctx)5252a8682a8SVincenzo Maffione port_register_hwall_rx(struct TestContext *ctx)
5262a8682a8SVincenzo Maffione {
5272a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
5282a8682a8SVincenzo Maffione 	ctx->nr_flags |= NR_RX_RINGS_ONLY;
5292a8682a8SVincenzo Maffione 	return port_register(ctx);
5302a8682a8SVincenzo Maffione }
5312a8682a8SVincenzo Maffione 
53236d6e657SVincenzo Maffione 
53336d6e657SVincenzo Maffione static int
vale_mkname(char * vpname,struct TestContext * ctx)53436d6e657SVincenzo Maffione vale_mkname(char *vpname, struct TestContext *ctx)
53536d6e657SVincenzo Maffione {
53636d6e657SVincenzo Maffione 	if (snprintf(vpname, NM_IFNAMSZ, "%s:%s", ctx->bdgname, ctx->ifname_ext) >= NM_IFNAMSZ) {
53736d6e657SVincenzo Maffione 		fprintf(stderr, "%s:%s too long (max %d chars)\n", ctx->bdgname, ctx->ifname_ext,
53836d6e657SVincenzo Maffione 				NM_IFNAMSZ - 1);
53936d6e657SVincenzo Maffione 		return -1;
54036d6e657SVincenzo Maffione 	}
54136d6e657SVincenzo Maffione 	return 0;
54236d6e657SVincenzo Maffione }
54336d6e657SVincenzo Maffione 
54436d6e657SVincenzo Maffione 
5452a8682a8SVincenzo Maffione /* NETMAP_REQ_VALE_ATTACH */
5462a8682a8SVincenzo Maffione static int
vale_attach(struct TestContext * ctx)5472a8682a8SVincenzo Maffione vale_attach(struct TestContext *ctx)
5482a8682a8SVincenzo Maffione {
5492a8682a8SVincenzo Maffione 	struct nmreq_vale_attach req;
5502a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
55136d6e657SVincenzo Maffione 	char vpname[NM_IFNAMSZ];
5522a8682a8SVincenzo Maffione 	int ret;
5532a8682a8SVincenzo Maffione 
55436d6e657SVincenzo Maffione 	if (vale_mkname(vpname, ctx) < 0)
55536d6e657SVincenzo Maffione 		return -1;
5562a8682a8SVincenzo Maffione 
5572a8682a8SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
5582a8682a8SVincenzo Maffione 	nmreq_hdr_init(&hdr, vpname);
5592a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
5602a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
5612a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
5622a8682a8SVincenzo Maffione 	req.reg.nr_mem_id = ctx->nr_mem_id;
5632a8682a8SVincenzo Maffione 	if (ctx->nr_mode == 0) {
5642a8682a8SVincenzo Maffione 		ctx->nr_mode = NR_REG_ALL_NIC; /* default */
5652a8682a8SVincenzo Maffione 	}
5662a8682a8SVincenzo Maffione 	req.reg.nr_mode = ctx->nr_mode;
5672a8682a8SVincenzo Maffione 	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
5682a8682a8SVincenzo Maffione 	if (ret != 0) {
5692a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
5702a8682a8SVincenzo Maffione 		return ret;
5712a8682a8SVincenzo Maffione 	}
5722a8682a8SVincenzo Maffione 	printf("nr_mem_id %u\n", req.reg.nr_mem_id);
5732a8682a8SVincenzo Maffione 
5742a8682a8SVincenzo Maffione 	return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
5752a8682a8SVincenzo Maffione 	        (ctx->nr_mem_id == req.reg.nr_mem_id)) &&
5762a8682a8SVincenzo Maffione 	                       (ctx->nr_flags == req.reg.nr_flags)
5772a8682a8SVincenzo Maffione 	               ? 0
5782a8682a8SVincenzo Maffione 	               : -1;
5792a8682a8SVincenzo Maffione }
5802a8682a8SVincenzo Maffione 
5812a8682a8SVincenzo Maffione /* NETMAP_REQ_VALE_DETACH */
5822a8682a8SVincenzo Maffione static int
vale_detach(struct TestContext * ctx)5832a8682a8SVincenzo Maffione vale_detach(struct TestContext *ctx)
5842a8682a8SVincenzo Maffione {
5852a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
5862a8682a8SVincenzo Maffione 	struct nmreq_vale_detach req;
58736d6e657SVincenzo Maffione 	char vpname[NM_IFNAMSZ];
5882a8682a8SVincenzo Maffione 	int ret;
5892a8682a8SVincenzo Maffione 
59036d6e657SVincenzo Maffione 	if (vale_mkname(vpname, ctx) < 0)
59136d6e657SVincenzo Maffione 		return -1;
5922a8682a8SVincenzo Maffione 
5932a8682a8SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
5942a8682a8SVincenzo Maffione 	nmreq_hdr_init(&hdr, vpname);
5952a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
5962a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
5972a8682a8SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
5982a8682a8SVincenzo Maffione 	if (ret != 0) {
5992a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
6002a8682a8SVincenzo Maffione 		return ret;
6012a8682a8SVincenzo Maffione 	}
6022a8682a8SVincenzo Maffione 
6032a8682a8SVincenzo Maffione 	return 0;
6042a8682a8SVincenzo Maffione }
6052a8682a8SVincenzo Maffione 
6062a8682a8SVincenzo Maffione /* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
6072a8682a8SVincenzo Maffione static int
vale_attach_detach(struct TestContext * ctx)6082a8682a8SVincenzo Maffione vale_attach_detach(struct TestContext *ctx)
6092a8682a8SVincenzo Maffione {
6102a8682a8SVincenzo Maffione 	int ret;
6112a8682a8SVincenzo Maffione 
6122a8682a8SVincenzo Maffione 	if ((ret = vale_attach(ctx)) != 0) {
6132a8682a8SVincenzo Maffione 		return ret;
6142a8682a8SVincenzo Maffione 	}
6152a8682a8SVincenzo Maffione 
6162a8682a8SVincenzo Maffione 	return vale_detach(ctx);
6172a8682a8SVincenzo Maffione }
6182a8682a8SVincenzo Maffione 
6192a8682a8SVincenzo Maffione static int
vale_attach_detach_host_rings(struct TestContext * ctx)6202a8682a8SVincenzo Maffione vale_attach_detach_host_rings(struct TestContext *ctx)
6212a8682a8SVincenzo Maffione {
6222a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_NIC_SW;
6232a8682a8SVincenzo Maffione 	return vale_attach_detach(ctx);
6242a8682a8SVincenzo Maffione }
6252a8682a8SVincenzo Maffione 
6262a8682a8SVincenzo Maffione /* First NETMAP_REQ_PORT_HDR_SET and the NETMAP_REQ_PORT_HDR_GET
6272a8682a8SVincenzo Maffione  * to check that we get the same value. */
6282a8682a8SVincenzo Maffione static int
port_hdr_set_and_get(struct TestContext * ctx)6292a8682a8SVincenzo Maffione port_hdr_set_and_get(struct TestContext *ctx)
6302a8682a8SVincenzo Maffione {
6312a8682a8SVincenzo Maffione 	struct nmreq_port_hdr req;
6322a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
6332a8682a8SVincenzo Maffione 	int ret;
6342a8682a8SVincenzo Maffione 
63508f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname_ext);
6362a8682a8SVincenzo Maffione 
63708f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
6382a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
6392a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
6402a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
6412a8682a8SVincenzo Maffione 	req.nr_hdr_len = ctx->nr_hdr_len;
6422a8682a8SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
6432a8682a8SVincenzo Maffione 	if (ret != 0) {
6442a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
6452a8682a8SVincenzo Maffione 		return ret;
6462a8682a8SVincenzo Maffione 	}
6472a8682a8SVincenzo Maffione 
6482a8682a8SVincenzo Maffione 	if (req.nr_hdr_len != ctx->nr_hdr_len) {
6492a8682a8SVincenzo Maffione 		return -1;
6502a8682a8SVincenzo Maffione 	}
6512a8682a8SVincenzo Maffione 
65208f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname_ext);
6532a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
6542a8682a8SVincenzo Maffione 	req.nr_hdr_len = 0;
6552a8682a8SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
6562a8682a8SVincenzo Maffione 	if (ret != 0) {
6572a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
6582a8682a8SVincenzo Maffione 		return ret;
6592a8682a8SVincenzo Maffione 	}
6602a8682a8SVincenzo Maffione 	printf("nr_hdr_len %u\n", req.nr_hdr_len);
6612a8682a8SVincenzo Maffione 
6622a8682a8SVincenzo Maffione 	return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
6632a8682a8SVincenzo Maffione }
6642a8682a8SVincenzo Maffione 
6652a8682a8SVincenzo Maffione /*
6662a8682a8SVincenzo Maffione  * Possible lengths for the VirtIO network header, as specified by
6672a8682a8SVincenzo Maffione  * the standard:
6682a8682a8SVincenzo Maffione  *    http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html
6692a8682a8SVincenzo Maffione  */
6702a8682a8SVincenzo Maffione #define VIRTIO_NET_HDR_LEN				10
6712a8682a8SVincenzo Maffione #define VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS	12
6722a8682a8SVincenzo Maffione 
6732a8682a8SVincenzo Maffione static int
vale_ephemeral_port_hdr_manipulation(struct TestContext * ctx)6742a8682a8SVincenzo Maffione vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
6752a8682a8SVincenzo Maffione {
6762a8682a8SVincenzo Maffione 	int ret;
6772a8682a8SVincenzo Maffione 
67808f34ad9SVincenzo Maffione 	strncpy(ctx->ifname_ext, "vale:eph0", sizeof(ctx->ifname_ext));
6792a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
6802a8682a8SVincenzo Maffione 	if ((ret = port_register(ctx))) {
6812a8682a8SVincenzo Maffione 		return ret;
6822a8682a8SVincenzo Maffione 	}
6832a8682a8SVincenzo Maffione 	/* Try to set and get all the acceptable values. */
6842a8682a8SVincenzo Maffione 	ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS;
6852a8682a8SVincenzo Maffione 	if ((ret = port_hdr_set_and_get(ctx))) {
6862a8682a8SVincenzo Maffione 		return ret;
6872a8682a8SVincenzo Maffione 	}
6882a8682a8SVincenzo Maffione 	ctx->nr_hdr_len = 0;
6892a8682a8SVincenzo Maffione 	if ((ret = port_hdr_set_and_get(ctx))) {
6902a8682a8SVincenzo Maffione 		return ret;
6912a8682a8SVincenzo Maffione 	}
6922a8682a8SVincenzo Maffione 	ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN;
6932a8682a8SVincenzo Maffione 	if ((ret = port_hdr_set_and_get(ctx))) {
6942a8682a8SVincenzo Maffione 		return ret;
6952a8682a8SVincenzo Maffione 	}
6962a8682a8SVincenzo Maffione 	return 0;
6972a8682a8SVincenzo Maffione }
6982a8682a8SVincenzo Maffione 
6992a8682a8SVincenzo Maffione static int
vale_persistent_port(struct TestContext * ctx)7002a8682a8SVincenzo Maffione vale_persistent_port(struct TestContext *ctx)
7012a8682a8SVincenzo Maffione {
7022a8682a8SVincenzo Maffione 	struct nmreq_vale_newif req;
7032a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
7042a8682a8SVincenzo Maffione 	int result;
7052a8682a8SVincenzo Maffione 	int ret;
7062a8682a8SVincenzo Maffione 
70708f34ad9SVincenzo Maffione 	strncpy(ctx->ifname_ext, "per4", sizeof(ctx->ifname_ext));
7082a8682a8SVincenzo Maffione 
70908f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname_ext);
7102a8682a8SVincenzo Maffione 
71108f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
7122a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
7132a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
7142a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
7152a8682a8SVincenzo Maffione 	req.nr_mem_id   = ctx->nr_mem_id;
7162a8682a8SVincenzo Maffione 	req.nr_tx_slots = ctx->nr_tx_slots;
7172a8682a8SVincenzo Maffione 	req.nr_rx_slots = ctx->nr_rx_slots;
7182a8682a8SVincenzo Maffione 	req.nr_tx_rings = ctx->nr_tx_rings;
7192a8682a8SVincenzo Maffione 	req.nr_rx_rings = ctx->nr_rx_rings;
7202a8682a8SVincenzo Maffione 	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
7212a8682a8SVincenzo Maffione 	if (ret != 0) {
7222a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
7232a8682a8SVincenzo Maffione 		return ret;
7242a8682a8SVincenzo Maffione 	}
7252a8682a8SVincenzo Maffione 
7262a8682a8SVincenzo Maffione 	/* Attach the persistent VALE port to a switch and then detach. */
7272a8682a8SVincenzo Maffione 	result = vale_attach_detach(ctx);
7282a8682a8SVincenzo Maffione 
72908f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname_ext);
7302a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
7312a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)NULL;
7322a8682a8SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
7332a8682a8SVincenzo Maffione 	if (ret != 0) {
7342a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
7352a8682a8SVincenzo Maffione 		if (result == 0) {
7362a8682a8SVincenzo Maffione 			result = ret;
7372a8682a8SVincenzo Maffione 		}
7382a8682a8SVincenzo Maffione 	}
7392a8682a8SVincenzo Maffione 
7402a8682a8SVincenzo Maffione 	return result;
7412a8682a8SVincenzo Maffione }
7422a8682a8SVincenzo Maffione 
7432a8682a8SVincenzo Maffione /* Single NETMAP_REQ_POOLS_INFO_GET. */
7442a8682a8SVincenzo Maffione static int
pools_info_get(struct TestContext * ctx)7452a8682a8SVincenzo Maffione pools_info_get(struct TestContext *ctx)
7462a8682a8SVincenzo Maffione {
7472a8682a8SVincenzo Maffione 	struct nmreq_pools_info req;
7482a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
7492a8682a8SVincenzo Maffione 	int ret;
7502a8682a8SVincenzo Maffione 
75108f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname_ext);
7522a8682a8SVincenzo Maffione 
75308f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
7542a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
7552a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
7562a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
7572a8682a8SVincenzo Maffione 	req.nr_mem_id = ctx->nr_mem_id;
7582a8682a8SVincenzo Maffione 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
7592a8682a8SVincenzo Maffione 	if (ret != 0) {
7602a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
7612a8682a8SVincenzo Maffione 		return ret;
7622a8682a8SVincenzo Maffione 	}
7635854d718SVincenzo Maffione 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
7642a8682a8SVincenzo Maffione 	printf("nr_mem_id %u\n", req.nr_mem_id);
7655854d718SVincenzo Maffione 	printf("nr_if_pool_offset 0x%llx\n",
7665854d718SVincenzo Maffione 		(unsigned long long)req.nr_if_pool_offset);
7672a8682a8SVincenzo Maffione 	printf("nr_if_pool_objtotal %u\n", req.nr_if_pool_objtotal);
7682a8682a8SVincenzo Maffione 	printf("nr_if_pool_objsize %u\n", req.nr_if_pool_objsize);
7695854d718SVincenzo Maffione 	printf("nr_ring_pool_offset 0x%llx\n",
7705854d718SVincenzo Maffione 		(unsigned long long)req.nr_if_pool_offset);
7712a8682a8SVincenzo Maffione 	printf("nr_ring_pool_objtotal %u\n", req.nr_ring_pool_objtotal);
7722a8682a8SVincenzo Maffione 	printf("nr_ring_pool_objsize %u\n", req.nr_ring_pool_objsize);
7735854d718SVincenzo Maffione 	printf("nr_buf_pool_offset 0x%llx\n",
7745854d718SVincenzo Maffione 		(unsigned long long)req.nr_buf_pool_offset);
7752a8682a8SVincenzo Maffione 	printf("nr_buf_pool_objtotal %u\n", req.nr_buf_pool_objtotal);
7762a8682a8SVincenzo Maffione 	printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
7772a8682a8SVincenzo Maffione 
7782a8682a8SVincenzo Maffione 	return req.nr_memsize && req.nr_if_pool_objtotal &&
7792a8682a8SVincenzo Maffione 	                       req.nr_if_pool_objsize &&
7802a8682a8SVincenzo Maffione 	                       req.nr_ring_pool_objtotal &&
7812a8682a8SVincenzo Maffione 	                       req.nr_ring_pool_objsize &&
7822a8682a8SVincenzo Maffione 	                       req.nr_buf_pool_objtotal &&
7832a8682a8SVincenzo Maffione 	                       req.nr_buf_pool_objsize
7842a8682a8SVincenzo Maffione 	               ? 0
7852a8682a8SVincenzo Maffione 	               : -1;
7862a8682a8SVincenzo Maffione }
7872a8682a8SVincenzo Maffione 
7882a8682a8SVincenzo Maffione static int
pools_info_get_and_register(struct TestContext * ctx)7892a8682a8SVincenzo Maffione pools_info_get_and_register(struct TestContext *ctx)
7902a8682a8SVincenzo Maffione {
7912a8682a8SVincenzo Maffione 	int ret;
7922a8682a8SVincenzo Maffione 
7932a8682a8SVincenzo Maffione 	/* Check that we can get pools info before we register
7942a8682a8SVincenzo Maffione 	 * a netmap interface. */
7952a8682a8SVincenzo Maffione 	ret = pools_info_get(ctx);
7962a8682a8SVincenzo Maffione 	if (ret != 0) {
7972a8682a8SVincenzo Maffione 		return ret;
7982a8682a8SVincenzo Maffione 	}
7992a8682a8SVincenzo Maffione 
8002a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ONE_NIC;
8012a8682a8SVincenzo Maffione 	ret          = port_register(ctx);
8022a8682a8SVincenzo Maffione 	if (ret != 0) {
8032a8682a8SVincenzo Maffione 		return ret;
8042a8682a8SVincenzo Maffione 	}
8052a8682a8SVincenzo Maffione 	ctx->nr_mem_id = 1;
8062a8682a8SVincenzo Maffione 
8072a8682a8SVincenzo Maffione 	/* Check that we can get pools info also after we register. */
8082a8682a8SVincenzo Maffione 	return pools_info_get(ctx);
8092a8682a8SVincenzo Maffione }
8102a8682a8SVincenzo Maffione 
8112a8682a8SVincenzo Maffione static int
pools_info_get_empty_ifname(struct TestContext * ctx)8122a8682a8SVincenzo Maffione pools_info_get_empty_ifname(struct TestContext *ctx)
8132a8682a8SVincenzo Maffione {
81408f34ad9SVincenzo Maffione 	strncpy(ctx->ifname_ext, "", sizeof(ctx->ifname_ext));
8152a8682a8SVincenzo Maffione 	return pools_info_get(ctx) != 0 ? 0 : -1;
8162a8682a8SVincenzo Maffione }
8172a8682a8SVincenzo Maffione 
8182a8682a8SVincenzo Maffione static int
pipe_master(struct TestContext * ctx)8192a8682a8SVincenzo Maffione pipe_master(struct TestContext *ctx)
8202a8682a8SVincenzo Maffione {
82108f34ad9SVincenzo Maffione 	strncat(ctx->ifname_ext, "{pipeid1", sizeof(ctx->ifname_ext));
8222a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_NIC_SW;
8232a8682a8SVincenzo Maffione 
8242a8682a8SVincenzo Maffione 	if (port_register(ctx) == 0) {
8252a8682a8SVincenzo Maffione 		printf("pipes should not accept NR_REG_NIC_SW\n");
8262a8682a8SVincenzo Maffione 		return -1;
8272a8682a8SVincenzo Maffione 	}
8282a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
8292a8682a8SVincenzo Maffione 
8302a8682a8SVincenzo Maffione 	return port_register(ctx);
8312a8682a8SVincenzo Maffione }
8322a8682a8SVincenzo Maffione 
8332a8682a8SVincenzo Maffione static int
pipe_slave(struct TestContext * ctx)8342a8682a8SVincenzo Maffione pipe_slave(struct TestContext *ctx)
8352a8682a8SVincenzo Maffione {
83608f34ad9SVincenzo Maffione 	strncat(ctx->ifname_ext, "}pipeid2", sizeof(ctx->ifname_ext));
8372a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
8382a8682a8SVincenzo Maffione 
8392a8682a8SVincenzo Maffione 	return port_register(ctx);
8402a8682a8SVincenzo Maffione }
8412a8682a8SVincenzo Maffione 
8422a8682a8SVincenzo Maffione /* Test PORT_INFO_GET and POOLS_INFO_GET on a pipe. This is useful to test the
84336d6e657SVincenzo Maffione  * registration request used internally by netmap. */
8442a8682a8SVincenzo Maffione static int
pipe_port_info_get(struct TestContext * ctx)8452a8682a8SVincenzo Maffione pipe_port_info_get(struct TestContext *ctx)
8462a8682a8SVincenzo Maffione {
84708f34ad9SVincenzo Maffione 	strncat(ctx->ifname_ext, "}pipeid3", sizeof(ctx->ifname_ext));
8482a8682a8SVincenzo Maffione 
8492a8682a8SVincenzo Maffione 	return port_info_get(ctx);
8502a8682a8SVincenzo Maffione }
8512a8682a8SVincenzo Maffione 
8522a8682a8SVincenzo Maffione static int
pipe_pools_info_get(struct TestContext * ctx)8532a8682a8SVincenzo Maffione pipe_pools_info_get(struct TestContext *ctx)
8542a8682a8SVincenzo Maffione {
85508f34ad9SVincenzo Maffione 	strncat(ctx->ifname_ext, "{xid", sizeof(ctx->ifname_ext));
8562a8682a8SVincenzo Maffione 
8572a8682a8SVincenzo Maffione 	return pools_info_get(ctx);
8582a8682a8SVincenzo Maffione }
8592a8682a8SVincenzo Maffione 
8602a8682a8SVincenzo Maffione /* NETMAP_REQ_VALE_POLLING_ENABLE */
8612a8682a8SVincenzo Maffione static int
vale_polling_enable(struct TestContext * ctx)8622a8682a8SVincenzo Maffione vale_polling_enable(struct TestContext *ctx)
8632a8682a8SVincenzo Maffione {
8642a8682a8SVincenzo Maffione 	struct nmreq_vale_polling req;
8652a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
86636d6e657SVincenzo Maffione 	char vpname[NM_IFNAMSZ];
8672a8682a8SVincenzo Maffione 	int ret;
8682a8682a8SVincenzo Maffione 
86936d6e657SVincenzo Maffione 	if (vale_mkname(vpname, ctx) < 0)
87036d6e657SVincenzo Maffione 		return -1;
87136d6e657SVincenzo Maffione 
8722a8682a8SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
8732a8682a8SVincenzo Maffione 
8742a8682a8SVincenzo Maffione 	nmreq_hdr_init(&hdr, vpname);
8752a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
8762a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
8772a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
8782a8682a8SVincenzo Maffione 	req.nr_mode             = ctx->nr_mode;
8792a8682a8SVincenzo Maffione 	req.nr_first_cpu_id     = ctx->nr_first_cpu_id;
8802a8682a8SVincenzo Maffione 	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
8812a8682a8SVincenzo Maffione 	ret                     = ioctl(ctx->fd, NIOCCTRL, &hdr);
8822a8682a8SVincenzo Maffione 	if (ret != 0) {
8832a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
8842a8682a8SVincenzo Maffione 		return ret;
8852a8682a8SVincenzo Maffione 	}
8862a8682a8SVincenzo Maffione 
8872a8682a8SVincenzo Maffione 	return (req.nr_mode == ctx->nr_mode &&
8882a8682a8SVincenzo Maffione 	        req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
8892a8682a8SVincenzo Maffione 	        req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
8902a8682a8SVincenzo Maffione 	               ? 0
8912a8682a8SVincenzo Maffione 	               : -1;
8922a8682a8SVincenzo Maffione }
8932a8682a8SVincenzo Maffione 
8942a8682a8SVincenzo Maffione /* NETMAP_REQ_VALE_POLLING_DISABLE */
8952a8682a8SVincenzo Maffione static int
vale_polling_disable(struct TestContext * ctx)8962a8682a8SVincenzo Maffione vale_polling_disable(struct TestContext *ctx)
8972a8682a8SVincenzo Maffione {
8982a8682a8SVincenzo Maffione 	struct nmreq_vale_polling req;
8992a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
90036d6e657SVincenzo Maffione 	char vpname[NM_IFNAMSZ];
9012a8682a8SVincenzo Maffione 	int ret;
9022a8682a8SVincenzo Maffione 
90336d6e657SVincenzo Maffione 	if (vale_mkname(vpname, ctx) < 0)
90436d6e657SVincenzo Maffione 		return -1;
90536d6e657SVincenzo Maffione 
9062a8682a8SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
9072a8682a8SVincenzo Maffione 
9082a8682a8SVincenzo Maffione 	nmreq_hdr_init(&hdr, vpname);
9092a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
9102a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
9112a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
9122a8682a8SVincenzo Maffione 	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
9132a8682a8SVincenzo Maffione 	if (ret != 0) {
9142a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
9152a8682a8SVincenzo Maffione 		return ret;
9162a8682a8SVincenzo Maffione 	}
9172a8682a8SVincenzo Maffione 
9182a8682a8SVincenzo Maffione 	return 0;
9192a8682a8SVincenzo Maffione }
9202a8682a8SVincenzo Maffione 
9212a8682a8SVincenzo Maffione static int
vale_polling_enable_disable(struct TestContext * ctx)9222a8682a8SVincenzo Maffione vale_polling_enable_disable(struct TestContext *ctx)
9232a8682a8SVincenzo Maffione {
9242a8682a8SVincenzo Maffione 	int ret = 0;
9252a8682a8SVincenzo Maffione 
9262a8682a8SVincenzo Maffione 	if ((ret = vale_attach(ctx)) != 0) {
9272a8682a8SVincenzo Maffione 		return ret;
9282a8682a8SVincenzo Maffione 	}
9292a8682a8SVincenzo Maffione 
9302a8682a8SVincenzo Maffione 	ctx->nr_mode             = NETMAP_POLLING_MODE_SINGLE_CPU;
9312a8682a8SVincenzo Maffione 	ctx->nr_num_polling_cpus = 1;
9322a8682a8SVincenzo Maffione 	ctx->nr_first_cpu_id     = 0;
9332a8682a8SVincenzo Maffione 	if ((ret = vale_polling_enable(ctx))) {
9342a8682a8SVincenzo Maffione 		vale_detach(ctx);
9352a8682a8SVincenzo Maffione #ifdef __FreeBSD__
9362a8682a8SVincenzo Maffione 		/* NETMAP_REQ_VALE_POLLING_DISABLE is disabled on FreeBSD,
9372a8682a8SVincenzo Maffione 		 * because it is currently broken. We are happy to see that
9382a8682a8SVincenzo Maffione 		 * it fails. */
9392a8682a8SVincenzo Maffione 		return 0;
94008f34ad9SVincenzo Maffione #else
9412a8682a8SVincenzo Maffione 		return ret;
94208f34ad9SVincenzo Maffione #endif
9432a8682a8SVincenzo Maffione 	}
9442a8682a8SVincenzo Maffione 
9452a8682a8SVincenzo Maffione 	if ((ret = vale_polling_disable(ctx))) {
9462a8682a8SVincenzo Maffione 		vale_detach(ctx);
9472a8682a8SVincenzo Maffione 		return ret;
9482a8682a8SVincenzo Maffione 	}
9492a8682a8SVincenzo Maffione 
9502a8682a8SVincenzo Maffione 	return vale_detach(ctx);
9512a8682a8SVincenzo Maffione }
9522a8682a8SVincenzo Maffione 
9532a8682a8SVincenzo Maffione static void
push_option(struct nmreq_option * opt,struct TestContext * ctx)9542a8682a8SVincenzo Maffione push_option(struct nmreq_option *opt, struct TestContext *ctx)
9552a8682a8SVincenzo Maffione {
9562a8682a8SVincenzo Maffione 	opt->nro_next = (uintptr_t)ctx->nr_opt;
9572a8682a8SVincenzo Maffione 	ctx->nr_opt   = opt;
9582a8682a8SVincenzo Maffione }
9592a8682a8SVincenzo Maffione 
9602a8682a8SVincenzo Maffione static void
clear_options(struct TestContext * ctx)9612a8682a8SVincenzo Maffione clear_options(struct TestContext *ctx)
9622a8682a8SVincenzo Maffione {
9632a8682a8SVincenzo Maffione 	ctx->nr_opt = NULL;
9642a8682a8SVincenzo Maffione }
9652a8682a8SVincenzo Maffione 
9662a8682a8SVincenzo Maffione static int
checkoption(struct nmreq_option * opt,struct nmreq_option * exp)9672a8682a8SVincenzo Maffione checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
9682a8682a8SVincenzo Maffione {
9692a8682a8SVincenzo Maffione 	if (opt->nro_next != exp->nro_next) {
9702a8682a8SVincenzo Maffione 		printf("nro_next %p expected %p\n",
9712a8682a8SVincenzo Maffione 		       (void *)(uintptr_t)opt->nro_next,
9722a8682a8SVincenzo Maffione 		       (void *)(uintptr_t)exp->nro_next);
9732a8682a8SVincenzo Maffione 		return -1;
9742a8682a8SVincenzo Maffione 	}
9752a8682a8SVincenzo Maffione 	if (opt->nro_reqtype != exp->nro_reqtype) {
9762a8682a8SVincenzo Maffione 		printf("nro_reqtype %u expected %u\n", opt->nro_reqtype,
9772a8682a8SVincenzo Maffione 		       exp->nro_reqtype);
9782a8682a8SVincenzo Maffione 		return -1;
9792a8682a8SVincenzo Maffione 	}
9802a8682a8SVincenzo Maffione 	if (opt->nro_status != exp->nro_status) {
9812a8682a8SVincenzo Maffione 		printf("nro_status %u expected %u\n", opt->nro_status,
9822a8682a8SVincenzo Maffione 		       exp->nro_status);
9832a8682a8SVincenzo Maffione 		return -1;
9842a8682a8SVincenzo Maffione 	}
9852a8682a8SVincenzo Maffione 	return 0;
9862a8682a8SVincenzo Maffione }
9872a8682a8SVincenzo Maffione 
9882a8682a8SVincenzo Maffione static int
unsupported_option(struct TestContext * ctx)9892a8682a8SVincenzo Maffione unsupported_option(struct TestContext *ctx)
9902a8682a8SVincenzo Maffione {
9912a8682a8SVincenzo Maffione 	struct nmreq_option opt, save;
9922a8682a8SVincenzo Maffione 
99308f34ad9SVincenzo Maffione 	printf("Testing unsupported option on %s\n", ctx->ifname_ext);
9942a8682a8SVincenzo Maffione 
9952a8682a8SVincenzo Maffione 	memset(&opt, 0, sizeof(opt));
9962a8682a8SVincenzo Maffione 	opt.nro_reqtype = 1234;
9972a8682a8SVincenzo Maffione 	push_option(&opt, ctx);
9982a8682a8SVincenzo Maffione 	save = opt;
9992a8682a8SVincenzo Maffione 
10002a8682a8SVincenzo Maffione 	if (port_register_hwall(ctx) >= 0)
10012a8682a8SVincenzo Maffione 		return -1;
10022a8682a8SVincenzo Maffione 
10032a8682a8SVincenzo Maffione 	clear_options(ctx);
10042a8682a8SVincenzo Maffione 	save.nro_status = EOPNOTSUPP;
10052a8682a8SVincenzo Maffione 	return checkoption(&opt, &save);
10062a8682a8SVincenzo Maffione }
10072a8682a8SVincenzo Maffione 
10082a8682a8SVincenzo Maffione static int
infinite_options(struct TestContext * ctx)10092a8682a8SVincenzo Maffione infinite_options(struct TestContext *ctx)
10102a8682a8SVincenzo Maffione {
10112a8682a8SVincenzo Maffione 	struct nmreq_option opt;
10122a8682a8SVincenzo Maffione 
1013e2a431a0SVincenzo Maffione 	printf("Testing infinite list of options on %s (invalid options)\n", ctx->ifname_ext);
10142a8682a8SVincenzo Maffione 
1015e2a431a0SVincenzo Maffione 	memset(&opt, 0, sizeof(opt));
1016e2a431a0SVincenzo Maffione 	opt.nro_reqtype = NETMAP_REQ_OPT_MAX + 1;
10172a8682a8SVincenzo Maffione 	push_option(&opt, ctx);
10182a8682a8SVincenzo Maffione 	opt.nro_next = (uintptr_t)&opt;
10192a8682a8SVincenzo Maffione 	if (port_register_hwall(ctx) >= 0)
10202a8682a8SVincenzo Maffione 		return -1;
10212a8682a8SVincenzo Maffione 	clear_options(ctx);
10222a8682a8SVincenzo Maffione 	return (errno == EMSGSIZE ? 0 : -1);
10232a8682a8SVincenzo Maffione }
10242a8682a8SVincenzo Maffione 
1025e2a431a0SVincenzo Maffione static int
infinite_options2(struct TestContext * ctx)1026e2a431a0SVincenzo Maffione infinite_options2(struct TestContext *ctx)
1027e2a431a0SVincenzo Maffione {
1028e2a431a0SVincenzo Maffione 	struct nmreq_option opt;
1029e2a431a0SVincenzo Maffione 
1030e2a431a0SVincenzo Maffione 	printf("Testing infinite list of options on %s (valid options)\n", ctx->ifname_ext);
1031e2a431a0SVincenzo Maffione 
1032e2a431a0SVincenzo Maffione 	memset(&opt, 0, sizeof(opt));
1033e2a431a0SVincenzo Maffione 	opt.nro_reqtype = NETMAP_REQ_OPT_OFFSETS;
1034e2a431a0SVincenzo Maffione 	push_option(&opt, ctx);
1035e2a431a0SVincenzo Maffione 	opt.nro_next = (uintptr_t)&opt;
1036e2a431a0SVincenzo Maffione 	if (port_register_hwall(ctx) >= 0)
1037e2a431a0SVincenzo Maffione 		return -1;
1038e2a431a0SVincenzo Maffione 	clear_options(ctx);
1039e2a431a0SVincenzo Maffione 	return (errno == EINVAL ? 0 : -1);
1040e2a431a0SVincenzo Maffione }
1041e2a431a0SVincenzo Maffione 
10422a8682a8SVincenzo Maffione #ifdef CONFIG_NETMAP_EXTMEM
10432a8682a8SVincenzo Maffione int
change_param(const char * pname,unsigned long newv,unsigned long * poldv)10442a8682a8SVincenzo Maffione change_param(const char *pname, unsigned long newv, unsigned long *poldv)
10452a8682a8SVincenzo Maffione {
10462a8682a8SVincenzo Maffione #ifdef __linux__
10472a8682a8SVincenzo Maffione 	char param[256] = "/sys/module/netmap/parameters/";
10482a8682a8SVincenzo Maffione 	unsigned long oldv;
10492a8682a8SVincenzo Maffione 	FILE *f;
10502a8682a8SVincenzo Maffione 
10512a8682a8SVincenzo Maffione 	strncat(param, pname, sizeof(param) - 1);
10522a8682a8SVincenzo Maffione 
10532a8682a8SVincenzo Maffione 	f = fopen(param, "r+");
10542a8682a8SVincenzo Maffione 	if (f == NULL) {
10552a8682a8SVincenzo Maffione 		perror(param);
10562a8682a8SVincenzo Maffione 		return -1;
10572a8682a8SVincenzo Maffione 	}
10582a8682a8SVincenzo Maffione 	if (fscanf(f, "%ld", &oldv) != 1) {
10592a8682a8SVincenzo Maffione 		perror(param);
10602a8682a8SVincenzo Maffione 		fclose(f);
10612a8682a8SVincenzo Maffione 		return -1;
10622a8682a8SVincenzo Maffione 	}
10632a8682a8SVincenzo Maffione 	if (poldv)
10642a8682a8SVincenzo Maffione 		*poldv = oldv;
10652a8682a8SVincenzo Maffione 	rewind(f);
10662a8682a8SVincenzo Maffione 	if (fprintf(f, "%ld\n", newv) < 0) {
10672a8682a8SVincenzo Maffione 		perror(param);
10682a8682a8SVincenzo Maffione 		fclose(f);
10692a8682a8SVincenzo Maffione 		return -1;
10702a8682a8SVincenzo Maffione 	}
10712a8682a8SVincenzo Maffione 	fclose(f);
10722a8682a8SVincenzo Maffione 	printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
10732a8682a8SVincenzo Maffione #endif /* __linux__ */
10742a8682a8SVincenzo Maffione 	return 0;
10752a8682a8SVincenzo Maffione }
10762a8682a8SVincenzo Maffione 
10772a8682a8SVincenzo Maffione static int
push_extmem_option(struct TestContext * ctx,const struct nmreq_pools_info * pi,struct nmreq_opt_extmem * e)10782a8682a8SVincenzo Maffione push_extmem_option(struct TestContext *ctx, const struct nmreq_pools_info *pi,
10792a8682a8SVincenzo Maffione 		struct nmreq_opt_extmem *e)
10802a8682a8SVincenzo Maffione {
10812a8682a8SVincenzo Maffione 	void *addr;
10822a8682a8SVincenzo Maffione 
10832a8682a8SVincenzo Maffione 	addr = mmap(NULL, pi->nr_memsize, PROT_READ | PROT_WRITE,
10842a8682a8SVincenzo Maffione 	            MAP_ANONYMOUS | MAP_SHARED, -1, 0);
10852a8682a8SVincenzo Maffione 	if (addr == MAP_FAILED) {
10862a8682a8SVincenzo Maffione 		perror("mmap");
10872a8682a8SVincenzo Maffione 		return -1;
10882a8682a8SVincenzo Maffione 	}
10892a8682a8SVincenzo Maffione 
10902a8682a8SVincenzo Maffione 	memset(e, 0, sizeof(*e));
10912a8682a8SVincenzo Maffione 	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
10922a8682a8SVincenzo Maffione 	e->nro_info = *pi;
10932a8682a8SVincenzo Maffione 	e->nro_usrptr          = (uintptr_t)addr;
10942a8682a8SVincenzo Maffione 
10952a8682a8SVincenzo Maffione 	push_option(&e->nro_opt, ctx);
10962a8682a8SVincenzo Maffione 
10972a8682a8SVincenzo Maffione 	return 0;
10982a8682a8SVincenzo Maffione }
10992a8682a8SVincenzo Maffione 
11002a8682a8SVincenzo Maffione static int
pop_extmem_option(struct TestContext * ctx,struct nmreq_opt_extmem * exp)11012a8682a8SVincenzo Maffione pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
11022a8682a8SVincenzo Maffione {
11032a8682a8SVincenzo Maffione 	struct nmreq_opt_extmem *e;
11042a8682a8SVincenzo Maffione 	int ret;
11052a8682a8SVincenzo Maffione 
11062a8682a8SVincenzo Maffione 	e           = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
11072a8682a8SVincenzo Maffione 	ctx->nr_opt = (struct nmreq_option *)(uintptr_t)ctx->nr_opt->nro_next;
11082a8682a8SVincenzo Maffione 
11092a8682a8SVincenzo Maffione 	if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
11102a8682a8SVincenzo Maffione 		return ret;
11112a8682a8SVincenzo Maffione 	}
11122a8682a8SVincenzo Maffione 
11132a8682a8SVincenzo Maffione 	if (e->nro_usrptr != exp->nro_usrptr) {
11142a8682a8SVincenzo Maffione 		printf("usrptr %" PRIu64 " expected %" PRIu64 "\n",
11152a8682a8SVincenzo Maffione 		       e->nro_usrptr, exp->nro_usrptr);
11162a8682a8SVincenzo Maffione 		return -1;
11172a8682a8SVincenzo Maffione 	}
11182a8682a8SVincenzo Maffione 	if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
11192a8682a8SVincenzo Maffione 		printf("memsize %" PRIu64 " expected %" PRIu64 "\n",
11202a8682a8SVincenzo Maffione 		       e->nro_info.nr_memsize, exp->nro_info.nr_memsize);
11212a8682a8SVincenzo Maffione 		return -1;
11222a8682a8SVincenzo Maffione 	}
11232a8682a8SVincenzo Maffione 
11242a8682a8SVincenzo Maffione 	if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr,
11252a8682a8SVincenzo Maffione 	                  e->nro_info.nr_memsize)))
11262a8682a8SVincenzo Maffione 		return ret;
11272a8682a8SVincenzo Maffione 
11282a8682a8SVincenzo Maffione 	return 0;
11292a8682a8SVincenzo Maffione }
11302a8682a8SVincenzo Maffione 
11312a8682a8SVincenzo Maffione static int
_extmem_option(struct TestContext * ctx,const struct nmreq_pools_info * pi)11322a8682a8SVincenzo Maffione _extmem_option(struct TestContext *ctx,
11332a8682a8SVincenzo Maffione 		const struct nmreq_pools_info *pi)
11342a8682a8SVincenzo Maffione {
11352a8682a8SVincenzo Maffione 	struct nmreq_opt_extmem e, save;
11362a8682a8SVincenzo Maffione 	int ret;
11372a8682a8SVincenzo Maffione 
11382a8682a8SVincenzo Maffione 	if ((ret = push_extmem_option(ctx, pi, &e)) < 0)
11392a8682a8SVincenzo Maffione 		return ret;
11402a8682a8SVincenzo Maffione 
11412a8682a8SVincenzo Maffione 	save = e;
11422a8682a8SVincenzo Maffione 
114308f34ad9SVincenzo Maffione 	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
11442a8682a8SVincenzo Maffione 	ctx->nr_tx_slots = 16;
11452a8682a8SVincenzo Maffione 	ctx->nr_rx_slots = 16;
11462a8682a8SVincenzo Maffione 
11472a8682a8SVincenzo Maffione 	if ((ret = port_register_hwall(ctx)))
11482a8682a8SVincenzo Maffione 		return ret;
11492a8682a8SVincenzo Maffione 
11502a8682a8SVincenzo Maffione 	ret = pop_extmem_option(ctx, &save);
11512a8682a8SVincenzo Maffione 
11522a8682a8SVincenzo Maffione 	return ret;
11532a8682a8SVincenzo Maffione }
11542a8682a8SVincenzo Maffione 
11552a8682a8SVincenzo Maffione static size_t
pools_info_min_memsize(const struct nmreq_pools_info * pi)11562a8682a8SVincenzo Maffione pools_info_min_memsize(const struct nmreq_pools_info *pi)
11572a8682a8SVincenzo Maffione {
11582a8682a8SVincenzo Maffione 	size_t tot = 0;
11592a8682a8SVincenzo Maffione 
11602a8682a8SVincenzo Maffione 	tot += pi->nr_if_pool_objtotal * pi->nr_if_pool_objsize;
11612a8682a8SVincenzo Maffione 	tot += pi->nr_ring_pool_objtotal * pi->nr_ring_pool_objsize;
11622a8682a8SVincenzo Maffione 	tot += pi->nr_buf_pool_objtotal * pi->nr_buf_pool_objsize;
11632a8682a8SVincenzo Maffione 
11642a8682a8SVincenzo Maffione 	return tot;
11652a8682a8SVincenzo Maffione }
11662a8682a8SVincenzo Maffione 
11672a8682a8SVincenzo Maffione /*
11682a8682a8SVincenzo Maffione  * Fill the specification of a netmap memory allocator to be
11692a8682a8SVincenzo Maffione  * used with the 'struct nmreq_opt_extmem' option. Arbitrary
11702a8682a8SVincenzo Maffione  * values are used for the parameters, but with enough netmap
11712a8682a8SVincenzo Maffione  * rings, netmap ifs, and buffers to support a VALE port.
11722a8682a8SVincenzo Maffione  */
11732a8682a8SVincenzo Maffione static void
pools_info_fill(struct nmreq_pools_info * pi)11742a8682a8SVincenzo Maffione pools_info_fill(struct nmreq_pools_info *pi)
11752a8682a8SVincenzo Maffione {
11762a8682a8SVincenzo Maffione 	pi->nr_if_pool_objtotal = 2;
11772a8682a8SVincenzo Maffione 	pi->nr_if_pool_objsize = 1024;
11782a8682a8SVincenzo Maffione 	pi->nr_ring_pool_objtotal = 64;
11792a8682a8SVincenzo Maffione 	pi->nr_ring_pool_objsize = 512;
11802a8682a8SVincenzo Maffione 	pi->nr_buf_pool_objtotal = 4096;
11812a8682a8SVincenzo Maffione 	pi->nr_buf_pool_objsize = 2048;
11822a8682a8SVincenzo Maffione 	pi->nr_memsize = pools_info_min_memsize(pi);
11832a8682a8SVincenzo Maffione }
11842a8682a8SVincenzo Maffione 
11852a8682a8SVincenzo Maffione static int
extmem_option(struct TestContext * ctx)11862a8682a8SVincenzo Maffione extmem_option(struct TestContext *ctx)
11872a8682a8SVincenzo Maffione {
11882a8682a8SVincenzo Maffione 	struct nmreq_pools_info	pools_info;
11892a8682a8SVincenzo Maffione 
11902a8682a8SVincenzo Maffione 	pools_info_fill(&pools_info);
11912a8682a8SVincenzo Maffione 
11922a8682a8SVincenzo Maffione 	printf("Testing extmem option on vale0:0\n");
11932a8682a8SVincenzo Maffione 	return _extmem_option(ctx, &pools_info);
11942a8682a8SVincenzo Maffione }
11952a8682a8SVincenzo Maffione 
11962a8682a8SVincenzo Maffione static int
bad_extmem_option(struct TestContext * ctx)11972a8682a8SVincenzo Maffione bad_extmem_option(struct TestContext *ctx)
11982a8682a8SVincenzo Maffione {
11992a8682a8SVincenzo Maffione 	struct nmreq_pools_info	pools_info;
12002a8682a8SVincenzo Maffione 
12012a8682a8SVincenzo Maffione 	printf("Testing bad extmem option on vale0:0\n");
12022a8682a8SVincenzo Maffione 
12032a8682a8SVincenzo Maffione 	pools_info_fill(&pools_info);
12042a8682a8SVincenzo Maffione 	/* Request a large ring size, to make sure that the kernel
12052a8682a8SVincenzo Maffione 	 * rejects our request. */
12065e874d26SVincenzo Maffione 	pools_info.nr_ring_pool_objsize = (1 << 20);
12072a8682a8SVincenzo Maffione 
12082a8682a8SVincenzo Maffione 	return _extmem_option(ctx, &pools_info) < 0 ? 0 : -1;
12092a8682a8SVincenzo Maffione }
12102a8682a8SVincenzo Maffione 
12112a8682a8SVincenzo Maffione static int
duplicate_extmem_options(struct TestContext * ctx)12122a8682a8SVincenzo Maffione duplicate_extmem_options(struct TestContext *ctx)
12132a8682a8SVincenzo Maffione {
12142a8682a8SVincenzo Maffione 	struct nmreq_opt_extmem e1, save1, e2, save2;
12152a8682a8SVincenzo Maffione 	struct nmreq_pools_info	pools_info;
12162a8682a8SVincenzo Maffione 	int ret;
12172a8682a8SVincenzo Maffione 
12182a8682a8SVincenzo Maffione 	printf("Testing duplicate extmem option on vale0:0\n");
12192a8682a8SVincenzo Maffione 
12202a8682a8SVincenzo Maffione 	pools_info_fill(&pools_info);
12212a8682a8SVincenzo Maffione 
12222a8682a8SVincenzo Maffione 	if ((ret = push_extmem_option(ctx, &pools_info, &e1)) < 0)
12232a8682a8SVincenzo Maffione 		return ret;
12242a8682a8SVincenzo Maffione 
12252a8682a8SVincenzo Maffione 	if ((ret = push_extmem_option(ctx, &pools_info, &e2)) < 0) {
12262a8682a8SVincenzo Maffione 		clear_options(ctx);
12272a8682a8SVincenzo Maffione 		return ret;
12282a8682a8SVincenzo Maffione 	}
12292a8682a8SVincenzo Maffione 
12302a8682a8SVincenzo Maffione 	save1 = e1;
12312a8682a8SVincenzo Maffione 	save2 = e2;
12322a8682a8SVincenzo Maffione 
12335e874d26SVincenzo Maffione 	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
12345e874d26SVincenzo Maffione 	ctx->nr_tx_slots = 16;
12355e874d26SVincenzo Maffione 	ctx->nr_rx_slots = 16;
12365e874d26SVincenzo Maffione 
12372a8682a8SVincenzo Maffione 	ret = port_register_hwall(ctx);
12382a8682a8SVincenzo Maffione 	if (ret >= 0) {
12392a8682a8SVincenzo Maffione 		printf("duplicate option not detected\n");
12402a8682a8SVincenzo Maffione 		return -1;
12412a8682a8SVincenzo Maffione 	}
12422a8682a8SVincenzo Maffione 
12432a8682a8SVincenzo Maffione 	save2.nro_opt.nro_status = EINVAL;
12442a8682a8SVincenzo Maffione 	if ((ret = pop_extmem_option(ctx, &save2)))
12452a8682a8SVincenzo Maffione 		return ret;
12462a8682a8SVincenzo Maffione 
12472a8682a8SVincenzo Maffione 	save1.nro_opt.nro_status = EINVAL;
12482a8682a8SVincenzo Maffione 	if ((ret = pop_extmem_option(ctx, &save1)))
12492a8682a8SVincenzo Maffione 		return ret;
12502a8682a8SVincenzo Maffione 
12512a8682a8SVincenzo Maffione 	return 0;
12522a8682a8SVincenzo Maffione }
12532a8682a8SVincenzo Maffione #endif /* CONFIG_NETMAP_EXTMEM */
12542a8682a8SVincenzo Maffione 
12552a8682a8SVincenzo Maffione static int
push_csb_option(struct TestContext * ctx,struct nmreq_opt_csb * opt)12562a8682a8SVincenzo Maffione push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
12572a8682a8SVincenzo Maffione {
12582a8682a8SVincenzo Maffione 	size_t csb_size;
12592a8682a8SVincenzo Maffione 	int num_entries;
12602a8682a8SVincenzo Maffione 	int ret;
12612a8682a8SVincenzo Maffione 
12622a8682a8SVincenzo Maffione 	ctx->nr_flags |= NR_EXCLUSIVE;
12632a8682a8SVincenzo Maffione 
12642a8682a8SVincenzo Maffione 	/* Get port info in order to use num_registered_rings(). */
12652a8682a8SVincenzo Maffione 	ret = port_info_get(ctx);
12662a8682a8SVincenzo Maffione 	if (ret != 0) {
12672a8682a8SVincenzo Maffione 		return ret;
12682a8682a8SVincenzo Maffione 	}
12692a8682a8SVincenzo Maffione 	num_entries = num_registered_rings(ctx);
12702a8682a8SVincenzo Maffione 
12712a8682a8SVincenzo Maffione 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
12722a8682a8SVincenzo Maffione 	           num_entries;
12732a8682a8SVincenzo Maffione 	assert(csb_size > 0);
12742a8682a8SVincenzo Maffione 	if (ctx->csb) {
12752a8682a8SVincenzo Maffione 		free(ctx->csb);
12762a8682a8SVincenzo Maffione 	}
12772a8682a8SVincenzo Maffione 	ret = posix_memalign(&ctx->csb, sizeof(struct nm_csb_atok), csb_size);
12782a8682a8SVincenzo Maffione 	if (ret != 0) {
12792a8682a8SVincenzo Maffione 		printf("Failed to allocate CSB memory\n");
12802a8682a8SVincenzo Maffione 		exit(EXIT_FAILURE);
12812a8682a8SVincenzo Maffione 	}
12822a8682a8SVincenzo Maffione 
12832a8682a8SVincenzo Maffione 	memset(opt, 0, sizeof(*opt));
12842a8682a8SVincenzo Maffione 	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
12852a8682a8SVincenzo Maffione 	opt->csb_atok            = (uintptr_t)ctx->csb;
12862a8682a8SVincenzo Maffione 	opt->csb_ktoa            = (uintptr_t)(((uint8_t *)ctx->csb) +
12872a8682a8SVincenzo Maffione                                     sizeof(struct nm_csb_atok) * num_entries);
12882a8682a8SVincenzo Maffione 
12892a8682a8SVincenzo Maffione 	printf("Pushing option NETMAP_REQ_OPT_CSB\n");
12902a8682a8SVincenzo Maffione 	push_option(&opt->nro_opt, ctx);
12912a8682a8SVincenzo Maffione 
12922a8682a8SVincenzo Maffione 	return 0;
12932a8682a8SVincenzo Maffione }
12942a8682a8SVincenzo Maffione 
12952a8682a8SVincenzo Maffione static int
csb_mode(struct TestContext * ctx)12962a8682a8SVincenzo Maffione csb_mode(struct TestContext *ctx)
12972a8682a8SVincenzo Maffione {
12982a8682a8SVincenzo Maffione 	struct nmreq_opt_csb opt;
12992a8682a8SVincenzo Maffione 	int ret;
13002a8682a8SVincenzo Maffione 
13012a8682a8SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
13022a8682a8SVincenzo Maffione 	if (ret != 0) {
13032a8682a8SVincenzo Maffione 		return ret;
13042a8682a8SVincenzo Maffione 	}
13052a8682a8SVincenzo Maffione 
13062a8682a8SVincenzo Maffione 	ret = port_register_hwall(ctx);
13072a8682a8SVincenzo Maffione 	clear_options(ctx);
13082a8682a8SVincenzo Maffione 
13092a8682a8SVincenzo Maffione 	return ret;
13102a8682a8SVincenzo Maffione }
13112a8682a8SVincenzo Maffione 
13122a8682a8SVincenzo Maffione static int
csb_mode_invalid_memory(struct TestContext * ctx)13132a8682a8SVincenzo Maffione csb_mode_invalid_memory(struct TestContext *ctx)
13142a8682a8SVincenzo Maffione {
13152a8682a8SVincenzo Maffione 	struct nmreq_opt_csb opt;
13162a8682a8SVincenzo Maffione 	int ret;
13172a8682a8SVincenzo Maffione 
13182a8682a8SVincenzo Maffione 	memset(&opt, 0, sizeof(opt));
13192a8682a8SVincenzo Maffione 	opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
13202a8682a8SVincenzo Maffione 	opt.csb_atok            = (uintptr_t)0x10;
13212a8682a8SVincenzo Maffione 	opt.csb_ktoa            = (uintptr_t)0x800;
13222a8682a8SVincenzo Maffione 	push_option(&opt.nro_opt, ctx);
13232a8682a8SVincenzo Maffione 
13242a8682a8SVincenzo Maffione 	ctx->nr_flags = NR_EXCLUSIVE;
13252a8682a8SVincenzo Maffione 	ret           = port_register_hwall(ctx);
13262a8682a8SVincenzo Maffione 	clear_options(ctx);
13272a8682a8SVincenzo Maffione 
13282a8682a8SVincenzo Maffione 	return (ret < 0) ? 0 : -1;
13292a8682a8SVincenzo Maffione }
13302a8682a8SVincenzo Maffione 
13312a8682a8SVincenzo Maffione static int
sync_kloop_stop(struct TestContext * ctx)13322a8682a8SVincenzo Maffione sync_kloop_stop(struct TestContext *ctx)
13332a8682a8SVincenzo Maffione {
13342a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
13352a8682a8SVincenzo Maffione 	int ret;
13362a8682a8SVincenzo Maffione 
133708f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname_ext);
13382a8682a8SVincenzo Maffione 
133908f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
13402a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
13412a8682a8SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
13422a8682a8SVincenzo Maffione 	if (ret != 0) {
13432a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
13442a8682a8SVincenzo Maffione 	}
13452a8682a8SVincenzo Maffione 
13462a8682a8SVincenzo Maffione 	return ret;
13472a8682a8SVincenzo Maffione }
13482a8682a8SVincenzo Maffione 
13492a8682a8SVincenzo Maffione static void *
sync_kloop_worker(void * opaque)13502a8682a8SVincenzo Maffione sync_kloop_worker(void *opaque)
13512a8682a8SVincenzo Maffione {
13522a8682a8SVincenzo Maffione 	struct TestContext *ctx = opaque;
13532a8682a8SVincenzo Maffione 	struct nmreq_sync_kloop_start req;
13542a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
13552a8682a8SVincenzo Maffione 	int ret;
13562a8682a8SVincenzo Maffione 
135708f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname_ext);
13582a8682a8SVincenzo Maffione 
135908f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
13602a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
13612a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
13622a8682a8SVincenzo Maffione 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
13632a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
13642a8682a8SVincenzo Maffione 	req.sleep_us = 500;
13652a8682a8SVincenzo Maffione 	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
13662a8682a8SVincenzo Maffione 	if (ret != 0) {
13672a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
13682a8682a8SVincenzo Maffione 	}
13692a8682a8SVincenzo Maffione 
13702a8682a8SVincenzo Maffione 	if (ctx->sem) {
13712a8682a8SVincenzo Maffione 		sem_post(ctx->sem);
13722a8682a8SVincenzo Maffione 	}
13732a8682a8SVincenzo Maffione 
13742a8682a8SVincenzo Maffione 	pthread_exit(ret ? (void *)THRET_FAILURE : (void *)THRET_SUCCESS);
13752a8682a8SVincenzo Maffione }
13762a8682a8SVincenzo Maffione 
13772a8682a8SVincenzo Maffione static int
sync_kloop_start_stop(struct TestContext * ctx)13782a8682a8SVincenzo Maffione sync_kloop_start_stop(struct TestContext *ctx)
13792a8682a8SVincenzo Maffione {
13802a8682a8SVincenzo Maffione 	pthread_t th;
13812a8682a8SVincenzo Maffione 	void *thret = THRET_FAILURE;
13822a8682a8SVincenzo Maffione 	int ret;
13832a8682a8SVincenzo Maffione 
13842a8682a8SVincenzo Maffione 	ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
13852a8682a8SVincenzo Maffione 	if (ret != 0) {
13862a8682a8SVincenzo Maffione 		printf("pthread_create(kloop): %s\n", strerror(ret));
13872a8682a8SVincenzo Maffione 		return -1;
13882a8682a8SVincenzo Maffione 	}
13892a8682a8SVincenzo Maffione 
13902a8682a8SVincenzo Maffione 	ret = sync_kloop_stop(ctx);
13912a8682a8SVincenzo Maffione 	if (ret != 0) {
13922a8682a8SVincenzo Maffione 		return ret;
13932a8682a8SVincenzo Maffione 	}
13942a8682a8SVincenzo Maffione 
13952a8682a8SVincenzo Maffione 	ret = pthread_join(th, &thret);
13962a8682a8SVincenzo Maffione 	if (ret != 0) {
13972a8682a8SVincenzo Maffione 		printf("pthread_join(kloop): %s\n", strerror(ret));
13982a8682a8SVincenzo Maffione 	}
13992a8682a8SVincenzo Maffione 
14002a8682a8SVincenzo Maffione 	return thret == THRET_SUCCESS ? 0 : -1;
14012a8682a8SVincenzo Maffione }
14022a8682a8SVincenzo Maffione 
14032a8682a8SVincenzo Maffione static int
sync_kloop(struct TestContext * ctx)14042a8682a8SVincenzo Maffione sync_kloop(struct TestContext *ctx)
14052a8682a8SVincenzo Maffione {
14062a8682a8SVincenzo Maffione 	int ret;
14072a8682a8SVincenzo Maffione 
14082a8682a8SVincenzo Maffione 	ret = csb_mode(ctx);
14092a8682a8SVincenzo Maffione 	if (ret != 0) {
14102a8682a8SVincenzo Maffione 		return ret;
14112a8682a8SVincenzo Maffione 	}
14122a8682a8SVincenzo Maffione 
14132a8682a8SVincenzo Maffione 	return sync_kloop_start_stop(ctx);
14142a8682a8SVincenzo Maffione }
14152a8682a8SVincenzo Maffione 
14162a8682a8SVincenzo Maffione static int
sync_kloop_eventfds(struct TestContext * ctx)14172a8682a8SVincenzo Maffione sync_kloop_eventfds(struct TestContext *ctx)
14182a8682a8SVincenzo Maffione {
14195e874d26SVincenzo Maffione 	struct nmreq_opt_sync_kloop_eventfds *evopt = NULL;
14205e874d26SVincenzo Maffione 	struct nmreq_opt_sync_kloop_mode modeopt;
14215e874d26SVincenzo Maffione 	struct nmreq_option evsave;
14222a8682a8SVincenzo Maffione 	int num_entries;
14232a8682a8SVincenzo Maffione 	size_t opt_size;
14242a8682a8SVincenzo Maffione 	int ret, i;
14252a8682a8SVincenzo Maffione 
14265e874d26SVincenzo Maffione 	memset(&modeopt, 0, sizeof(modeopt));
14275e874d26SVincenzo Maffione 	modeopt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_MODE;
14285e874d26SVincenzo Maffione 	modeopt.mode = ctx->sync_kloop_mode;
14295e874d26SVincenzo Maffione 	push_option(&modeopt.nro_opt, ctx);
14305e874d26SVincenzo Maffione 
14312a8682a8SVincenzo Maffione 	num_entries = num_registered_rings(ctx);
14325e874d26SVincenzo Maffione 	opt_size    = sizeof(*evopt) + num_entries * sizeof(evopt->eventfds[0]);
14335e874d26SVincenzo Maffione 	evopt = calloc(1, opt_size);
14345e874d26SVincenzo Maffione 	evopt->nro_opt.nro_next    = 0;
14355e874d26SVincenzo Maffione 	evopt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
14365e874d26SVincenzo Maffione 	evopt->nro_opt.nro_status  = 0;
14375e874d26SVincenzo Maffione 	evopt->nro_opt.nro_size    = opt_size;
14382a8682a8SVincenzo Maffione 	for (i = 0; i < num_entries; i++) {
14392a8682a8SVincenzo Maffione 		int efd = eventfd(0, 0);
14402a8682a8SVincenzo Maffione 
14415e874d26SVincenzo Maffione 		evopt->eventfds[i].ioeventfd = efd;
14422a8682a8SVincenzo Maffione 		efd                        = eventfd(0, 0);
14435e874d26SVincenzo Maffione 		evopt->eventfds[i].irqfd = efd;
14442a8682a8SVincenzo Maffione 	}
14452a8682a8SVincenzo Maffione 
14465e874d26SVincenzo Maffione 	push_option(&evopt->nro_opt, ctx);
14475e874d26SVincenzo Maffione 	evsave = evopt->nro_opt;
14482a8682a8SVincenzo Maffione 
14492a8682a8SVincenzo Maffione 	ret = sync_kloop_start_stop(ctx);
14502a8682a8SVincenzo Maffione 	if (ret != 0) {
14515e874d26SVincenzo Maffione 		free(evopt);
14522a8682a8SVincenzo Maffione 		clear_options(ctx);
14532a8682a8SVincenzo Maffione 		return ret;
14542a8682a8SVincenzo Maffione 	}
14552a8682a8SVincenzo Maffione #ifdef __linux__
14565e874d26SVincenzo Maffione 	evsave.nro_status = 0;
14572a8682a8SVincenzo Maffione #else  /* !__linux__ */
14585e874d26SVincenzo Maffione 	evsave.nro_status = EOPNOTSUPP;
14592a8682a8SVincenzo Maffione #endif /* !__linux__ */
14602a8682a8SVincenzo Maffione 
14615e874d26SVincenzo Maffione 	ret = checkoption(&evopt->nro_opt, &evsave);
14625e874d26SVincenzo Maffione 	free(evopt);
14632a8682a8SVincenzo Maffione 	clear_options(ctx);
14642a8682a8SVincenzo Maffione 
14652a8682a8SVincenzo Maffione 	return ret;
14662a8682a8SVincenzo Maffione }
14672a8682a8SVincenzo Maffione 
14682a8682a8SVincenzo Maffione static int
sync_kloop_eventfds_all_mode(struct TestContext * ctx,uint32_t sync_kloop_mode)14695e874d26SVincenzo Maffione sync_kloop_eventfds_all_mode(struct TestContext *ctx,
14705e874d26SVincenzo Maffione 			     uint32_t sync_kloop_mode)
14712a8682a8SVincenzo Maffione {
14722a8682a8SVincenzo Maffione 	int ret;
14732a8682a8SVincenzo Maffione 
14742a8682a8SVincenzo Maffione 	ret = csb_mode(ctx);
14752a8682a8SVincenzo Maffione 	if (ret != 0) {
14762a8682a8SVincenzo Maffione 		return ret;
14772a8682a8SVincenzo Maffione 	}
14782a8682a8SVincenzo Maffione 
14795e874d26SVincenzo Maffione 	ctx->sync_kloop_mode = sync_kloop_mode;
14805e874d26SVincenzo Maffione 
14812a8682a8SVincenzo Maffione 	return sync_kloop_eventfds(ctx);
14822a8682a8SVincenzo Maffione }
14832a8682a8SVincenzo Maffione 
14842a8682a8SVincenzo Maffione static int
sync_kloop_eventfds_all(struct TestContext * ctx)14855e874d26SVincenzo Maffione sync_kloop_eventfds_all(struct TestContext *ctx)
14865e874d26SVincenzo Maffione {
14875e874d26SVincenzo Maffione 	return sync_kloop_eventfds_all_mode(ctx, 0);
14885e874d26SVincenzo Maffione }
14895e874d26SVincenzo Maffione 
14905e874d26SVincenzo Maffione static int
sync_kloop_eventfds_all_tx(struct TestContext * ctx)14912a8682a8SVincenzo Maffione sync_kloop_eventfds_all_tx(struct TestContext *ctx)
14922a8682a8SVincenzo Maffione {
14932a8682a8SVincenzo Maffione 	struct nmreq_opt_csb opt;
14942a8682a8SVincenzo Maffione 	int ret;
14952a8682a8SVincenzo Maffione 
14962a8682a8SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
14972a8682a8SVincenzo Maffione 	if (ret != 0) {
14982a8682a8SVincenzo Maffione 		return ret;
14992a8682a8SVincenzo Maffione 	}
15002a8682a8SVincenzo Maffione 
15012a8682a8SVincenzo Maffione 	ret = port_register_hwall_tx(ctx);
15022a8682a8SVincenzo Maffione 	if (ret != 0) {
15032a8682a8SVincenzo Maffione 		return ret;
15042a8682a8SVincenzo Maffione 	}
15052a8682a8SVincenzo Maffione 	clear_options(ctx);
15062a8682a8SVincenzo Maffione 
15072a8682a8SVincenzo Maffione 	return sync_kloop_eventfds(ctx);
15082a8682a8SVincenzo Maffione }
15092a8682a8SVincenzo Maffione 
15102a8682a8SVincenzo Maffione static int
sync_kloop_eventfds_all_direct(struct TestContext * ctx)15115e874d26SVincenzo Maffione sync_kloop_eventfds_all_direct(struct TestContext *ctx)
15125e874d26SVincenzo Maffione {
15135e874d26SVincenzo Maffione 	return sync_kloop_eventfds_all_mode(ctx,
15145e874d26SVincenzo Maffione 	    NM_OPT_SYNC_KLOOP_DIRECT_TX | NM_OPT_SYNC_KLOOP_DIRECT_RX);
15155e874d26SVincenzo Maffione }
15165e874d26SVincenzo Maffione 
15175e874d26SVincenzo Maffione static int
sync_kloop_eventfds_all_direct_tx(struct TestContext * ctx)15185e874d26SVincenzo Maffione sync_kloop_eventfds_all_direct_tx(struct TestContext *ctx)
15195e874d26SVincenzo Maffione {
15205e874d26SVincenzo Maffione 	return sync_kloop_eventfds_all_mode(ctx,
15215e874d26SVincenzo Maffione 	    NM_OPT_SYNC_KLOOP_DIRECT_TX);
15225e874d26SVincenzo Maffione }
15235e874d26SVincenzo Maffione 
15245e874d26SVincenzo Maffione static int
sync_kloop_eventfds_all_direct_rx(struct TestContext * ctx)15255e874d26SVincenzo Maffione sync_kloop_eventfds_all_direct_rx(struct TestContext *ctx)
15265e874d26SVincenzo Maffione {
15275e874d26SVincenzo Maffione 	return sync_kloop_eventfds_all_mode(ctx,
15285e874d26SVincenzo Maffione 	    NM_OPT_SYNC_KLOOP_DIRECT_RX);
15295e874d26SVincenzo Maffione }
15305e874d26SVincenzo Maffione 
15315e874d26SVincenzo Maffione static int
sync_kloop_nocsb(struct TestContext * ctx)15322a8682a8SVincenzo Maffione sync_kloop_nocsb(struct TestContext *ctx)
15332a8682a8SVincenzo Maffione {
15342a8682a8SVincenzo Maffione 	int ret;
15352a8682a8SVincenzo Maffione 
15362a8682a8SVincenzo Maffione 	ret = port_register_hwall(ctx);
15372a8682a8SVincenzo Maffione 	if (ret != 0) {
15382a8682a8SVincenzo Maffione 		return ret;
15392a8682a8SVincenzo Maffione 	}
15402a8682a8SVincenzo Maffione 
15412a8682a8SVincenzo Maffione 	/* Sync kloop must fail because we did not use
15422a8682a8SVincenzo Maffione 	 * NETMAP_REQ_CSB_ENABLE. */
15432a8682a8SVincenzo Maffione 	return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
15442a8682a8SVincenzo Maffione }
15452a8682a8SVincenzo Maffione 
15462a8682a8SVincenzo Maffione static int
csb_enable(struct TestContext * ctx)15472a8682a8SVincenzo Maffione csb_enable(struct TestContext *ctx)
15482a8682a8SVincenzo Maffione {
15492a8682a8SVincenzo Maffione 	struct nmreq_option saveopt;
15502a8682a8SVincenzo Maffione 	struct nmreq_opt_csb opt;
15512a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
15522a8682a8SVincenzo Maffione 	int ret;
15532a8682a8SVincenzo Maffione 
15542a8682a8SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
15552a8682a8SVincenzo Maffione 	if (ret != 0) {
15562a8682a8SVincenzo Maffione 		return ret;
15572a8682a8SVincenzo Maffione 	}
15582a8682a8SVincenzo Maffione 	saveopt = opt.nro_opt;
15592a8682a8SVincenzo Maffione 	saveopt.nro_status = 0;
15602a8682a8SVincenzo Maffione 
156108f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
15622a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_CSB_ENABLE;
15632a8682a8SVincenzo Maffione 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
15642a8682a8SVincenzo Maffione 	hdr.nr_body = (uintptr_t)NULL;
15652a8682a8SVincenzo Maffione 
156608f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname_ext);
15672a8682a8SVincenzo Maffione 
15682a8682a8SVincenzo Maffione 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
15692a8682a8SVincenzo Maffione 	if (ret != 0) {
15702a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, CSB_ENABLE)");
15712a8682a8SVincenzo Maffione 		return ret;
15722a8682a8SVincenzo Maffione 	}
15732a8682a8SVincenzo Maffione 
15742a8682a8SVincenzo Maffione 	ret = checkoption(&opt.nro_opt, &saveopt);
15752a8682a8SVincenzo Maffione 	clear_options(ctx);
15762a8682a8SVincenzo Maffione 
15772a8682a8SVincenzo Maffione 	return ret;
15782a8682a8SVincenzo Maffione }
15792a8682a8SVincenzo Maffione 
15802a8682a8SVincenzo Maffione static int
sync_kloop_csb_enable(struct TestContext * ctx)15812a8682a8SVincenzo Maffione sync_kloop_csb_enable(struct TestContext *ctx)
15822a8682a8SVincenzo Maffione {
15832a8682a8SVincenzo Maffione 	int ret;
15842a8682a8SVincenzo Maffione 
15852a8682a8SVincenzo Maffione 	ctx->nr_flags |= NR_EXCLUSIVE;
15862a8682a8SVincenzo Maffione 	ret = port_register_hwall(ctx);
15872a8682a8SVincenzo Maffione 	if (ret != 0) {
15882a8682a8SVincenzo Maffione 		return ret;
15892a8682a8SVincenzo Maffione 	}
15902a8682a8SVincenzo Maffione 
15912a8682a8SVincenzo Maffione 	ret = csb_enable(ctx);
15922a8682a8SVincenzo Maffione 	if (ret != 0) {
15932a8682a8SVincenzo Maffione 		return ret;
15942a8682a8SVincenzo Maffione 	}
15952a8682a8SVincenzo Maffione 
15962a8682a8SVincenzo Maffione 	return sync_kloop_start_stop(ctx);
15972a8682a8SVincenzo Maffione }
15982a8682a8SVincenzo Maffione 
15992a8682a8SVincenzo Maffione static int
sync_kloop_conflict(struct TestContext * ctx)16002a8682a8SVincenzo Maffione sync_kloop_conflict(struct TestContext *ctx)
16012a8682a8SVincenzo Maffione {
16022a8682a8SVincenzo Maffione 	struct nmreq_opt_csb opt;
16032a8682a8SVincenzo Maffione 	pthread_t th1, th2;
16042a8682a8SVincenzo Maffione 	void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
16052a8682a8SVincenzo Maffione 	struct timespec to;
16062a8682a8SVincenzo Maffione 	sem_t sem;
16072a8682a8SVincenzo Maffione 	int err = 0;
16082a8682a8SVincenzo Maffione 	int ret;
16092a8682a8SVincenzo Maffione 
16102a8682a8SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
16112a8682a8SVincenzo Maffione 	if (ret != 0) {
16122a8682a8SVincenzo Maffione 		return ret;
16132a8682a8SVincenzo Maffione 	}
16142a8682a8SVincenzo Maffione 
16152a8682a8SVincenzo Maffione 	ret = port_register_hwall(ctx);
16162a8682a8SVincenzo Maffione 	if (ret != 0) {
16172a8682a8SVincenzo Maffione 		return ret;
16182a8682a8SVincenzo Maffione 	}
16192a8682a8SVincenzo Maffione 	clear_options(ctx);
16202a8682a8SVincenzo Maffione 
16212a8682a8SVincenzo Maffione 	ret = sem_init(&sem, 0, 0);
16222a8682a8SVincenzo Maffione 	if (ret != 0) {
16232a8682a8SVincenzo Maffione 		printf("sem_init() failed: %s\n", strerror(ret));
16242a8682a8SVincenzo Maffione 		return ret;
16252a8682a8SVincenzo Maffione 	}
16262a8682a8SVincenzo Maffione 	ctx->sem = &sem;
16272a8682a8SVincenzo Maffione 
16282a8682a8SVincenzo Maffione 	ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
16292a8682a8SVincenzo Maffione 	err |= ret;
16302a8682a8SVincenzo Maffione 	if (ret != 0) {
16312a8682a8SVincenzo Maffione 		printf("pthread_create(kloop1): %s\n", strerror(ret));
16322a8682a8SVincenzo Maffione 	}
16332a8682a8SVincenzo Maffione 
16342a8682a8SVincenzo Maffione 	ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
16352a8682a8SVincenzo Maffione 	err |= ret;
16362a8682a8SVincenzo Maffione 	if (ret != 0) {
16372a8682a8SVincenzo Maffione 		printf("pthread_create(kloop2): %s\n", strerror(ret));
16382a8682a8SVincenzo Maffione 	}
16392a8682a8SVincenzo Maffione 
16402a8682a8SVincenzo Maffione 	/* Wait for one of the two threads to fail to start the kloop, to
16412a8682a8SVincenzo Maffione 	 * avoid a race condition where th1 starts the loop and stops,
16422a8682a8SVincenzo Maffione 	 * and after that th2 starts the loop successfully. */
16432a8682a8SVincenzo Maffione 	clock_gettime(CLOCK_REALTIME, &to);
16442a8682a8SVincenzo Maffione 	to.tv_sec += 2;
16452a8682a8SVincenzo Maffione 	ret = sem_timedwait(&sem, &to);
16462a8682a8SVincenzo Maffione 	err |= ret;
16472a8682a8SVincenzo Maffione 	if (ret != 0) {
16482a8682a8SVincenzo Maffione 		printf("sem_timedwait() failed: %s\n", strerror(errno));
16492a8682a8SVincenzo Maffione 	}
16502a8682a8SVincenzo Maffione 
16512a8682a8SVincenzo Maffione 	err |= sync_kloop_stop(ctx);
16522a8682a8SVincenzo Maffione 
16532a8682a8SVincenzo Maffione 	ret = pthread_join(th1, &thret1);
16542a8682a8SVincenzo Maffione 	err |= ret;
16552a8682a8SVincenzo Maffione 	if (ret != 0) {
16562a8682a8SVincenzo Maffione 		printf("pthread_join(kloop1): %s\n", strerror(ret));
16572a8682a8SVincenzo Maffione 	}
16582a8682a8SVincenzo Maffione 
16592a8682a8SVincenzo Maffione 	ret = pthread_join(th2, &thret2);
16602a8682a8SVincenzo Maffione 	err |= ret;
16612a8682a8SVincenzo Maffione 	if (ret != 0) {
16622a8682a8SVincenzo Maffione 		printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
16632a8682a8SVincenzo Maffione 	}
16642a8682a8SVincenzo Maffione 
16652a8682a8SVincenzo Maffione 	sem_destroy(&sem);
16662a8682a8SVincenzo Maffione 	ctx->sem = NULL;
16672a8682a8SVincenzo Maffione 	if (err) {
16682a8682a8SVincenzo Maffione 		return err;
16692a8682a8SVincenzo Maffione 	}
16702a8682a8SVincenzo Maffione 
16712a8682a8SVincenzo Maffione 	/* Check that one of the two failed, while the other one succeeded. */
16722a8682a8SVincenzo Maffione 	return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
16732a8682a8SVincenzo Maffione 			(thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
16742a8682a8SVincenzo Maffione 	               ? 0
16752a8682a8SVincenzo Maffione 	               : -1;
16762a8682a8SVincenzo Maffione }
16772a8682a8SVincenzo Maffione 
16782a8682a8SVincenzo Maffione static int
sync_kloop_eventfds_mismatch(struct TestContext * ctx)16792a8682a8SVincenzo Maffione sync_kloop_eventfds_mismatch(struct TestContext *ctx)
16802a8682a8SVincenzo Maffione {
16812a8682a8SVincenzo Maffione 	struct nmreq_opt_csb opt;
16822a8682a8SVincenzo Maffione 	int ret;
16832a8682a8SVincenzo Maffione 
16842a8682a8SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
16852a8682a8SVincenzo Maffione 	if (ret != 0) {
16862a8682a8SVincenzo Maffione 		return ret;
16872a8682a8SVincenzo Maffione 	}
16882a8682a8SVincenzo Maffione 
16892a8682a8SVincenzo Maffione 	ret = port_register_hwall_rx(ctx);
16902a8682a8SVincenzo Maffione 	if (ret != 0) {
16912a8682a8SVincenzo Maffione 		return ret;
16922a8682a8SVincenzo Maffione 	}
16932a8682a8SVincenzo Maffione 	clear_options(ctx);
16942a8682a8SVincenzo Maffione 
16952a8682a8SVincenzo Maffione 	/* Deceive num_registered_rings() to trigger a failure of
16962a8682a8SVincenzo Maffione 	 * sync_kloop_eventfds(). The latter will think that all the
16972a8682a8SVincenzo Maffione 	 * rings were registered, and allocate the wrong number of
16982a8682a8SVincenzo Maffione 	 * eventfds. */
16992a8682a8SVincenzo Maffione 	ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
17002a8682a8SVincenzo Maffione 
17012a8682a8SVincenzo Maffione 	return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
17022a8682a8SVincenzo Maffione }
17032a8682a8SVincenzo Maffione 
17042a8682a8SVincenzo Maffione static int
null_port(struct TestContext * ctx)17052a8682a8SVincenzo Maffione null_port(struct TestContext *ctx)
17062a8682a8SVincenzo Maffione {
17072a8682a8SVincenzo Maffione 	int ret;
17082a8682a8SVincenzo Maffione 
17092a8682a8SVincenzo Maffione 	ctx->nr_mem_id = 1;
17102a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_NULL;
17112a8682a8SVincenzo Maffione 	ctx->nr_tx_rings = 10;
17122a8682a8SVincenzo Maffione 	ctx->nr_rx_rings = 5;
17132a8682a8SVincenzo Maffione 	ctx->nr_tx_slots = 256;
17142a8682a8SVincenzo Maffione 	ctx->nr_rx_slots = 100;
17152a8682a8SVincenzo Maffione 	ret = port_register(ctx);
17162a8682a8SVincenzo Maffione 	if (ret != 0) {
17172a8682a8SVincenzo Maffione 		return ret;
17182a8682a8SVincenzo Maffione 	}
17192a8682a8SVincenzo Maffione 	return 0;
17202a8682a8SVincenzo Maffione }
17212a8682a8SVincenzo Maffione 
17222a8682a8SVincenzo Maffione static int
null_port_all_zero(struct TestContext * ctx)17232a8682a8SVincenzo Maffione null_port_all_zero(struct TestContext *ctx)
17242a8682a8SVincenzo Maffione {
17252a8682a8SVincenzo Maffione 	int ret;
17262a8682a8SVincenzo Maffione 
17272a8682a8SVincenzo Maffione 	ctx->nr_mem_id = 1;
17282a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_NULL;
17292a8682a8SVincenzo Maffione 	ctx->nr_tx_rings = 0;
17302a8682a8SVincenzo Maffione 	ctx->nr_rx_rings = 0;
17312a8682a8SVincenzo Maffione 	ctx->nr_tx_slots = 0;
17322a8682a8SVincenzo Maffione 	ctx->nr_rx_slots = 0;
17332a8682a8SVincenzo Maffione 	ret = port_register(ctx);
17342a8682a8SVincenzo Maffione 	if (ret != 0) {
17352a8682a8SVincenzo Maffione 		return ret;
17362a8682a8SVincenzo Maffione 	}
17372a8682a8SVincenzo Maffione 	return 0;
17382a8682a8SVincenzo Maffione }
17392a8682a8SVincenzo Maffione 
17402a8682a8SVincenzo Maffione static int
null_port_sync(struct TestContext * ctx)17412a8682a8SVincenzo Maffione null_port_sync(struct TestContext *ctx)
17422a8682a8SVincenzo Maffione {
17432a8682a8SVincenzo Maffione 	int ret;
17442a8682a8SVincenzo Maffione 
17452a8682a8SVincenzo Maffione 	ctx->nr_mem_id = 1;
17462a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_NULL;
17472a8682a8SVincenzo Maffione 	ctx->nr_tx_rings = 10;
17482a8682a8SVincenzo Maffione 	ctx->nr_rx_rings = 5;
17492a8682a8SVincenzo Maffione 	ctx->nr_tx_slots = 256;
17502a8682a8SVincenzo Maffione 	ctx->nr_rx_slots = 100;
17512a8682a8SVincenzo Maffione 	ret = port_register(ctx);
17522a8682a8SVincenzo Maffione 	if (ret != 0) {
17532a8682a8SVincenzo Maffione 		return ret;
17542a8682a8SVincenzo Maffione 	}
17552a8682a8SVincenzo Maffione 	ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
17562a8682a8SVincenzo Maffione 	if (ret != 0) {
17572a8682a8SVincenzo Maffione 		return ret;
17582a8682a8SVincenzo Maffione 	}
17592a8682a8SVincenzo Maffione 	return 0;
17602a8682a8SVincenzo Maffione }
17612a8682a8SVincenzo Maffione 
176236d6e657SVincenzo Maffione struct nmreq_parse_test {
176336d6e657SVincenzo Maffione 	const char *ifname;
176436d6e657SVincenzo Maffione 	const char *exp_port;
176536d6e657SVincenzo Maffione 	const char *exp_suff;
176636d6e657SVincenzo Maffione 	int exp_error;
176736d6e657SVincenzo Maffione 	uint32_t exp_mode;
176836d6e657SVincenzo Maffione 	uint16_t exp_ringid;
176936d6e657SVincenzo Maffione 	uint64_t exp_flags;
177036d6e657SVincenzo Maffione };
177136d6e657SVincenzo Maffione 
177236d6e657SVincenzo Maffione static struct nmreq_parse_test nmreq_parse_tests[] = {
177336d6e657SVincenzo Maffione 	/* port spec is the input. The expected results are as follows:
177436d6e657SVincenzo Maffione 	 * - port: what should go into hdr.nr_name
177536d6e657SVincenzo Maffione 	 * - suff: the trailing part of the input after parsing (NULL means equal to port spec)
177636d6e657SVincenzo Maffione 	 * - err: the expected return value, interpreted as follows
177736d6e657SVincenzo Maffione 	 *       err > 0 => nmreq_header_parse should fail with the given error
177836d6e657SVincenzo Maffione 	 *       err < 0 => nrmeq_header_parse should succeed, but nmreq_register_decode should
177936d6e657SVincenzo Maffione 	 *       		   fail with error |err|
178036d6e657SVincenzo Maffione 	 *       err = 0 => should succeed
178136d6e657SVincenzo Maffione 	 * - mode, ringid flags: what should go into the corresponding nr_* fields in the
178236d6e657SVincenzo Maffione 	 *   	nmreq_register struct in case of success
178336d6e657SVincenzo Maffione 	 */
178436d6e657SVincenzo Maffione 
178536d6e657SVincenzo Maffione 	/*port spec*/			/*port*/	/*suff*/    /*err*/	/*mode*/    /*ringid*/ /*flags*/
178636d6e657SVincenzo Maffione 	{ "netmap:eth0",		"eth0",		"",		0, 	NR_REG_ALL_NIC,	0,	0 },
178736d6e657SVincenzo Maffione 	{ "netmap:eth0-1",		"eth0",		"",		0, 	NR_REG_ONE_NIC, 1,	0 },
178836d6e657SVincenzo Maffione 	{ "netmap:eth0-",		"eth0",		"-",		-EINVAL,0,		0,	0 },
178936d6e657SVincenzo Maffione 	{ "netmap:eth0/x",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_EXCLUSIVE },
179036d6e657SVincenzo Maffione 	{ "netmap:eth0/z",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_ZCOPY_MON },
179136d6e657SVincenzo Maffione 	{ "netmap:eth0/r",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_MONITOR_RX },
179236d6e657SVincenzo Maffione 	{ "netmap:eth0/t",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_MONITOR_TX },
179336d6e657SVincenzo Maffione 	{ "netmap:eth0-2/Tx",		"eth0",		"",		0, 	NR_REG_ONE_NIC, 2,	NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
179436d6e657SVincenzo Maffione 	{ "netmap:eth0*",		"eth0",		"",		0, 	NR_REG_NIC_SW,  0,	0 },
179536d6e657SVincenzo Maffione 	{ "netmap:eth0^",		"eth0",		"",		0, 	NR_REG_SW,	0,	0 },
179636d6e657SVincenzo Maffione 	{ "netmap:eth0@2",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	0 },
179736d6e657SVincenzo Maffione 	{ "netmap:eth0@2/R",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	NR_RX_RINGS_ONLY },
179836d6e657SVincenzo Maffione 	{ "netmap:eth0@netmap:lo/R",	"eth0",	        "@netmap:lo/R",	0,	NR_REG_ALL_NIC,	0,	0 },
179936d6e657SVincenzo Maffione 	{ "netmap:eth0/R@xxx",		"eth0",	        "@xxx",		0,	NR_REG_ALL_NIC,	0,	NR_RX_RINGS_ONLY },
180036d6e657SVincenzo Maffione 	{ "netmap:eth0@2/R@2",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	NR_RX_RINGS_ONLY },
180136d6e657SVincenzo Maffione 	{ "netmap:eth0@2/R@3",		"eth0",	        "@2/R@3",	-EINVAL,0,		0,	0 },
180236d6e657SVincenzo Maffione 	{ "netmap:eth0@",		"eth0",	        "@",		-EINVAL,0,		0,	0 },
180336d6e657SVincenzo Maffione 	{ "netmap:",			"",		NULL,		EINVAL, 0,		0,	0 },
180436d6e657SVincenzo Maffione 	{ "netmap:^",			"",		NULL,		EINVAL,	0,		0,	0 },
180536d6e657SVincenzo Maffione 	{ "netmap:{",			"",		NULL,		EINVAL,	0,		0,	0 },
180636d6e657SVincenzo Maffione 	{ "eth0",			NULL,		NULL,		EINVAL, 0,		0,	0 },
180736d6e657SVincenzo Maffione 	{ "vale0:0",			"vale0:0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
180836d6e657SVincenzo Maffione 	{ "vale:0",			"vale:0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
180936d6e657SVincenzo Maffione 	{ "valeXXX:YYY",		"valeXXX:YYY",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
181036d6e657SVincenzo Maffione 	{ "valeXXX:YYY-4",		"valeXXX:YYY",	"",		0,	NR_REG_ONE_NIC, 4,	0 },
181136d6e657SVincenzo Maffione 	{ "netmapXXX:eth0",		NULL,		NULL,		EINVAL,	0,		0,	0 },
181236d6e657SVincenzo Maffione 	{ "netmap:14",			"14",		"",		0, 	NR_REG_ALL_NIC,	0,	0 },
181336d6e657SVincenzo Maffione 	{ "netmap:pipe{0",		"pipe{0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
181436d6e657SVincenzo Maffione 	{ "netmap:pipe{in",		"pipe{in",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
181536d6e657SVincenzo Maffione 	{ "netmap:pipe{in-7",		"pipe{in",	"",		0,	NR_REG_ONE_NIC, 7,	0 },
181636d6e657SVincenzo Maffione 	{ "vale0:0{0",			"vale0:0{0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
181736d6e657SVincenzo Maffione 	{ "netmap:pipe{1}2",		NULL,		NULL,		EINVAL, 0,		0,	0 },
181836d6e657SVincenzo Maffione 	{ "vale0:0@opt", 		"vale0:0",	"@opt",		0,	NR_REG_ALL_NIC, 0,	0 },
181936d6e657SVincenzo Maffione 	{ "vale0:0/Tx@opt", 		"vale0:0",	"@opt",		0,	NR_REG_ALL_NIC, 0,	NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
182036d6e657SVincenzo Maffione 	{ "vale0:0-3@opt", 		"vale0:0",	"@opt",		0,	NR_REG_ONE_NIC, 3,	0 },
182136d6e657SVincenzo Maffione 	{ "vale0:0@", 			"vale0:0",	"@",		-EINVAL,0,	        0,	0 },
182236d6e657SVincenzo Maffione 	{ "",				NULL,		NULL,		EINVAL, 0,		0,	0 },
182336d6e657SVincenzo Maffione 	{ NULL,				NULL,		NULL,		0, 	0,		0,	0 },
182436d6e657SVincenzo Maffione };
182536d6e657SVincenzo Maffione 
182636d6e657SVincenzo Maffione static void
randomize(void * dst,size_t n)182736d6e657SVincenzo Maffione randomize(void *dst, size_t n)
182836d6e657SVincenzo Maffione {
182936d6e657SVincenzo Maffione 	size_t i;
183036d6e657SVincenzo Maffione 	char *dst_ = dst;
183136d6e657SVincenzo Maffione 
183236d6e657SVincenzo Maffione 	for (i = 0; i < n; i++)
183336d6e657SVincenzo Maffione 		dst_[i] = (char)random();
183436d6e657SVincenzo Maffione }
183536d6e657SVincenzo Maffione 
183636d6e657SVincenzo Maffione static int
nmreq_hdr_parsing(struct TestContext * ctx,struct nmreq_parse_test * t,struct nmreq_header * hdr)183736d6e657SVincenzo Maffione nmreq_hdr_parsing(struct TestContext *ctx,
183836d6e657SVincenzo Maffione 		struct nmreq_parse_test *t,
183936d6e657SVincenzo Maffione 		struct nmreq_header *hdr)
184036d6e657SVincenzo Maffione {
184136d6e657SVincenzo Maffione 	const char *save;
184236d6e657SVincenzo Maffione 	struct nmreq_header orig_hdr;
184336d6e657SVincenzo Maffione 
184436d6e657SVincenzo Maffione 	save = ctx->ifparse = t->ifname;
184536d6e657SVincenzo Maffione 	orig_hdr = *hdr;
184636d6e657SVincenzo Maffione 
184736d6e657SVincenzo Maffione 	printf("nmreq_header: \"%s\"\n", ctx->ifparse);
184836d6e657SVincenzo Maffione 	if (nmreq_header_decode(&ctx->ifparse, hdr, ctx->nmctx) < 0) {
184936d6e657SVincenzo Maffione 		if (t->exp_error > 0) {
185036d6e657SVincenzo Maffione 			if (errno != t->exp_error) {
185136d6e657SVincenzo Maffione 				printf("!!! got errno=%d, want %d\n",
185236d6e657SVincenzo Maffione 						errno, t->exp_error);
185336d6e657SVincenzo Maffione 				return -1;
185436d6e657SVincenzo Maffione 			}
185536d6e657SVincenzo Maffione 			if (ctx->ifparse != save) {
185636d6e657SVincenzo Maffione 				printf("!!! parse error, but first arg changed\n");
185736d6e657SVincenzo Maffione 				return -1;
185836d6e657SVincenzo Maffione 			}
185936d6e657SVincenzo Maffione 			if (memcmp(&orig_hdr, hdr, sizeof(*hdr))) {
186036d6e657SVincenzo Maffione 				printf("!!! parse error, but header changed\n");
186136d6e657SVincenzo Maffione 				return -1;
186236d6e657SVincenzo Maffione 			}
186336d6e657SVincenzo Maffione 			return 0;
186436d6e657SVincenzo Maffione 		}
186536d6e657SVincenzo Maffione 		printf ("!!! nmreq_header_decode was expected to succeed, but it failed with error %d\n", errno);
186636d6e657SVincenzo Maffione 		return -1;
186736d6e657SVincenzo Maffione 	}
186836d6e657SVincenzo Maffione 	if (t->exp_error > 0) {
186936d6e657SVincenzo Maffione 		printf("!!! nmreq_header_decode returns 0, but error %d was expected\n", t->exp_error);
187036d6e657SVincenzo Maffione 		return -1;
187136d6e657SVincenzo Maffione 	}
187236d6e657SVincenzo Maffione 	if (strcmp(t->exp_port, hdr->nr_name) != 0) {
187336d6e657SVincenzo Maffione 		printf("!!! got '%s', want '%s'\n", hdr->nr_name, t->exp_port);
187436d6e657SVincenzo Maffione 		return -1;
187536d6e657SVincenzo Maffione 	}
187636d6e657SVincenzo Maffione 	if (hdr->nr_reqtype != orig_hdr.nr_reqtype ||
187736d6e657SVincenzo Maffione 	    hdr->nr_options != orig_hdr.nr_options ||
187836d6e657SVincenzo Maffione 	    hdr->nr_body    != orig_hdr.nr_body) {
187936d6e657SVincenzo Maffione 		printf("!!! some fields of the nmreq_header where changed unexpectedly\n");
188036d6e657SVincenzo Maffione 		return -1;
188136d6e657SVincenzo Maffione 	}
188236d6e657SVincenzo Maffione 	return 0;
188336d6e657SVincenzo Maffione }
188436d6e657SVincenzo Maffione 
188536d6e657SVincenzo Maffione static int
nmreq_reg_parsing(struct TestContext * ctx,struct nmreq_parse_test * t,struct nmreq_register * reg)188636d6e657SVincenzo Maffione nmreq_reg_parsing(struct TestContext *ctx,
188736d6e657SVincenzo Maffione 		struct nmreq_parse_test *t,
188836d6e657SVincenzo Maffione 		struct nmreq_register *reg)
188936d6e657SVincenzo Maffione {
189036d6e657SVincenzo Maffione 	const char *save;
189136d6e657SVincenzo Maffione 	struct nmreq_register orig_reg;
189236d6e657SVincenzo Maffione 
189336d6e657SVincenzo Maffione 
189436d6e657SVincenzo Maffione 	save = ctx->ifparse;
189536d6e657SVincenzo Maffione 	orig_reg = *reg;
189636d6e657SVincenzo Maffione 
189736d6e657SVincenzo Maffione 	printf("nmreq_register: \"%s\"\n", ctx->ifparse);
189836d6e657SVincenzo Maffione 	if (nmreq_register_decode(&ctx->ifparse, reg, ctx->nmctx) < 0) {
189936d6e657SVincenzo Maffione 		if (t->exp_error < 0) {
190036d6e657SVincenzo Maffione 			if (errno != -t->exp_error) {
190136d6e657SVincenzo Maffione 				printf("!!! got errno=%d, want %d\n",
190236d6e657SVincenzo Maffione 						errno, -t->exp_error);
190336d6e657SVincenzo Maffione 				return -1;
190436d6e657SVincenzo Maffione 			}
190536d6e657SVincenzo Maffione 			if (ctx->ifparse != save) {
190636d6e657SVincenzo Maffione 				printf("!!! parse error, but first arg changed\n");
190736d6e657SVincenzo Maffione 				return -1;
190836d6e657SVincenzo Maffione 			}
190936d6e657SVincenzo Maffione 			if (memcmp(&orig_reg, reg, sizeof(*reg))) {
191036d6e657SVincenzo Maffione 				printf("!!! parse error, but nmreq_register changed\n");
191136d6e657SVincenzo Maffione 				return -1;
191236d6e657SVincenzo Maffione 			}
191336d6e657SVincenzo Maffione 			return 0;
191436d6e657SVincenzo Maffione 		}
191536d6e657SVincenzo Maffione 		printf ("!!! parse failed but it should have succeeded\n");
191636d6e657SVincenzo Maffione 		return -1;
191736d6e657SVincenzo Maffione 	}
191836d6e657SVincenzo Maffione 	if (t->exp_error < 0) {
191936d6e657SVincenzo Maffione 		printf("!!! nmreq_register_decode returns 0, but error %d was expected\n", -t->exp_error);
192036d6e657SVincenzo Maffione 		return -1;
192136d6e657SVincenzo Maffione 	}
192236d6e657SVincenzo Maffione 	if (reg->nr_mode != t->exp_mode) {
192336d6e657SVincenzo Maffione 		printf("!!! got nr_mode '%d', want '%d'\n", reg->nr_mode, t->exp_mode);
192436d6e657SVincenzo Maffione 		return -1;
192536d6e657SVincenzo Maffione 	}
192636d6e657SVincenzo Maffione 	if (reg->nr_ringid != t->exp_ringid) {
192736d6e657SVincenzo Maffione 		printf("!!! got nr_ringid '%d', want '%d'\n", reg->nr_ringid, t->exp_ringid);
192836d6e657SVincenzo Maffione 		return -1;
192936d6e657SVincenzo Maffione 	}
193036d6e657SVincenzo Maffione 	if (reg->nr_flags != t->exp_flags) {
193136d6e657SVincenzo Maffione 		printf("!!! got nm_flags '%llx', want '%llx\n", (unsigned long long)reg->nr_flags,
193236d6e657SVincenzo Maffione 				(unsigned long long)t->exp_flags);
193336d6e657SVincenzo Maffione 		return -1;
193436d6e657SVincenzo Maffione 	}
193536d6e657SVincenzo Maffione 	if (reg->nr_offset     != orig_reg.nr_offset     ||
193636d6e657SVincenzo Maffione 	    reg->nr_memsize    != orig_reg.nr_memsize    ||
193736d6e657SVincenzo Maffione 	    reg->nr_tx_slots   != orig_reg.nr_tx_slots   ||
193836d6e657SVincenzo Maffione 	    reg->nr_rx_slots   != orig_reg.nr_rx_slots   ||
193936d6e657SVincenzo Maffione 	    reg->nr_tx_rings   != orig_reg.nr_tx_rings   ||
194036d6e657SVincenzo Maffione 	    reg->nr_rx_rings   != orig_reg.nr_rx_rings   ||
194136d6e657SVincenzo Maffione 	    reg->nr_extra_bufs != orig_reg.nr_extra_bufs)
194236d6e657SVincenzo Maffione 	{
194336d6e657SVincenzo Maffione 		printf("!!! some fields of the nmreq_register where changed unexpectedly\n");
194436d6e657SVincenzo Maffione 		return -1;
194536d6e657SVincenzo Maffione 	}
194636d6e657SVincenzo Maffione 	return 0;
194736d6e657SVincenzo Maffione }
194836d6e657SVincenzo Maffione 
194936d6e657SVincenzo Maffione static void
nmctx_parsing_error(struct nmctx * ctx,const char * msg)195036d6e657SVincenzo Maffione nmctx_parsing_error(struct nmctx *ctx, const char *msg)
195136d6e657SVincenzo Maffione {
195236d6e657SVincenzo Maffione 	(void)ctx;
195336d6e657SVincenzo Maffione 	printf("    got message: %s\n", msg);
195436d6e657SVincenzo Maffione }
195536d6e657SVincenzo Maffione 
195636d6e657SVincenzo Maffione static int
nmreq_parsing(struct TestContext * ctx)195736d6e657SVincenzo Maffione nmreq_parsing(struct TestContext *ctx)
195836d6e657SVincenzo Maffione {
195936d6e657SVincenzo Maffione 	struct nmreq_parse_test *t;
196036d6e657SVincenzo Maffione 	struct nmreq_header hdr;
196136d6e657SVincenzo Maffione 	struct nmreq_register reg;
196236d6e657SVincenzo Maffione 	struct nmctx test_nmctx, *nmctx;
196336d6e657SVincenzo Maffione 	int ret = 0;
196436d6e657SVincenzo Maffione 
196536d6e657SVincenzo Maffione 	nmctx = nmctx_get();
196636d6e657SVincenzo Maffione 	if (nmctx == NULL) {
196736d6e657SVincenzo Maffione 		printf("Failed to acquire nmctx: %s", strerror(errno));
196836d6e657SVincenzo Maffione 		return -1;
196936d6e657SVincenzo Maffione 	}
197036d6e657SVincenzo Maffione 	test_nmctx = *nmctx;
197136d6e657SVincenzo Maffione 	test_nmctx.error = nmctx_parsing_error;
197236d6e657SVincenzo Maffione 	ctx->nmctx = &test_nmctx;
197336d6e657SVincenzo Maffione 	for (t = nmreq_parse_tests; t->ifname != NULL; t++) {
197436d6e657SVincenzo Maffione 		const char *exp_suff = t->exp_suff != NULL ?
197536d6e657SVincenzo Maffione 			t->exp_suff : t->ifname;
197636d6e657SVincenzo Maffione 
197736d6e657SVincenzo Maffione 		randomize(&hdr, sizeof(hdr));
197836d6e657SVincenzo Maffione 		randomize(&reg, sizeof(reg));
197936d6e657SVincenzo Maffione 		reg.nr_mem_id = 0;
198036d6e657SVincenzo Maffione 		if (nmreq_hdr_parsing(ctx, t, &hdr) < 0) {
198136d6e657SVincenzo Maffione 			ret = -1;
198236d6e657SVincenzo Maffione 		} else if (t->exp_error <= 0 && nmreq_reg_parsing(ctx, t, &reg) < 0) {
198336d6e657SVincenzo Maffione 			ret = -1;
198436d6e657SVincenzo Maffione 		}
198536d6e657SVincenzo Maffione 		if (strcmp(ctx->ifparse, exp_suff) != 0) {
198636d6e657SVincenzo Maffione 			printf("!!! string suffix after parse is '%s', but it should be '%s'\n",
198736d6e657SVincenzo Maffione 					ctx->ifparse, exp_suff);
198836d6e657SVincenzo Maffione 			ret = -1;
198936d6e657SVincenzo Maffione 		}
199036d6e657SVincenzo Maffione 	}
1991f4db3905SJohn Baldwin 	ctx->nmctx = NULL;
199236d6e657SVincenzo Maffione 	return ret;
199336d6e657SVincenzo Maffione }
199436d6e657SVincenzo Maffione 
199536d6e657SVincenzo Maffione static int
binarycomp(struct TestContext * ctx)199636d6e657SVincenzo Maffione binarycomp(struct TestContext *ctx)
199736d6e657SVincenzo Maffione {
199836d6e657SVincenzo Maffione #define ckroff(f, o) do {\
199936d6e657SVincenzo Maffione 	if (offsetof(struct netmap_ring, f) != (o)) {\
200036d6e657SVincenzo Maffione 		printf("offset of netmap_ring.%s is %zd, but it should be %d",\
200136d6e657SVincenzo Maffione 				#f, offsetof(struct netmap_ring, f), (o));\
200236d6e657SVincenzo Maffione 		return -1;\
200336d6e657SVincenzo Maffione 	}\
200436d6e657SVincenzo Maffione } while (0)
200536d6e657SVincenzo Maffione 
200636d6e657SVincenzo Maffione 	(void)ctx;
200736d6e657SVincenzo Maffione 
200836d6e657SVincenzo Maffione 	ckroff(buf_ofs, 0);
200936d6e657SVincenzo Maffione 	ckroff(num_slots, 8);
201036d6e657SVincenzo Maffione 	ckroff(nr_buf_size, 12);
201136d6e657SVincenzo Maffione 	ckroff(ringid, 16);
201236d6e657SVincenzo Maffione 	ckroff(dir, 18);
201336d6e657SVincenzo Maffione 	ckroff(head, 20);
201436d6e657SVincenzo Maffione 	ckroff(cur, 24);
201536d6e657SVincenzo Maffione 	ckroff(tail, 28);
201636d6e657SVincenzo Maffione 	ckroff(flags, 32);
201736d6e657SVincenzo Maffione 	ckroff(ts, 40);
201836d6e657SVincenzo Maffione 	ckroff(offset_mask, 56);
201936d6e657SVincenzo Maffione 	ckroff(buf_align, 64);
202036d6e657SVincenzo Maffione 	ckroff(sem, 128);
202136d6e657SVincenzo Maffione 	ckroff(slot, 256);
202236d6e657SVincenzo Maffione 
202336d6e657SVincenzo Maffione 	return 0;
202436d6e657SVincenzo Maffione }
202536d6e657SVincenzo Maffione 
20262a8682a8SVincenzo Maffione static void
usage(const char * prog)20272a8682a8SVincenzo Maffione usage(const char *prog)
20282a8682a8SVincenzo Maffione {
20292a8682a8SVincenzo Maffione 	printf("%s -i IFNAME\n"
20302a8682a8SVincenzo Maffione 	       "[-j TEST_NUM1[-[TEST_NUM2]] | -[TEST_NUM_2]]\n"
20312a8682a8SVincenzo Maffione 	       "[-l (list test cases)]\n",
20322a8682a8SVincenzo Maffione 	       prog);
20332a8682a8SVincenzo Maffione }
20342a8682a8SVincenzo Maffione 
20352a8682a8SVincenzo Maffione struct mytest {
20362a8682a8SVincenzo Maffione 	testfunc_t test;
20372a8682a8SVincenzo Maffione 	const char *name;
20382a8682a8SVincenzo Maffione };
20392a8682a8SVincenzo Maffione 
20402a8682a8SVincenzo Maffione #define decltest(f)                                                            \
20412a8682a8SVincenzo Maffione 	{                                                                      \
20422a8682a8SVincenzo Maffione 		.test = f, .name = #f                                          \
20432a8682a8SVincenzo Maffione 	}
20442a8682a8SVincenzo Maffione 
20452a8682a8SVincenzo Maffione static struct mytest tests[] = {
20462a8682a8SVincenzo Maffione 	decltest(port_info_get),
20472a8682a8SVincenzo Maffione 	decltest(port_register_hwall_host),
20482a8682a8SVincenzo Maffione 	decltest(port_register_hwall),
20494f6858e8SVincenzo Maffione 	decltest(port_register_hostall),
20504f6858e8SVincenzo Maffione 	decltest(port_register_single_hw_pair),
20514f6858e8SVincenzo Maffione 	decltest(port_register_single_host_pair),
20524f6858e8SVincenzo Maffione 	decltest(port_register_hostall_many),
20532a8682a8SVincenzo Maffione 	decltest(vale_attach_detach),
20542a8682a8SVincenzo Maffione 	decltest(vale_attach_detach_host_rings),
20552a8682a8SVincenzo Maffione 	decltest(vale_ephemeral_port_hdr_manipulation),
20562a8682a8SVincenzo Maffione 	decltest(vale_persistent_port),
20572a8682a8SVincenzo Maffione 	decltest(pools_info_get_and_register),
20582a8682a8SVincenzo Maffione 	decltest(pools_info_get_empty_ifname),
20592a8682a8SVincenzo Maffione 	decltest(pipe_master),
20602a8682a8SVincenzo Maffione 	decltest(pipe_slave),
20612a8682a8SVincenzo Maffione 	decltest(pipe_port_info_get),
20622a8682a8SVincenzo Maffione 	decltest(pipe_pools_info_get),
20632a8682a8SVincenzo Maffione 	decltest(vale_polling_enable_disable),
20642a8682a8SVincenzo Maffione 	decltest(unsupported_option),
20652a8682a8SVincenzo Maffione 	decltest(infinite_options),
2066e2a431a0SVincenzo Maffione 	decltest(infinite_options2),
20672a8682a8SVincenzo Maffione #ifdef CONFIG_NETMAP_EXTMEM
20682a8682a8SVincenzo Maffione 	decltest(extmem_option),
20692a8682a8SVincenzo Maffione 	decltest(bad_extmem_option),
20702a8682a8SVincenzo Maffione 	decltest(duplicate_extmem_options),
20712a8682a8SVincenzo Maffione #endif /* CONFIG_NETMAP_EXTMEM */
20722a8682a8SVincenzo Maffione 	decltest(csb_mode),
20732a8682a8SVincenzo Maffione 	decltest(csb_mode_invalid_memory),
20742a8682a8SVincenzo Maffione 	decltest(sync_kloop),
20752a8682a8SVincenzo Maffione 	decltest(sync_kloop_eventfds_all),
20762a8682a8SVincenzo Maffione 	decltest(sync_kloop_eventfds_all_tx),
20775e874d26SVincenzo Maffione 	decltest(sync_kloop_eventfds_all_direct),
20785e874d26SVincenzo Maffione 	decltest(sync_kloop_eventfds_all_direct_tx),
20795e874d26SVincenzo Maffione 	decltest(sync_kloop_eventfds_all_direct_rx),
20802a8682a8SVincenzo Maffione 	decltest(sync_kloop_nocsb),
20812a8682a8SVincenzo Maffione 	decltest(sync_kloop_csb_enable),
20822a8682a8SVincenzo Maffione 	decltest(sync_kloop_conflict),
20832a8682a8SVincenzo Maffione 	decltest(sync_kloop_eventfds_mismatch),
20842a8682a8SVincenzo Maffione 	decltest(null_port),
20852a8682a8SVincenzo Maffione 	decltest(null_port_all_zero),
20862a8682a8SVincenzo Maffione 	decltest(null_port_sync),
20872a8682a8SVincenzo Maffione 	decltest(legacy_regif_default),
20882a8682a8SVincenzo Maffione 	decltest(legacy_regif_all_nic),
20892a8682a8SVincenzo Maffione 	decltest(legacy_regif_12),
20902a8682a8SVincenzo Maffione 	decltest(legacy_regif_sw),
20912a8682a8SVincenzo Maffione 	decltest(legacy_regif_future),
20922a8682a8SVincenzo Maffione 	decltest(legacy_regif_extra_bufs),
20932a8682a8SVincenzo Maffione 	decltest(legacy_regif_extra_bufs_pipe),
20942a8682a8SVincenzo Maffione 	decltest(legacy_regif_extra_bufs_pipe_vale),
209536d6e657SVincenzo Maffione 	decltest(nmreq_parsing),
209636d6e657SVincenzo Maffione 	decltest(binarycomp),
20972a8682a8SVincenzo Maffione };
20982a8682a8SVincenzo Maffione 
20992a8682a8SVincenzo Maffione static void
context_cleanup(struct TestContext * ctx)21002a8682a8SVincenzo Maffione context_cleanup(struct TestContext *ctx)
21012a8682a8SVincenzo Maffione {
21022a8682a8SVincenzo Maffione 	if (ctx->csb) {
21032a8682a8SVincenzo Maffione 		free(ctx->csb);
21042a8682a8SVincenzo Maffione 		ctx->csb = NULL;
21052a8682a8SVincenzo Maffione 	}
21062a8682a8SVincenzo Maffione 
21072a8682a8SVincenzo Maffione 	close(ctx->fd);
21082a8682a8SVincenzo Maffione 	ctx->fd = -1;
21092a8682a8SVincenzo Maffione }
21102a8682a8SVincenzo Maffione 
21112a8682a8SVincenzo Maffione static int
parse_interval(const char * arg,int * j,int * k)21122a8682a8SVincenzo Maffione parse_interval(const char *arg, int *j, int *k)
21132a8682a8SVincenzo Maffione {
21142a8682a8SVincenzo Maffione 	const char *scan = arg;
21152a8682a8SVincenzo Maffione 	char *rest;
21162a8682a8SVincenzo Maffione 
21172a8682a8SVincenzo Maffione 	*j = 0;
21182a8682a8SVincenzo Maffione 	*k = -1;
21192a8682a8SVincenzo Maffione 	if (*scan == '-') {
21202a8682a8SVincenzo Maffione 		scan++;
21212a8682a8SVincenzo Maffione 		goto get_k;
21222a8682a8SVincenzo Maffione 	}
21232a8682a8SVincenzo Maffione 	if (!isdigit(*scan))
21242a8682a8SVincenzo Maffione 		goto err;
21252a8682a8SVincenzo Maffione 	*k = strtol(scan, &rest, 10);
21262a8682a8SVincenzo Maffione 	*j = *k - 1;
21272a8682a8SVincenzo Maffione 	scan = rest;
21282a8682a8SVincenzo Maffione 	if (*scan == '-') {
21292a8682a8SVincenzo Maffione 		*k = -1;
21302a8682a8SVincenzo Maffione 		scan++;
21312a8682a8SVincenzo Maffione 	}
21322a8682a8SVincenzo Maffione get_k:
21332a8682a8SVincenzo Maffione 	if (*scan == '\0')
21342a8682a8SVincenzo Maffione 		return 0;
21352a8682a8SVincenzo Maffione 	if (!isdigit(*scan))
21362a8682a8SVincenzo Maffione 		goto err;
21372a8682a8SVincenzo Maffione 	*k = strtol(scan, &rest, 10);
21382a8682a8SVincenzo Maffione 	scan = rest;
21392a8682a8SVincenzo Maffione 	if (!(*scan == '\0'))
21402a8682a8SVincenzo Maffione 		goto err;
21412a8682a8SVincenzo Maffione 
21422a8682a8SVincenzo Maffione 	return 0;
21432a8682a8SVincenzo Maffione 
21442a8682a8SVincenzo Maffione err:
21452a8682a8SVincenzo Maffione 	fprintf(stderr, "syntax error in '%s', must be num[-[num]] or -[num]\n", arg);
21462a8682a8SVincenzo Maffione 	return -1;
21472a8682a8SVincenzo Maffione }
21482a8682a8SVincenzo Maffione 
21492a8682a8SVincenzo Maffione #define ARGV_APPEND(_av, _ac, _x)\
21502a8682a8SVincenzo Maffione 	do {\
21512a8682a8SVincenzo Maffione 		assert((int)(_ac) < (int)(sizeof(_av)/sizeof((_av)[0])));\
21522a8682a8SVincenzo Maffione 		(_av)[(_ac)++] = _x;\
21532a8682a8SVincenzo Maffione 	} while (0)
21542a8682a8SVincenzo Maffione 
21552a8682a8SVincenzo Maffione static void
tap_cleanup(int signo)21562a8682a8SVincenzo Maffione tap_cleanup(int signo)
21572a8682a8SVincenzo Maffione {
21582a8682a8SVincenzo Maffione 	const char *av[8];
21592a8682a8SVincenzo Maffione 	int ac = 0;
21602a8682a8SVincenzo Maffione 
21612a8682a8SVincenzo Maffione 	(void)signo;
21622a8682a8SVincenzo Maffione #ifdef __FreeBSD__
21632a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, "ifconfig");
21642a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, ctx_.ifname);
21652a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, "destroy");
21662a8682a8SVincenzo Maffione #else
21672a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, "ip");
21682a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, "link");
21692a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, "del");
21702a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, ctx_.ifname);
21712a8682a8SVincenzo Maffione #endif
21722a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, NULL);
21732a8682a8SVincenzo Maffione 	if (exec_command(ac, av)) {
21742a8682a8SVincenzo Maffione 		printf("Failed to destroy tap interface\n");
21752a8682a8SVincenzo Maffione 	}
21762a8682a8SVincenzo Maffione }
21772a8682a8SVincenzo Maffione 
21782a8682a8SVincenzo Maffione int
main(int argc,char ** argv)21792a8682a8SVincenzo Maffione main(int argc, char **argv)
21802a8682a8SVincenzo Maffione {
21812a8682a8SVincenzo Maffione 	int create_tap = 1;
21822a8682a8SVincenzo Maffione 	int num_tests;
21832a8682a8SVincenzo Maffione 	int ret  = 0;
21842a8682a8SVincenzo Maffione 	int j    = 0;
21852a8682a8SVincenzo Maffione 	int k    = -1;
21862a8682a8SVincenzo Maffione 	int list = 0;
21872a8682a8SVincenzo Maffione 	int opt;
21882a8682a8SVincenzo Maffione 	int i;
21892a8682a8SVincenzo Maffione 
21907d757b71SOlivier Cochard #ifdef __FreeBSD__
21917d757b71SOlivier Cochard 	PLAIN_REQUIRE_KERNEL_MODULE("if_tap", 0);
2192c9c9de93SEnji Cooper 	PLAIN_REQUIRE_KERNEL_MODULE("netmap", 0);
21937d757b71SOlivier Cochard #endif
21947d757b71SOlivier Cochard 
21952a8682a8SVincenzo Maffione 	memset(&ctx_, 0, sizeof(ctx_));
21962a8682a8SVincenzo Maffione 
21972a8682a8SVincenzo Maffione 	{
21982a8682a8SVincenzo Maffione 		struct timespec t;
21992a8682a8SVincenzo Maffione 		int idx;
22002a8682a8SVincenzo Maffione 
22012a8682a8SVincenzo Maffione 		clock_gettime(CLOCK_REALTIME, &t);
22022a8682a8SVincenzo Maffione 		srand((unsigned int)t.tv_nsec);
22032a8682a8SVincenzo Maffione 		idx = rand() % 8000 + 100;
22042a8682a8SVincenzo Maffione 		snprintf(ctx_.ifname, sizeof(ctx_.ifname), "tap%d", idx);
22052a8682a8SVincenzo Maffione 		idx = rand() % 800 + 100;
22062a8682a8SVincenzo Maffione 		snprintf(ctx_.bdgname, sizeof(ctx_.bdgname), "vale%d", idx);
22072a8682a8SVincenzo Maffione 	}
22082a8682a8SVincenzo Maffione 
22092a8682a8SVincenzo Maffione 	while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
22102a8682a8SVincenzo Maffione 		switch (opt) {
22112a8682a8SVincenzo Maffione 		case 'h':
22122a8682a8SVincenzo Maffione 			usage(argv[0]);
22132a8682a8SVincenzo Maffione 			return 0;
22142a8682a8SVincenzo Maffione 
22152a8682a8SVincenzo Maffione 		case 'i':
22162a8682a8SVincenzo Maffione 			strncpy(ctx_.ifname, optarg, sizeof(ctx_.ifname) - 1);
22172a8682a8SVincenzo Maffione 			create_tap = 0;
22182a8682a8SVincenzo Maffione 			break;
22192a8682a8SVincenzo Maffione 
22202a8682a8SVincenzo Maffione 		case 'j':
22212a8682a8SVincenzo Maffione 			if (parse_interval(optarg, &j, &k) < 0) {
22222a8682a8SVincenzo Maffione 				usage(argv[0]);
22232a8682a8SVincenzo Maffione 				return -1;
22242a8682a8SVincenzo Maffione 			}
22252a8682a8SVincenzo Maffione 			break;
22262a8682a8SVincenzo Maffione 
22272a8682a8SVincenzo Maffione 		case 'l':
22282a8682a8SVincenzo Maffione 			list = 1;
22292a8682a8SVincenzo Maffione 			create_tap = 0;
22302a8682a8SVincenzo Maffione 			break;
22312a8682a8SVincenzo Maffione 
22322a8682a8SVincenzo Maffione 		default:
22332a8682a8SVincenzo Maffione 			printf("    Unrecognized option %c\n", opt);
22342a8682a8SVincenzo Maffione 			usage(argv[0]);
22352a8682a8SVincenzo Maffione 			return -1;
22362a8682a8SVincenzo Maffione 		}
22372a8682a8SVincenzo Maffione 	}
22382a8682a8SVincenzo Maffione 
22392a8682a8SVincenzo Maffione 	num_tests = sizeof(tests) / sizeof(tests[0]);
22402a8682a8SVincenzo Maffione 
22412a8682a8SVincenzo Maffione 	if (j < 0 || j >= num_tests || k > num_tests) {
22422a8682a8SVincenzo Maffione 		fprintf(stderr, "Test interval %d-%d out of range (%d-%d)\n",
22432a8682a8SVincenzo Maffione 				j + 1, k, 1, num_tests + 1);
22442a8682a8SVincenzo Maffione 		return -1;
22452a8682a8SVincenzo Maffione 	}
22462a8682a8SVincenzo Maffione 
22472a8682a8SVincenzo Maffione 	if (k < 0)
22482a8682a8SVincenzo Maffione 		k = num_tests;
22492a8682a8SVincenzo Maffione 
22502a8682a8SVincenzo Maffione 	if (list) {
22512a8682a8SVincenzo Maffione 		printf("Available tests:\n");
22522a8682a8SVincenzo Maffione 		for (i = 0; i < num_tests; i++) {
22532a8682a8SVincenzo Maffione 			printf("#%03d: %s\n", i + 1, tests[i].name);
22542a8682a8SVincenzo Maffione 		}
22552a8682a8SVincenzo Maffione 		return 0;
22562a8682a8SVincenzo Maffione 	}
22572a8682a8SVincenzo Maffione 
22582a8682a8SVincenzo Maffione 	if (create_tap) {
22592a8682a8SVincenzo Maffione 		struct sigaction sa;
22602a8682a8SVincenzo Maffione 		const char *av[8];
22612a8682a8SVincenzo Maffione 		int ac = 0;
22622a8682a8SVincenzo Maffione #ifdef __FreeBSD__
22632a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "ifconfig");
22642a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, ctx_.ifname);
22652a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "create");
22662a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "up");
22672a8682a8SVincenzo Maffione #else
22682a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "ip");
22692a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "tuntap");
22702a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "add");
22712a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "mode");
22722a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "tap");
22732a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "name");
22742a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, ctx_.ifname);
22752a8682a8SVincenzo Maffione #endif
22762a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, NULL);
22772a8682a8SVincenzo Maffione 		if (exec_command(ac, av)) {
22782a8682a8SVincenzo Maffione 			printf("Failed to create tap interface\n");
22792a8682a8SVincenzo Maffione 			return -1;
22802a8682a8SVincenzo Maffione 		}
22812a8682a8SVincenzo Maffione 
22822a8682a8SVincenzo Maffione 		sa.sa_handler = tap_cleanup;
22832a8682a8SVincenzo Maffione 		sigemptyset(&sa.sa_mask);
22842a8682a8SVincenzo Maffione 		sa.sa_flags = SA_RESTART;
22852a8682a8SVincenzo Maffione 		ret         = sigaction(SIGINT, &sa, NULL);
22862a8682a8SVincenzo Maffione 		if (ret) {
22872a8682a8SVincenzo Maffione 			perror("sigaction(SIGINT)");
22882a8682a8SVincenzo Maffione 			goto out;
22892a8682a8SVincenzo Maffione 		}
22902a8682a8SVincenzo Maffione 		ret = sigaction(SIGTERM, &sa, NULL);
22912a8682a8SVincenzo Maffione 		if (ret) {
22922a8682a8SVincenzo Maffione 			perror("sigaction(SIGTERM)");
22932a8682a8SVincenzo Maffione 			goto out;
22942a8682a8SVincenzo Maffione 		}
22952a8682a8SVincenzo Maffione 	}
22962a8682a8SVincenzo Maffione 
22972a8682a8SVincenzo Maffione 	for (i = j; i < k; i++) {
22982a8682a8SVincenzo Maffione 		struct TestContext ctxcopy;
22992a8682a8SVincenzo Maffione 		int fd;
23002a8682a8SVincenzo Maffione 		printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
23012a8682a8SVincenzo Maffione 		fd = open("/dev/netmap", O_RDWR);
23022a8682a8SVincenzo Maffione 		if (fd < 0) {
23032a8682a8SVincenzo Maffione 			perror("open(/dev/netmap)");
23042a8682a8SVincenzo Maffione 			ret = fd;
23052a8682a8SVincenzo Maffione 			goto out;
23062a8682a8SVincenzo Maffione 		}
23072a8682a8SVincenzo Maffione 		memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
23082a8682a8SVincenzo Maffione 		ctxcopy.fd = fd;
230908f34ad9SVincenzo Maffione 		memcpy(ctxcopy.ifname_ext, ctxcopy.ifname,
231008f34ad9SVincenzo Maffione 			sizeof(ctxcopy.ifname));
23112a8682a8SVincenzo Maffione 		ret        = tests[i].test(&ctxcopy);
23122a8682a8SVincenzo Maffione 		if (ret != 0) {
23132a8682a8SVincenzo Maffione 			printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
23142a8682a8SVincenzo Maffione 			goto out;
23152a8682a8SVincenzo Maffione 		}
23162a8682a8SVincenzo Maffione 		printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
23172a8682a8SVincenzo Maffione 		context_cleanup(&ctxcopy);
23182a8682a8SVincenzo Maffione 	}
23192a8682a8SVincenzo Maffione out:
23202a8682a8SVincenzo Maffione 	tap_cleanup(0);
23212a8682a8SVincenzo Maffione 
23222a8682a8SVincenzo Maffione 	return ret;
23232a8682a8SVincenzo Maffione }
2324