12a8682a8SVincenzo Maffione /*-
22a8682a8SVincenzo Maffione  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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  * $FreeBSD$
282a8682a8SVincenzo Maffione  */
292a8682a8SVincenzo Maffione 
302a8682a8SVincenzo Maffione #include <sys/ioctl.h>
312a8682a8SVincenzo Maffione #include <sys/mman.h>
322a8682a8SVincenzo Maffione #include <sys/wait.h>
332a8682a8SVincenzo Maffione 
342a8682a8SVincenzo Maffione #include <assert.h>
352a8682a8SVincenzo Maffione #include <ctype.h>
362a8682a8SVincenzo Maffione #include <errno.h>
372a8682a8SVincenzo Maffione #include <fcntl.h>
382a8682a8SVincenzo Maffione #include <inttypes.h>
392a8682a8SVincenzo Maffione #include <net/if.h>
402a8682a8SVincenzo Maffione #include <net/netmap.h>
412a8682a8SVincenzo Maffione #include <pthread.h>
422a8682a8SVincenzo Maffione #include <semaphore.h>
432a8682a8SVincenzo Maffione #include <stdint.h>
442a8682a8SVincenzo Maffione #include <stdio.h>
452a8682a8SVincenzo Maffione #include <stdlib.h>
462a8682a8SVincenzo Maffione #include <string.h>
472a8682a8SVincenzo Maffione #include <time.h>
482a8682a8SVincenzo Maffione #include <unistd.h>
492a8682a8SVincenzo Maffione #include <signal.h>
502a8682a8SVincenzo Maffione 
517d757b71SOlivier Cochard #ifdef __FreeBSD__
527d757b71SOlivier Cochard #include "freebsd_test_suite/macros.h"
537d757b71SOlivier Cochard 
542a8682a8SVincenzo Maffione static int
eventfd(int x __unused,int y __unused)552a8682a8SVincenzo Maffione eventfd(int x __unused, int y __unused)
562a8682a8SVincenzo Maffione {
572a8682a8SVincenzo Maffione 	errno = ENODEV;
582a8682a8SVincenzo Maffione 	return -1;
592a8682a8SVincenzo Maffione }
60*4f6858e8SVincenzo Maffione #else /* __linux__ */
61*4f6858e8SVincenzo Maffione #include <sys/eventfd.h>
62*4f6858e8SVincenzo Maffione #endif
632a8682a8SVincenzo Maffione 
642a8682a8SVincenzo Maffione static int
exec_command(int argc,const char * const argv[])652a8682a8SVincenzo Maffione exec_command(int argc, const char *const argv[])
662a8682a8SVincenzo Maffione {
672a8682a8SVincenzo Maffione 	pid_t child_pid;
682a8682a8SVincenzo Maffione 	pid_t wret;
692a8682a8SVincenzo Maffione 	int child_status;
702a8682a8SVincenzo Maffione 	int i;
712a8682a8SVincenzo Maffione 
722a8682a8SVincenzo Maffione 	printf("Executing command: ");
732a8682a8SVincenzo Maffione 	for (i = 0; i < argc - 1; i++) {
742a8682a8SVincenzo Maffione 		if (!argv[i]) {
752a8682a8SVincenzo Maffione 			/* Invalid argument. */
762a8682a8SVincenzo Maffione 			return -1;
772a8682a8SVincenzo Maffione 		}
782a8682a8SVincenzo Maffione 		if (i > 0) {
792a8682a8SVincenzo Maffione 			putchar(' ');
802a8682a8SVincenzo Maffione 		}
812a8682a8SVincenzo Maffione 		printf("%s", argv[i]);
822a8682a8SVincenzo Maffione 	}
832a8682a8SVincenzo Maffione 	putchar('\n');
842a8682a8SVincenzo Maffione 
852a8682a8SVincenzo Maffione 	child_pid = fork();
862a8682a8SVincenzo Maffione 	if (child_pid == 0) {
872a8682a8SVincenzo Maffione 		char **av;
8808f34ad9SVincenzo Maffione 		int fds[3];
892a8682a8SVincenzo Maffione 
902a8682a8SVincenzo Maffione 		/* Child process. Redirect stdin, stdout
912a8682a8SVincenzo Maffione 		 * and stderr. */
9208f34ad9SVincenzo Maffione 		for (i = 0; i < 3; i++) {
9308f34ad9SVincenzo Maffione 			close(i);
9408f34ad9SVincenzo Maffione 			fds[i] = open("/dev/null", O_RDONLY);
9508f34ad9SVincenzo Maffione 			if (fds[i] < 0) {
9608f34ad9SVincenzo Maffione 				for (i--; i >= 0; i--) {
9708f34ad9SVincenzo Maffione 					close(fds[i]);
9808f34ad9SVincenzo Maffione 				}
992a8682a8SVincenzo Maffione 				return -1;
1002a8682a8SVincenzo Maffione 			}
10108f34ad9SVincenzo Maffione 		}
1022a8682a8SVincenzo Maffione 
1032a8682a8SVincenzo Maffione 		/* Make a copy of the arguments, passing them to execvp. */
1042a8682a8SVincenzo Maffione 		av = calloc(argc, sizeof(av[0]));
1052a8682a8SVincenzo Maffione 		if (!av) {
1062a8682a8SVincenzo Maffione 			exit(EXIT_FAILURE);
1072a8682a8SVincenzo Maffione 		}
1082a8682a8SVincenzo Maffione 		for (i = 0; i < argc - 1; i++) {
1092a8682a8SVincenzo Maffione 			av[i] = strdup(argv[i]);
1102a8682a8SVincenzo Maffione 			if (!av[i]) {
1112a8682a8SVincenzo Maffione 				exit(EXIT_FAILURE);
1122a8682a8SVincenzo Maffione 			}
1132a8682a8SVincenzo Maffione 		}
1142a8682a8SVincenzo Maffione 		execvp(av[0], av);
1152a8682a8SVincenzo Maffione 		perror("execvp()");
1162a8682a8SVincenzo Maffione 		exit(EXIT_FAILURE);
1172a8682a8SVincenzo Maffione 	}
1182a8682a8SVincenzo Maffione 
1192a8682a8SVincenzo Maffione 	wret = waitpid(child_pid, &child_status, 0);
1202a8682a8SVincenzo Maffione 	if (wret < 0) {
1212a8682a8SVincenzo Maffione 		fprintf(stderr, "waitpid() failed: %s\n", strerror(errno));
1222a8682a8SVincenzo Maffione 		return wret;
1232a8682a8SVincenzo Maffione 	}
1242a8682a8SVincenzo Maffione 	if (WIFEXITED(child_status)) {
1252a8682a8SVincenzo Maffione 		return WEXITSTATUS(child_status);
1262a8682a8SVincenzo Maffione 	}
1272a8682a8SVincenzo Maffione 
1282a8682a8SVincenzo Maffione 	return -1;
1292a8682a8SVincenzo Maffione }
1302a8682a8SVincenzo Maffione 
1312a8682a8SVincenzo Maffione 
1322a8682a8SVincenzo Maffione #define THRET_SUCCESS	((void *)128)
1332a8682a8SVincenzo Maffione #define THRET_FAILURE	((void *)0)
1342a8682a8SVincenzo Maffione 
1352a8682a8SVincenzo Maffione struct TestContext {
13608f34ad9SVincenzo Maffione 	char ifname[64];
13708f34ad9SVincenzo Maffione 	char ifname_ext[128];
1382a8682a8SVincenzo Maffione 	char bdgname[64];
1392a8682a8SVincenzo Maffione 	uint32_t nr_tx_slots;   /* slots in tx rings */
1402a8682a8SVincenzo Maffione 	uint32_t nr_rx_slots;   /* slots in rx rings */
1412a8682a8SVincenzo Maffione 	uint16_t nr_tx_rings;   /* number of tx rings */
1422a8682a8SVincenzo Maffione 	uint16_t nr_rx_rings;   /* number of rx rings */
143*4f6858e8SVincenzo Maffione 	uint16_t nr_host_tx_rings;   /* number of host tx rings */
144*4f6858e8SVincenzo Maffione 	uint16_t nr_host_rx_rings;   /* number of host rx rings */
1452a8682a8SVincenzo Maffione 	uint16_t nr_mem_id;     /* id of the memory allocator */
1462a8682a8SVincenzo Maffione 	uint16_t nr_ringid;     /* ring(s) we care about */
1472a8682a8SVincenzo Maffione 	uint32_t nr_mode;       /* specify NR_REG_* modes */
1482a8682a8SVincenzo Maffione 	uint32_t nr_extra_bufs; /* number of requested extra buffers */
1492a8682a8SVincenzo Maffione 	uint64_t nr_flags;      /* additional flags (see below) */
1502a8682a8SVincenzo Maffione 	uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
1512a8682a8SVincenzo Maffione 	uint32_t nr_first_cpu_id;     /* vale polling */
1522a8682a8SVincenzo Maffione 	uint32_t nr_num_polling_cpus; /* vale polling */
1535e874d26SVincenzo Maffione 	uint32_t sync_kloop_mode; /* sync-kloop */
1542a8682a8SVincenzo Maffione 	int fd; /* netmap file descriptor */
1552a8682a8SVincenzo Maffione 
1562a8682a8SVincenzo Maffione 	void *csb;                    /* CSB entries (atok and ktoa) */
1572a8682a8SVincenzo Maffione 	struct nmreq_option *nr_opt;  /* list of options */
1582a8682a8SVincenzo Maffione 	sem_t *sem;	/* for thread synchronization */
1592a8682a8SVincenzo Maffione };
1602a8682a8SVincenzo Maffione 
1612a8682a8SVincenzo Maffione static struct TestContext ctx_;
1622a8682a8SVincenzo Maffione 
1632a8682a8SVincenzo Maffione typedef int (*testfunc_t)(struct TestContext *ctx);
1642a8682a8SVincenzo Maffione 
1652a8682a8SVincenzo Maffione static void
nmreq_hdr_init(struct nmreq_header * hdr,const char * ifname)1662a8682a8SVincenzo Maffione nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
1672a8682a8SVincenzo Maffione {
1682a8682a8SVincenzo Maffione 	memset(hdr, 0, sizeof(*hdr));
1692a8682a8SVincenzo Maffione 	hdr->nr_version = NETMAP_API;
1702a8682a8SVincenzo Maffione 	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name) - 1);
1712a8682a8SVincenzo Maffione }
1722a8682a8SVincenzo Maffione 
1732a8682a8SVincenzo Maffione /* Single NETMAP_REQ_PORT_INFO_GET. */
1742a8682a8SVincenzo Maffione static int
port_info_get(struct TestContext * ctx)1752a8682a8SVincenzo Maffione port_info_get(struct TestContext *ctx)
1762a8682a8SVincenzo Maffione {
1772a8682a8SVincenzo Maffione 	struct nmreq_port_info_get req;
1782a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
1792a8682a8SVincenzo Maffione 	int success;
1802a8682a8SVincenzo Maffione 	int ret;
1812a8682a8SVincenzo Maffione 
18208f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname_ext);
1832a8682a8SVincenzo Maffione 
18408f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
1852a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
1862a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
1872a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
1882a8682a8SVincenzo Maffione 	req.nr_mem_id = ctx->nr_mem_id;
1892a8682a8SVincenzo Maffione 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
1902a8682a8SVincenzo Maffione 	if (ret != 0) {
1912a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
1922a8682a8SVincenzo Maffione 		return ret;
1932a8682a8SVincenzo Maffione 	}
1945854d718SVincenzo Maffione 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
1952a8682a8SVincenzo Maffione 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
1962a8682a8SVincenzo Maffione 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
1972a8682a8SVincenzo Maffione 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
1982a8682a8SVincenzo Maffione 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
1992a8682a8SVincenzo Maffione 	printf("nr_mem_id %u\n", req.nr_mem_id);
2002a8682a8SVincenzo Maffione 
2012a8682a8SVincenzo Maffione 	success = req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
2022a8682a8SVincenzo Maffione 	          req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings;
2032a8682a8SVincenzo Maffione 	if (!success) {
2042a8682a8SVincenzo Maffione 		return -1;
2052a8682a8SVincenzo Maffione 	}
2062a8682a8SVincenzo Maffione 
2072a8682a8SVincenzo Maffione 	/* Write back results to the context structure. */
2082a8682a8SVincenzo Maffione 	ctx->nr_tx_slots = req.nr_tx_slots;
2092a8682a8SVincenzo Maffione 	ctx->nr_rx_slots = req.nr_rx_slots;
2102a8682a8SVincenzo Maffione 	ctx->nr_tx_rings = req.nr_tx_rings;
2112a8682a8SVincenzo Maffione 	ctx->nr_rx_rings = req.nr_rx_rings;
2122a8682a8SVincenzo Maffione 	ctx->nr_mem_id   = req.nr_mem_id;
2132a8682a8SVincenzo Maffione 
2142a8682a8SVincenzo Maffione 	return 0;
2152a8682a8SVincenzo Maffione }
2162a8682a8SVincenzo Maffione 
2172a8682a8SVincenzo Maffione /* Single NETMAP_REQ_REGISTER, no use. */
2182a8682a8SVincenzo Maffione static int
port_register(struct TestContext * ctx)2192a8682a8SVincenzo Maffione port_register(struct TestContext *ctx)
2202a8682a8SVincenzo Maffione {
2212a8682a8SVincenzo Maffione 	struct nmreq_register req;
2222a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
2232a8682a8SVincenzo Maffione 	int success;
2242a8682a8SVincenzo Maffione 	int ret;
2252a8682a8SVincenzo Maffione 
2262a8682a8SVincenzo Maffione 	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
2275854d718SVincenzo Maffione 	       "flags=0x%llx) on '%s'\n",
2285854d718SVincenzo Maffione 	       ctx->nr_mode, ctx->nr_ringid, (unsigned long long)ctx->nr_flags,
22908f34ad9SVincenzo Maffione 	       ctx->ifname_ext);
2302a8682a8SVincenzo Maffione 
23108f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
2322a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
2332a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
2342a8682a8SVincenzo Maffione 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
2352a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
2362a8682a8SVincenzo Maffione 	req.nr_mem_id     = ctx->nr_mem_id;
2372a8682a8SVincenzo Maffione 	req.nr_mode       = ctx->nr_mode;
2382a8682a8SVincenzo Maffione 	req.nr_ringid     = ctx->nr_ringid;
2392a8682a8SVincenzo Maffione 	req.nr_flags      = ctx->nr_flags;
2402a8682a8SVincenzo Maffione 	req.nr_tx_slots   = ctx->nr_tx_slots;
2412a8682a8SVincenzo Maffione 	req.nr_rx_slots   = ctx->nr_rx_slots;
2422a8682a8SVincenzo Maffione 	req.nr_tx_rings   = ctx->nr_tx_rings;
243*4f6858e8SVincenzo Maffione 	req.nr_host_tx_rings = ctx->nr_host_tx_rings;
244*4f6858e8SVincenzo Maffione 	req.nr_host_rx_rings = ctx->nr_host_rx_rings;
2452a8682a8SVincenzo Maffione 	req.nr_rx_rings   = ctx->nr_rx_rings;
2462a8682a8SVincenzo Maffione 	req.nr_extra_bufs = ctx->nr_extra_bufs;
2472a8682a8SVincenzo Maffione 	ret               = ioctl(ctx->fd, NIOCCTRL, &hdr);
2482a8682a8SVincenzo Maffione 	if (ret != 0) {
2492a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
2502a8682a8SVincenzo Maffione 		return ret;
2512a8682a8SVincenzo Maffione 	}
2525854d718SVincenzo Maffione 	printf("nr_offset 0x%llx\n", (unsigned long long)req.nr_offset);
2535854d718SVincenzo Maffione 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
2542a8682a8SVincenzo Maffione 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
2552a8682a8SVincenzo Maffione 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
2562a8682a8SVincenzo Maffione 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
2572a8682a8SVincenzo Maffione 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
258*4f6858e8SVincenzo Maffione 	printf("nr_host_tx_rings %u\n", req.nr_host_tx_rings);
259*4f6858e8SVincenzo Maffione 	printf("nr_host_rx_rings %u\n", req.nr_host_rx_rings);
2602a8682a8SVincenzo Maffione 	printf("nr_mem_id %u\n", req.nr_mem_id);
2612a8682a8SVincenzo Maffione 	printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
2622a8682a8SVincenzo Maffione 
2632a8682a8SVincenzo Maffione 	success = req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
2642a8682a8SVincenzo Maffione 		       (ctx->nr_ringid == req.nr_ringid) &&
2652a8682a8SVincenzo Maffione 		       (ctx->nr_flags == req.nr_flags) &&
2662a8682a8SVincenzo Maffione 		       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
2672a8682a8SVincenzo Maffione 			(ctx->nr_tx_slots == req.nr_tx_slots)) &&
2682a8682a8SVincenzo Maffione 		       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
2692a8682a8SVincenzo Maffione 			(ctx->nr_rx_slots == req.nr_rx_slots)) &&
2702a8682a8SVincenzo Maffione 		       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
2712a8682a8SVincenzo Maffione 			(ctx->nr_tx_rings == req.nr_tx_rings)) &&
2722a8682a8SVincenzo Maffione 		       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
2732a8682a8SVincenzo Maffione 			(ctx->nr_rx_rings == req.nr_rx_rings)) &&
274*4f6858e8SVincenzo Maffione 		       ((!ctx->nr_host_tx_rings && req.nr_host_tx_rings) ||
275*4f6858e8SVincenzo Maffione 			(ctx->nr_host_tx_rings == req.nr_host_tx_rings)) &&
276*4f6858e8SVincenzo Maffione 		       ((!ctx->nr_host_rx_rings && req.nr_host_rx_rings) ||
277*4f6858e8SVincenzo Maffione 			(ctx->nr_host_rx_rings == req.nr_host_rx_rings)) &&
2782a8682a8SVincenzo Maffione 		       ((!ctx->nr_mem_id && req.nr_mem_id) ||
2792a8682a8SVincenzo Maffione 			(ctx->nr_mem_id == req.nr_mem_id)) &&
2802a8682a8SVincenzo Maffione 		       (ctx->nr_extra_bufs == req.nr_extra_bufs);
2812a8682a8SVincenzo Maffione 	if (!success) {
2822a8682a8SVincenzo Maffione 		return -1;
2832a8682a8SVincenzo Maffione 	}
2842a8682a8SVincenzo Maffione 
2852a8682a8SVincenzo Maffione 	/* Write back results to the context structure.*/
2862a8682a8SVincenzo Maffione 	ctx->nr_tx_slots   = req.nr_tx_slots;
2872a8682a8SVincenzo Maffione 	ctx->nr_rx_slots   = req.nr_rx_slots;
2882a8682a8SVincenzo Maffione 	ctx->nr_tx_rings   = req.nr_tx_rings;
2892a8682a8SVincenzo Maffione 	ctx->nr_rx_rings   = req.nr_rx_rings;
290*4f6858e8SVincenzo Maffione 	ctx->nr_host_tx_rings = req.nr_host_tx_rings;
291*4f6858e8SVincenzo Maffione 	ctx->nr_host_rx_rings = req.nr_host_rx_rings;
2922a8682a8SVincenzo Maffione 	ctx->nr_mem_id     = req.nr_mem_id;
2932a8682a8SVincenzo Maffione 	ctx->nr_extra_bufs = req.nr_extra_bufs;
2942a8682a8SVincenzo Maffione 
2952a8682a8SVincenzo Maffione 	return 0;
2962a8682a8SVincenzo Maffione }
2972a8682a8SVincenzo Maffione 
2982a8682a8SVincenzo Maffione static int
niocregif(struct TestContext * ctx,int netmap_api)2992a8682a8SVincenzo Maffione niocregif(struct TestContext *ctx, int netmap_api)
3002a8682a8SVincenzo Maffione {
3012a8682a8SVincenzo Maffione 	struct nmreq req;
3022a8682a8SVincenzo Maffione 	int success;
3032a8682a8SVincenzo Maffione 	int ret;
3042a8682a8SVincenzo Maffione 
30508f34ad9SVincenzo Maffione 	printf("Testing legacy NIOCREGIF on '%s'\n", ctx->ifname_ext);
3062a8682a8SVincenzo Maffione 
3072a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
30808f34ad9SVincenzo Maffione 	memcpy(req.nr_name, ctx->ifname_ext, sizeof(req.nr_name));
3092a8682a8SVincenzo Maffione 	req.nr_name[sizeof(req.nr_name) - 1] = '\0';
3102a8682a8SVincenzo Maffione 	req.nr_version = netmap_api;
3112a8682a8SVincenzo Maffione 	req.nr_ringid     = ctx->nr_ringid;
3122a8682a8SVincenzo Maffione 	req.nr_flags      = ctx->nr_mode | ctx->nr_flags;
3132a8682a8SVincenzo Maffione 	req.nr_tx_slots   = ctx->nr_tx_slots;
3142a8682a8SVincenzo Maffione 	req.nr_rx_slots   = ctx->nr_rx_slots;
3152a8682a8SVincenzo Maffione 	req.nr_tx_rings   = ctx->nr_tx_rings;
3162a8682a8SVincenzo Maffione 	req.nr_rx_rings   = ctx->nr_rx_rings;
3172a8682a8SVincenzo Maffione 	req.nr_arg2     = ctx->nr_mem_id;
3182a8682a8SVincenzo Maffione 	req.nr_arg3 = ctx->nr_extra_bufs;
3192a8682a8SVincenzo Maffione 
3202a8682a8SVincenzo Maffione 	ret = ioctl(ctx->fd, NIOCREGIF, &req);
3212a8682a8SVincenzo Maffione 	if (ret != 0) {
3222a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCREGIF)");
3232a8682a8SVincenzo Maffione 		return ret;
3242a8682a8SVincenzo Maffione 	}
3252a8682a8SVincenzo Maffione 
3262a8682a8SVincenzo Maffione 	printf("nr_offset 0x%x\n", req.nr_offset);
3272a8682a8SVincenzo Maffione 	printf("nr_memsize  %u\n", req.nr_memsize);
3282a8682a8SVincenzo Maffione 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
3292a8682a8SVincenzo Maffione 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
3302a8682a8SVincenzo Maffione 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
3312a8682a8SVincenzo Maffione 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
3322a8682a8SVincenzo Maffione 	printf("nr_version  %d\n", req.nr_version);
3332a8682a8SVincenzo Maffione 	printf("nr_ringid   %x\n", req.nr_ringid);
3342a8682a8SVincenzo Maffione 	printf("nr_flags    %x\n", req.nr_flags);
3352a8682a8SVincenzo Maffione 	printf("nr_arg2     %u\n", req.nr_arg2);
3362a8682a8SVincenzo Maffione 	printf("nr_arg3     %u\n", req.nr_arg3);
3372a8682a8SVincenzo Maffione 
3382a8682a8SVincenzo Maffione 	success = req.nr_memsize &&
3392a8682a8SVincenzo Maffione 	       (ctx->nr_ringid == req.nr_ringid) &&
3402a8682a8SVincenzo Maffione 	       ((ctx->nr_mode | ctx->nr_flags) == req.nr_flags) &&
3412a8682a8SVincenzo Maffione 	       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
3422a8682a8SVincenzo Maffione 		(ctx->nr_tx_slots == req.nr_tx_slots)) &&
3432a8682a8SVincenzo Maffione 	       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
3442a8682a8SVincenzo Maffione 		(ctx->nr_rx_slots == req.nr_rx_slots)) &&
3452a8682a8SVincenzo Maffione 	       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
3462a8682a8SVincenzo Maffione 		(ctx->nr_tx_rings == req.nr_tx_rings)) &&
3472a8682a8SVincenzo Maffione 	       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
3482a8682a8SVincenzo Maffione 		(ctx->nr_rx_rings == req.nr_rx_rings)) &&
3492a8682a8SVincenzo Maffione 	       ((!ctx->nr_mem_id && req.nr_arg2) ||
3502a8682a8SVincenzo Maffione 		(ctx->nr_mem_id == req.nr_arg2)) &&
3512a8682a8SVincenzo Maffione 	       (ctx->nr_extra_bufs == req.nr_arg3);
3522a8682a8SVincenzo Maffione 	if (!success) {
3532a8682a8SVincenzo Maffione 		return -1;
3542a8682a8SVincenzo Maffione 	}
3552a8682a8SVincenzo Maffione 
3562a8682a8SVincenzo Maffione 	/* Write back results to the context structure.*/
3572a8682a8SVincenzo Maffione 	ctx->nr_tx_slots   = req.nr_tx_slots;
3582a8682a8SVincenzo Maffione 	ctx->nr_rx_slots   = req.nr_rx_slots;
3592a8682a8SVincenzo Maffione 	ctx->nr_tx_rings   = req.nr_tx_rings;
3602a8682a8SVincenzo Maffione 	ctx->nr_rx_rings   = req.nr_rx_rings;
3612a8682a8SVincenzo Maffione 	ctx->nr_mem_id     = req.nr_arg2;
3622a8682a8SVincenzo Maffione 	ctx->nr_extra_bufs = req.nr_arg3;
3632a8682a8SVincenzo Maffione 
3642a8682a8SVincenzo Maffione 	return ret;
3652a8682a8SVincenzo Maffione }
3662a8682a8SVincenzo Maffione 
3672a8682a8SVincenzo Maffione /* The 11 ABI is the one right before the introduction of the new NIOCCTRL
3682a8682a8SVincenzo Maffione  * ABI. The 11 ABI is useful to perform tests with legacy applications
3695e874d26SVincenzo Maffione  * (which use the 11 ABI) and new kernel (which uses 12, or higher).
3705e874d26SVincenzo Maffione  * However, version 14 introduced a change in the layout of struct netmap_if,
3715e874d26SVincenzo Maffione  * so that binary backward compatibility to 11 is not supported anymore.
3725e874d26SVincenzo Maffione  */
3735e874d26SVincenzo Maffione #define NETMAP_API_NIOCREGIF	14
3742a8682a8SVincenzo Maffione 
3752a8682a8SVincenzo Maffione static int
legacy_regif_default(struct TestContext * ctx)3762a8682a8SVincenzo Maffione legacy_regif_default(struct TestContext *ctx)
3772a8682a8SVincenzo Maffione {
3782a8682a8SVincenzo Maffione 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
3792a8682a8SVincenzo Maffione }
3802a8682a8SVincenzo Maffione 
3812a8682a8SVincenzo Maffione static int
legacy_regif_all_nic(struct TestContext * ctx)3822a8682a8SVincenzo Maffione legacy_regif_all_nic(struct TestContext *ctx)
3832a8682a8SVincenzo Maffione {
3842a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
3852a8682a8SVincenzo Maffione 	return niocregif(ctx, NETMAP_API);
3862a8682a8SVincenzo Maffione }
3872a8682a8SVincenzo Maffione 
3882a8682a8SVincenzo Maffione static int
legacy_regif_12(struct TestContext * ctx)3892a8682a8SVincenzo Maffione legacy_regif_12(struct TestContext *ctx)
3902a8682a8SVincenzo Maffione {
3912a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
3922a8682a8SVincenzo Maffione 	return niocregif(ctx, NETMAP_API_NIOCREGIF+1);
3932a8682a8SVincenzo Maffione }
3942a8682a8SVincenzo Maffione 
3952a8682a8SVincenzo Maffione static int
legacy_regif_sw(struct TestContext * ctx)3962a8682a8SVincenzo Maffione legacy_regif_sw(struct TestContext *ctx)
3972a8682a8SVincenzo Maffione {
3982a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_SW;
3992a8682a8SVincenzo Maffione 	return niocregif(ctx,  NETMAP_API_NIOCREGIF);
4002a8682a8SVincenzo Maffione }
4012a8682a8SVincenzo Maffione 
4022a8682a8SVincenzo Maffione static int
legacy_regif_future(struct TestContext * ctx)4032a8682a8SVincenzo Maffione legacy_regif_future(struct TestContext *ctx)
4042a8682a8SVincenzo Maffione {
4052a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_NIC_SW;
4062a8682a8SVincenzo Maffione 	/* Test forward compatibility for the legacy ABI. This means
4072a8682a8SVincenzo Maffione 	 * using an older kernel (with ABI 12 or higher) and a newer
4082a8682a8SVincenzo Maffione 	 * application (with ABI greater than NETMAP_API). */
4092a8682a8SVincenzo Maffione 	return niocregif(ctx, NETMAP_API+2);
4102a8682a8SVincenzo Maffione }
4112a8682a8SVincenzo Maffione 
4122a8682a8SVincenzo Maffione static int
legacy_regif_extra_bufs(struct TestContext * ctx)4132a8682a8SVincenzo Maffione legacy_regif_extra_bufs(struct TestContext *ctx)
4142a8682a8SVincenzo Maffione {
4152a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
4162a8682a8SVincenzo Maffione 	ctx->nr_extra_bufs = 20;	/* arbitrary number of extra bufs */
4172a8682a8SVincenzo Maffione 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
4182a8682a8SVincenzo Maffione }
4192a8682a8SVincenzo Maffione 
4202a8682a8SVincenzo Maffione static int
legacy_regif_extra_bufs_pipe(struct TestContext * ctx)4212a8682a8SVincenzo Maffione legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
4222a8682a8SVincenzo Maffione {
42308f34ad9SVincenzo Maffione 	strncat(ctx->ifname_ext, "{pipeexbuf", sizeof(ctx->ifname_ext));
4242a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
4252a8682a8SVincenzo Maffione 	ctx->nr_extra_bufs = 58;	/* arbitrary number of extra bufs */
4262a8682a8SVincenzo Maffione 
4272a8682a8SVincenzo Maffione 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
4282a8682a8SVincenzo Maffione }
4292a8682a8SVincenzo Maffione 
4302a8682a8SVincenzo Maffione static int
legacy_regif_extra_bufs_pipe_vale(struct TestContext * ctx)4312a8682a8SVincenzo Maffione legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
4322a8682a8SVincenzo Maffione {
43308f34ad9SVincenzo Maffione 	strncpy(ctx->ifname_ext, "valeX1:Y4", sizeof(ctx->ifname_ext));
4342a8682a8SVincenzo Maffione 	return legacy_regif_extra_bufs_pipe(ctx);
4352a8682a8SVincenzo Maffione }
4362a8682a8SVincenzo Maffione 
4372a8682a8SVincenzo Maffione /* Only valid after a successful port_register(). */
4382a8682a8SVincenzo Maffione static int
num_registered_rings(struct TestContext * ctx)4392a8682a8SVincenzo Maffione num_registered_rings(struct TestContext *ctx)
4402a8682a8SVincenzo Maffione {
4412a8682a8SVincenzo Maffione 	if (ctx->nr_flags & NR_TX_RINGS_ONLY) {
4422a8682a8SVincenzo Maffione 		return ctx->nr_tx_rings;
4432a8682a8SVincenzo Maffione 	}
4442a8682a8SVincenzo Maffione 	if (ctx->nr_flags & NR_RX_RINGS_ONLY) {
4452a8682a8SVincenzo Maffione 		return ctx->nr_rx_rings;
4462a8682a8SVincenzo Maffione 	}
4472a8682a8SVincenzo Maffione 
4482a8682a8SVincenzo Maffione 	return ctx->nr_tx_rings + ctx->nr_rx_rings;
4492a8682a8SVincenzo Maffione }
4502a8682a8SVincenzo Maffione 
4512a8682a8SVincenzo Maffione static int
port_register_hwall_host(struct TestContext * ctx)4522a8682a8SVincenzo Maffione port_register_hwall_host(struct TestContext *ctx)
4532a8682a8SVincenzo Maffione {
4542a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_NIC_SW;
4552a8682a8SVincenzo Maffione 	return port_register(ctx);
4562a8682a8SVincenzo Maffione }
4572a8682a8SVincenzo Maffione 
4582a8682a8SVincenzo Maffione static int
port_register_hostall(struct TestContext * ctx)459*4f6858e8SVincenzo Maffione port_register_hostall(struct TestContext *ctx)
4602a8682a8SVincenzo Maffione {
4612a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_SW;
4622a8682a8SVincenzo Maffione 	return port_register(ctx);
4632a8682a8SVincenzo Maffione }
4642a8682a8SVincenzo Maffione 
4652a8682a8SVincenzo Maffione static int
port_register_hwall(struct TestContext * ctx)4662a8682a8SVincenzo Maffione port_register_hwall(struct TestContext *ctx)
4672a8682a8SVincenzo Maffione {
4682a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
4692a8682a8SVincenzo Maffione 	return port_register(ctx);
4702a8682a8SVincenzo Maffione }
4712a8682a8SVincenzo Maffione 
4722a8682a8SVincenzo Maffione static int
port_register_single_hw_pair(struct TestContext * ctx)473*4f6858e8SVincenzo Maffione port_register_single_hw_pair(struct TestContext *ctx)
4742a8682a8SVincenzo Maffione {
4752a8682a8SVincenzo Maffione 	ctx->nr_mode   = NR_REG_ONE_NIC;
4762a8682a8SVincenzo Maffione 	ctx->nr_ringid = 0;
4772a8682a8SVincenzo Maffione 	return port_register(ctx);
4782a8682a8SVincenzo Maffione }
4792a8682a8SVincenzo Maffione 
4802a8682a8SVincenzo Maffione static int
port_register_single_host_pair(struct TestContext * ctx)481*4f6858e8SVincenzo Maffione port_register_single_host_pair(struct TestContext *ctx)
482*4f6858e8SVincenzo Maffione {
483*4f6858e8SVincenzo Maffione 	ctx->nr_mode   = NR_REG_ONE_SW;
484*4f6858e8SVincenzo Maffione 	ctx->nr_host_tx_rings = 2;
485*4f6858e8SVincenzo Maffione 	ctx->nr_host_rx_rings = 2;
486*4f6858e8SVincenzo Maffione 	ctx->nr_ringid = 1;
487*4f6858e8SVincenzo Maffione 	return port_register(ctx);
488*4f6858e8SVincenzo Maffione }
489*4f6858e8SVincenzo Maffione 
490*4f6858e8SVincenzo Maffione static int
port_register_hostall_many(struct TestContext * ctx)491*4f6858e8SVincenzo Maffione port_register_hostall_many(struct TestContext *ctx)
492*4f6858e8SVincenzo Maffione {
493*4f6858e8SVincenzo Maffione 	ctx->nr_mode   = NR_REG_SW;
494*4f6858e8SVincenzo Maffione 	ctx->nr_host_tx_rings = 5;
495*4f6858e8SVincenzo Maffione 	ctx->nr_host_rx_rings = 4;
496*4f6858e8SVincenzo Maffione 	return port_register(ctx);
497*4f6858e8SVincenzo Maffione }
498*4f6858e8SVincenzo Maffione 
499*4f6858e8SVincenzo Maffione static int
port_register_hwall_tx(struct TestContext * ctx)5002a8682a8SVincenzo Maffione port_register_hwall_tx(struct TestContext *ctx)
5012a8682a8SVincenzo Maffione {
5022a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
5032a8682a8SVincenzo Maffione 	ctx->nr_flags |= NR_TX_RINGS_ONLY;
5042a8682a8SVincenzo Maffione 	return port_register(ctx);
5052a8682a8SVincenzo Maffione }
5062a8682a8SVincenzo Maffione 
5072a8682a8SVincenzo Maffione static int
port_register_hwall_rx(struct TestContext * ctx)5082a8682a8SVincenzo Maffione port_register_hwall_rx(struct TestContext *ctx)
5092a8682a8SVincenzo Maffione {
5102a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
5112a8682a8SVincenzo Maffione 	ctx->nr_flags |= NR_RX_RINGS_ONLY;
5122a8682a8SVincenzo Maffione 	return port_register(ctx);
5132a8682a8SVincenzo Maffione }
5142a8682a8SVincenzo Maffione 
5152a8682a8SVincenzo Maffione /* NETMAP_REQ_VALE_ATTACH */
5162a8682a8SVincenzo Maffione static int
vale_attach(struct TestContext * ctx)5172a8682a8SVincenzo Maffione vale_attach(struct TestContext *ctx)
5182a8682a8SVincenzo Maffione {
5192a8682a8SVincenzo Maffione 	struct nmreq_vale_attach req;
5202a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
52108f34ad9SVincenzo Maffione 	char vpname[sizeof(ctx->bdgname) + 1 + sizeof(ctx->ifname_ext)];
5222a8682a8SVincenzo Maffione 	int ret;
5232a8682a8SVincenzo Maffione 
52408f34ad9SVincenzo Maffione 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
5252a8682a8SVincenzo Maffione 
5262a8682a8SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
5272a8682a8SVincenzo Maffione 	nmreq_hdr_init(&hdr, vpname);
5282a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
5292a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
5302a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
5312a8682a8SVincenzo Maffione 	req.reg.nr_mem_id = ctx->nr_mem_id;
5322a8682a8SVincenzo Maffione 	if (ctx->nr_mode == 0) {
5332a8682a8SVincenzo Maffione 		ctx->nr_mode = NR_REG_ALL_NIC; /* default */
5342a8682a8SVincenzo Maffione 	}
5352a8682a8SVincenzo Maffione 	req.reg.nr_mode = ctx->nr_mode;
5362a8682a8SVincenzo Maffione 	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
5372a8682a8SVincenzo Maffione 	if (ret != 0) {
5382a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
5392a8682a8SVincenzo Maffione 		return ret;
5402a8682a8SVincenzo Maffione 	}
5412a8682a8SVincenzo Maffione 	printf("nr_mem_id %u\n", req.reg.nr_mem_id);
5422a8682a8SVincenzo Maffione 
5432a8682a8SVincenzo Maffione 	return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
5442a8682a8SVincenzo Maffione 	        (ctx->nr_mem_id == req.reg.nr_mem_id)) &&
5452a8682a8SVincenzo Maffione 	                       (ctx->nr_flags == req.reg.nr_flags)
5462a8682a8SVincenzo Maffione 	               ? 0
5472a8682a8SVincenzo Maffione 	               : -1;
5482a8682a8SVincenzo Maffione }
5492a8682a8SVincenzo Maffione 
5502a8682a8SVincenzo Maffione /* NETMAP_REQ_VALE_DETACH */
5512a8682a8SVincenzo Maffione static int
vale_detach(struct TestContext * ctx)5522a8682a8SVincenzo Maffione vale_detach(struct TestContext *ctx)
5532a8682a8SVincenzo Maffione {
5542a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
5552a8682a8SVincenzo Maffione 	struct nmreq_vale_detach req;
5562a8682a8SVincenzo Maffione 	char vpname[256];
5572a8682a8SVincenzo Maffione 	int ret;
5582a8682a8SVincenzo Maffione 
55908f34ad9SVincenzo Maffione 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
5602a8682a8SVincenzo Maffione 
5612a8682a8SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
5622a8682a8SVincenzo Maffione 	nmreq_hdr_init(&hdr, vpname);
5632a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
5642a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
5652a8682a8SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
5662a8682a8SVincenzo Maffione 	if (ret != 0) {
5672a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
5682a8682a8SVincenzo Maffione 		return ret;
5692a8682a8SVincenzo Maffione 	}
5702a8682a8SVincenzo Maffione 
5712a8682a8SVincenzo Maffione 	return 0;
5722a8682a8SVincenzo Maffione }
5732a8682a8SVincenzo Maffione 
5742a8682a8SVincenzo Maffione /* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
5752a8682a8SVincenzo Maffione static int
vale_attach_detach(struct TestContext * ctx)5762a8682a8SVincenzo Maffione vale_attach_detach(struct TestContext *ctx)
5772a8682a8SVincenzo Maffione {
5782a8682a8SVincenzo Maffione 	int ret;
5792a8682a8SVincenzo Maffione 
5802a8682a8SVincenzo Maffione 	if ((ret = vale_attach(ctx)) != 0) {
5812a8682a8SVincenzo Maffione 		return ret;
5822a8682a8SVincenzo Maffione 	}
5832a8682a8SVincenzo Maffione 
5842a8682a8SVincenzo Maffione 	return vale_detach(ctx);
5852a8682a8SVincenzo Maffione }
5862a8682a8SVincenzo Maffione 
5872a8682a8SVincenzo Maffione static int
vale_attach_detach_host_rings(struct TestContext * ctx)5882a8682a8SVincenzo Maffione vale_attach_detach_host_rings(struct TestContext *ctx)
5892a8682a8SVincenzo Maffione {
5902a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_NIC_SW;
5912a8682a8SVincenzo Maffione 	return vale_attach_detach(ctx);
5922a8682a8SVincenzo Maffione }
5932a8682a8SVincenzo Maffione 
5942a8682a8SVincenzo Maffione /* First NETMAP_REQ_PORT_HDR_SET and the NETMAP_REQ_PORT_HDR_GET
5952a8682a8SVincenzo Maffione  * to check that we get the same value. */
5962a8682a8SVincenzo Maffione static int
port_hdr_set_and_get(struct TestContext * ctx)5972a8682a8SVincenzo Maffione port_hdr_set_and_get(struct TestContext *ctx)
5982a8682a8SVincenzo Maffione {
5992a8682a8SVincenzo Maffione 	struct nmreq_port_hdr req;
6002a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
6012a8682a8SVincenzo Maffione 	int ret;
6022a8682a8SVincenzo Maffione 
60308f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname_ext);
6042a8682a8SVincenzo Maffione 
60508f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
6062a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
6072a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
6082a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
6092a8682a8SVincenzo Maffione 	req.nr_hdr_len = ctx->nr_hdr_len;
6102a8682a8SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
6112a8682a8SVincenzo Maffione 	if (ret != 0) {
6122a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
6132a8682a8SVincenzo Maffione 		return ret;
6142a8682a8SVincenzo Maffione 	}
6152a8682a8SVincenzo Maffione 
6162a8682a8SVincenzo Maffione 	if (req.nr_hdr_len != ctx->nr_hdr_len) {
6172a8682a8SVincenzo Maffione 		return -1;
6182a8682a8SVincenzo Maffione 	}
6192a8682a8SVincenzo Maffione 
62008f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname_ext);
6212a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
6222a8682a8SVincenzo Maffione 	req.nr_hdr_len = 0;
6232a8682a8SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
6242a8682a8SVincenzo Maffione 	if (ret != 0) {
6252a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
6262a8682a8SVincenzo Maffione 		return ret;
6272a8682a8SVincenzo Maffione 	}
6282a8682a8SVincenzo Maffione 	printf("nr_hdr_len %u\n", req.nr_hdr_len);
6292a8682a8SVincenzo Maffione 
6302a8682a8SVincenzo Maffione 	return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
6312a8682a8SVincenzo Maffione }
6322a8682a8SVincenzo Maffione 
6332a8682a8SVincenzo Maffione /*
6342a8682a8SVincenzo Maffione  * Possible lengths for the VirtIO network header, as specified by
6352a8682a8SVincenzo Maffione  * the standard:
6362a8682a8SVincenzo Maffione  *    http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html
6372a8682a8SVincenzo Maffione  */
6382a8682a8SVincenzo Maffione #define VIRTIO_NET_HDR_LEN				10
6392a8682a8SVincenzo Maffione #define VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS	12
6402a8682a8SVincenzo Maffione 
6412a8682a8SVincenzo Maffione static int
vale_ephemeral_port_hdr_manipulation(struct TestContext * ctx)6422a8682a8SVincenzo Maffione vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
6432a8682a8SVincenzo Maffione {
6442a8682a8SVincenzo Maffione 	int ret;
6452a8682a8SVincenzo Maffione 
64608f34ad9SVincenzo Maffione 	strncpy(ctx->ifname_ext, "vale:eph0", sizeof(ctx->ifname_ext));
6472a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
6482a8682a8SVincenzo Maffione 	if ((ret = port_register(ctx))) {
6492a8682a8SVincenzo Maffione 		return ret;
6502a8682a8SVincenzo Maffione 	}
6512a8682a8SVincenzo Maffione 	/* Try to set and get all the acceptable values. */
6522a8682a8SVincenzo Maffione 	ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS;
6532a8682a8SVincenzo Maffione 	if ((ret = port_hdr_set_and_get(ctx))) {
6542a8682a8SVincenzo Maffione 		return ret;
6552a8682a8SVincenzo Maffione 	}
6562a8682a8SVincenzo Maffione 	ctx->nr_hdr_len = 0;
6572a8682a8SVincenzo Maffione 	if ((ret = port_hdr_set_and_get(ctx))) {
6582a8682a8SVincenzo Maffione 		return ret;
6592a8682a8SVincenzo Maffione 	}
6602a8682a8SVincenzo Maffione 	ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN;
6612a8682a8SVincenzo Maffione 	if ((ret = port_hdr_set_and_get(ctx))) {
6622a8682a8SVincenzo Maffione 		return ret;
6632a8682a8SVincenzo Maffione 	}
6642a8682a8SVincenzo Maffione 	return 0;
6652a8682a8SVincenzo Maffione }
6662a8682a8SVincenzo Maffione 
6672a8682a8SVincenzo Maffione static int
vale_persistent_port(struct TestContext * ctx)6682a8682a8SVincenzo Maffione vale_persistent_port(struct TestContext *ctx)
6692a8682a8SVincenzo Maffione {
6702a8682a8SVincenzo Maffione 	struct nmreq_vale_newif req;
6712a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
6722a8682a8SVincenzo Maffione 	int result;
6732a8682a8SVincenzo Maffione 	int ret;
6742a8682a8SVincenzo Maffione 
67508f34ad9SVincenzo Maffione 	strncpy(ctx->ifname_ext, "per4", sizeof(ctx->ifname_ext));
6762a8682a8SVincenzo Maffione 
67708f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname_ext);
6782a8682a8SVincenzo Maffione 
67908f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
6802a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
6812a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
6822a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
6832a8682a8SVincenzo Maffione 	req.nr_mem_id   = ctx->nr_mem_id;
6842a8682a8SVincenzo Maffione 	req.nr_tx_slots = ctx->nr_tx_slots;
6852a8682a8SVincenzo Maffione 	req.nr_rx_slots = ctx->nr_rx_slots;
6862a8682a8SVincenzo Maffione 	req.nr_tx_rings = ctx->nr_tx_rings;
6872a8682a8SVincenzo Maffione 	req.nr_rx_rings = ctx->nr_rx_rings;
6882a8682a8SVincenzo Maffione 	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
6892a8682a8SVincenzo Maffione 	if (ret != 0) {
6902a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
6912a8682a8SVincenzo Maffione 		return ret;
6922a8682a8SVincenzo Maffione 	}
6932a8682a8SVincenzo Maffione 
6942a8682a8SVincenzo Maffione 	/* Attach the persistent VALE port to a switch and then detach. */
6952a8682a8SVincenzo Maffione 	result = vale_attach_detach(ctx);
6962a8682a8SVincenzo Maffione 
69708f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname_ext);
6982a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
6992a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)NULL;
7002a8682a8SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
7012a8682a8SVincenzo Maffione 	if (ret != 0) {
7022a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
7032a8682a8SVincenzo Maffione 		if (result == 0) {
7042a8682a8SVincenzo Maffione 			result = ret;
7052a8682a8SVincenzo Maffione 		}
7062a8682a8SVincenzo Maffione 	}
7072a8682a8SVincenzo Maffione 
7082a8682a8SVincenzo Maffione 	return result;
7092a8682a8SVincenzo Maffione }
7102a8682a8SVincenzo Maffione 
7112a8682a8SVincenzo Maffione /* Single NETMAP_REQ_POOLS_INFO_GET. */
7122a8682a8SVincenzo Maffione static int
pools_info_get(struct TestContext * ctx)7132a8682a8SVincenzo Maffione pools_info_get(struct TestContext *ctx)
7142a8682a8SVincenzo Maffione {
7152a8682a8SVincenzo Maffione 	struct nmreq_pools_info req;
7162a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
7172a8682a8SVincenzo Maffione 	int ret;
7182a8682a8SVincenzo Maffione 
71908f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname_ext);
7202a8682a8SVincenzo Maffione 
72108f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
7222a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
7232a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
7242a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
7252a8682a8SVincenzo Maffione 	req.nr_mem_id = ctx->nr_mem_id;
7262a8682a8SVincenzo Maffione 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
7272a8682a8SVincenzo Maffione 	if (ret != 0) {
7282a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
7292a8682a8SVincenzo Maffione 		return ret;
7302a8682a8SVincenzo Maffione 	}
7315854d718SVincenzo Maffione 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
7322a8682a8SVincenzo Maffione 	printf("nr_mem_id %u\n", req.nr_mem_id);
7335854d718SVincenzo Maffione 	printf("nr_if_pool_offset 0x%llx\n",
7345854d718SVincenzo Maffione 		(unsigned long long)req.nr_if_pool_offset);
7352a8682a8SVincenzo Maffione 	printf("nr_if_pool_objtotal %u\n", req.nr_if_pool_objtotal);
7362a8682a8SVincenzo Maffione 	printf("nr_if_pool_objsize %u\n", req.nr_if_pool_objsize);
7375854d718SVincenzo Maffione 	printf("nr_ring_pool_offset 0x%llx\n",
7385854d718SVincenzo Maffione 		(unsigned long long)req.nr_if_pool_offset);
7392a8682a8SVincenzo Maffione 	printf("nr_ring_pool_objtotal %u\n", req.nr_ring_pool_objtotal);
7402a8682a8SVincenzo Maffione 	printf("nr_ring_pool_objsize %u\n", req.nr_ring_pool_objsize);
7415854d718SVincenzo Maffione 	printf("nr_buf_pool_offset 0x%llx\n",
7425854d718SVincenzo Maffione 		(unsigned long long)req.nr_buf_pool_offset);
7432a8682a8SVincenzo Maffione 	printf("nr_buf_pool_objtotal %u\n", req.nr_buf_pool_objtotal);
7442a8682a8SVincenzo Maffione 	printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
7452a8682a8SVincenzo Maffione 
7462a8682a8SVincenzo Maffione 	return req.nr_memsize && req.nr_if_pool_objtotal &&
7472a8682a8SVincenzo Maffione 	                       req.nr_if_pool_objsize &&
7482a8682a8SVincenzo Maffione 	                       req.nr_ring_pool_objtotal &&
7492a8682a8SVincenzo Maffione 	                       req.nr_ring_pool_objsize &&
7502a8682a8SVincenzo Maffione 	                       req.nr_buf_pool_objtotal &&
7512a8682a8SVincenzo Maffione 	                       req.nr_buf_pool_objsize
7522a8682a8SVincenzo Maffione 	               ? 0
7532a8682a8SVincenzo Maffione 	               : -1;
7542a8682a8SVincenzo Maffione }
7552a8682a8SVincenzo Maffione 
7562a8682a8SVincenzo Maffione static int
pools_info_get_and_register(struct TestContext * ctx)7572a8682a8SVincenzo Maffione pools_info_get_and_register(struct TestContext *ctx)
7582a8682a8SVincenzo Maffione {
7592a8682a8SVincenzo Maffione 	int ret;
7602a8682a8SVincenzo Maffione 
7612a8682a8SVincenzo Maffione 	/* Check that we can get pools info before we register
7622a8682a8SVincenzo Maffione 	 * a netmap interface. */
7632a8682a8SVincenzo Maffione 	ret = pools_info_get(ctx);
7642a8682a8SVincenzo Maffione 	if (ret != 0) {
7652a8682a8SVincenzo Maffione 		return ret;
7662a8682a8SVincenzo Maffione 	}
7672a8682a8SVincenzo Maffione 
7682a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ONE_NIC;
7692a8682a8SVincenzo Maffione 	ret          = port_register(ctx);
7702a8682a8SVincenzo Maffione 	if (ret != 0) {
7712a8682a8SVincenzo Maffione 		return ret;
7722a8682a8SVincenzo Maffione 	}
7732a8682a8SVincenzo Maffione 	ctx->nr_mem_id = 1;
7742a8682a8SVincenzo Maffione 
7752a8682a8SVincenzo Maffione 	/* Check that we can get pools info also after we register. */
7762a8682a8SVincenzo Maffione 	return pools_info_get(ctx);
7772a8682a8SVincenzo Maffione }
7782a8682a8SVincenzo Maffione 
7792a8682a8SVincenzo Maffione static int
pools_info_get_empty_ifname(struct TestContext * ctx)7802a8682a8SVincenzo Maffione pools_info_get_empty_ifname(struct TestContext *ctx)
7812a8682a8SVincenzo Maffione {
78208f34ad9SVincenzo Maffione 	strncpy(ctx->ifname_ext, "", sizeof(ctx->ifname_ext));
7832a8682a8SVincenzo Maffione 	return pools_info_get(ctx) != 0 ? 0 : -1;
7842a8682a8SVincenzo Maffione }
7852a8682a8SVincenzo Maffione 
7862a8682a8SVincenzo Maffione static int
pipe_master(struct TestContext * ctx)7872a8682a8SVincenzo Maffione pipe_master(struct TestContext *ctx)
7882a8682a8SVincenzo Maffione {
78908f34ad9SVincenzo Maffione 	strncat(ctx->ifname_ext, "{pipeid1", sizeof(ctx->ifname_ext));
7902a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_NIC_SW;
7912a8682a8SVincenzo Maffione 
7922a8682a8SVincenzo Maffione 	if (port_register(ctx) == 0) {
7932a8682a8SVincenzo Maffione 		printf("pipes should not accept NR_REG_NIC_SW\n");
7942a8682a8SVincenzo Maffione 		return -1;
7952a8682a8SVincenzo Maffione 	}
7962a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
7972a8682a8SVincenzo Maffione 
7982a8682a8SVincenzo Maffione 	return port_register(ctx);
7992a8682a8SVincenzo Maffione }
8002a8682a8SVincenzo Maffione 
8012a8682a8SVincenzo Maffione static int
pipe_slave(struct TestContext * ctx)8022a8682a8SVincenzo Maffione pipe_slave(struct TestContext *ctx)
8032a8682a8SVincenzo Maffione {
80408f34ad9SVincenzo Maffione 	strncat(ctx->ifname_ext, "}pipeid2", sizeof(ctx->ifname_ext));
8052a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
8062a8682a8SVincenzo Maffione 
8072a8682a8SVincenzo Maffione 	return port_register(ctx);
8082a8682a8SVincenzo Maffione }
8092a8682a8SVincenzo Maffione 
8102a8682a8SVincenzo Maffione /* Test PORT_INFO_GET and POOLS_INFO_GET on a pipe. This is useful to test the
8112a8682a8SVincenzo Maffione  * registration request used internall by netmap. */
8122a8682a8SVincenzo Maffione static int
pipe_port_info_get(struct TestContext * ctx)8132a8682a8SVincenzo Maffione pipe_port_info_get(struct TestContext *ctx)
8142a8682a8SVincenzo Maffione {
81508f34ad9SVincenzo Maffione 	strncat(ctx->ifname_ext, "}pipeid3", sizeof(ctx->ifname_ext));
8162a8682a8SVincenzo Maffione 
8172a8682a8SVincenzo Maffione 	return port_info_get(ctx);
8182a8682a8SVincenzo Maffione }
8192a8682a8SVincenzo Maffione 
8202a8682a8SVincenzo Maffione static int
pipe_pools_info_get(struct TestContext * ctx)8212a8682a8SVincenzo Maffione pipe_pools_info_get(struct TestContext *ctx)
8222a8682a8SVincenzo Maffione {
82308f34ad9SVincenzo Maffione 	strncat(ctx->ifname_ext, "{xid", sizeof(ctx->ifname_ext));
8242a8682a8SVincenzo Maffione 
8252a8682a8SVincenzo Maffione 	return pools_info_get(ctx);
8262a8682a8SVincenzo Maffione }
8272a8682a8SVincenzo Maffione 
8282a8682a8SVincenzo Maffione /* NETMAP_REQ_VALE_POLLING_ENABLE */
8292a8682a8SVincenzo Maffione static int
vale_polling_enable(struct TestContext * ctx)8302a8682a8SVincenzo Maffione vale_polling_enable(struct TestContext *ctx)
8312a8682a8SVincenzo Maffione {
8322a8682a8SVincenzo Maffione 	struct nmreq_vale_polling req;
8332a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
8342a8682a8SVincenzo Maffione 	char vpname[256];
8352a8682a8SVincenzo Maffione 	int ret;
8362a8682a8SVincenzo Maffione 
83708f34ad9SVincenzo Maffione 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
8382a8682a8SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
8392a8682a8SVincenzo Maffione 
8402a8682a8SVincenzo Maffione 	nmreq_hdr_init(&hdr, vpname);
8412a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
8422a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
8432a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
8442a8682a8SVincenzo Maffione 	req.nr_mode             = ctx->nr_mode;
8452a8682a8SVincenzo Maffione 	req.nr_first_cpu_id     = ctx->nr_first_cpu_id;
8462a8682a8SVincenzo Maffione 	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
8472a8682a8SVincenzo Maffione 	ret                     = ioctl(ctx->fd, NIOCCTRL, &hdr);
8482a8682a8SVincenzo Maffione 	if (ret != 0) {
8492a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
8502a8682a8SVincenzo Maffione 		return ret;
8512a8682a8SVincenzo Maffione 	}
8522a8682a8SVincenzo Maffione 
8532a8682a8SVincenzo Maffione 	return (req.nr_mode == ctx->nr_mode &&
8542a8682a8SVincenzo Maffione 	        req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
8552a8682a8SVincenzo Maffione 	        req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
8562a8682a8SVincenzo Maffione 	               ? 0
8572a8682a8SVincenzo Maffione 	               : -1;
8582a8682a8SVincenzo Maffione }
8592a8682a8SVincenzo Maffione 
8602a8682a8SVincenzo Maffione /* NETMAP_REQ_VALE_POLLING_DISABLE */
8612a8682a8SVincenzo Maffione static int
vale_polling_disable(struct TestContext * ctx)8622a8682a8SVincenzo Maffione vale_polling_disable(struct TestContext *ctx)
8632a8682a8SVincenzo Maffione {
8642a8682a8SVincenzo Maffione 	struct nmreq_vale_polling req;
8652a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
8662a8682a8SVincenzo Maffione 	char vpname[256];
8672a8682a8SVincenzo Maffione 	int ret;
8682a8682a8SVincenzo Maffione 
86908f34ad9SVincenzo Maffione 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
8702a8682a8SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
8712a8682a8SVincenzo Maffione 
8722a8682a8SVincenzo Maffione 	nmreq_hdr_init(&hdr, vpname);
8732a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
8742a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
8752a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
8762a8682a8SVincenzo Maffione 	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
8772a8682a8SVincenzo Maffione 	if (ret != 0) {
8782a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
8792a8682a8SVincenzo Maffione 		return ret;
8802a8682a8SVincenzo Maffione 	}
8812a8682a8SVincenzo Maffione 
8822a8682a8SVincenzo Maffione 	return 0;
8832a8682a8SVincenzo Maffione }
8842a8682a8SVincenzo Maffione 
8852a8682a8SVincenzo Maffione static int
vale_polling_enable_disable(struct TestContext * ctx)8862a8682a8SVincenzo Maffione vale_polling_enable_disable(struct TestContext *ctx)
8872a8682a8SVincenzo Maffione {
8882a8682a8SVincenzo Maffione 	int ret = 0;
8892a8682a8SVincenzo Maffione 
8902a8682a8SVincenzo Maffione 	if ((ret = vale_attach(ctx)) != 0) {
8912a8682a8SVincenzo Maffione 		return ret;
8922a8682a8SVincenzo Maffione 	}
8932a8682a8SVincenzo Maffione 
8942a8682a8SVincenzo Maffione 	ctx->nr_mode             = NETMAP_POLLING_MODE_SINGLE_CPU;
8952a8682a8SVincenzo Maffione 	ctx->nr_num_polling_cpus = 1;
8962a8682a8SVincenzo Maffione 	ctx->nr_first_cpu_id     = 0;
8972a8682a8SVincenzo Maffione 	if ((ret = vale_polling_enable(ctx))) {
8982a8682a8SVincenzo Maffione 		vale_detach(ctx);
8992a8682a8SVincenzo Maffione #ifdef __FreeBSD__
9002a8682a8SVincenzo Maffione 		/* NETMAP_REQ_VALE_POLLING_DISABLE is disabled on FreeBSD,
9012a8682a8SVincenzo Maffione 		 * because it is currently broken. We are happy to see that
9022a8682a8SVincenzo Maffione 		 * it fails. */
9032a8682a8SVincenzo Maffione 		return 0;
90408f34ad9SVincenzo Maffione #else
9052a8682a8SVincenzo Maffione 		return ret;
90608f34ad9SVincenzo Maffione #endif
9072a8682a8SVincenzo Maffione 	}
9082a8682a8SVincenzo Maffione 
9092a8682a8SVincenzo Maffione 	if ((ret = vale_polling_disable(ctx))) {
9102a8682a8SVincenzo Maffione 		vale_detach(ctx);
9112a8682a8SVincenzo Maffione 		return ret;
9122a8682a8SVincenzo Maffione 	}
9132a8682a8SVincenzo Maffione 
9142a8682a8SVincenzo Maffione 	return vale_detach(ctx);
9152a8682a8SVincenzo Maffione }
9162a8682a8SVincenzo Maffione 
9172a8682a8SVincenzo Maffione static void
push_option(struct nmreq_option * opt,struct TestContext * ctx)9182a8682a8SVincenzo Maffione push_option(struct nmreq_option *opt, struct TestContext *ctx)
9192a8682a8SVincenzo Maffione {
9202a8682a8SVincenzo Maffione 	opt->nro_next = (uintptr_t)ctx->nr_opt;
9212a8682a8SVincenzo Maffione 	ctx->nr_opt   = opt;
9222a8682a8SVincenzo Maffione }
9232a8682a8SVincenzo Maffione 
9242a8682a8SVincenzo Maffione static void
clear_options(struct TestContext * ctx)9252a8682a8SVincenzo Maffione clear_options(struct TestContext *ctx)
9262a8682a8SVincenzo Maffione {
9272a8682a8SVincenzo Maffione 	ctx->nr_opt = NULL;
9282a8682a8SVincenzo Maffione }
9292a8682a8SVincenzo Maffione 
9302a8682a8SVincenzo Maffione static int
checkoption(struct nmreq_option * opt,struct nmreq_option * exp)9312a8682a8SVincenzo Maffione checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
9322a8682a8SVincenzo Maffione {
9332a8682a8SVincenzo Maffione 	if (opt->nro_next != exp->nro_next) {
9342a8682a8SVincenzo Maffione 		printf("nro_next %p expected %p\n",
9352a8682a8SVincenzo Maffione 		       (void *)(uintptr_t)opt->nro_next,
9362a8682a8SVincenzo Maffione 		       (void *)(uintptr_t)exp->nro_next);
9372a8682a8SVincenzo Maffione 		return -1;
9382a8682a8SVincenzo Maffione 	}
9392a8682a8SVincenzo Maffione 	if (opt->nro_reqtype != exp->nro_reqtype) {
9402a8682a8SVincenzo Maffione 		printf("nro_reqtype %u expected %u\n", opt->nro_reqtype,
9412a8682a8SVincenzo Maffione 		       exp->nro_reqtype);
9422a8682a8SVincenzo Maffione 		return -1;
9432a8682a8SVincenzo Maffione 	}
9442a8682a8SVincenzo Maffione 	if (opt->nro_status != exp->nro_status) {
9452a8682a8SVincenzo Maffione 		printf("nro_status %u expected %u\n", opt->nro_status,
9462a8682a8SVincenzo Maffione 		       exp->nro_status);
9472a8682a8SVincenzo Maffione 		return -1;
9482a8682a8SVincenzo Maffione 	}
9492a8682a8SVincenzo Maffione 	return 0;
9502a8682a8SVincenzo Maffione }
9512a8682a8SVincenzo Maffione 
9522a8682a8SVincenzo Maffione static int
unsupported_option(struct TestContext * ctx)9532a8682a8SVincenzo Maffione unsupported_option(struct TestContext *ctx)
9542a8682a8SVincenzo Maffione {
9552a8682a8SVincenzo Maffione 	struct nmreq_option opt, save;
9562a8682a8SVincenzo Maffione 
95708f34ad9SVincenzo Maffione 	printf("Testing unsupported option on %s\n", ctx->ifname_ext);
9582a8682a8SVincenzo Maffione 
9592a8682a8SVincenzo Maffione 	memset(&opt, 0, sizeof(opt));
9602a8682a8SVincenzo Maffione 	opt.nro_reqtype = 1234;
9612a8682a8SVincenzo Maffione 	push_option(&opt, ctx);
9622a8682a8SVincenzo Maffione 	save = opt;
9632a8682a8SVincenzo Maffione 
9642a8682a8SVincenzo Maffione 	if (port_register_hwall(ctx) >= 0)
9652a8682a8SVincenzo Maffione 		return -1;
9662a8682a8SVincenzo Maffione 
9672a8682a8SVincenzo Maffione 	clear_options(ctx);
9682a8682a8SVincenzo Maffione 	save.nro_status = EOPNOTSUPP;
9692a8682a8SVincenzo Maffione 	return checkoption(&opt, &save);
9702a8682a8SVincenzo Maffione }
9712a8682a8SVincenzo Maffione 
9722a8682a8SVincenzo Maffione static int
infinite_options(struct TestContext * ctx)9732a8682a8SVincenzo Maffione infinite_options(struct TestContext *ctx)
9742a8682a8SVincenzo Maffione {
9752a8682a8SVincenzo Maffione 	struct nmreq_option opt;
9762a8682a8SVincenzo Maffione 
97708f34ad9SVincenzo Maffione 	printf("Testing infinite list of options on %s\n", ctx->ifname_ext);
9782a8682a8SVincenzo Maffione 
9792a8682a8SVincenzo Maffione 	opt.nro_reqtype = 1234;
9802a8682a8SVincenzo Maffione 	push_option(&opt, ctx);
9812a8682a8SVincenzo Maffione 	opt.nro_next = (uintptr_t)&opt;
9822a8682a8SVincenzo Maffione 	if (port_register_hwall(ctx) >= 0)
9832a8682a8SVincenzo Maffione 		return -1;
9842a8682a8SVincenzo Maffione 	clear_options(ctx);
9852a8682a8SVincenzo Maffione 	return (errno == EMSGSIZE ? 0 : -1);
9862a8682a8SVincenzo Maffione }
9872a8682a8SVincenzo Maffione 
9882a8682a8SVincenzo Maffione #ifdef CONFIG_NETMAP_EXTMEM
9892a8682a8SVincenzo Maffione int
change_param(const char * pname,unsigned long newv,unsigned long * poldv)9902a8682a8SVincenzo Maffione change_param(const char *pname, unsigned long newv, unsigned long *poldv)
9912a8682a8SVincenzo Maffione {
9922a8682a8SVincenzo Maffione #ifdef __linux__
9932a8682a8SVincenzo Maffione 	char param[256] = "/sys/module/netmap/parameters/";
9942a8682a8SVincenzo Maffione 	unsigned long oldv;
9952a8682a8SVincenzo Maffione 	FILE *f;
9962a8682a8SVincenzo Maffione 
9972a8682a8SVincenzo Maffione 	strncat(param, pname, sizeof(param) - 1);
9982a8682a8SVincenzo Maffione 
9992a8682a8SVincenzo Maffione 	f = fopen(param, "r+");
10002a8682a8SVincenzo Maffione 	if (f == NULL) {
10012a8682a8SVincenzo Maffione 		perror(param);
10022a8682a8SVincenzo Maffione 		return -1;
10032a8682a8SVincenzo Maffione 	}
10042a8682a8SVincenzo Maffione 	if (fscanf(f, "%ld", &oldv) != 1) {
10052a8682a8SVincenzo Maffione 		perror(param);
10062a8682a8SVincenzo Maffione 		fclose(f);
10072a8682a8SVincenzo Maffione 		return -1;
10082a8682a8SVincenzo Maffione 	}
10092a8682a8SVincenzo Maffione 	if (poldv)
10102a8682a8SVincenzo Maffione 		*poldv = oldv;
10112a8682a8SVincenzo Maffione 	rewind(f);
10122a8682a8SVincenzo Maffione 	if (fprintf(f, "%ld\n", newv) < 0) {
10132a8682a8SVincenzo Maffione 		perror(param);
10142a8682a8SVincenzo Maffione 		fclose(f);
10152a8682a8SVincenzo Maffione 		return -1;
10162a8682a8SVincenzo Maffione 	}
10172a8682a8SVincenzo Maffione 	fclose(f);
10182a8682a8SVincenzo Maffione 	printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
10192a8682a8SVincenzo Maffione #endif /* __linux__ */
10202a8682a8SVincenzo Maffione 	return 0;
10212a8682a8SVincenzo Maffione }
10222a8682a8SVincenzo Maffione 
10232a8682a8SVincenzo Maffione static int
push_extmem_option(struct TestContext * ctx,const struct nmreq_pools_info * pi,struct nmreq_opt_extmem * e)10242a8682a8SVincenzo Maffione push_extmem_option(struct TestContext *ctx, const struct nmreq_pools_info *pi,
10252a8682a8SVincenzo Maffione 		struct nmreq_opt_extmem *e)
10262a8682a8SVincenzo Maffione {
10272a8682a8SVincenzo Maffione 	void *addr;
10282a8682a8SVincenzo Maffione 
10292a8682a8SVincenzo Maffione 	addr = mmap(NULL, pi->nr_memsize, PROT_READ | PROT_WRITE,
10302a8682a8SVincenzo Maffione 	            MAP_ANONYMOUS | MAP_SHARED, -1, 0);
10312a8682a8SVincenzo Maffione 	if (addr == MAP_FAILED) {
10322a8682a8SVincenzo Maffione 		perror("mmap");
10332a8682a8SVincenzo Maffione 		return -1;
10342a8682a8SVincenzo Maffione 	}
10352a8682a8SVincenzo Maffione 
10362a8682a8SVincenzo Maffione 	memset(e, 0, sizeof(*e));
10372a8682a8SVincenzo Maffione 	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
10382a8682a8SVincenzo Maffione 	e->nro_info = *pi;
10392a8682a8SVincenzo Maffione 	e->nro_usrptr          = (uintptr_t)addr;
10402a8682a8SVincenzo Maffione 
10412a8682a8SVincenzo Maffione 	push_option(&e->nro_opt, ctx);
10422a8682a8SVincenzo Maffione 
10432a8682a8SVincenzo Maffione 	return 0;
10442a8682a8SVincenzo Maffione }
10452a8682a8SVincenzo Maffione 
10462a8682a8SVincenzo Maffione static int
pop_extmem_option(struct TestContext * ctx,struct nmreq_opt_extmem * exp)10472a8682a8SVincenzo Maffione pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
10482a8682a8SVincenzo Maffione {
10492a8682a8SVincenzo Maffione 	struct nmreq_opt_extmem *e;
10502a8682a8SVincenzo Maffione 	int ret;
10512a8682a8SVincenzo Maffione 
10522a8682a8SVincenzo Maffione 	e           = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
10532a8682a8SVincenzo Maffione 	ctx->nr_opt = (struct nmreq_option *)(uintptr_t)ctx->nr_opt->nro_next;
10542a8682a8SVincenzo Maffione 
10552a8682a8SVincenzo Maffione 	if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
10562a8682a8SVincenzo Maffione 		return ret;
10572a8682a8SVincenzo Maffione 	}
10582a8682a8SVincenzo Maffione 
10592a8682a8SVincenzo Maffione 	if (e->nro_usrptr != exp->nro_usrptr) {
10602a8682a8SVincenzo Maffione 		printf("usrptr %" PRIu64 " expected %" PRIu64 "\n",
10612a8682a8SVincenzo Maffione 		       e->nro_usrptr, exp->nro_usrptr);
10622a8682a8SVincenzo Maffione 		return -1;
10632a8682a8SVincenzo Maffione 	}
10642a8682a8SVincenzo Maffione 	if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
10652a8682a8SVincenzo Maffione 		printf("memsize %" PRIu64 " expected %" PRIu64 "\n",
10662a8682a8SVincenzo Maffione 		       e->nro_info.nr_memsize, exp->nro_info.nr_memsize);
10672a8682a8SVincenzo Maffione 		return -1;
10682a8682a8SVincenzo Maffione 	}
10692a8682a8SVincenzo Maffione 
10702a8682a8SVincenzo Maffione 	if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr,
10712a8682a8SVincenzo Maffione 	                  e->nro_info.nr_memsize)))
10722a8682a8SVincenzo Maffione 		return ret;
10732a8682a8SVincenzo Maffione 
10742a8682a8SVincenzo Maffione 	return 0;
10752a8682a8SVincenzo Maffione }
10762a8682a8SVincenzo Maffione 
10772a8682a8SVincenzo Maffione static int
_extmem_option(struct TestContext * ctx,const struct nmreq_pools_info * pi)10782a8682a8SVincenzo Maffione _extmem_option(struct TestContext *ctx,
10792a8682a8SVincenzo Maffione 		const struct nmreq_pools_info *pi)
10802a8682a8SVincenzo Maffione {
10812a8682a8SVincenzo Maffione 	struct nmreq_opt_extmem e, save;
10822a8682a8SVincenzo Maffione 	int ret;
10832a8682a8SVincenzo Maffione 
10842a8682a8SVincenzo Maffione 	if ((ret = push_extmem_option(ctx, pi, &e)) < 0)
10852a8682a8SVincenzo Maffione 		return ret;
10862a8682a8SVincenzo Maffione 
10872a8682a8SVincenzo Maffione 	save = e;
10882a8682a8SVincenzo Maffione 
108908f34ad9SVincenzo Maffione 	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
10902a8682a8SVincenzo Maffione 	ctx->nr_tx_slots = 16;
10912a8682a8SVincenzo Maffione 	ctx->nr_rx_slots = 16;
10922a8682a8SVincenzo Maffione 
10932a8682a8SVincenzo Maffione 	if ((ret = port_register_hwall(ctx)))
10942a8682a8SVincenzo Maffione 		return ret;
10952a8682a8SVincenzo Maffione 
10962a8682a8SVincenzo Maffione 	ret = pop_extmem_option(ctx, &save);
10972a8682a8SVincenzo Maffione 
10982a8682a8SVincenzo Maffione 	return ret;
10992a8682a8SVincenzo Maffione }
11002a8682a8SVincenzo Maffione 
11012a8682a8SVincenzo Maffione static size_t
pools_info_min_memsize(const struct nmreq_pools_info * pi)11022a8682a8SVincenzo Maffione pools_info_min_memsize(const struct nmreq_pools_info *pi)
11032a8682a8SVincenzo Maffione {
11042a8682a8SVincenzo Maffione 	size_t tot = 0;
11052a8682a8SVincenzo Maffione 
11062a8682a8SVincenzo Maffione 	tot += pi->nr_if_pool_objtotal * pi->nr_if_pool_objsize;
11072a8682a8SVincenzo Maffione 	tot += pi->nr_ring_pool_objtotal * pi->nr_ring_pool_objsize;
11082a8682a8SVincenzo Maffione 	tot += pi->nr_buf_pool_objtotal * pi->nr_buf_pool_objsize;
11092a8682a8SVincenzo Maffione 
11102a8682a8SVincenzo Maffione 	return tot;
11112a8682a8SVincenzo Maffione }
11122a8682a8SVincenzo Maffione 
11132a8682a8SVincenzo Maffione /*
11142a8682a8SVincenzo Maffione  * Fill the specification of a netmap memory allocator to be
11152a8682a8SVincenzo Maffione  * used with the 'struct nmreq_opt_extmem' option. Arbitrary
11162a8682a8SVincenzo Maffione  * values are used for the parameters, but with enough netmap
11172a8682a8SVincenzo Maffione  * rings, netmap ifs, and buffers to support a VALE port.
11182a8682a8SVincenzo Maffione  */
11192a8682a8SVincenzo Maffione static void
pools_info_fill(struct nmreq_pools_info * pi)11202a8682a8SVincenzo Maffione pools_info_fill(struct nmreq_pools_info *pi)
11212a8682a8SVincenzo Maffione {
11222a8682a8SVincenzo Maffione 	pi->nr_if_pool_objtotal = 2;
11232a8682a8SVincenzo Maffione 	pi->nr_if_pool_objsize = 1024;
11242a8682a8SVincenzo Maffione 	pi->nr_ring_pool_objtotal = 64;
11252a8682a8SVincenzo Maffione 	pi->nr_ring_pool_objsize = 512;
11262a8682a8SVincenzo Maffione 	pi->nr_buf_pool_objtotal = 4096;
11272a8682a8SVincenzo Maffione 	pi->nr_buf_pool_objsize = 2048;
11282a8682a8SVincenzo Maffione 	pi->nr_memsize = pools_info_min_memsize(pi);
11292a8682a8SVincenzo Maffione }
11302a8682a8SVincenzo Maffione 
11312a8682a8SVincenzo Maffione static int
extmem_option(struct TestContext * ctx)11322a8682a8SVincenzo Maffione extmem_option(struct TestContext *ctx)
11332a8682a8SVincenzo Maffione {
11342a8682a8SVincenzo Maffione 	struct nmreq_pools_info	pools_info;
11352a8682a8SVincenzo Maffione 
11362a8682a8SVincenzo Maffione 	pools_info_fill(&pools_info);
11372a8682a8SVincenzo Maffione 
11382a8682a8SVincenzo Maffione 	printf("Testing extmem option on vale0:0\n");
11392a8682a8SVincenzo Maffione 	return _extmem_option(ctx, &pools_info);
11402a8682a8SVincenzo Maffione }
11412a8682a8SVincenzo Maffione 
11422a8682a8SVincenzo Maffione static int
bad_extmem_option(struct TestContext * ctx)11432a8682a8SVincenzo Maffione bad_extmem_option(struct TestContext *ctx)
11442a8682a8SVincenzo Maffione {
11452a8682a8SVincenzo Maffione 	struct nmreq_pools_info	pools_info;
11462a8682a8SVincenzo Maffione 
11472a8682a8SVincenzo Maffione 	printf("Testing bad extmem option on vale0:0\n");
11482a8682a8SVincenzo Maffione 
11492a8682a8SVincenzo Maffione 	pools_info_fill(&pools_info);
11502a8682a8SVincenzo Maffione 	/* Request a large ring size, to make sure that the kernel
11512a8682a8SVincenzo Maffione 	 * rejects our request. */
11525e874d26SVincenzo Maffione 	pools_info.nr_ring_pool_objsize = (1 << 20);
11532a8682a8SVincenzo Maffione 
11542a8682a8SVincenzo Maffione 	return _extmem_option(ctx, &pools_info) < 0 ? 0 : -1;
11552a8682a8SVincenzo Maffione }
11562a8682a8SVincenzo Maffione 
11572a8682a8SVincenzo Maffione static int
duplicate_extmem_options(struct TestContext * ctx)11582a8682a8SVincenzo Maffione duplicate_extmem_options(struct TestContext *ctx)
11592a8682a8SVincenzo Maffione {
11602a8682a8SVincenzo Maffione 	struct nmreq_opt_extmem e1, save1, e2, save2;
11612a8682a8SVincenzo Maffione 	struct nmreq_pools_info	pools_info;
11622a8682a8SVincenzo Maffione 	int ret;
11632a8682a8SVincenzo Maffione 
11642a8682a8SVincenzo Maffione 	printf("Testing duplicate extmem option on vale0:0\n");
11652a8682a8SVincenzo Maffione 
11662a8682a8SVincenzo Maffione 	pools_info_fill(&pools_info);
11672a8682a8SVincenzo Maffione 
11682a8682a8SVincenzo Maffione 	if ((ret = push_extmem_option(ctx, &pools_info, &e1)) < 0)
11692a8682a8SVincenzo Maffione 		return ret;
11702a8682a8SVincenzo Maffione 
11712a8682a8SVincenzo Maffione 	if ((ret = push_extmem_option(ctx, &pools_info, &e2)) < 0) {
11722a8682a8SVincenzo Maffione 		clear_options(ctx);
11732a8682a8SVincenzo Maffione 		return ret;
11742a8682a8SVincenzo Maffione 	}
11752a8682a8SVincenzo Maffione 
11762a8682a8SVincenzo Maffione 	save1 = e1;
11772a8682a8SVincenzo Maffione 	save2 = e2;
11782a8682a8SVincenzo Maffione 
11795e874d26SVincenzo Maffione 	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
11805e874d26SVincenzo Maffione 	ctx->nr_tx_slots = 16;
11815e874d26SVincenzo Maffione 	ctx->nr_rx_slots = 16;
11825e874d26SVincenzo Maffione 
11832a8682a8SVincenzo Maffione 	ret = port_register_hwall(ctx);
11842a8682a8SVincenzo Maffione 	if (ret >= 0) {
11852a8682a8SVincenzo Maffione 		printf("duplicate option not detected\n");
11862a8682a8SVincenzo Maffione 		return -1;
11872a8682a8SVincenzo Maffione 	}
11882a8682a8SVincenzo Maffione 
11892a8682a8SVincenzo Maffione 	save2.nro_opt.nro_status = EINVAL;
11902a8682a8SVincenzo Maffione 	if ((ret = pop_extmem_option(ctx, &save2)))
11912a8682a8SVincenzo Maffione 		return ret;
11922a8682a8SVincenzo Maffione 
11932a8682a8SVincenzo Maffione 	save1.nro_opt.nro_status = EINVAL;
11942a8682a8SVincenzo Maffione 	if ((ret = pop_extmem_option(ctx, &save1)))
11952a8682a8SVincenzo Maffione 		return ret;
11962a8682a8SVincenzo Maffione 
11972a8682a8SVincenzo Maffione 	return 0;
11982a8682a8SVincenzo Maffione }
11992a8682a8SVincenzo Maffione #endif /* CONFIG_NETMAP_EXTMEM */
12002a8682a8SVincenzo Maffione 
12012a8682a8SVincenzo Maffione static int
push_csb_option(struct TestContext * ctx,struct nmreq_opt_csb * opt)12022a8682a8SVincenzo Maffione push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
12032a8682a8SVincenzo Maffione {
12042a8682a8SVincenzo Maffione 	size_t csb_size;
12052a8682a8SVincenzo Maffione 	int num_entries;
12062a8682a8SVincenzo Maffione 	int ret;
12072a8682a8SVincenzo Maffione 
12082a8682a8SVincenzo Maffione 	ctx->nr_flags |= NR_EXCLUSIVE;
12092a8682a8SVincenzo Maffione 
12102a8682a8SVincenzo Maffione 	/* Get port info in order to use num_registered_rings(). */
12112a8682a8SVincenzo Maffione 	ret = port_info_get(ctx);
12122a8682a8SVincenzo Maffione 	if (ret != 0) {
12132a8682a8SVincenzo Maffione 		return ret;
12142a8682a8SVincenzo Maffione 	}
12152a8682a8SVincenzo Maffione 	num_entries = num_registered_rings(ctx);
12162a8682a8SVincenzo Maffione 
12172a8682a8SVincenzo Maffione 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
12182a8682a8SVincenzo Maffione 	           num_entries;
12192a8682a8SVincenzo Maffione 	assert(csb_size > 0);
12202a8682a8SVincenzo Maffione 	if (ctx->csb) {
12212a8682a8SVincenzo Maffione 		free(ctx->csb);
12222a8682a8SVincenzo Maffione 	}
12232a8682a8SVincenzo Maffione 	ret = posix_memalign(&ctx->csb, sizeof(struct nm_csb_atok), csb_size);
12242a8682a8SVincenzo Maffione 	if (ret != 0) {
12252a8682a8SVincenzo Maffione 		printf("Failed to allocate CSB memory\n");
12262a8682a8SVincenzo Maffione 		exit(EXIT_FAILURE);
12272a8682a8SVincenzo Maffione 	}
12282a8682a8SVincenzo Maffione 
12292a8682a8SVincenzo Maffione 	memset(opt, 0, sizeof(*opt));
12302a8682a8SVincenzo Maffione 	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
12312a8682a8SVincenzo Maffione 	opt->csb_atok            = (uintptr_t)ctx->csb;
12322a8682a8SVincenzo Maffione 	opt->csb_ktoa            = (uintptr_t)(((uint8_t *)ctx->csb) +
12332a8682a8SVincenzo Maffione                                     sizeof(struct nm_csb_atok) * num_entries);
12342a8682a8SVincenzo Maffione 
12352a8682a8SVincenzo Maffione 	printf("Pushing option NETMAP_REQ_OPT_CSB\n");
12362a8682a8SVincenzo Maffione 	push_option(&opt->nro_opt, ctx);
12372a8682a8SVincenzo Maffione 
12382a8682a8SVincenzo Maffione 	return 0;
12392a8682a8SVincenzo Maffione }
12402a8682a8SVincenzo Maffione 
12412a8682a8SVincenzo Maffione static int
csb_mode(struct TestContext * ctx)12422a8682a8SVincenzo Maffione csb_mode(struct TestContext *ctx)
12432a8682a8SVincenzo Maffione {
12442a8682a8SVincenzo Maffione 	struct nmreq_opt_csb opt;
12452a8682a8SVincenzo Maffione 	int ret;
12462a8682a8SVincenzo Maffione 
12472a8682a8SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
12482a8682a8SVincenzo Maffione 	if (ret != 0) {
12492a8682a8SVincenzo Maffione 		return ret;
12502a8682a8SVincenzo Maffione 	}
12512a8682a8SVincenzo Maffione 
12522a8682a8SVincenzo Maffione 	ret = port_register_hwall(ctx);
12532a8682a8SVincenzo Maffione 	clear_options(ctx);
12542a8682a8SVincenzo Maffione 
12552a8682a8SVincenzo Maffione 	return ret;
12562a8682a8SVincenzo Maffione }
12572a8682a8SVincenzo Maffione 
12582a8682a8SVincenzo Maffione static int
csb_mode_invalid_memory(struct TestContext * ctx)12592a8682a8SVincenzo Maffione csb_mode_invalid_memory(struct TestContext *ctx)
12602a8682a8SVincenzo Maffione {
12612a8682a8SVincenzo Maffione 	struct nmreq_opt_csb opt;
12622a8682a8SVincenzo Maffione 	int ret;
12632a8682a8SVincenzo Maffione 
12642a8682a8SVincenzo Maffione 	memset(&opt, 0, sizeof(opt));
12652a8682a8SVincenzo Maffione 	opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
12662a8682a8SVincenzo Maffione 	opt.csb_atok            = (uintptr_t)0x10;
12672a8682a8SVincenzo Maffione 	opt.csb_ktoa            = (uintptr_t)0x800;
12682a8682a8SVincenzo Maffione 	push_option(&opt.nro_opt, ctx);
12692a8682a8SVincenzo Maffione 
12702a8682a8SVincenzo Maffione 	ctx->nr_flags = NR_EXCLUSIVE;
12712a8682a8SVincenzo Maffione 	ret           = port_register_hwall(ctx);
12722a8682a8SVincenzo Maffione 	clear_options(ctx);
12732a8682a8SVincenzo Maffione 
12742a8682a8SVincenzo Maffione 	return (ret < 0) ? 0 : -1;
12752a8682a8SVincenzo Maffione }
12762a8682a8SVincenzo Maffione 
12772a8682a8SVincenzo Maffione static int
sync_kloop_stop(struct TestContext * ctx)12782a8682a8SVincenzo Maffione sync_kloop_stop(struct TestContext *ctx)
12792a8682a8SVincenzo Maffione {
12802a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
12812a8682a8SVincenzo Maffione 	int ret;
12822a8682a8SVincenzo Maffione 
128308f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname_ext);
12842a8682a8SVincenzo Maffione 
128508f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
12862a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
12872a8682a8SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
12882a8682a8SVincenzo Maffione 	if (ret != 0) {
12892a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
12902a8682a8SVincenzo Maffione 	}
12912a8682a8SVincenzo Maffione 
12922a8682a8SVincenzo Maffione 	return ret;
12932a8682a8SVincenzo Maffione }
12942a8682a8SVincenzo Maffione 
12952a8682a8SVincenzo Maffione static void *
sync_kloop_worker(void * opaque)12962a8682a8SVincenzo Maffione sync_kloop_worker(void *opaque)
12972a8682a8SVincenzo Maffione {
12982a8682a8SVincenzo Maffione 	struct TestContext *ctx = opaque;
12992a8682a8SVincenzo Maffione 	struct nmreq_sync_kloop_start req;
13002a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
13012a8682a8SVincenzo Maffione 	int ret;
13022a8682a8SVincenzo Maffione 
130308f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname_ext);
13042a8682a8SVincenzo Maffione 
130508f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
13062a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
13072a8682a8SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
13082a8682a8SVincenzo Maffione 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
13092a8682a8SVincenzo Maffione 	memset(&req, 0, sizeof(req));
13102a8682a8SVincenzo Maffione 	req.sleep_us = 500;
13112a8682a8SVincenzo Maffione 	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
13122a8682a8SVincenzo Maffione 	if (ret != 0) {
13132a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
13142a8682a8SVincenzo Maffione 	}
13152a8682a8SVincenzo Maffione 
13162a8682a8SVincenzo Maffione 	if (ctx->sem) {
13172a8682a8SVincenzo Maffione 		sem_post(ctx->sem);
13182a8682a8SVincenzo Maffione 	}
13192a8682a8SVincenzo Maffione 
13202a8682a8SVincenzo Maffione 	pthread_exit(ret ? (void *)THRET_FAILURE : (void *)THRET_SUCCESS);
13212a8682a8SVincenzo Maffione }
13222a8682a8SVincenzo Maffione 
13232a8682a8SVincenzo Maffione static int
sync_kloop_start_stop(struct TestContext * ctx)13242a8682a8SVincenzo Maffione sync_kloop_start_stop(struct TestContext *ctx)
13252a8682a8SVincenzo Maffione {
13262a8682a8SVincenzo Maffione 	pthread_t th;
13272a8682a8SVincenzo Maffione 	void *thret = THRET_FAILURE;
13282a8682a8SVincenzo Maffione 	int ret;
13292a8682a8SVincenzo Maffione 
13302a8682a8SVincenzo Maffione 	ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
13312a8682a8SVincenzo Maffione 	if (ret != 0) {
13322a8682a8SVincenzo Maffione 		printf("pthread_create(kloop): %s\n", strerror(ret));
13332a8682a8SVincenzo Maffione 		return -1;
13342a8682a8SVincenzo Maffione 	}
13352a8682a8SVincenzo Maffione 
13362a8682a8SVincenzo Maffione 	ret = sync_kloop_stop(ctx);
13372a8682a8SVincenzo Maffione 	if (ret != 0) {
13382a8682a8SVincenzo Maffione 		return ret;
13392a8682a8SVincenzo Maffione 	}
13402a8682a8SVincenzo Maffione 
13412a8682a8SVincenzo Maffione 	ret = pthread_join(th, &thret);
13422a8682a8SVincenzo Maffione 	if (ret != 0) {
13432a8682a8SVincenzo Maffione 		printf("pthread_join(kloop): %s\n", strerror(ret));
13442a8682a8SVincenzo Maffione 	}
13452a8682a8SVincenzo Maffione 
13462a8682a8SVincenzo Maffione 	return thret == THRET_SUCCESS ? 0 : -1;
13472a8682a8SVincenzo Maffione }
13482a8682a8SVincenzo Maffione 
13492a8682a8SVincenzo Maffione static int
sync_kloop(struct TestContext * ctx)13502a8682a8SVincenzo Maffione sync_kloop(struct TestContext *ctx)
13512a8682a8SVincenzo Maffione {
13522a8682a8SVincenzo Maffione 	int ret;
13532a8682a8SVincenzo Maffione 
13542a8682a8SVincenzo Maffione 	ret = csb_mode(ctx);
13552a8682a8SVincenzo Maffione 	if (ret != 0) {
13562a8682a8SVincenzo Maffione 		return ret;
13572a8682a8SVincenzo Maffione 	}
13582a8682a8SVincenzo Maffione 
13592a8682a8SVincenzo Maffione 	return sync_kloop_start_stop(ctx);
13602a8682a8SVincenzo Maffione }
13612a8682a8SVincenzo Maffione 
13622a8682a8SVincenzo Maffione static int
sync_kloop_eventfds(struct TestContext * ctx)13632a8682a8SVincenzo Maffione sync_kloop_eventfds(struct TestContext *ctx)
13642a8682a8SVincenzo Maffione {
13655e874d26SVincenzo Maffione 	struct nmreq_opt_sync_kloop_eventfds *evopt = NULL;
13665e874d26SVincenzo Maffione 	struct nmreq_opt_sync_kloop_mode modeopt;
13675e874d26SVincenzo Maffione 	struct nmreq_option evsave;
13682a8682a8SVincenzo Maffione 	int num_entries;
13692a8682a8SVincenzo Maffione 	size_t opt_size;
13702a8682a8SVincenzo Maffione 	int ret, i;
13712a8682a8SVincenzo Maffione 
13725e874d26SVincenzo Maffione 	memset(&modeopt, 0, sizeof(modeopt));
13735e874d26SVincenzo Maffione 	modeopt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_MODE;
13745e874d26SVincenzo Maffione 	modeopt.mode = ctx->sync_kloop_mode;
13755e874d26SVincenzo Maffione 	push_option(&modeopt.nro_opt, ctx);
13765e874d26SVincenzo Maffione 
13772a8682a8SVincenzo Maffione 	num_entries = num_registered_rings(ctx);
13785e874d26SVincenzo Maffione 	opt_size    = sizeof(*evopt) + num_entries * sizeof(evopt->eventfds[0]);
13795e874d26SVincenzo Maffione 	evopt = calloc(1, opt_size);
13805e874d26SVincenzo Maffione 	evopt->nro_opt.nro_next    = 0;
13815e874d26SVincenzo Maffione 	evopt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
13825e874d26SVincenzo Maffione 	evopt->nro_opt.nro_status  = 0;
13835e874d26SVincenzo Maffione 	evopt->nro_opt.nro_size    = opt_size;
13842a8682a8SVincenzo Maffione 	for (i = 0; i < num_entries; i++) {
13852a8682a8SVincenzo Maffione 		int efd = eventfd(0, 0);
13862a8682a8SVincenzo Maffione 
13875e874d26SVincenzo Maffione 		evopt->eventfds[i].ioeventfd = efd;
13882a8682a8SVincenzo Maffione 		efd                        = eventfd(0, 0);
13895e874d26SVincenzo Maffione 		evopt->eventfds[i].irqfd = efd;
13902a8682a8SVincenzo Maffione 	}
13912a8682a8SVincenzo Maffione 
13925e874d26SVincenzo Maffione 	push_option(&evopt->nro_opt, ctx);
13935e874d26SVincenzo Maffione 	evsave = evopt->nro_opt;
13942a8682a8SVincenzo Maffione 
13952a8682a8SVincenzo Maffione 	ret = sync_kloop_start_stop(ctx);
13962a8682a8SVincenzo Maffione 	if (ret != 0) {
13975e874d26SVincenzo Maffione 		free(evopt);
13982a8682a8SVincenzo Maffione 		clear_options(ctx);
13992a8682a8SVincenzo Maffione 		return ret;
14002a8682a8SVincenzo Maffione 	}
14012a8682a8SVincenzo Maffione #ifdef __linux__
14025e874d26SVincenzo Maffione 	evsave.nro_status = 0;
14032a8682a8SVincenzo Maffione #else  /* !__linux__ */
14045e874d26SVincenzo Maffione 	evsave.nro_status = EOPNOTSUPP;
14052a8682a8SVincenzo Maffione #endif /* !__linux__ */
14062a8682a8SVincenzo Maffione 
14075e874d26SVincenzo Maffione 	ret = checkoption(&evopt->nro_opt, &evsave);
14085e874d26SVincenzo Maffione 	free(evopt);
14092a8682a8SVincenzo Maffione 	clear_options(ctx);
14102a8682a8SVincenzo Maffione 
14112a8682a8SVincenzo Maffione 	return ret;
14122a8682a8SVincenzo Maffione }
14132a8682a8SVincenzo Maffione 
14142a8682a8SVincenzo Maffione static int
sync_kloop_eventfds_all_mode(struct TestContext * ctx,uint32_t sync_kloop_mode)14155e874d26SVincenzo Maffione sync_kloop_eventfds_all_mode(struct TestContext *ctx,
14165e874d26SVincenzo Maffione 			     uint32_t sync_kloop_mode)
14172a8682a8SVincenzo Maffione {
14182a8682a8SVincenzo Maffione 	int ret;
14192a8682a8SVincenzo Maffione 
14202a8682a8SVincenzo Maffione 	ret = csb_mode(ctx);
14212a8682a8SVincenzo Maffione 	if (ret != 0) {
14222a8682a8SVincenzo Maffione 		return ret;
14232a8682a8SVincenzo Maffione 	}
14242a8682a8SVincenzo Maffione 
14255e874d26SVincenzo Maffione 	ctx->sync_kloop_mode = sync_kloop_mode;
14265e874d26SVincenzo Maffione 
14272a8682a8SVincenzo Maffione 	return sync_kloop_eventfds(ctx);
14282a8682a8SVincenzo Maffione }
14292a8682a8SVincenzo Maffione 
14302a8682a8SVincenzo Maffione static int
sync_kloop_eventfds_all(struct TestContext * ctx)14315e874d26SVincenzo Maffione sync_kloop_eventfds_all(struct TestContext *ctx)
14325e874d26SVincenzo Maffione {
14335e874d26SVincenzo Maffione 	return sync_kloop_eventfds_all_mode(ctx, 0);
14345e874d26SVincenzo Maffione }
14355e874d26SVincenzo Maffione 
14365e874d26SVincenzo Maffione static int
sync_kloop_eventfds_all_tx(struct TestContext * ctx)14372a8682a8SVincenzo Maffione sync_kloop_eventfds_all_tx(struct TestContext *ctx)
14382a8682a8SVincenzo Maffione {
14392a8682a8SVincenzo Maffione 	struct nmreq_opt_csb opt;
14402a8682a8SVincenzo Maffione 	int ret;
14412a8682a8SVincenzo Maffione 
14422a8682a8SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
14432a8682a8SVincenzo Maffione 	if (ret != 0) {
14442a8682a8SVincenzo Maffione 		return ret;
14452a8682a8SVincenzo Maffione 	}
14462a8682a8SVincenzo Maffione 
14472a8682a8SVincenzo Maffione 	ret = port_register_hwall_tx(ctx);
14482a8682a8SVincenzo Maffione 	if (ret != 0) {
14492a8682a8SVincenzo Maffione 		return ret;
14502a8682a8SVincenzo Maffione 	}
14512a8682a8SVincenzo Maffione 	clear_options(ctx);
14522a8682a8SVincenzo Maffione 
14532a8682a8SVincenzo Maffione 	return sync_kloop_eventfds(ctx);
14542a8682a8SVincenzo Maffione }
14552a8682a8SVincenzo Maffione 
14562a8682a8SVincenzo Maffione static int
sync_kloop_eventfds_all_direct(struct TestContext * ctx)14575e874d26SVincenzo Maffione sync_kloop_eventfds_all_direct(struct TestContext *ctx)
14585e874d26SVincenzo Maffione {
14595e874d26SVincenzo Maffione 	return sync_kloop_eventfds_all_mode(ctx,
14605e874d26SVincenzo Maffione 	    NM_OPT_SYNC_KLOOP_DIRECT_TX | NM_OPT_SYNC_KLOOP_DIRECT_RX);
14615e874d26SVincenzo Maffione }
14625e874d26SVincenzo Maffione 
14635e874d26SVincenzo Maffione static int
sync_kloop_eventfds_all_direct_tx(struct TestContext * ctx)14645e874d26SVincenzo Maffione sync_kloop_eventfds_all_direct_tx(struct TestContext *ctx)
14655e874d26SVincenzo Maffione {
14665e874d26SVincenzo Maffione 	return sync_kloop_eventfds_all_mode(ctx,
14675e874d26SVincenzo Maffione 	    NM_OPT_SYNC_KLOOP_DIRECT_TX);
14685e874d26SVincenzo Maffione }
14695e874d26SVincenzo Maffione 
14705e874d26SVincenzo Maffione static int
sync_kloop_eventfds_all_direct_rx(struct TestContext * ctx)14715e874d26SVincenzo Maffione sync_kloop_eventfds_all_direct_rx(struct TestContext *ctx)
14725e874d26SVincenzo Maffione {
14735e874d26SVincenzo Maffione 	return sync_kloop_eventfds_all_mode(ctx,
14745e874d26SVincenzo Maffione 	    NM_OPT_SYNC_KLOOP_DIRECT_RX);
14755e874d26SVincenzo Maffione }
14765e874d26SVincenzo Maffione 
14775e874d26SVincenzo Maffione static int
sync_kloop_nocsb(struct TestContext * ctx)14782a8682a8SVincenzo Maffione sync_kloop_nocsb(struct TestContext *ctx)
14792a8682a8SVincenzo Maffione {
14802a8682a8SVincenzo Maffione 	int ret;
14812a8682a8SVincenzo Maffione 
14822a8682a8SVincenzo Maffione 	ret = port_register_hwall(ctx);
14832a8682a8SVincenzo Maffione 	if (ret != 0) {
14842a8682a8SVincenzo Maffione 		return ret;
14852a8682a8SVincenzo Maffione 	}
14862a8682a8SVincenzo Maffione 
14872a8682a8SVincenzo Maffione 	/* Sync kloop must fail because we did not use
14882a8682a8SVincenzo Maffione 	 * NETMAP_REQ_CSB_ENABLE. */
14892a8682a8SVincenzo Maffione 	return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
14902a8682a8SVincenzo Maffione }
14912a8682a8SVincenzo Maffione 
14922a8682a8SVincenzo Maffione static int
csb_enable(struct TestContext * ctx)14932a8682a8SVincenzo Maffione csb_enable(struct TestContext *ctx)
14942a8682a8SVincenzo Maffione {
14952a8682a8SVincenzo Maffione 	struct nmreq_option saveopt;
14962a8682a8SVincenzo Maffione 	struct nmreq_opt_csb opt;
14972a8682a8SVincenzo Maffione 	struct nmreq_header hdr;
14982a8682a8SVincenzo Maffione 	int ret;
14992a8682a8SVincenzo Maffione 
15002a8682a8SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
15012a8682a8SVincenzo Maffione 	if (ret != 0) {
15022a8682a8SVincenzo Maffione 		return ret;
15032a8682a8SVincenzo Maffione 	}
15042a8682a8SVincenzo Maffione 	saveopt = opt.nro_opt;
15052a8682a8SVincenzo Maffione 	saveopt.nro_status = 0;
15062a8682a8SVincenzo Maffione 
150708f34ad9SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
15082a8682a8SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_CSB_ENABLE;
15092a8682a8SVincenzo Maffione 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
15102a8682a8SVincenzo Maffione 	hdr.nr_body = (uintptr_t)NULL;
15112a8682a8SVincenzo Maffione 
151208f34ad9SVincenzo Maffione 	printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname_ext);
15132a8682a8SVincenzo Maffione 
15142a8682a8SVincenzo Maffione 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
15152a8682a8SVincenzo Maffione 	if (ret != 0) {
15162a8682a8SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, CSB_ENABLE)");
15172a8682a8SVincenzo Maffione 		return ret;
15182a8682a8SVincenzo Maffione 	}
15192a8682a8SVincenzo Maffione 
15202a8682a8SVincenzo Maffione 	ret = checkoption(&opt.nro_opt, &saveopt);
15212a8682a8SVincenzo Maffione 	clear_options(ctx);
15222a8682a8SVincenzo Maffione 
15232a8682a8SVincenzo Maffione 	return ret;
15242a8682a8SVincenzo Maffione }
15252a8682a8SVincenzo Maffione 
15262a8682a8SVincenzo Maffione static int
sync_kloop_csb_enable(struct TestContext * ctx)15272a8682a8SVincenzo Maffione sync_kloop_csb_enable(struct TestContext *ctx)
15282a8682a8SVincenzo Maffione {
15292a8682a8SVincenzo Maffione 	int ret;
15302a8682a8SVincenzo Maffione 
15312a8682a8SVincenzo Maffione 	ctx->nr_flags |= NR_EXCLUSIVE;
15322a8682a8SVincenzo Maffione 	ret = port_register_hwall(ctx);
15332a8682a8SVincenzo Maffione 	if (ret != 0) {
15342a8682a8SVincenzo Maffione 		return ret;
15352a8682a8SVincenzo Maffione 	}
15362a8682a8SVincenzo Maffione 
15372a8682a8SVincenzo Maffione 	ret = csb_enable(ctx);
15382a8682a8SVincenzo Maffione 	if (ret != 0) {
15392a8682a8SVincenzo Maffione 		return ret;
15402a8682a8SVincenzo Maffione 	}
15412a8682a8SVincenzo Maffione 
15422a8682a8SVincenzo Maffione 	return sync_kloop_start_stop(ctx);
15432a8682a8SVincenzo Maffione }
15442a8682a8SVincenzo Maffione 
15452a8682a8SVincenzo Maffione static int
sync_kloop_conflict(struct TestContext * ctx)15462a8682a8SVincenzo Maffione sync_kloop_conflict(struct TestContext *ctx)
15472a8682a8SVincenzo Maffione {
15482a8682a8SVincenzo Maffione 	struct nmreq_opt_csb opt;
15492a8682a8SVincenzo Maffione 	pthread_t th1, th2;
15502a8682a8SVincenzo Maffione 	void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
15512a8682a8SVincenzo Maffione 	struct timespec to;
15522a8682a8SVincenzo Maffione 	sem_t sem;
15532a8682a8SVincenzo Maffione 	int err = 0;
15542a8682a8SVincenzo Maffione 	int ret;
15552a8682a8SVincenzo Maffione 
15562a8682a8SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
15572a8682a8SVincenzo Maffione 	if (ret != 0) {
15582a8682a8SVincenzo Maffione 		return ret;
15592a8682a8SVincenzo Maffione 	}
15602a8682a8SVincenzo Maffione 
15612a8682a8SVincenzo Maffione 	ret = port_register_hwall(ctx);
15622a8682a8SVincenzo Maffione 	if (ret != 0) {
15632a8682a8SVincenzo Maffione 		return ret;
15642a8682a8SVincenzo Maffione 	}
15652a8682a8SVincenzo Maffione 	clear_options(ctx);
15662a8682a8SVincenzo Maffione 
15672a8682a8SVincenzo Maffione 	ret = sem_init(&sem, 0, 0);
15682a8682a8SVincenzo Maffione 	if (ret != 0) {
15692a8682a8SVincenzo Maffione 		printf("sem_init() failed: %s\n", strerror(ret));
15702a8682a8SVincenzo Maffione 		return ret;
15712a8682a8SVincenzo Maffione 	}
15722a8682a8SVincenzo Maffione 	ctx->sem = &sem;
15732a8682a8SVincenzo Maffione 
15742a8682a8SVincenzo Maffione 	ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
15752a8682a8SVincenzo Maffione 	err |= ret;
15762a8682a8SVincenzo Maffione 	if (ret != 0) {
15772a8682a8SVincenzo Maffione 		printf("pthread_create(kloop1): %s\n", strerror(ret));
15782a8682a8SVincenzo Maffione 	}
15792a8682a8SVincenzo Maffione 
15802a8682a8SVincenzo Maffione 	ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
15812a8682a8SVincenzo Maffione 	err |= ret;
15822a8682a8SVincenzo Maffione 	if (ret != 0) {
15832a8682a8SVincenzo Maffione 		printf("pthread_create(kloop2): %s\n", strerror(ret));
15842a8682a8SVincenzo Maffione 	}
15852a8682a8SVincenzo Maffione 
15862a8682a8SVincenzo Maffione 	/* Wait for one of the two threads to fail to start the kloop, to
15872a8682a8SVincenzo Maffione 	 * avoid a race condition where th1 starts the loop and stops,
15882a8682a8SVincenzo Maffione 	 * and after that th2 starts the loop successfully. */
15892a8682a8SVincenzo Maffione 	clock_gettime(CLOCK_REALTIME, &to);
15902a8682a8SVincenzo Maffione 	to.tv_sec += 2;
15912a8682a8SVincenzo Maffione 	ret = sem_timedwait(&sem, &to);
15922a8682a8SVincenzo Maffione 	err |= ret;
15932a8682a8SVincenzo Maffione 	if (ret != 0) {
15942a8682a8SVincenzo Maffione 		printf("sem_timedwait() failed: %s\n", strerror(errno));
15952a8682a8SVincenzo Maffione 	}
15962a8682a8SVincenzo Maffione 
15972a8682a8SVincenzo Maffione 	err |= sync_kloop_stop(ctx);
15982a8682a8SVincenzo Maffione 
15992a8682a8SVincenzo Maffione 	ret = pthread_join(th1, &thret1);
16002a8682a8SVincenzo Maffione 	err |= ret;
16012a8682a8SVincenzo Maffione 	if (ret != 0) {
16022a8682a8SVincenzo Maffione 		printf("pthread_join(kloop1): %s\n", strerror(ret));
16032a8682a8SVincenzo Maffione 	}
16042a8682a8SVincenzo Maffione 
16052a8682a8SVincenzo Maffione 	ret = pthread_join(th2, &thret2);
16062a8682a8SVincenzo Maffione 	err |= ret;
16072a8682a8SVincenzo Maffione 	if (ret != 0) {
16082a8682a8SVincenzo Maffione 		printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
16092a8682a8SVincenzo Maffione 	}
16102a8682a8SVincenzo Maffione 
16112a8682a8SVincenzo Maffione 	sem_destroy(&sem);
16122a8682a8SVincenzo Maffione 	ctx->sem = NULL;
16132a8682a8SVincenzo Maffione 	if (err) {
16142a8682a8SVincenzo Maffione 		return err;
16152a8682a8SVincenzo Maffione 	}
16162a8682a8SVincenzo Maffione 
16172a8682a8SVincenzo Maffione 	/* Check that one of the two failed, while the other one succeeded. */
16182a8682a8SVincenzo Maffione 	return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
16192a8682a8SVincenzo Maffione 			(thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
16202a8682a8SVincenzo Maffione 	               ? 0
16212a8682a8SVincenzo Maffione 	               : -1;
16222a8682a8SVincenzo Maffione }
16232a8682a8SVincenzo Maffione 
16242a8682a8SVincenzo Maffione static int
sync_kloop_eventfds_mismatch(struct TestContext * ctx)16252a8682a8SVincenzo Maffione sync_kloop_eventfds_mismatch(struct TestContext *ctx)
16262a8682a8SVincenzo Maffione {
16272a8682a8SVincenzo Maffione 	struct nmreq_opt_csb opt;
16282a8682a8SVincenzo Maffione 	int ret;
16292a8682a8SVincenzo Maffione 
16302a8682a8SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
16312a8682a8SVincenzo Maffione 	if (ret != 0) {
16322a8682a8SVincenzo Maffione 		return ret;
16332a8682a8SVincenzo Maffione 	}
16342a8682a8SVincenzo Maffione 
16352a8682a8SVincenzo Maffione 	ret = port_register_hwall_rx(ctx);
16362a8682a8SVincenzo Maffione 	if (ret != 0) {
16372a8682a8SVincenzo Maffione 		return ret;
16382a8682a8SVincenzo Maffione 	}
16392a8682a8SVincenzo Maffione 	clear_options(ctx);
16402a8682a8SVincenzo Maffione 
16412a8682a8SVincenzo Maffione 	/* Deceive num_registered_rings() to trigger a failure of
16422a8682a8SVincenzo Maffione 	 * sync_kloop_eventfds(). The latter will think that all the
16432a8682a8SVincenzo Maffione 	 * rings were registered, and allocate the wrong number of
16442a8682a8SVincenzo Maffione 	 * eventfds. */
16452a8682a8SVincenzo Maffione 	ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
16462a8682a8SVincenzo Maffione 
16472a8682a8SVincenzo Maffione 	return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
16482a8682a8SVincenzo Maffione }
16492a8682a8SVincenzo Maffione 
16502a8682a8SVincenzo Maffione static int
null_port(struct TestContext * ctx)16512a8682a8SVincenzo Maffione null_port(struct TestContext *ctx)
16522a8682a8SVincenzo Maffione {
16532a8682a8SVincenzo Maffione 	int ret;
16542a8682a8SVincenzo Maffione 
16552a8682a8SVincenzo Maffione 	ctx->nr_mem_id = 1;
16562a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_NULL;
16572a8682a8SVincenzo Maffione 	ctx->nr_tx_rings = 10;
16582a8682a8SVincenzo Maffione 	ctx->nr_rx_rings = 5;
16592a8682a8SVincenzo Maffione 	ctx->nr_tx_slots = 256;
16602a8682a8SVincenzo Maffione 	ctx->nr_rx_slots = 100;
16612a8682a8SVincenzo Maffione 	ret = port_register(ctx);
16622a8682a8SVincenzo Maffione 	if (ret != 0) {
16632a8682a8SVincenzo Maffione 		return ret;
16642a8682a8SVincenzo Maffione 	}
16652a8682a8SVincenzo Maffione 	return 0;
16662a8682a8SVincenzo Maffione }
16672a8682a8SVincenzo Maffione 
16682a8682a8SVincenzo Maffione static int
null_port_all_zero(struct TestContext * ctx)16692a8682a8SVincenzo Maffione null_port_all_zero(struct TestContext *ctx)
16702a8682a8SVincenzo Maffione {
16712a8682a8SVincenzo Maffione 	int ret;
16722a8682a8SVincenzo Maffione 
16732a8682a8SVincenzo Maffione 	ctx->nr_mem_id = 1;
16742a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_NULL;
16752a8682a8SVincenzo Maffione 	ctx->nr_tx_rings = 0;
16762a8682a8SVincenzo Maffione 	ctx->nr_rx_rings = 0;
16772a8682a8SVincenzo Maffione 	ctx->nr_tx_slots = 0;
16782a8682a8SVincenzo Maffione 	ctx->nr_rx_slots = 0;
16792a8682a8SVincenzo Maffione 	ret = port_register(ctx);
16802a8682a8SVincenzo Maffione 	if (ret != 0) {
16812a8682a8SVincenzo Maffione 		return ret;
16822a8682a8SVincenzo Maffione 	}
16832a8682a8SVincenzo Maffione 	return 0;
16842a8682a8SVincenzo Maffione }
16852a8682a8SVincenzo Maffione 
16862a8682a8SVincenzo Maffione static int
null_port_sync(struct TestContext * ctx)16872a8682a8SVincenzo Maffione null_port_sync(struct TestContext *ctx)
16882a8682a8SVincenzo Maffione {
16892a8682a8SVincenzo Maffione 	int ret;
16902a8682a8SVincenzo Maffione 
16912a8682a8SVincenzo Maffione 	ctx->nr_mem_id = 1;
16922a8682a8SVincenzo Maffione 	ctx->nr_mode = NR_REG_NULL;
16932a8682a8SVincenzo Maffione 	ctx->nr_tx_rings = 10;
16942a8682a8SVincenzo Maffione 	ctx->nr_rx_rings = 5;
16952a8682a8SVincenzo Maffione 	ctx->nr_tx_slots = 256;
16962a8682a8SVincenzo Maffione 	ctx->nr_rx_slots = 100;
16972a8682a8SVincenzo Maffione 	ret = port_register(ctx);
16982a8682a8SVincenzo Maffione 	if (ret != 0) {
16992a8682a8SVincenzo Maffione 		return ret;
17002a8682a8SVincenzo Maffione 	}
17012a8682a8SVincenzo Maffione 	ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
17022a8682a8SVincenzo Maffione 	if (ret != 0) {
17032a8682a8SVincenzo Maffione 		return ret;
17042a8682a8SVincenzo Maffione 	}
17052a8682a8SVincenzo Maffione 	return 0;
17062a8682a8SVincenzo Maffione }
17072a8682a8SVincenzo Maffione 
17082a8682a8SVincenzo Maffione static void
usage(const char * prog)17092a8682a8SVincenzo Maffione usage(const char *prog)
17102a8682a8SVincenzo Maffione {
17112a8682a8SVincenzo Maffione 	printf("%s -i IFNAME\n"
17122a8682a8SVincenzo Maffione 	       "[-j TEST_NUM1[-[TEST_NUM2]] | -[TEST_NUM_2]]\n"
17132a8682a8SVincenzo Maffione 	       "[-l (list test cases)]\n",
17142a8682a8SVincenzo Maffione 	       prog);
17152a8682a8SVincenzo Maffione }
17162a8682a8SVincenzo Maffione 
17172a8682a8SVincenzo Maffione struct mytest {
17182a8682a8SVincenzo Maffione 	testfunc_t test;
17192a8682a8SVincenzo Maffione 	const char *name;
17202a8682a8SVincenzo Maffione };
17212a8682a8SVincenzo Maffione 
17222a8682a8SVincenzo Maffione #define decltest(f)                                                            \
17232a8682a8SVincenzo Maffione 	{                                                                      \
17242a8682a8SVincenzo Maffione 		.test = f, .name = #f                                          \
17252a8682a8SVincenzo Maffione 	}
17262a8682a8SVincenzo Maffione 
17272a8682a8SVincenzo Maffione static struct mytest tests[] = {
17282a8682a8SVincenzo Maffione 	decltest(port_info_get),
17292a8682a8SVincenzo Maffione 	decltest(port_register_hwall_host),
17302a8682a8SVincenzo Maffione 	decltest(port_register_hwall),
1731*4f6858e8SVincenzo Maffione 	decltest(port_register_hostall),
1732*4f6858e8SVincenzo Maffione 	decltest(port_register_single_hw_pair),
1733*4f6858e8SVincenzo Maffione 	decltest(port_register_single_host_pair),
1734*4f6858e8SVincenzo Maffione 	decltest(port_register_hostall_many),
17352a8682a8SVincenzo Maffione 	decltest(vale_attach_detach),
17362a8682a8SVincenzo Maffione 	decltest(vale_attach_detach_host_rings),
17372a8682a8SVincenzo Maffione 	decltest(vale_ephemeral_port_hdr_manipulation),
17382a8682a8SVincenzo Maffione 	decltest(vale_persistent_port),
17392a8682a8SVincenzo Maffione 	decltest(pools_info_get_and_register),
17402a8682a8SVincenzo Maffione 	decltest(pools_info_get_empty_ifname),
17412a8682a8SVincenzo Maffione 	decltest(pipe_master),
17422a8682a8SVincenzo Maffione 	decltest(pipe_slave),
17432a8682a8SVincenzo Maffione 	decltest(pipe_port_info_get),
17442a8682a8SVincenzo Maffione 	decltest(pipe_pools_info_get),
17452a8682a8SVincenzo Maffione 	decltest(vale_polling_enable_disable),
17462a8682a8SVincenzo Maffione 	decltest(unsupported_option),
17472a8682a8SVincenzo Maffione 	decltest(infinite_options),
17482a8682a8SVincenzo Maffione #ifdef CONFIG_NETMAP_EXTMEM
17492a8682a8SVincenzo Maffione 	decltest(extmem_option),
17502a8682a8SVincenzo Maffione 	decltest(bad_extmem_option),
17512a8682a8SVincenzo Maffione 	decltest(duplicate_extmem_options),
17522a8682a8SVincenzo Maffione #endif /* CONFIG_NETMAP_EXTMEM */
17532a8682a8SVincenzo Maffione 	decltest(csb_mode),
17542a8682a8SVincenzo Maffione 	decltest(csb_mode_invalid_memory),
17552a8682a8SVincenzo Maffione 	decltest(sync_kloop),
17562a8682a8SVincenzo Maffione 	decltest(sync_kloop_eventfds_all),
17572a8682a8SVincenzo Maffione 	decltest(sync_kloop_eventfds_all_tx),
17585e874d26SVincenzo Maffione 	decltest(sync_kloop_eventfds_all_direct),
17595e874d26SVincenzo Maffione 	decltest(sync_kloop_eventfds_all_direct_tx),
17605e874d26SVincenzo Maffione 	decltest(sync_kloop_eventfds_all_direct_rx),
17612a8682a8SVincenzo Maffione 	decltest(sync_kloop_nocsb),
17622a8682a8SVincenzo Maffione 	decltest(sync_kloop_csb_enable),
17632a8682a8SVincenzo Maffione 	decltest(sync_kloop_conflict),
17642a8682a8SVincenzo Maffione 	decltest(sync_kloop_eventfds_mismatch),
17652a8682a8SVincenzo Maffione 	decltest(null_port),
17662a8682a8SVincenzo Maffione 	decltest(null_port_all_zero),
17672a8682a8SVincenzo Maffione 	decltest(null_port_sync),
17682a8682a8SVincenzo Maffione 	decltest(legacy_regif_default),
17692a8682a8SVincenzo Maffione 	decltest(legacy_regif_all_nic),
17702a8682a8SVincenzo Maffione 	decltest(legacy_regif_12),
17712a8682a8SVincenzo Maffione 	decltest(legacy_regif_sw),
17722a8682a8SVincenzo Maffione 	decltest(legacy_regif_future),
17732a8682a8SVincenzo Maffione 	decltest(legacy_regif_extra_bufs),
17742a8682a8SVincenzo Maffione 	decltest(legacy_regif_extra_bufs_pipe),
17752a8682a8SVincenzo Maffione 	decltest(legacy_regif_extra_bufs_pipe_vale),
17762a8682a8SVincenzo Maffione };
17772a8682a8SVincenzo Maffione 
17782a8682a8SVincenzo Maffione static void
context_cleanup(struct TestContext * ctx)17792a8682a8SVincenzo Maffione context_cleanup(struct TestContext *ctx)
17802a8682a8SVincenzo Maffione {
17812a8682a8SVincenzo Maffione 	if (ctx->csb) {
17822a8682a8SVincenzo Maffione 		free(ctx->csb);
17832a8682a8SVincenzo Maffione 		ctx->csb = NULL;
17842a8682a8SVincenzo Maffione 	}
17852a8682a8SVincenzo Maffione 
17862a8682a8SVincenzo Maffione 	close(ctx->fd);
17872a8682a8SVincenzo Maffione 	ctx->fd = -1;
17882a8682a8SVincenzo Maffione }
17892a8682a8SVincenzo Maffione 
17902a8682a8SVincenzo Maffione static int
parse_interval(const char * arg,int * j,int * k)17912a8682a8SVincenzo Maffione parse_interval(const char *arg, int *j, int *k)
17922a8682a8SVincenzo Maffione {
17932a8682a8SVincenzo Maffione 	const char *scan = arg;
17942a8682a8SVincenzo Maffione 	char *rest;
17952a8682a8SVincenzo Maffione 
17962a8682a8SVincenzo Maffione 	*j = 0;
17972a8682a8SVincenzo Maffione 	*k = -1;
17982a8682a8SVincenzo Maffione 	if (*scan == '-') {
17992a8682a8SVincenzo Maffione 		scan++;
18002a8682a8SVincenzo Maffione 		goto get_k;
18012a8682a8SVincenzo Maffione 	}
18022a8682a8SVincenzo Maffione 	if (!isdigit(*scan))
18032a8682a8SVincenzo Maffione 		goto err;
18042a8682a8SVincenzo Maffione 	*k = strtol(scan, &rest, 10);
18052a8682a8SVincenzo Maffione 	*j = *k - 1;
18062a8682a8SVincenzo Maffione 	scan = rest;
18072a8682a8SVincenzo Maffione 	if (*scan == '-') {
18082a8682a8SVincenzo Maffione 		*k = -1;
18092a8682a8SVincenzo Maffione 		scan++;
18102a8682a8SVincenzo Maffione 	}
18112a8682a8SVincenzo Maffione get_k:
18122a8682a8SVincenzo Maffione 	if (*scan == '\0')
18132a8682a8SVincenzo Maffione 		return 0;
18142a8682a8SVincenzo Maffione 	if (!isdigit(*scan))
18152a8682a8SVincenzo Maffione 		goto err;
18162a8682a8SVincenzo Maffione 	*k = strtol(scan, &rest, 10);
18172a8682a8SVincenzo Maffione 	scan = rest;
18182a8682a8SVincenzo Maffione 	if (!(*scan == '\0'))
18192a8682a8SVincenzo Maffione 		goto err;
18202a8682a8SVincenzo Maffione 
18212a8682a8SVincenzo Maffione 	return 0;
18222a8682a8SVincenzo Maffione 
18232a8682a8SVincenzo Maffione err:
18242a8682a8SVincenzo Maffione 	fprintf(stderr, "syntax error in '%s', must be num[-[num]] or -[num]\n", arg);
18252a8682a8SVincenzo Maffione 	return -1;
18262a8682a8SVincenzo Maffione }
18272a8682a8SVincenzo Maffione 
18282a8682a8SVincenzo Maffione #define ARGV_APPEND(_av, _ac, _x)\
18292a8682a8SVincenzo Maffione 	do {\
18302a8682a8SVincenzo Maffione 		assert((int)(_ac) < (int)(sizeof(_av)/sizeof((_av)[0])));\
18312a8682a8SVincenzo Maffione 		(_av)[(_ac)++] = _x;\
18322a8682a8SVincenzo Maffione 	} while (0)
18332a8682a8SVincenzo Maffione 
18342a8682a8SVincenzo Maffione static void
tap_cleanup(int signo)18352a8682a8SVincenzo Maffione tap_cleanup(int signo)
18362a8682a8SVincenzo Maffione {
18372a8682a8SVincenzo Maffione 	const char *av[8];
18382a8682a8SVincenzo Maffione 	int ac = 0;
18392a8682a8SVincenzo Maffione 
18402a8682a8SVincenzo Maffione 	(void)signo;
18412a8682a8SVincenzo Maffione #ifdef __FreeBSD__
18422a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, "ifconfig");
18432a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, ctx_.ifname);
18442a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, "destroy");
18452a8682a8SVincenzo Maffione #else
18462a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, "ip");
18472a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, "link");
18482a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, "del");
18492a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, ctx_.ifname);
18502a8682a8SVincenzo Maffione #endif
18512a8682a8SVincenzo Maffione 	ARGV_APPEND(av, ac, NULL);
18522a8682a8SVincenzo Maffione 	if (exec_command(ac, av)) {
18532a8682a8SVincenzo Maffione 		printf("Failed to destroy tap interface\n");
18542a8682a8SVincenzo Maffione 	}
18552a8682a8SVincenzo Maffione }
18562a8682a8SVincenzo Maffione 
18572a8682a8SVincenzo Maffione int
main(int argc,char ** argv)18582a8682a8SVincenzo Maffione main(int argc, char **argv)
18592a8682a8SVincenzo Maffione {
18602a8682a8SVincenzo Maffione 	int create_tap = 1;
18612a8682a8SVincenzo Maffione 	int num_tests;
18622a8682a8SVincenzo Maffione 	int ret  = 0;
18632a8682a8SVincenzo Maffione 	int j    = 0;
18642a8682a8SVincenzo Maffione 	int k    = -1;
18652a8682a8SVincenzo Maffione 	int list = 0;
18662a8682a8SVincenzo Maffione 	int opt;
18672a8682a8SVincenzo Maffione 	int i;
18682a8682a8SVincenzo Maffione 
18697d757b71SOlivier Cochard #ifdef __FreeBSD__
18707d757b71SOlivier Cochard 	PLAIN_REQUIRE_KERNEL_MODULE("if_tap", 0);
1871c9c9de93SEnji Cooper 	PLAIN_REQUIRE_KERNEL_MODULE("netmap", 0);
18727d757b71SOlivier Cochard #endif
18737d757b71SOlivier Cochard 
18742a8682a8SVincenzo Maffione 	memset(&ctx_, 0, sizeof(ctx_));
18752a8682a8SVincenzo Maffione 
18762a8682a8SVincenzo Maffione 	{
18772a8682a8SVincenzo Maffione 		struct timespec t;
18782a8682a8SVincenzo Maffione 		int idx;
18792a8682a8SVincenzo Maffione 
18802a8682a8SVincenzo Maffione 		clock_gettime(CLOCK_REALTIME, &t);
18812a8682a8SVincenzo Maffione 		srand((unsigned int)t.tv_nsec);
18822a8682a8SVincenzo Maffione 		idx = rand() % 8000 + 100;
18832a8682a8SVincenzo Maffione 		snprintf(ctx_.ifname, sizeof(ctx_.ifname), "tap%d", idx);
18842a8682a8SVincenzo Maffione 		idx = rand() % 800 + 100;
18852a8682a8SVincenzo Maffione 		snprintf(ctx_.bdgname, sizeof(ctx_.bdgname), "vale%d", idx);
18862a8682a8SVincenzo Maffione 	}
18872a8682a8SVincenzo Maffione 
18882a8682a8SVincenzo Maffione 	while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
18892a8682a8SVincenzo Maffione 		switch (opt) {
18902a8682a8SVincenzo Maffione 		case 'h':
18912a8682a8SVincenzo Maffione 			usage(argv[0]);
18922a8682a8SVincenzo Maffione 			return 0;
18932a8682a8SVincenzo Maffione 
18942a8682a8SVincenzo Maffione 		case 'i':
18952a8682a8SVincenzo Maffione 			strncpy(ctx_.ifname, optarg, sizeof(ctx_.ifname) - 1);
18962a8682a8SVincenzo Maffione 			create_tap = 0;
18972a8682a8SVincenzo Maffione 			break;
18982a8682a8SVincenzo Maffione 
18992a8682a8SVincenzo Maffione 		case 'j':
19002a8682a8SVincenzo Maffione 			if (parse_interval(optarg, &j, &k) < 0) {
19012a8682a8SVincenzo Maffione 				usage(argv[0]);
19022a8682a8SVincenzo Maffione 				return -1;
19032a8682a8SVincenzo Maffione 			}
19042a8682a8SVincenzo Maffione 			break;
19052a8682a8SVincenzo Maffione 
19062a8682a8SVincenzo Maffione 		case 'l':
19072a8682a8SVincenzo Maffione 			list = 1;
19082a8682a8SVincenzo Maffione 			create_tap = 0;
19092a8682a8SVincenzo Maffione 			break;
19102a8682a8SVincenzo Maffione 
19112a8682a8SVincenzo Maffione 		default:
19122a8682a8SVincenzo Maffione 			printf("    Unrecognized option %c\n", opt);
19132a8682a8SVincenzo Maffione 			usage(argv[0]);
19142a8682a8SVincenzo Maffione 			return -1;
19152a8682a8SVincenzo Maffione 		}
19162a8682a8SVincenzo Maffione 	}
19172a8682a8SVincenzo Maffione 
19182a8682a8SVincenzo Maffione 	num_tests = sizeof(tests) / sizeof(tests[0]);
19192a8682a8SVincenzo Maffione 
19202a8682a8SVincenzo Maffione 	if (j < 0 || j >= num_tests || k > num_tests) {
19212a8682a8SVincenzo Maffione 		fprintf(stderr, "Test interval %d-%d out of range (%d-%d)\n",
19222a8682a8SVincenzo Maffione 				j + 1, k, 1, num_tests + 1);
19232a8682a8SVincenzo Maffione 		return -1;
19242a8682a8SVincenzo Maffione 	}
19252a8682a8SVincenzo Maffione 
19262a8682a8SVincenzo Maffione 	if (k < 0)
19272a8682a8SVincenzo Maffione 		k = num_tests;
19282a8682a8SVincenzo Maffione 
19292a8682a8SVincenzo Maffione 	if (list) {
19302a8682a8SVincenzo Maffione 		printf("Available tests:\n");
19312a8682a8SVincenzo Maffione 		for (i = 0; i < num_tests; i++) {
19322a8682a8SVincenzo Maffione 			printf("#%03d: %s\n", i + 1, tests[i].name);
19332a8682a8SVincenzo Maffione 		}
19342a8682a8SVincenzo Maffione 		return 0;
19352a8682a8SVincenzo Maffione 	}
19362a8682a8SVincenzo Maffione 
19372a8682a8SVincenzo Maffione 	if (create_tap) {
19382a8682a8SVincenzo Maffione 		struct sigaction sa;
19392a8682a8SVincenzo Maffione 		const char *av[8];
19402a8682a8SVincenzo Maffione 		int ac = 0;
19412a8682a8SVincenzo Maffione #ifdef __FreeBSD__
19422a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "ifconfig");
19432a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, ctx_.ifname);
19442a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "create");
19452a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "up");
19462a8682a8SVincenzo Maffione #else
19472a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "ip");
19482a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "tuntap");
19492a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "add");
19502a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "mode");
19512a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "tap");
19522a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, "name");
19532a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, ctx_.ifname);
19542a8682a8SVincenzo Maffione #endif
19552a8682a8SVincenzo Maffione 		ARGV_APPEND(av, ac, NULL);
19562a8682a8SVincenzo Maffione 		if (exec_command(ac, av)) {
19572a8682a8SVincenzo Maffione 			printf("Failed to create tap interface\n");
19582a8682a8SVincenzo Maffione 			return -1;
19592a8682a8SVincenzo Maffione 		}
19602a8682a8SVincenzo Maffione 
19612a8682a8SVincenzo Maffione 		sa.sa_handler = tap_cleanup;
19622a8682a8SVincenzo Maffione 		sigemptyset(&sa.sa_mask);
19632a8682a8SVincenzo Maffione 		sa.sa_flags = SA_RESTART;
19642a8682a8SVincenzo Maffione 		ret         = sigaction(SIGINT, &sa, NULL);
19652a8682a8SVincenzo Maffione 		if (ret) {
19662a8682a8SVincenzo Maffione 			perror("sigaction(SIGINT)");
19672a8682a8SVincenzo Maffione 			goto out;
19682a8682a8SVincenzo Maffione 		}
19692a8682a8SVincenzo Maffione 		ret = sigaction(SIGTERM, &sa, NULL);
19702a8682a8SVincenzo Maffione 		if (ret) {
19712a8682a8SVincenzo Maffione 			perror("sigaction(SIGTERM)");
19722a8682a8SVincenzo Maffione 			goto out;
19732a8682a8SVincenzo Maffione 		}
19742a8682a8SVincenzo Maffione 	}
19752a8682a8SVincenzo Maffione 
19762a8682a8SVincenzo Maffione 	for (i = j; i < k; i++) {
19772a8682a8SVincenzo Maffione 		struct TestContext ctxcopy;
19782a8682a8SVincenzo Maffione 		int fd;
19792a8682a8SVincenzo Maffione 		printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
19802a8682a8SVincenzo Maffione 		fd = open("/dev/netmap", O_RDWR);
19812a8682a8SVincenzo Maffione 		if (fd < 0) {
19822a8682a8SVincenzo Maffione 			perror("open(/dev/netmap)");
19832a8682a8SVincenzo Maffione 			ret = fd;
19842a8682a8SVincenzo Maffione 			goto out;
19852a8682a8SVincenzo Maffione 		}
19862a8682a8SVincenzo Maffione 		memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
19872a8682a8SVincenzo Maffione 		ctxcopy.fd = fd;
198808f34ad9SVincenzo Maffione 		memcpy(ctxcopy.ifname_ext, ctxcopy.ifname,
198908f34ad9SVincenzo Maffione 			sizeof(ctxcopy.ifname));
19902a8682a8SVincenzo Maffione 		ret        = tests[i].test(&ctxcopy);
19912a8682a8SVincenzo Maffione 		if (ret != 0) {
19922a8682a8SVincenzo Maffione 			printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
19932a8682a8SVincenzo Maffione 			goto out;
19942a8682a8SVincenzo Maffione 		}
19952a8682a8SVincenzo Maffione 		printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
19962a8682a8SVincenzo Maffione 		context_cleanup(&ctxcopy);
19972a8682a8SVincenzo Maffione 	}
19982a8682a8SVincenzo Maffione out:
19992a8682a8SVincenzo Maffione 	tap_cleanup(0);
20002a8682a8SVincenzo Maffione 
20012a8682a8SVincenzo Maffione 	return ret;
20022a8682a8SVincenzo Maffione }
2003