11b1076c4SVincenzo Maffione /*-
21b1076c4SVincenzo Maffione  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
31b1076c4SVincenzo Maffione  *
41b1076c4SVincenzo Maffione  * Copyright (C) 2018 Vincenzo Maffione
51b1076c4SVincenzo Maffione  *
61b1076c4SVincenzo Maffione  * Redistribution and use in source and binary forms, with or without
71b1076c4SVincenzo Maffione  * modification, are permitted provided that the following conditions
81b1076c4SVincenzo Maffione  * are met:
91b1076c4SVincenzo Maffione  *   1. Redistributions of source code must retain the above copyright
101b1076c4SVincenzo Maffione  *      notice, this list of conditions and the following disclaimer.
111b1076c4SVincenzo Maffione  *   2. Redistributions in binary form must reproduce the above copyright
121b1076c4SVincenzo Maffione  *      notice, this list of conditions and the following disclaimer in the
131b1076c4SVincenzo Maffione  *      documentation and/or other materials provided with the distribution.
141b1076c4SVincenzo Maffione  *
151b1076c4SVincenzo Maffione  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
161b1076c4SVincenzo Maffione  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
171b1076c4SVincenzo Maffione  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
181b1076c4SVincenzo Maffione  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
191b1076c4SVincenzo Maffione  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
201b1076c4SVincenzo Maffione  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
211b1076c4SVincenzo Maffione  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221b1076c4SVincenzo Maffione  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
231b1076c4SVincenzo Maffione  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
241b1076c4SVincenzo Maffione  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
251b1076c4SVincenzo Maffione  * SUCH DAMAGE.
261b1076c4SVincenzo Maffione  *
271b1076c4SVincenzo Maffione  * $FreeBSD$
281b1076c4SVincenzo Maffione  */
291b1076c4SVincenzo Maffione 
301b1076c4SVincenzo Maffione #include <sys/ioctl.h>
311b1076c4SVincenzo Maffione #include <sys/mman.h>
321b1076c4SVincenzo Maffione #include <sys/wait.h>
331b1076c4SVincenzo Maffione 
341b1076c4SVincenzo Maffione #include <assert.h>
351b1076c4SVincenzo Maffione #include <ctype.h>
361b1076c4SVincenzo Maffione #include <errno.h>
371b1076c4SVincenzo Maffione #include <fcntl.h>
381b1076c4SVincenzo Maffione #include <inttypes.h>
391b1076c4SVincenzo Maffione #include <net/if.h>
401b1076c4SVincenzo Maffione #include <net/netmap.h>
411b1076c4SVincenzo Maffione #include <pthread.h>
421b1076c4SVincenzo Maffione #include <semaphore.h>
431b1076c4SVincenzo Maffione #include <stdint.h>
441b1076c4SVincenzo Maffione #include <stdio.h>
451b1076c4SVincenzo Maffione #include <stdlib.h>
461b1076c4SVincenzo Maffione #include <string.h>
471b1076c4SVincenzo Maffione #include <time.h>
481b1076c4SVincenzo Maffione #include <unistd.h>
491b1076c4SVincenzo Maffione #include <signal.h>
501b1076c4SVincenzo Maffione 
5105e2b301SEnji Cooper #ifdef __FreeBSD__
5205e2b301SEnji Cooper #include "freebsd_test_suite/macros.h"
5305e2b301SEnji Cooper 
541b1076c4SVincenzo Maffione static int
eventfd(int x __unused,int y __unused)551b1076c4SVincenzo Maffione eventfd(int x __unused, int y __unused)
561b1076c4SVincenzo Maffione {
571b1076c4SVincenzo Maffione 	errno = ENODEV;
581b1076c4SVincenzo Maffione 	return -1;
591b1076c4SVincenzo Maffione }
60*06a67b22SVincenzo Maffione #else /* __linux__ */
61*06a67b22SVincenzo Maffione #include <sys/eventfd.h>
62*06a67b22SVincenzo Maffione #endif
631b1076c4SVincenzo Maffione 
641b1076c4SVincenzo Maffione static int
exec_command(int argc,const char * const argv[])651b1076c4SVincenzo Maffione exec_command(int argc, const char *const argv[])
661b1076c4SVincenzo Maffione {
671b1076c4SVincenzo Maffione 	pid_t child_pid;
681b1076c4SVincenzo Maffione 	pid_t wret;
691b1076c4SVincenzo Maffione 	int child_status;
701b1076c4SVincenzo Maffione 	int i;
711b1076c4SVincenzo Maffione 
721b1076c4SVincenzo Maffione 	printf("Executing command: ");
731b1076c4SVincenzo Maffione 	for (i = 0; i < argc - 1; i++) {
741b1076c4SVincenzo Maffione 		if (!argv[i]) {
751b1076c4SVincenzo Maffione 			/* Invalid argument. */
761b1076c4SVincenzo Maffione 			return -1;
771b1076c4SVincenzo Maffione 		}
781b1076c4SVincenzo Maffione 		if (i > 0) {
791b1076c4SVincenzo Maffione 			putchar(' ');
801b1076c4SVincenzo Maffione 		}
811b1076c4SVincenzo Maffione 		printf("%s", argv[i]);
821b1076c4SVincenzo Maffione 	}
831b1076c4SVincenzo Maffione 	putchar('\n');
841b1076c4SVincenzo Maffione 
851b1076c4SVincenzo Maffione 	child_pid = fork();
861b1076c4SVincenzo Maffione 	if (child_pid == 0) {
871b1076c4SVincenzo Maffione 		char **av;
887c72d869SVincenzo Maffione 		int fds[3];
891b1076c4SVincenzo Maffione 
901b1076c4SVincenzo Maffione 		/* Child process. Redirect stdin, stdout
911b1076c4SVincenzo Maffione 		 * and stderr. */
927c72d869SVincenzo Maffione 		for (i = 0; i < 3; i++) {
937c72d869SVincenzo Maffione 			close(i);
947c72d869SVincenzo Maffione 			fds[i] = open("/dev/null", O_RDONLY);
957c72d869SVincenzo Maffione 			if (fds[i] < 0) {
967c72d869SVincenzo Maffione 				for (i--; i >= 0; i--) {
977c72d869SVincenzo Maffione 					close(fds[i]);
987c72d869SVincenzo Maffione 				}
991b1076c4SVincenzo Maffione 				return -1;
1001b1076c4SVincenzo Maffione 			}
1017c72d869SVincenzo Maffione 		}
1021b1076c4SVincenzo Maffione 
1031b1076c4SVincenzo Maffione 		/* Make a copy of the arguments, passing them to execvp. */
1041b1076c4SVincenzo Maffione 		av = calloc(argc, sizeof(av[0]));
1051b1076c4SVincenzo Maffione 		if (!av) {
1061b1076c4SVincenzo Maffione 			exit(EXIT_FAILURE);
1071b1076c4SVincenzo Maffione 		}
1081b1076c4SVincenzo Maffione 		for (i = 0; i < argc - 1; i++) {
1091b1076c4SVincenzo Maffione 			av[i] = strdup(argv[i]);
1101b1076c4SVincenzo Maffione 			if (!av[i]) {
1111b1076c4SVincenzo Maffione 				exit(EXIT_FAILURE);
1121b1076c4SVincenzo Maffione 			}
1131b1076c4SVincenzo Maffione 		}
1141b1076c4SVincenzo Maffione 		execvp(av[0], av);
1151b1076c4SVincenzo Maffione 		perror("execvp()");
1161b1076c4SVincenzo Maffione 		exit(EXIT_FAILURE);
1171b1076c4SVincenzo Maffione 	}
1181b1076c4SVincenzo Maffione 
1191b1076c4SVincenzo Maffione 	wret = waitpid(child_pid, &child_status, 0);
1201b1076c4SVincenzo Maffione 	if (wret < 0) {
1211b1076c4SVincenzo Maffione 		fprintf(stderr, "waitpid() failed: %s\n", strerror(errno));
1221b1076c4SVincenzo Maffione 		return wret;
1231b1076c4SVincenzo Maffione 	}
1241b1076c4SVincenzo Maffione 	if (WIFEXITED(child_status)) {
1251b1076c4SVincenzo Maffione 		return WEXITSTATUS(child_status);
1261b1076c4SVincenzo Maffione 	}
1271b1076c4SVincenzo Maffione 
1281b1076c4SVincenzo Maffione 	return -1;
1291b1076c4SVincenzo Maffione }
1301b1076c4SVincenzo Maffione 
1311b1076c4SVincenzo Maffione 
1321b1076c4SVincenzo Maffione #define THRET_SUCCESS	((void *)128)
1331b1076c4SVincenzo Maffione #define THRET_FAILURE	((void *)0)
1341b1076c4SVincenzo Maffione 
1351b1076c4SVincenzo Maffione struct TestContext {
1367c72d869SVincenzo Maffione 	char ifname[64];
1377c72d869SVincenzo Maffione 	char ifname_ext[128];
1381b1076c4SVincenzo Maffione 	char bdgname[64];
1391b1076c4SVincenzo Maffione 	uint32_t nr_tx_slots;   /* slots in tx rings */
1401b1076c4SVincenzo Maffione 	uint32_t nr_rx_slots;   /* slots in rx rings */
1411b1076c4SVincenzo Maffione 	uint16_t nr_tx_rings;   /* number of tx rings */
1421b1076c4SVincenzo Maffione 	uint16_t nr_rx_rings;   /* number of rx rings */
143*06a67b22SVincenzo Maffione 	uint16_t nr_host_tx_rings;   /* number of host tx rings */
144*06a67b22SVincenzo Maffione 	uint16_t nr_host_rx_rings;   /* number of host rx rings */
1451b1076c4SVincenzo Maffione 	uint16_t nr_mem_id;     /* id of the memory allocator */
1461b1076c4SVincenzo Maffione 	uint16_t nr_ringid;     /* ring(s) we care about */
1471b1076c4SVincenzo Maffione 	uint32_t nr_mode;       /* specify NR_REG_* modes */
1481b1076c4SVincenzo Maffione 	uint32_t nr_extra_bufs; /* number of requested extra buffers */
1491b1076c4SVincenzo Maffione 	uint64_t nr_flags;      /* additional flags (see below) */
1501b1076c4SVincenzo Maffione 	uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
1511b1076c4SVincenzo Maffione 	uint32_t nr_first_cpu_id;     /* vale polling */
1521b1076c4SVincenzo Maffione 	uint32_t nr_num_polling_cpus; /* vale polling */
1537af42e83SVincenzo Maffione 	uint32_t sync_kloop_mode; /* sync-kloop */
1541b1076c4SVincenzo Maffione 	int fd; /* netmap file descriptor */
1551b1076c4SVincenzo Maffione 
1561b1076c4SVincenzo Maffione 	void *csb;                    /* CSB entries (atok and ktoa) */
1571b1076c4SVincenzo Maffione 	struct nmreq_option *nr_opt;  /* list of options */
1581b1076c4SVincenzo Maffione 	sem_t *sem;	/* for thread synchronization */
1591b1076c4SVincenzo Maffione };
1601b1076c4SVincenzo Maffione 
1611b1076c4SVincenzo Maffione static struct TestContext ctx_;
1621b1076c4SVincenzo Maffione 
1631b1076c4SVincenzo Maffione typedef int (*testfunc_t)(struct TestContext *ctx);
1641b1076c4SVincenzo Maffione 
1651b1076c4SVincenzo Maffione static void
nmreq_hdr_init(struct nmreq_header * hdr,const char * ifname)1661b1076c4SVincenzo Maffione nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
1671b1076c4SVincenzo Maffione {
1681b1076c4SVincenzo Maffione 	memset(hdr, 0, sizeof(*hdr));
1691b1076c4SVincenzo Maffione 	hdr->nr_version = NETMAP_API;
1701b1076c4SVincenzo Maffione 	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name) - 1);
1711b1076c4SVincenzo Maffione }
1721b1076c4SVincenzo Maffione 
1731b1076c4SVincenzo Maffione /* Single NETMAP_REQ_PORT_INFO_GET. */
1741b1076c4SVincenzo Maffione static int
port_info_get(struct TestContext * ctx)1751b1076c4SVincenzo Maffione port_info_get(struct TestContext *ctx)
1761b1076c4SVincenzo Maffione {
1771b1076c4SVincenzo Maffione 	struct nmreq_port_info_get req;
1781b1076c4SVincenzo Maffione 	struct nmreq_header hdr;
1791b1076c4SVincenzo Maffione 	int success;
1801b1076c4SVincenzo Maffione 	int ret;
1811b1076c4SVincenzo Maffione 
1827c72d869SVincenzo Maffione 	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname_ext);
1831b1076c4SVincenzo Maffione 
1847c72d869SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
1851b1076c4SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
1861b1076c4SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
1871b1076c4SVincenzo Maffione 	memset(&req, 0, sizeof(req));
1881b1076c4SVincenzo Maffione 	req.nr_mem_id = ctx->nr_mem_id;
1891b1076c4SVincenzo Maffione 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
1901b1076c4SVincenzo Maffione 	if (ret != 0) {
1911b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
1921b1076c4SVincenzo Maffione 		return ret;
1931b1076c4SVincenzo Maffione 	}
1941b1076c4SVincenzo Maffione 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
1951b1076c4SVincenzo Maffione 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
1961b1076c4SVincenzo Maffione 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
1971b1076c4SVincenzo Maffione 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
1981b1076c4SVincenzo Maffione 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
1991b1076c4SVincenzo Maffione 	printf("nr_mem_id %u\n", req.nr_mem_id);
2001b1076c4SVincenzo Maffione 
2011b1076c4SVincenzo Maffione 	success = req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
2021b1076c4SVincenzo Maffione 	          req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings;
2031b1076c4SVincenzo Maffione 	if (!success) {
2041b1076c4SVincenzo Maffione 		return -1;
2051b1076c4SVincenzo Maffione 	}
2061b1076c4SVincenzo Maffione 
2071b1076c4SVincenzo Maffione 	/* Write back results to the context structure. */
2081b1076c4SVincenzo Maffione 	ctx->nr_tx_slots = req.nr_tx_slots;
2091b1076c4SVincenzo Maffione 	ctx->nr_rx_slots = req.nr_rx_slots;
2101b1076c4SVincenzo Maffione 	ctx->nr_tx_rings = req.nr_tx_rings;
2111b1076c4SVincenzo Maffione 	ctx->nr_rx_rings = req.nr_rx_rings;
2121b1076c4SVincenzo Maffione 	ctx->nr_mem_id   = req.nr_mem_id;
2131b1076c4SVincenzo Maffione 
2141b1076c4SVincenzo Maffione 	return 0;
2151b1076c4SVincenzo Maffione }
2161b1076c4SVincenzo Maffione 
2171b1076c4SVincenzo Maffione /* Single NETMAP_REQ_REGISTER, no use. */
2181b1076c4SVincenzo Maffione static int
port_register(struct TestContext * ctx)2191b1076c4SVincenzo Maffione port_register(struct TestContext *ctx)
2201b1076c4SVincenzo Maffione {
2211b1076c4SVincenzo Maffione 	struct nmreq_register req;
2221b1076c4SVincenzo Maffione 	struct nmreq_header hdr;
2231b1076c4SVincenzo Maffione 	int success;
2241b1076c4SVincenzo Maffione 	int ret;
2251b1076c4SVincenzo Maffione 
2261b1076c4SVincenzo Maffione 	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
2271b1076c4SVincenzo Maffione 	       "flags=0x%llx) on '%s'\n",
2281b1076c4SVincenzo Maffione 	       ctx->nr_mode, ctx->nr_ringid, (unsigned long long)ctx->nr_flags,
2297c72d869SVincenzo Maffione 	       ctx->ifname_ext);
2301b1076c4SVincenzo Maffione 
2317c72d869SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
2321b1076c4SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
2331b1076c4SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
2341b1076c4SVincenzo Maffione 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
2351b1076c4SVincenzo Maffione 	memset(&req, 0, sizeof(req));
2361b1076c4SVincenzo Maffione 	req.nr_mem_id     = ctx->nr_mem_id;
2371b1076c4SVincenzo Maffione 	req.nr_mode       = ctx->nr_mode;
2381b1076c4SVincenzo Maffione 	req.nr_ringid     = ctx->nr_ringid;
2391b1076c4SVincenzo Maffione 	req.nr_flags      = ctx->nr_flags;
2401b1076c4SVincenzo Maffione 	req.nr_tx_slots   = ctx->nr_tx_slots;
2411b1076c4SVincenzo Maffione 	req.nr_rx_slots   = ctx->nr_rx_slots;
2421b1076c4SVincenzo Maffione 	req.nr_tx_rings   = ctx->nr_tx_rings;
243*06a67b22SVincenzo Maffione 	req.nr_host_tx_rings = ctx->nr_host_tx_rings;
244*06a67b22SVincenzo Maffione 	req.nr_host_rx_rings = ctx->nr_host_rx_rings;
2451b1076c4SVincenzo Maffione 	req.nr_rx_rings   = ctx->nr_rx_rings;
2461b1076c4SVincenzo Maffione 	req.nr_extra_bufs = ctx->nr_extra_bufs;
2471b1076c4SVincenzo Maffione 	ret               = ioctl(ctx->fd, NIOCCTRL, &hdr);
2481b1076c4SVincenzo Maffione 	if (ret != 0) {
2491b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
2501b1076c4SVincenzo Maffione 		return ret;
2511b1076c4SVincenzo Maffione 	}
2521b1076c4SVincenzo Maffione 	printf("nr_offset 0x%llx\n", (unsigned long long)req.nr_offset);
2531b1076c4SVincenzo Maffione 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
2541b1076c4SVincenzo Maffione 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
2551b1076c4SVincenzo Maffione 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
2561b1076c4SVincenzo Maffione 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
2571b1076c4SVincenzo Maffione 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
258*06a67b22SVincenzo Maffione 	printf("nr_host_tx_rings %u\n", req.nr_host_tx_rings);
259*06a67b22SVincenzo Maffione 	printf("nr_host_rx_rings %u\n", req.nr_host_rx_rings);
2601b1076c4SVincenzo Maffione 	printf("nr_mem_id %u\n", req.nr_mem_id);
2611b1076c4SVincenzo Maffione 	printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
2621b1076c4SVincenzo Maffione 
2631b1076c4SVincenzo Maffione 	success = req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
2641b1076c4SVincenzo Maffione 		       (ctx->nr_ringid == req.nr_ringid) &&
2651b1076c4SVincenzo Maffione 		       (ctx->nr_flags == req.nr_flags) &&
2661b1076c4SVincenzo Maffione 		       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
2671b1076c4SVincenzo Maffione 			(ctx->nr_tx_slots == req.nr_tx_slots)) &&
2681b1076c4SVincenzo Maffione 		       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
2691b1076c4SVincenzo Maffione 			(ctx->nr_rx_slots == req.nr_rx_slots)) &&
2701b1076c4SVincenzo Maffione 		       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
2711b1076c4SVincenzo Maffione 			(ctx->nr_tx_rings == req.nr_tx_rings)) &&
2721b1076c4SVincenzo Maffione 		       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
2731b1076c4SVincenzo Maffione 			(ctx->nr_rx_rings == req.nr_rx_rings)) &&
274*06a67b22SVincenzo Maffione 		       ((!ctx->nr_host_tx_rings && req.nr_host_tx_rings) ||
275*06a67b22SVincenzo Maffione 			(ctx->nr_host_tx_rings == req.nr_host_tx_rings)) &&
276*06a67b22SVincenzo Maffione 		       ((!ctx->nr_host_rx_rings && req.nr_host_rx_rings) ||
277*06a67b22SVincenzo Maffione 			(ctx->nr_host_rx_rings == req.nr_host_rx_rings)) &&
2781b1076c4SVincenzo Maffione 		       ((!ctx->nr_mem_id && req.nr_mem_id) ||
2791b1076c4SVincenzo Maffione 			(ctx->nr_mem_id == req.nr_mem_id)) &&
2801b1076c4SVincenzo Maffione 		       (ctx->nr_extra_bufs == req.nr_extra_bufs);
2811b1076c4SVincenzo Maffione 	if (!success) {
2821b1076c4SVincenzo Maffione 		return -1;
2831b1076c4SVincenzo Maffione 	}
2841b1076c4SVincenzo Maffione 
2851b1076c4SVincenzo Maffione 	/* Write back results to the context structure.*/
2861b1076c4SVincenzo Maffione 	ctx->nr_tx_slots   = req.nr_tx_slots;
2871b1076c4SVincenzo Maffione 	ctx->nr_rx_slots   = req.nr_rx_slots;
2881b1076c4SVincenzo Maffione 	ctx->nr_tx_rings   = req.nr_tx_rings;
2891b1076c4SVincenzo Maffione 	ctx->nr_rx_rings   = req.nr_rx_rings;
290*06a67b22SVincenzo Maffione 	ctx->nr_host_tx_rings = req.nr_host_tx_rings;
291*06a67b22SVincenzo Maffione 	ctx->nr_host_rx_rings = req.nr_host_rx_rings;
2921b1076c4SVincenzo Maffione 	ctx->nr_mem_id     = req.nr_mem_id;
2931b1076c4SVincenzo Maffione 	ctx->nr_extra_bufs = req.nr_extra_bufs;
2941b1076c4SVincenzo Maffione 
2951b1076c4SVincenzo Maffione 	return 0;
2961b1076c4SVincenzo Maffione }
2971b1076c4SVincenzo Maffione 
2981b1076c4SVincenzo Maffione static int
niocregif(struct TestContext * ctx,int netmap_api)2991b1076c4SVincenzo Maffione niocregif(struct TestContext *ctx, int netmap_api)
3001b1076c4SVincenzo Maffione {
3011b1076c4SVincenzo Maffione 	struct nmreq req;
3021b1076c4SVincenzo Maffione 	int success;
3031b1076c4SVincenzo Maffione 	int ret;
3041b1076c4SVincenzo Maffione 
3057c72d869SVincenzo Maffione 	printf("Testing legacy NIOCREGIF on '%s'\n", ctx->ifname_ext);
3061b1076c4SVincenzo Maffione 
3071b1076c4SVincenzo Maffione 	memset(&req, 0, sizeof(req));
3087c72d869SVincenzo Maffione 	memcpy(req.nr_name, ctx->ifname_ext, sizeof(req.nr_name));
3091b1076c4SVincenzo Maffione 	req.nr_name[sizeof(req.nr_name) - 1] = '\0';
3101b1076c4SVincenzo Maffione 	req.nr_version = netmap_api;
3111b1076c4SVincenzo Maffione 	req.nr_ringid     = ctx->nr_ringid;
3121b1076c4SVincenzo Maffione 	req.nr_flags      = ctx->nr_mode | ctx->nr_flags;
3131b1076c4SVincenzo Maffione 	req.nr_tx_slots   = ctx->nr_tx_slots;
3141b1076c4SVincenzo Maffione 	req.nr_rx_slots   = ctx->nr_rx_slots;
3151b1076c4SVincenzo Maffione 	req.nr_tx_rings   = ctx->nr_tx_rings;
3161b1076c4SVincenzo Maffione 	req.nr_rx_rings   = ctx->nr_rx_rings;
3171b1076c4SVincenzo Maffione 	req.nr_arg2     = ctx->nr_mem_id;
3181b1076c4SVincenzo Maffione 	req.nr_arg3 = ctx->nr_extra_bufs;
3191b1076c4SVincenzo Maffione 
3201b1076c4SVincenzo Maffione 	ret = ioctl(ctx->fd, NIOCREGIF, &req);
3211b1076c4SVincenzo Maffione 	if (ret != 0) {
3221b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCREGIF)");
3231b1076c4SVincenzo Maffione 		return ret;
3241b1076c4SVincenzo Maffione 	}
3251b1076c4SVincenzo Maffione 
3261b1076c4SVincenzo Maffione 	printf("nr_offset 0x%x\n", req.nr_offset);
3271b1076c4SVincenzo Maffione 	printf("nr_memsize  %u\n", req.nr_memsize);
3281b1076c4SVincenzo Maffione 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
3291b1076c4SVincenzo Maffione 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
3301b1076c4SVincenzo Maffione 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
3311b1076c4SVincenzo Maffione 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
3321b1076c4SVincenzo Maffione 	printf("nr_version  %d\n", req.nr_version);
3331b1076c4SVincenzo Maffione 	printf("nr_ringid   %x\n", req.nr_ringid);
3341b1076c4SVincenzo Maffione 	printf("nr_flags    %x\n", req.nr_flags);
3351b1076c4SVincenzo Maffione 	printf("nr_arg2     %u\n", req.nr_arg2);
3361b1076c4SVincenzo Maffione 	printf("nr_arg3     %u\n", req.nr_arg3);
3371b1076c4SVincenzo Maffione 
3381b1076c4SVincenzo Maffione 	success = req.nr_memsize &&
3391b1076c4SVincenzo Maffione 	       (ctx->nr_ringid == req.nr_ringid) &&
3401b1076c4SVincenzo Maffione 	       ((ctx->nr_mode | ctx->nr_flags) == req.nr_flags) &&
3411b1076c4SVincenzo Maffione 	       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
3421b1076c4SVincenzo Maffione 		(ctx->nr_tx_slots == req.nr_tx_slots)) &&
3431b1076c4SVincenzo Maffione 	       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
3441b1076c4SVincenzo Maffione 		(ctx->nr_rx_slots == req.nr_rx_slots)) &&
3451b1076c4SVincenzo Maffione 	       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
3461b1076c4SVincenzo Maffione 		(ctx->nr_tx_rings == req.nr_tx_rings)) &&
3471b1076c4SVincenzo Maffione 	       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
3481b1076c4SVincenzo Maffione 		(ctx->nr_rx_rings == req.nr_rx_rings)) &&
3491b1076c4SVincenzo Maffione 	       ((!ctx->nr_mem_id && req.nr_arg2) ||
3501b1076c4SVincenzo Maffione 		(ctx->nr_mem_id == req.nr_arg2)) &&
3511b1076c4SVincenzo Maffione 	       (ctx->nr_extra_bufs == req.nr_arg3);
3521b1076c4SVincenzo Maffione 	if (!success) {
3531b1076c4SVincenzo Maffione 		return -1;
3541b1076c4SVincenzo Maffione 	}
3551b1076c4SVincenzo Maffione 
3561b1076c4SVincenzo Maffione 	/* Write back results to the context structure.*/
3571b1076c4SVincenzo Maffione 	ctx->nr_tx_slots   = req.nr_tx_slots;
3581b1076c4SVincenzo Maffione 	ctx->nr_rx_slots   = req.nr_rx_slots;
3591b1076c4SVincenzo Maffione 	ctx->nr_tx_rings   = req.nr_tx_rings;
3601b1076c4SVincenzo Maffione 	ctx->nr_rx_rings   = req.nr_rx_rings;
3611b1076c4SVincenzo Maffione 	ctx->nr_mem_id     = req.nr_arg2;
3621b1076c4SVincenzo Maffione 	ctx->nr_extra_bufs = req.nr_arg3;
3631b1076c4SVincenzo Maffione 
3641b1076c4SVincenzo Maffione 	return ret;
3651b1076c4SVincenzo Maffione }
3661b1076c4SVincenzo Maffione 
3671b1076c4SVincenzo Maffione /* The 11 ABI is the one right before the introduction of the new NIOCCTRL
3681b1076c4SVincenzo Maffione  * ABI. The 11 ABI is useful to perform tests with legacy applications
3697af42e83SVincenzo Maffione  * (which use the 11 ABI) and new kernel (which uses 12, or higher).
3707af42e83SVincenzo Maffione  * However, version 14 introduced a change in the layout of struct netmap_if,
3717af42e83SVincenzo Maffione  * so that binary backward compatibility to 11 is not supported anymore.
3727af42e83SVincenzo Maffione  */
3737af42e83SVincenzo Maffione #define NETMAP_API_NIOCREGIF	14
3741b1076c4SVincenzo Maffione 
3751b1076c4SVincenzo Maffione static int
legacy_regif_default(struct TestContext * ctx)3761b1076c4SVincenzo Maffione legacy_regif_default(struct TestContext *ctx)
3771b1076c4SVincenzo Maffione {
3781b1076c4SVincenzo Maffione 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
3791b1076c4SVincenzo Maffione }
3801b1076c4SVincenzo Maffione 
3811b1076c4SVincenzo Maffione static int
legacy_regif_all_nic(struct TestContext * ctx)3821b1076c4SVincenzo Maffione legacy_regif_all_nic(struct TestContext *ctx)
3831b1076c4SVincenzo Maffione {
3841b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
3851b1076c4SVincenzo Maffione 	return niocregif(ctx, NETMAP_API);
3861b1076c4SVincenzo Maffione }
3871b1076c4SVincenzo Maffione 
3881b1076c4SVincenzo Maffione static int
legacy_regif_12(struct TestContext * ctx)3891b1076c4SVincenzo Maffione legacy_regif_12(struct TestContext *ctx)
3901b1076c4SVincenzo Maffione {
3911b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
3921b1076c4SVincenzo Maffione 	return niocregif(ctx, NETMAP_API_NIOCREGIF+1);
3931b1076c4SVincenzo Maffione }
3941b1076c4SVincenzo Maffione 
3951b1076c4SVincenzo Maffione static int
legacy_regif_sw(struct TestContext * ctx)3961b1076c4SVincenzo Maffione legacy_regif_sw(struct TestContext *ctx)
3971b1076c4SVincenzo Maffione {
3981b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_SW;
3991b1076c4SVincenzo Maffione 	return niocregif(ctx,  NETMAP_API_NIOCREGIF);
4001b1076c4SVincenzo Maffione }
4011b1076c4SVincenzo Maffione 
4021b1076c4SVincenzo Maffione static int
legacy_regif_future(struct TestContext * ctx)4031b1076c4SVincenzo Maffione legacy_regif_future(struct TestContext *ctx)
4041b1076c4SVincenzo Maffione {
4051b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_NIC_SW;
4061b1076c4SVincenzo Maffione 	/* Test forward compatibility for the legacy ABI. This means
4071b1076c4SVincenzo Maffione 	 * using an older kernel (with ABI 12 or higher) and a newer
4081b1076c4SVincenzo Maffione 	 * application (with ABI greater than NETMAP_API). */
4091b1076c4SVincenzo Maffione 	return niocregif(ctx, NETMAP_API+2);
4101b1076c4SVincenzo Maffione }
4111b1076c4SVincenzo Maffione 
4121b1076c4SVincenzo Maffione static int
legacy_regif_extra_bufs(struct TestContext * ctx)4131b1076c4SVincenzo Maffione legacy_regif_extra_bufs(struct TestContext *ctx)
4141b1076c4SVincenzo Maffione {
4151b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
4161b1076c4SVincenzo Maffione 	ctx->nr_extra_bufs = 20;	/* arbitrary number of extra bufs */
4171b1076c4SVincenzo Maffione 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
4181b1076c4SVincenzo Maffione }
4191b1076c4SVincenzo Maffione 
4201b1076c4SVincenzo Maffione static int
legacy_regif_extra_bufs_pipe(struct TestContext * ctx)4211b1076c4SVincenzo Maffione legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
4221b1076c4SVincenzo Maffione {
4237c72d869SVincenzo Maffione 	strncat(ctx->ifname_ext, "{pipeexbuf", sizeof(ctx->ifname_ext));
4241b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
4251b1076c4SVincenzo Maffione 	ctx->nr_extra_bufs = 58;	/* arbitrary number of extra bufs */
4261b1076c4SVincenzo Maffione 
4271b1076c4SVincenzo Maffione 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
4281b1076c4SVincenzo Maffione }
4291b1076c4SVincenzo Maffione 
4301b1076c4SVincenzo Maffione static int
legacy_regif_extra_bufs_pipe_vale(struct TestContext * ctx)4311b1076c4SVincenzo Maffione legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
4321b1076c4SVincenzo Maffione {
4337c72d869SVincenzo Maffione 	strncpy(ctx->ifname_ext, "valeX1:Y4", sizeof(ctx->ifname_ext));
4341b1076c4SVincenzo Maffione 	return legacy_regif_extra_bufs_pipe(ctx);
4351b1076c4SVincenzo Maffione }
4361b1076c4SVincenzo Maffione 
4371b1076c4SVincenzo Maffione /* Only valid after a successful port_register(). */
4381b1076c4SVincenzo Maffione static int
num_registered_rings(struct TestContext * ctx)4391b1076c4SVincenzo Maffione num_registered_rings(struct TestContext *ctx)
4401b1076c4SVincenzo Maffione {
4411b1076c4SVincenzo Maffione 	if (ctx->nr_flags & NR_TX_RINGS_ONLY) {
4421b1076c4SVincenzo Maffione 		return ctx->nr_tx_rings;
4431b1076c4SVincenzo Maffione 	}
4441b1076c4SVincenzo Maffione 	if (ctx->nr_flags & NR_RX_RINGS_ONLY) {
4451b1076c4SVincenzo Maffione 		return ctx->nr_rx_rings;
4461b1076c4SVincenzo Maffione 	}
4471b1076c4SVincenzo Maffione 
4481b1076c4SVincenzo Maffione 	return ctx->nr_tx_rings + ctx->nr_rx_rings;
4491b1076c4SVincenzo Maffione }
4501b1076c4SVincenzo Maffione 
4511b1076c4SVincenzo Maffione static int
port_register_hwall_host(struct TestContext * ctx)4521b1076c4SVincenzo Maffione port_register_hwall_host(struct TestContext *ctx)
4531b1076c4SVincenzo Maffione {
4541b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_NIC_SW;
4551b1076c4SVincenzo Maffione 	return port_register(ctx);
4561b1076c4SVincenzo Maffione }
4571b1076c4SVincenzo Maffione 
4581b1076c4SVincenzo Maffione static int
port_register_hostall(struct TestContext * ctx)459*06a67b22SVincenzo Maffione port_register_hostall(struct TestContext *ctx)
4601b1076c4SVincenzo Maffione {
4611b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_SW;
4621b1076c4SVincenzo Maffione 	return port_register(ctx);
4631b1076c4SVincenzo Maffione }
4641b1076c4SVincenzo Maffione 
4651b1076c4SVincenzo Maffione static int
port_register_hwall(struct TestContext * ctx)4661b1076c4SVincenzo Maffione port_register_hwall(struct TestContext *ctx)
4671b1076c4SVincenzo Maffione {
4681b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
4691b1076c4SVincenzo Maffione 	return port_register(ctx);
4701b1076c4SVincenzo Maffione }
4711b1076c4SVincenzo Maffione 
4721b1076c4SVincenzo Maffione static int
port_register_single_hw_pair(struct TestContext * ctx)473*06a67b22SVincenzo Maffione port_register_single_hw_pair(struct TestContext *ctx)
4741b1076c4SVincenzo Maffione {
4751b1076c4SVincenzo Maffione 	ctx->nr_mode   = NR_REG_ONE_NIC;
4761b1076c4SVincenzo Maffione 	ctx->nr_ringid = 0;
4771b1076c4SVincenzo Maffione 	return port_register(ctx);
4781b1076c4SVincenzo Maffione }
4791b1076c4SVincenzo Maffione 
4801b1076c4SVincenzo Maffione static int
port_register_single_host_pair(struct TestContext * ctx)481*06a67b22SVincenzo Maffione port_register_single_host_pair(struct TestContext *ctx)
482*06a67b22SVincenzo Maffione {
483*06a67b22SVincenzo Maffione 	ctx->nr_mode   = NR_REG_ONE_SW;
484*06a67b22SVincenzo Maffione 	ctx->nr_host_tx_rings = 2;
485*06a67b22SVincenzo Maffione 	ctx->nr_host_rx_rings = 2;
486*06a67b22SVincenzo Maffione 	ctx->nr_ringid = 1;
487*06a67b22SVincenzo Maffione 	return port_register(ctx);
488*06a67b22SVincenzo Maffione }
489*06a67b22SVincenzo Maffione 
490*06a67b22SVincenzo Maffione static int
port_register_hostall_many(struct TestContext * ctx)491*06a67b22SVincenzo Maffione port_register_hostall_many(struct TestContext *ctx)
492*06a67b22SVincenzo Maffione {
493*06a67b22SVincenzo Maffione 	ctx->nr_mode   = NR_REG_SW;
494*06a67b22SVincenzo Maffione 	ctx->nr_host_tx_rings = 5;
495*06a67b22SVincenzo Maffione 	ctx->nr_host_rx_rings = 4;
496*06a67b22SVincenzo Maffione 	return port_register(ctx);
497*06a67b22SVincenzo Maffione }
498*06a67b22SVincenzo Maffione 
499*06a67b22SVincenzo Maffione static int
port_register_hwall_tx(struct TestContext * ctx)5001b1076c4SVincenzo Maffione port_register_hwall_tx(struct TestContext *ctx)
5011b1076c4SVincenzo Maffione {
5021b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
5031b1076c4SVincenzo Maffione 	ctx->nr_flags |= NR_TX_RINGS_ONLY;
5041b1076c4SVincenzo Maffione 	return port_register(ctx);
5051b1076c4SVincenzo Maffione }
5061b1076c4SVincenzo Maffione 
5071b1076c4SVincenzo Maffione static int
port_register_hwall_rx(struct TestContext * ctx)5081b1076c4SVincenzo Maffione port_register_hwall_rx(struct TestContext *ctx)
5091b1076c4SVincenzo Maffione {
5101b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
5111b1076c4SVincenzo Maffione 	ctx->nr_flags |= NR_RX_RINGS_ONLY;
5121b1076c4SVincenzo Maffione 	return port_register(ctx);
5131b1076c4SVincenzo Maffione }
5141b1076c4SVincenzo Maffione 
5151b1076c4SVincenzo Maffione /* NETMAP_REQ_VALE_ATTACH */
5161b1076c4SVincenzo Maffione static int
vale_attach(struct TestContext * ctx)5171b1076c4SVincenzo Maffione vale_attach(struct TestContext *ctx)
5181b1076c4SVincenzo Maffione {
5191b1076c4SVincenzo Maffione 	struct nmreq_vale_attach req;
5201b1076c4SVincenzo Maffione 	struct nmreq_header hdr;
5217c72d869SVincenzo Maffione 	char vpname[sizeof(ctx->bdgname) + 1 + sizeof(ctx->ifname_ext)];
5221b1076c4SVincenzo Maffione 	int ret;
5231b1076c4SVincenzo Maffione 
5247c72d869SVincenzo Maffione 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
5251b1076c4SVincenzo Maffione 
5261b1076c4SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
5271b1076c4SVincenzo Maffione 	nmreq_hdr_init(&hdr, vpname);
5281b1076c4SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
5291b1076c4SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
5301b1076c4SVincenzo Maffione 	memset(&req, 0, sizeof(req));
5311b1076c4SVincenzo Maffione 	req.reg.nr_mem_id = ctx->nr_mem_id;
5321b1076c4SVincenzo Maffione 	if (ctx->nr_mode == 0) {
5331b1076c4SVincenzo Maffione 		ctx->nr_mode = NR_REG_ALL_NIC; /* default */
5341b1076c4SVincenzo Maffione 	}
5351b1076c4SVincenzo Maffione 	req.reg.nr_mode = ctx->nr_mode;
5361b1076c4SVincenzo Maffione 	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
5371b1076c4SVincenzo Maffione 	if (ret != 0) {
5381b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
5391b1076c4SVincenzo Maffione 		return ret;
5401b1076c4SVincenzo Maffione 	}
5411b1076c4SVincenzo Maffione 	printf("nr_mem_id %u\n", req.reg.nr_mem_id);
5421b1076c4SVincenzo Maffione 
5431b1076c4SVincenzo Maffione 	return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
5441b1076c4SVincenzo Maffione 	        (ctx->nr_mem_id == req.reg.nr_mem_id)) &&
5451b1076c4SVincenzo Maffione 	                       (ctx->nr_flags == req.reg.nr_flags)
5461b1076c4SVincenzo Maffione 	               ? 0
5471b1076c4SVincenzo Maffione 	               : -1;
5481b1076c4SVincenzo Maffione }
5491b1076c4SVincenzo Maffione 
5501b1076c4SVincenzo Maffione /* NETMAP_REQ_VALE_DETACH */
5511b1076c4SVincenzo Maffione static int
vale_detach(struct TestContext * ctx)5521b1076c4SVincenzo Maffione vale_detach(struct TestContext *ctx)
5531b1076c4SVincenzo Maffione {
5541b1076c4SVincenzo Maffione 	struct nmreq_header hdr;
5551b1076c4SVincenzo Maffione 	struct nmreq_vale_detach req;
5561b1076c4SVincenzo Maffione 	char vpname[256];
5571b1076c4SVincenzo Maffione 	int ret;
5581b1076c4SVincenzo Maffione 
5597c72d869SVincenzo Maffione 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
5601b1076c4SVincenzo Maffione 
5611b1076c4SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
5621b1076c4SVincenzo Maffione 	nmreq_hdr_init(&hdr, vpname);
5631b1076c4SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
5641b1076c4SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
5651b1076c4SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
5661b1076c4SVincenzo Maffione 	if (ret != 0) {
5671b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
5681b1076c4SVincenzo Maffione 		return ret;
5691b1076c4SVincenzo Maffione 	}
5701b1076c4SVincenzo Maffione 
5711b1076c4SVincenzo Maffione 	return 0;
5721b1076c4SVincenzo Maffione }
5731b1076c4SVincenzo Maffione 
5741b1076c4SVincenzo Maffione /* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
5751b1076c4SVincenzo Maffione static int
vale_attach_detach(struct TestContext * ctx)5761b1076c4SVincenzo Maffione vale_attach_detach(struct TestContext *ctx)
5771b1076c4SVincenzo Maffione {
5781b1076c4SVincenzo Maffione 	int ret;
5791b1076c4SVincenzo Maffione 
5801b1076c4SVincenzo Maffione 	if ((ret = vale_attach(ctx)) != 0) {
5811b1076c4SVincenzo Maffione 		return ret;
5821b1076c4SVincenzo Maffione 	}
5831b1076c4SVincenzo Maffione 
5841b1076c4SVincenzo Maffione 	return vale_detach(ctx);
5851b1076c4SVincenzo Maffione }
5861b1076c4SVincenzo Maffione 
5871b1076c4SVincenzo Maffione static int
vale_attach_detach_host_rings(struct TestContext * ctx)5881b1076c4SVincenzo Maffione vale_attach_detach_host_rings(struct TestContext *ctx)
5891b1076c4SVincenzo Maffione {
5901b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_NIC_SW;
5911b1076c4SVincenzo Maffione 	return vale_attach_detach(ctx);
5921b1076c4SVincenzo Maffione }
5931b1076c4SVincenzo Maffione 
5941b1076c4SVincenzo Maffione /* First NETMAP_REQ_PORT_HDR_SET and the NETMAP_REQ_PORT_HDR_GET
5951b1076c4SVincenzo Maffione  * to check that we get the same value. */
5961b1076c4SVincenzo Maffione static int
port_hdr_set_and_get(struct TestContext * ctx)5971b1076c4SVincenzo Maffione port_hdr_set_and_get(struct TestContext *ctx)
5981b1076c4SVincenzo Maffione {
5991b1076c4SVincenzo Maffione 	struct nmreq_port_hdr req;
6001b1076c4SVincenzo Maffione 	struct nmreq_header hdr;
6011b1076c4SVincenzo Maffione 	int ret;
6021b1076c4SVincenzo Maffione 
6037c72d869SVincenzo Maffione 	printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname_ext);
6041b1076c4SVincenzo Maffione 
6057c72d869SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
6061b1076c4SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
6071b1076c4SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
6081b1076c4SVincenzo Maffione 	memset(&req, 0, sizeof(req));
6091b1076c4SVincenzo Maffione 	req.nr_hdr_len = ctx->nr_hdr_len;
6101b1076c4SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
6111b1076c4SVincenzo Maffione 	if (ret != 0) {
6121b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
6131b1076c4SVincenzo Maffione 		return ret;
6141b1076c4SVincenzo Maffione 	}
6151b1076c4SVincenzo Maffione 
6161b1076c4SVincenzo Maffione 	if (req.nr_hdr_len != ctx->nr_hdr_len) {
6171b1076c4SVincenzo Maffione 		return -1;
6181b1076c4SVincenzo Maffione 	}
6191b1076c4SVincenzo Maffione 
6207c72d869SVincenzo Maffione 	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname_ext);
6211b1076c4SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
6221b1076c4SVincenzo Maffione 	req.nr_hdr_len = 0;
6231b1076c4SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
6241b1076c4SVincenzo Maffione 	if (ret != 0) {
6251b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
6261b1076c4SVincenzo Maffione 		return ret;
6271b1076c4SVincenzo Maffione 	}
6281b1076c4SVincenzo Maffione 	printf("nr_hdr_len %u\n", req.nr_hdr_len);
6291b1076c4SVincenzo Maffione 
6301b1076c4SVincenzo Maffione 	return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
6311b1076c4SVincenzo Maffione }
6321b1076c4SVincenzo Maffione 
6331b1076c4SVincenzo Maffione /*
6341b1076c4SVincenzo Maffione  * Possible lengths for the VirtIO network header, as specified by
6351b1076c4SVincenzo Maffione  * the standard:
6361b1076c4SVincenzo Maffione  *    http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html
6371b1076c4SVincenzo Maffione  */
6381b1076c4SVincenzo Maffione #define VIRTIO_NET_HDR_LEN				10
6391b1076c4SVincenzo Maffione #define VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS	12
6401b1076c4SVincenzo Maffione 
6411b1076c4SVincenzo Maffione static int
vale_ephemeral_port_hdr_manipulation(struct TestContext * ctx)6421b1076c4SVincenzo Maffione vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
6431b1076c4SVincenzo Maffione {
6441b1076c4SVincenzo Maffione 	int ret;
6451b1076c4SVincenzo Maffione 
6467c72d869SVincenzo Maffione 	strncpy(ctx->ifname_ext, "vale:eph0", sizeof(ctx->ifname_ext));
6471b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
6481b1076c4SVincenzo Maffione 	if ((ret = port_register(ctx))) {
6491b1076c4SVincenzo Maffione 		return ret;
6501b1076c4SVincenzo Maffione 	}
6511b1076c4SVincenzo Maffione 	/* Try to set and get all the acceptable values. */
6521b1076c4SVincenzo Maffione 	ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS;
6531b1076c4SVincenzo Maffione 	if ((ret = port_hdr_set_and_get(ctx))) {
6541b1076c4SVincenzo Maffione 		return ret;
6551b1076c4SVincenzo Maffione 	}
6561b1076c4SVincenzo Maffione 	ctx->nr_hdr_len = 0;
6571b1076c4SVincenzo Maffione 	if ((ret = port_hdr_set_and_get(ctx))) {
6581b1076c4SVincenzo Maffione 		return ret;
6591b1076c4SVincenzo Maffione 	}
6601b1076c4SVincenzo Maffione 	ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN;
6611b1076c4SVincenzo Maffione 	if ((ret = port_hdr_set_and_get(ctx))) {
6621b1076c4SVincenzo Maffione 		return ret;
6631b1076c4SVincenzo Maffione 	}
6641b1076c4SVincenzo Maffione 	return 0;
6651b1076c4SVincenzo Maffione }
6661b1076c4SVincenzo Maffione 
6671b1076c4SVincenzo Maffione static int
vale_persistent_port(struct TestContext * ctx)6681b1076c4SVincenzo Maffione vale_persistent_port(struct TestContext *ctx)
6691b1076c4SVincenzo Maffione {
6701b1076c4SVincenzo Maffione 	struct nmreq_vale_newif req;
6711b1076c4SVincenzo Maffione 	struct nmreq_header hdr;
6721b1076c4SVincenzo Maffione 	int result;
6731b1076c4SVincenzo Maffione 	int ret;
6741b1076c4SVincenzo Maffione 
6757c72d869SVincenzo Maffione 	strncpy(ctx->ifname_ext, "per4", sizeof(ctx->ifname_ext));
6761b1076c4SVincenzo Maffione 
6777c72d869SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname_ext);
6781b1076c4SVincenzo Maffione 
6797c72d869SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
6801b1076c4SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
6811b1076c4SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
6821b1076c4SVincenzo Maffione 	memset(&req, 0, sizeof(req));
6831b1076c4SVincenzo Maffione 	req.nr_mem_id   = ctx->nr_mem_id;
6841b1076c4SVincenzo Maffione 	req.nr_tx_slots = ctx->nr_tx_slots;
6851b1076c4SVincenzo Maffione 	req.nr_rx_slots = ctx->nr_rx_slots;
6861b1076c4SVincenzo Maffione 	req.nr_tx_rings = ctx->nr_tx_rings;
6871b1076c4SVincenzo Maffione 	req.nr_rx_rings = ctx->nr_rx_rings;
6881b1076c4SVincenzo Maffione 	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
6891b1076c4SVincenzo Maffione 	if (ret != 0) {
6901b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
6911b1076c4SVincenzo Maffione 		return ret;
6921b1076c4SVincenzo Maffione 	}
6931b1076c4SVincenzo Maffione 
6941b1076c4SVincenzo Maffione 	/* Attach the persistent VALE port to a switch and then detach. */
6951b1076c4SVincenzo Maffione 	result = vale_attach_detach(ctx);
6961b1076c4SVincenzo Maffione 
6977c72d869SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname_ext);
6981b1076c4SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
6991b1076c4SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)NULL;
7001b1076c4SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
7011b1076c4SVincenzo Maffione 	if (ret != 0) {
7021b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
7031b1076c4SVincenzo Maffione 		if (result == 0) {
7041b1076c4SVincenzo Maffione 			result = ret;
7051b1076c4SVincenzo Maffione 		}
7061b1076c4SVincenzo Maffione 	}
7071b1076c4SVincenzo Maffione 
7081b1076c4SVincenzo Maffione 	return result;
7091b1076c4SVincenzo Maffione }
7101b1076c4SVincenzo Maffione 
7111b1076c4SVincenzo Maffione /* Single NETMAP_REQ_POOLS_INFO_GET. */
7121b1076c4SVincenzo Maffione static int
pools_info_get(struct TestContext * ctx)7131b1076c4SVincenzo Maffione pools_info_get(struct TestContext *ctx)
7141b1076c4SVincenzo Maffione {
7151b1076c4SVincenzo Maffione 	struct nmreq_pools_info req;
7161b1076c4SVincenzo Maffione 	struct nmreq_header hdr;
7171b1076c4SVincenzo Maffione 	int ret;
7181b1076c4SVincenzo Maffione 
7197c72d869SVincenzo Maffione 	printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname_ext);
7201b1076c4SVincenzo Maffione 
7217c72d869SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
7221b1076c4SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
7231b1076c4SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
7241b1076c4SVincenzo Maffione 	memset(&req, 0, sizeof(req));
7251b1076c4SVincenzo Maffione 	req.nr_mem_id = ctx->nr_mem_id;
7261b1076c4SVincenzo Maffione 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
7271b1076c4SVincenzo Maffione 	if (ret != 0) {
7281b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
7291b1076c4SVincenzo Maffione 		return ret;
7301b1076c4SVincenzo Maffione 	}
7311b1076c4SVincenzo Maffione 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
7321b1076c4SVincenzo Maffione 	printf("nr_mem_id %u\n", req.nr_mem_id);
7331b1076c4SVincenzo Maffione 	printf("nr_if_pool_offset 0x%llx\n",
7341b1076c4SVincenzo Maffione 		(unsigned long long)req.nr_if_pool_offset);
7351b1076c4SVincenzo Maffione 	printf("nr_if_pool_objtotal %u\n", req.nr_if_pool_objtotal);
7361b1076c4SVincenzo Maffione 	printf("nr_if_pool_objsize %u\n", req.nr_if_pool_objsize);
7371b1076c4SVincenzo Maffione 	printf("nr_ring_pool_offset 0x%llx\n",
7381b1076c4SVincenzo Maffione 		(unsigned long long)req.nr_if_pool_offset);
7391b1076c4SVincenzo Maffione 	printf("nr_ring_pool_objtotal %u\n", req.nr_ring_pool_objtotal);
7401b1076c4SVincenzo Maffione 	printf("nr_ring_pool_objsize %u\n", req.nr_ring_pool_objsize);
7411b1076c4SVincenzo Maffione 	printf("nr_buf_pool_offset 0x%llx\n",
7421b1076c4SVincenzo Maffione 		(unsigned long long)req.nr_buf_pool_offset);
7431b1076c4SVincenzo Maffione 	printf("nr_buf_pool_objtotal %u\n", req.nr_buf_pool_objtotal);
7441b1076c4SVincenzo Maffione 	printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
7451b1076c4SVincenzo Maffione 
7461b1076c4SVincenzo Maffione 	return req.nr_memsize && req.nr_if_pool_objtotal &&
7471b1076c4SVincenzo Maffione 	                       req.nr_if_pool_objsize &&
7481b1076c4SVincenzo Maffione 	                       req.nr_ring_pool_objtotal &&
7491b1076c4SVincenzo Maffione 	                       req.nr_ring_pool_objsize &&
7501b1076c4SVincenzo Maffione 	                       req.nr_buf_pool_objtotal &&
7511b1076c4SVincenzo Maffione 	                       req.nr_buf_pool_objsize
7521b1076c4SVincenzo Maffione 	               ? 0
7531b1076c4SVincenzo Maffione 	               : -1;
7541b1076c4SVincenzo Maffione }
7551b1076c4SVincenzo Maffione 
7561b1076c4SVincenzo Maffione static int
pools_info_get_and_register(struct TestContext * ctx)7571b1076c4SVincenzo Maffione pools_info_get_and_register(struct TestContext *ctx)
7581b1076c4SVincenzo Maffione {
7591b1076c4SVincenzo Maffione 	int ret;
7601b1076c4SVincenzo Maffione 
7611b1076c4SVincenzo Maffione 	/* Check that we can get pools info before we register
7621b1076c4SVincenzo Maffione 	 * a netmap interface. */
7631b1076c4SVincenzo Maffione 	ret = pools_info_get(ctx);
7641b1076c4SVincenzo Maffione 	if (ret != 0) {
7651b1076c4SVincenzo Maffione 		return ret;
7661b1076c4SVincenzo Maffione 	}
7671b1076c4SVincenzo Maffione 
7681b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_ONE_NIC;
7691b1076c4SVincenzo Maffione 	ret          = port_register(ctx);
7701b1076c4SVincenzo Maffione 	if (ret != 0) {
7711b1076c4SVincenzo Maffione 		return ret;
7721b1076c4SVincenzo Maffione 	}
7731b1076c4SVincenzo Maffione 	ctx->nr_mem_id = 1;
7741b1076c4SVincenzo Maffione 
7751b1076c4SVincenzo Maffione 	/* Check that we can get pools info also after we register. */
7761b1076c4SVincenzo Maffione 	return pools_info_get(ctx);
7771b1076c4SVincenzo Maffione }
7781b1076c4SVincenzo Maffione 
7791b1076c4SVincenzo Maffione static int
pools_info_get_empty_ifname(struct TestContext * ctx)7801b1076c4SVincenzo Maffione pools_info_get_empty_ifname(struct TestContext *ctx)
7811b1076c4SVincenzo Maffione {
7827c72d869SVincenzo Maffione 	strncpy(ctx->ifname_ext, "", sizeof(ctx->ifname_ext));
7831b1076c4SVincenzo Maffione 	return pools_info_get(ctx) != 0 ? 0 : -1;
7841b1076c4SVincenzo Maffione }
7851b1076c4SVincenzo Maffione 
7861b1076c4SVincenzo Maffione static int
pipe_master(struct TestContext * ctx)7871b1076c4SVincenzo Maffione pipe_master(struct TestContext *ctx)
7881b1076c4SVincenzo Maffione {
7897c72d869SVincenzo Maffione 	strncat(ctx->ifname_ext, "{pipeid1", sizeof(ctx->ifname_ext));
7901b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_NIC_SW;
7911b1076c4SVincenzo Maffione 
7921b1076c4SVincenzo Maffione 	if (port_register(ctx) == 0) {
7931b1076c4SVincenzo Maffione 		printf("pipes should not accept NR_REG_NIC_SW\n");
7941b1076c4SVincenzo Maffione 		return -1;
7951b1076c4SVincenzo Maffione 	}
7961b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
7971b1076c4SVincenzo Maffione 
7981b1076c4SVincenzo Maffione 	return port_register(ctx);
7991b1076c4SVincenzo Maffione }
8001b1076c4SVincenzo Maffione 
8011b1076c4SVincenzo Maffione static int
pipe_slave(struct TestContext * ctx)8021b1076c4SVincenzo Maffione pipe_slave(struct TestContext *ctx)
8031b1076c4SVincenzo Maffione {
8047c72d869SVincenzo Maffione 	strncat(ctx->ifname_ext, "}pipeid2", sizeof(ctx->ifname_ext));
8051b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_ALL_NIC;
8061b1076c4SVincenzo Maffione 
8071b1076c4SVincenzo Maffione 	return port_register(ctx);
8081b1076c4SVincenzo Maffione }
8091b1076c4SVincenzo Maffione 
8101b1076c4SVincenzo Maffione /* Test PORT_INFO_GET and POOLS_INFO_GET on a pipe. This is useful to test the
8111b1076c4SVincenzo Maffione  * registration request used internall by netmap. */
8121b1076c4SVincenzo Maffione static int
pipe_port_info_get(struct TestContext * ctx)8131b1076c4SVincenzo Maffione pipe_port_info_get(struct TestContext *ctx)
8141b1076c4SVincenzo Maffione {
8157c72d869SVincenzo Maffione 	strncat(ctx->ifname_ext, "}pipeid3", sizeof(ctx->ifname_ext));
8161b1076c4SVincenzo Maffione 
8171b1076c4SVincenzo Maffione 	return port_info_get(ctx);
8181b1076c4SVincenzo Maffione }
8191b1076c4SVincenzo Maffione 
8201b1076c4SVincenzo Maffione static int
pipe_pools_info_get(struct TestContext * ctx)8211b1076c4SVincenzo Maffione pipe_pools_info_get(struct TestContext *ctx)
8221b1076c4SVincenzo Maffione {
8237c72d869SVincenzo Maffione 	strncat(ctx->ifname_ext, "{xid", sizeof(ctx->ifname_ext));
8241b1076c4SVincenzo Maffione 
8251b1076c4SVincenzo Maffione 	return pools_info_get(ctx);
8261b1076c4SVincenzo Maffione }
8271b1076c4SVincenzo Maffione 
8281b1076c4SVincenzo Maffione /* NETMAP_REQ_VALE_POLLING_ENABLE */
8291b1076c4SVincenzo Maffione static int
vale_polling_enable(struct TestContext * ctx)8301b1076c4SVincenzo Maffione vale_polling_enable(struct TestContext *ctx)
8311b1076c4SVincenzo Maffione {
8321b1076c4SVincenzo Maffione 	struct nmreq_vale_polling req;
8331b1076c4SVincenzo Maffione 	struct nmreq_header hdr;
8341b1076c4SVincenzo Maffione 	char vpname[256];
8351b1076c4SVincenzo Maffione 	int ret;
8361b1076c4SVincenzo Maffione 
8377c72d869SVincenzo Maffione 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
8381b1076c4SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
8391b1076c4SVincenzo Maffione 
8401b1076c4SVincenzo Maffione 	nmreq_hdr_init(&hdr, vpname);
8411b1076c4SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
8421b1076c4SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
8431b1076c4SVincenzo Maffione 	memset(&req, 0, sizeof(req));
8441b1076c4SVincenzo Maffione 	req.nr_mode             = ctx->nr_mode;
8451b1076c4SVincenzo Maffione 	req.nr_first_cpu_id     = ctx->nr_first_cpu_id;
8461b1076c4SVincenzo Maffione 	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
8471b1076c4SVincenzo Maffione 	ret                     = ioctl(ctx->fd, NIOCCTRL, &hdr);
8481b1076c4SVincenzo Maffione 	if (ret != 0) {
8491b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
8501b1076c4SVincenzo Maffione 		return ret;
8511b1076c4SVincenzo Maffione 	}
8521b1076c4SVincenzo Maffione 
8531b1076c4SVincenzo Maffione 	return (req.nr_mode == ctx->nr_mode &&
8541b1076c4SVincenzo Maffione 	        req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
8551b1076c4SVincenzo Maffione 	        req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
8561b1076c4SVincenzo Maffione 	               ? 0
8571b1076c4SVincenzo Maffione 	               : -1;
8581b1076c4SVincenzo Maffione }
8591b1076c4SVincenzo Maffione 
8601b1076c4SVincenzo Maffione /* NETMAP_REQ_VALE_POLLING_DISABLE */
8611b1076c4SVincenzo Maffione static int
vale_polling_disable(struct TestContext * ctx)8621b1076c4SVincenzo Maffione vale_polling_disable(struct TestContext *ctx)
8631b1076c4SVincenzo Maffione {
8641b1076c4SVincenzo Maffione 	struct nmreq_vale_polling req;
8651b1076c4SVincenzo Maffione 	struct nmreq_header hdr;
8661b1076c4SVincenzo Maffione 	char vpname[256];
8671b1076c4SVincenzo Maffione 	int ret;
8681b1076c4SVincenzo Maffione 
8697c72d869SVincenzo Maffione 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
8701b1076c4SVincenzo Maffione 	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
8711b1076c4SVincenzo Maffione 
8721b1076c4SVincenzo Maffione 	nmreq_hdr_init(&hdr, vpname);
8731b1076c4SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
8741b1076c4SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
8751b1076c4SVincenzo Maffione 	memset(&req, 0, sizeof(req));
8761b1076c4SVincenzo Maffione 	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
8771b1076c4SVincenzo Maffione 	if (ret != 0) {
8781b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
8791b1076c4SVincenzo Maffione 		return ret;
8801b1076c4SVincenzo Maffione 	}
8811b1076c4SVincenzo Maffione 
8821b1076c4SVincenzo Maffione 	return 0;
8831b1076c4SVincenzo Maffione }
8841b1076c4SVincenzo Maffione 
8851b1076c4SVincenzo Maffione static int
vale_polling_enable_disable(struct TestContext * ctx)8861b1076c4SVincenzo Maffione vale_polling_enable_disable(struct TestContext *ctx)
8871b1076c4SVincenzo Maffione {
8881b1076c4SVincenzo Maffione 	int ret = 0;
8891b1076c4SVincenzo Maffione 
8901b1076c4SVincenzo Maffione 	if ((ret = vale_attach(ctx)) != 0) {
8911b1076c4SVincenzo Maffione 		return ret;
8921b1076c4SVincenzo Maffione 	}
8931b1076c4SVincenzo Maffione 
8941b1076c4SVincenzo Maffione 	ctx->nr_mode             = NETMAP_POLLING_MODE_SINGLE_CPU;
8951b1076c4SVincenzo Maffione 	ctx->nr_num_polling_cpus = 1;
8961b1076c4SVincenzo Maffione 	ctx->nr_first_cpu_id     = 0;
8971b1076c4SVincenzo Maffione 	if ((ret = vale_polling_enable(ctx))) {
8981b1076c4SVincenzo Maffione 		vale_detach(ctx);
8991b1076c4SVincenzo Maffione #ifdef __FreeBSD__
9001b1076c4SVincenzo Maffione 		/* NETMAP_REQ_VALE_POLLING_DISABLE is disabled on FreeBSD,
9011b1076c4SVincenzo Maffione 		 * because it is currently broken. We are happy to see that
9021b1076c4SVincenzo Maffione 		 * it fails. */
9031b1076c4SVincenzo Maffione 		return 0;
9047c72d869SVincenzo Maffione #else
9051b1076c4SVincenzo Maffione 		return ret;
9067c72d869SVincenzo Maffione #endif
9071b1076c4SVincenzo Maffione 	}
9081b1076c4SVincenzo Maffione 
9091b1076c4SVincenzo Maffione 	if ((ret = vale_polling_disable(ctx))) {
9101b1076c4SVincenzo Maffione 		vale_detach(ctx);
9111b1076c4SVincenzo Maffione 		return ret;
9121b1076c4SVincenzo Maffione 	}
9131b1076c4SVincenzo Maffione 
9141b1076c4SVincenzo Maffione 	return vale_detach(ctx);
9151b1076c4SVincenzo Maffione }
9161b1076c4SVincenzo Maffione 
9171b1076c4SVincenzo Maffione static void
push_option(struct nmreq_option * opt,struct TestContext * ctx)9181b1076c4SVincenzo Maffione push_option(struct nmreq_option *opt, struct TestContext *ctx)
9191b1076c4SVincenzo Maffione {
9201b1076c4SVincenzo Maffione 	opt->nro_next = (uintptr_t)ctx->nr_opt;
9211b1076c4SVincenzo Maffione 	ctx->nr_opt   = opt;
9221b1076c4SVincenzo Maffione }
9231b1076c4SVincenzo Maffione 
9241b1076c4SVincenzo Maffione static void
clear_options(struct TestContext * ctx)9251b1076c4SVincenzo Maffione clear_options(struct TestContext *ctx)
9261b1076c4SVincenzo Maffione {
9271b1076c4SVincenzo Maffione 	ctx->nr_opt = NULL;
9281b1076c4SVincenzo Maffione }
9291b1076c4SVincenzo Maffione 
9301b1076c4SVincenzo Maffione static int
checkoption(struct nmreq_option * opt,struct nmreq_option * exp)9311b1076c4SVincenzo Maffione checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
9321b1076c4SVincenzo Maffione {
9331b1076c4SVincenzo Maffione 	if (opt->nro_next != exp->nro_next) {
9341b1076c4SVincenzo Maffione 		printf("nro_next %p expected %p\n",
9351b1076c4SVincenzo Maffione 		       (void *)(uintptr_t)opt->nro_next,
9361b1076c4SVincenzo Maffione 		       (void *)(uintptr_t)exp->nro_next);
9371b1076c4SVincenzo Maffione 		return -1;
9381b1076c4SVincenzo Maffione 	}
9391b1076c4SVincenzo Maffione 	if (opt->nro_reqtype != exp->nro_reqtype) {
9401b1076c4SVincenzo Maffione 		printf("nro_reqtype %u expected %u\n", opt->nro_reqtype,
9411b1076c4SVincenzo Maffione 		       exp->nro_reqtype);
9421b1076c4SVincenzo Maffione 		return -1;
9431b1076c4SVincenzo Maffione 	}
9441b1076c4SVincenzo Maffione 	if (opt->nro_status != exp->nro_status) {
9451b1076c4SVincenzo Maffione 		printf("nro_status %u expected %u\n", opt->nro_status,
9461b1076c4SVincenzo Maffione 		       exp->nro_status);
9471b1076c4SVincenzo Maffione 		return -1;
9481b1076c4SVincenzo Maffione 	}
9491b1076c4SVincenzo Maffione 	return 0;
9501b1076c4SVincenzo Maffione }
9511b1076c4SVincenzo Maffione 
9521b1076c4SVincenzo Maffione static int
unsupported_option(struct TestContext * ctx)9531b1076c4SVincenzo Maffione unsupported_option(struct TestContext *ctx)
9541b1076c4SVincenzo Maffione {
9551b1076c4SVincenzo Maffione 	struct nmreq_option opt, save;
9561b1076c4SVincenzo Maffione 
9577c72d869SVincenzo Maffione 	printf("Testing unsupported option on %s\n", ctx->ifname_ext);
9581b1076c4SVincenzo Maffione 
9591b1076c4SVincenzo Maffione 	memset(&opt, 0, sizeof(opt));
9601b1076c4SVincenzo Maffione 	opt.nro_reqtype = 1234;
9611b1076c4SVincenzo Maffione 	push_option(&opt, ctx);
9621b1076c4SVincenzo Maffione 	save = opt;
9631b1076c4SVincenzo Maffione 
9641b1076c4SVincenzo Maffione 	if (port_register_hwall(ctx) >= 0)
9651b1076c4SVincenzo Maffione 		return -1;
9661b1076c4SVincenzo Maffione 
9671b1076c4SVincenzo Maffione 	clear_options(ctx);
9681b1076c4SVincenzo Maffione 	save.nro_status = EOPNOTSUPP;
9691b1076c4SVincenzo Maffione 	return checkoption(&opt, &save);
9701b1076c4SVincenzo Maffione }
9711b1076c4SVincenzo Maffione 
9721b1076c4SVincenzo Maffione static int
infinite_options(struct TestContext * ctx)9731b1076c4SVincenzo Maffione infinite_options(struct TestContext *ctx)
9741b1076c4SVincenzo Maffione {
9751b1076c4SVincenzo Maffione 	struct nmreq_option opt;
9761b1076c4SVincenzo Maffione 
9777c72d869SVincenzo Maffione 	printf("Testing infinite list of options on %s\n", ctx->ifname_ext);
9781b1076c4SVincenzo Maffione 
9791b1076c4SVincenzo Maffione 	opt.nro_reqtype = 1234;
9801b1076c4SVincenzo Maffione 	push_option(&opt, ctx);
9811b1076c4SVincenzo Maffione 	opt.nro_next = (uintptr_t)&opt;
9821b1076c4SVincenzo Maffione 	if (port_register_hwall(ctx) >= 0)
9831b1076c4SVincenzo Maffione 		return -1;
9841b1076c4SVincenzo Maffione 	clear_options(ctx);
9851b1076c4SVincenzo Maffione 	return (errno == EMSGSIZE ? 0 : -1);
9861b1076c4SVincenzo Maffione }
9871b1076c4SVincenzo Maffione 
9881b1076c4SVincenzo Maffione #ifdef CONFIG_NETMAP_EXTMEM
9891b1076c4SVincenzo Maffione int
change_param(const char * pname,unsigned long newv,unsigned long * poldv)9901b1076c4SVincenzo Maffione change_param(const char *pname, unsigned long newv, unsigned long *poldv)
9911b1076c4SVincenzo Maffione {
9921b1076c4SVincenzo Maffione #ifdef __linux__
9931b1076c4SVincenzo Maffione 	char param[256] = "/sys/module/netmap/parameters/";
9941b1076c4SVincenzo Maffione 	unsigned long oldv;
9951b1076c4SVincenzo Maffione 	FILE *f;
9961b1076c4SVincenzo Maffione 
9971b1076c4SVincenzo Maffione 	strncat(param, pname, sizeof(param) - 1);
9981b1076c4SVincenzo Maffione 
9991b1076c4SVincenzo Maffione 	f = fopen(param, "r+");
10001b1076c4SVincenzo Maffione 	if (f == NULL) {
10011b1076c4SVincenzo Maffione 		perror(param);
10021b1076c4SVincenzo Maffione 		return -1;
10031b1076c4SVincenzo Maffione 	}
10041b1076c4SVincenzo Maffione 	if (fscanf(f, "%ld", &oldv) != 1) {
10051b1076c4SVincenzo Maffione 		perror(param);
10061b1076c4SVincenzo Maffione 		fclose(f);
10071b1076c4SVincenzo Maffione 		return -1;
10081b1076c4SVincenzo Maffione 	}
10091b1076c4SVincenzo Maffione 	if (poldv)
10101b1076c4SVincenzo Maffione 		*poldv = oldv;
10111b1076c4SVincenzo Maffione 	rewind(f);
10121b1076c4SVincenzo Maffione 	if (fprintf(f, "%ld\n", newv) < 0) {
10131b1076c4SVincenzo Maffione 		perror(param);
10141b1076c4SVincenzo Maffione 		fclose(f);
10151b1076c4SVincenzo Maffione 		return -1;
10161b1076c4SVincenzo Maffione 	}
10171b1076c4SVincenzo Maffione 	fclose(f);
10181b1076c4SVincenzo Maffione 	printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
10191b1076c4SVincenzo Maffione #endif /* __linux__ */
10201b1076c4SVincenzo Maffione 	return 0;
10211b1076c4SVincenzo Maffione }
10221b1076c4SVincenzo Maffione 
10231b1076c4SVincenzo Maffione static int
push_extmem_option(struct TestContext * ctx,const struct nmreq_pools_info * pi,struct nmreq_opt_extmem * e)10241b1076c4SVincenzo Maffione push_extmem_option(struct TestContext *ctx, const struct nmreq_pools_info *pi,
10251b1076c4SVincenzo Maffione 		struct nmreq_opt_extmem *e)
10261b1076c4SVincenzo Maffione {
10271b1076c4SVincenzo Maffione 	void *addr;
10281b1076c4SVincenzo Maffione 
10291b1076c4SVincenzo Maffione 	addr = mmap(NULL, pi->nr_memsize, PROT_READ | PROT_WRITE,
10301b1076c4SVincenzo Maffione 	            MAP_ANONYMOUS | MAP_SHARED, -1, 0);
10311b1076c4SVincenzo Maffione 	if (addr == MAP_FAILED) {
10321b1076c4SVincenzo Maffione 		perror("mmap");
10331b1076c4SVincenzo Maffione 		return -1;
10341b1076c4SVincenzo Maffione 	}
10351b1076c4SVincenzo Maffione 
10361b1076c4SVincenzo Maffione 	memset(e, 0, sizeof(*e));
10371b1076c4SVincenzo Maffione 	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
10381b1076c4SVincenzo Maffione 	e->nro_info = *pi;
10391b1076c4SVincenzo Maffione 	e->nro_usrptr          = (uintptr_t)addr;
10401b1076c4SVincenzo Maffione 
10411b1076c4SVincenzo Maffione 	push_option(&e->nro_opt, ctx);
10421b1076c4SVincenzo Maffione 
10431b1076c4SVincenzo Maffione 	return 0;
10441b1076c4SVincenzo Maffione }
10451b1076c4SVincenzo Maffione 
10461b1076c4SVincenzo Maffione static int
pop_extmem_option(struct TestContext * ctx,struct nmreq_opt_extmem * exp)10471b1076c4SVincenzo Maffione pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
10481b1076c4SVincenzo Maffione {
10491b1076c4SVincenzo Maffione 	struct nmreq_opt_extmem *e;
10501b1076c4SVincenzo Maffione 	int ret;
10511b1076c4SVincenzo Maffione 
10521b1076c4SVincenzo Maffione 	e           = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
10531b1076c4SVincenzo Maffione 	ctx->nr_opt = (struct nmreq_option *)(uintptr_t)ctx->nr_opt->nro_next;
10541b1076c4SVincenzo Maffione 
10551b1076c4SVincenzo Maffione 	if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
10561b1076c4SVincenzo Maffione 		return ret;
10571b1076c4SVincenzo Maffione 	}
10581b1076c4SVincenzo Maffione 
10591b1076c4SVincenzo Maffione 	if (e->nro_usrptr != exp->nro_usrptr) {
10601b1076c4SVincenzo Maffione 		printf("usrptr %" PRIu64 " expected %" PRIu64 "\n",
10611b1076c4SVincenzo Maffione 		       e->nro_usrptr, exp->nro_usrptr);
10621b1076c4SVincenzo Maffione 		return -1;
10631b1076c4SVincenzo Maffione 	}
10641b1076c4SVincenzo Maffione 	if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
10651b1076c4SVincenzo Maffione 		printf("memsize %" PRIu64 " expected %" PRIu64 "\n",
10661b1076c4SVincenzo Maffione 		       e->nro_info.nr_memsize, exp->nro_info.nr_memsize);
10671b1076c4SVincenzo Maffione 		return -1;
10681b1076c4SVincenzo Maffione 	}
10691b1076c4SVincenzo Maffione 
10701b1076c4SVincenzo Maffione 	if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr,
10711b1076c4SVincenzo Maffione 	                  e->nro_info.nr_memsize)))
10721b1076c4SVincenzo Maffione 		return ret;
10731b1076c4SVincenzo Maffione 
10741b1076c4SVincenzo Maffione 	return 0;
10751b1076c4SVincenzo Maffione }
10761b1076c4SVincenzo Maffione 
10771b1076c4SVincenzo Maffione static int
_extmem_option(struct TestContext * ctx,const struct nmreq_pools_info * pi)10781b1076c4SVincenzo Maffione _extmem_option(struct TestContext *ctx,
10791b1076c4SVincenzo Maffione 		const struct nmreq_pools_info *pi)
10801b1076c4SVincenzo Maffione {
10811b1076c4SVincenzo Maffione 	struct nmreq_opt_extmem e, save;
10821b1076c4SVincenzo Maffione 	int ret;
10831b1076c4SVincenzo Maffione 
10841b1076c4SVincenzo Maffione 	if ((ret = push_extmem_option(ctx, pi, &e)) < 0)
10851b1076c4SVincenzo Maffione 		return ret;
10861b1076c4SVincenzo Maffione 
10871b1076c4SVincenzo Maffione 	save = e;
10881b1076c4SVincenzo Maffione 
10897c72d869SVincenzo Maffione 	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
10901b1076c4SVincenzo Maffione 	ctx->nr_tx_slots = 16;
10911b1076c4SVincenzo Maffione 	ctx->nr_rx_slots = 16;
10921b1076c4SVincenzo Maffione 
10931b1076c4SVincenzo Maffione 	if ((ret = port_register_hwall(ctx)))
10941b1076c4SVincenzo Maffione 		return ret;
10951b1076c4SVincenzo Maffione 
10961b1076c4SVincenzo Maffione 	ret = pop_extmem_option(ctx, &save);
10971b1076c4SVincenzo Maffione 
10981b1076c4SVincenzo Maffione 	return ret;
10991b1076c4SVincenzo Maffione }
11001b1076c4SVincenzo Maffione 
11011b1076c4SVincenzo Maffione static size_t
pools_info_min_memsize(const struct nmreq_pools_info * pi)11021b1076c4SVincenzo Maffione pools_info_min_memsize(const struct nmreq_pools_info *pi)
11031b1076c4SVincenzo Maffione {
11041b1076c4SVincenzo Maffione 	size_t tot = 0;
11051b1076c4SVincenzo Maffione 
11061b1076c4SVincenzo Maffione 	tot += pi->nr_if_pool_objtotal * pi->nr_if_pool_objsize;
11071b1076c4SVincenzo Maffione 	tot += pi->nr_ring_pool_objtotal * pi->nr_ring_pool_objsize;
11081b1076c4SVincenzo Maffione 	tot += pi->nr_buf_pool_objtotal * pi->nr_buf_pool_objsize;
11091b1076c4SVincenzo Maffione 
11101b1076c4SVincenzo Maffione 	return tot;
11111b1076c4SVincenzo Maffione }
11121b1076c4SVincenzo Maffione 
11131b1076c4SVincenzo Maffione /*
11141b1076c4SVincenzo Maffione  * Fill the specification of a netmap memory allocator to be
11151b1076c4SVincenzo Maffione  * used with the 'struct nmreq_opt_extmem' option. Arbitrary
11161b1076c4SVincenzo Maffione  * values are used for the parameters, but with enough netmap
11171b1076c4SVincenzo Maffione  * rings, netmap ifs, and buffers to support a VALE port.
11181b1076c4SVincenzo Maffione  */
11191b1076c4SVincenzo Maffione static void
pools_info_fill(struct nmreq_pools_info * pi)11201b1076c4SVincenzo Maffione pools_info_fill(struct nmreq_pools_info *pi)
11211b1076c4SVincenzo Maffione {
11221b1076c4SVincenzo Maffione 	pi->nr_if_pool_objtotal = 2;
11231b1076c4SVincenzo Maffione 	pi->nr_if_pool_objsize = 1024;
11241b1076c4SVincenzo Maffione 	pi->nr_ring_pool_objtotal = 64;
11251b1076c4SVincenzo Maffione 	pi->nr_ring_pool_objsize = 512;
11261b1076c4SVincenzo Maffione 	pi->nr_buf_pool_objtotal = 4096;
11271b1076c4SVincenzo Maffione 	pi->nr_buf_pool_objsize = 2048;
11281b1076c4SVincenzo Maffione 	pi->nr_memsize = pools_info_min_memsize(pi);
11291b1076c4SVincenzo Maffione }
11301b1076c4SVincenzo Maffione 
11311b1076c4SVincenzo Maffione static int
extmem_option(struct TestContext * ctx)11321b1076c4SVincenzo Maffione extmem_option(struct TestContext *ctx)
11331b1076c4SVincenzo Maffione {
11341b1076c4SVincenzo Maffione 	struct nmreq_pools_info	pools_info;
11351b1076c4SVincenzo Maffione 
11361b1076c4SVincenzo Maffione 	pools_info_fill(&pools_info);
11371b1076c4SVincenzo Maffione 
11381b1076c4SVincenzo Maffione 	printf("Testing extmem option on vale0:0\n");
11391b1076c4SVincenzo Maffione 	return _extmem_option(ctx, &pools_info);
11401b1076c4SVincenzo Maffione }
11411b1076c4SVincenzo Maffione 
11421b1076c4SVincenzo Maffione static int
bad_extmem_option(struct TestContext * ctx)11431b1076c4SVincenzo Maffione bad_extmem_option(struct TestContext *ctx)
11441b1076c4SVincenzo Maffione {
11451b1076c4SVincenzo Maffione 	struct nmreq_pools_info	pools_info;
11461b1076c4SVincenzo Maffione 
11471b1076c4SVincenzo Maffione 	printf("Testing bad extmem option on vale0:0\n");
11481b1076c4SVincenzo Maffione 
11491b1076c4SVincenzo Maffione 	pools_info_fill(&pools_info);
11501b1076c4SVincenzo Maffione 	/* Request a large ring size, to make sure that the kernel
11511b1076c4SVincenzo Maffione 	 * rejects our request. */
11527af42e83SVincenzo Maffione 	pools_info.nr_ring_pool_objsize = (1 << 20);
11531b1076c4SVincenzo Maffione 
11541b1076c4SVincenzo Maffione 	return _extmem_option(ctx, &pools_info) < 0 ? 0 : -1;
11551b1076c4SVincenzo Maffione }
11561b1076c4SVincenzo Maffione 
11571b1076c4SVincenzo Maffione static int
duplicate_extmem_options(struct TestContext * ctx)11581b1076c4SVincenzo Maffione duplicate_extmem_options(struct TestContext *ctx)
11591b1076c4SVincenzo Maffione {
11601b1076c4SVincenzo Maffione 	struct nmreq_opt_extmem e1, save1, e2, save2;
11611b1076c4SVincenzo Maffione 	struct nmreq_pools_info	pools_info;
11621b1076c4SVincenzo Maffione 	int ret;
11631b1076c4SVincenzo Maffione 
11641b1076c4SVincenzo Maffione 	printf("Testing duplicate extmem option on vale0:0\n");
11651b1076c4SVincenzo Maffione 
11661b1076c4SVincenzo Maffione 	pools_info_fill(&pools_info);
11671b1076c4SVincenzo Maffione 
11681b1076c4SVincenzo Maffione 	if ((ret = push_extmem_option(ctx, &pools_info, &e1)) < 0)
11691b1076c4SVincenzo Maffione 		return ret;
11701b1076c4SVincenzo Maffione 
11711b1076c4SVincenzo Maffione 	if ((ret = push_extmem_option(ctx, &pools_info, &e2)) < 0) {
11721b1076c4SVincenzo Maffione 		clear_options(ctx);
11731b1076c4SVincenzo Maffione 		return ret;
11741b1076c4SVincenzo Maffione 	}
11751b1076c4SVincenzo Maffione 
11761b1076c4SVincenzo Maffione 	save1 = e1;
11771b1076c4SVincenzo Maffione 	save2 = e2;
11781b1076c4SVincenzo Maffione 
11797af42e83SVincenzo Maffione 	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
11807af42e83SVincenzo Maffione 	ctx->nr_tx_slots = 16;
11817af42e83SVincenzo Maffione 	ctx->nr_rx_slots = 16;
11827af42e83SVincenzo Maffione 
11831b1076c4SVincenzo Maffione 	ret = port_register_hwall(ctx);
11841b1076c4SVincenzo Maffione 	if (ret >= 0) {
11851b1076c4SVincenzo Maffione 		printf("duplicate option not detected\n");
11861b1076c4SVincenzo Maffione 		return -1;
11871b1076c4SVincenzo Maffione 	}
11881b1076c4SVincenzo Maffione 
11891b1076c4SVincenzo Maffione 	save2.nro_opt.nro_status = EINVAL;
11901b1076c4SVincenzo Maffione 	if ((ret = pop_extmem_option(ctx, &save2)))
11911b1076c4SVincenzo Maffione 		return ret;
11921b1076c4SVincenzo Maffione 
11931b1076c4SVincenzo Maffione 	save1.nro_opt.nro_status = EINVAL;
11941b1076c4SVincenzo Maffione 	if ((ret = pop_extmem_option(ctx, &save1)))
11951b1076c4SVincenzo Maffione 		return ret;
11961b1076c4SVincenzo Maffione 
11971b1076c4SVincenzo Maffione 	return 0;
11981b1076c4SVincenzo Maffione }
11991b1076c4SVincenzo Maffione #endif /* CONFIG_NETMAP_EXTMEM */
12001b1076c4SVincenzo Maffione 
12011b1076c4SVincenzo Maffione static int
push_csb_option(struct TestContext * ctx,struct nmreq_opt_csb * opt)12021b1076c4SVincenzo Maffione push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
12031b1076c4SVincenzo Maffione {
12041b1076c4SVincenzo Maffione 	size_t csb_size;
12051b1076c4SVincenzo Maffione 	int num_entries;
12061b1076c4SVincenzo Maffione 	int ret;
12071b1076c4SVincenzo Maffione 
12081b1076c4SVincenzo Maffione 	ctx->nr_flags |= NR_EXCLUSIVE;
12091b1076c4SVincenzo Maffione 
12101b1076c4SVincenzo Maffione 	/* Get port info in order to use num_registered_rings(). */
12111b1076c4SVincenzo Maffione 	ret = port_info_get(ctx);
12121b1076c4SVincenzo Maffione 	if (ret != 0) {
12131b1076c4SVincenzo Maffione 		return ret;
12141b1076c4SVincenzo Maffione 	}
12151b1076c4SVincenzo Maffione 	num_entries = num_registered_rings(ctx);
12161b1076c4SVincenzo Maffione 
12171b1076c4SVincenzo Maffione 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
12181b1076c4SVincenzo Maffione 	           num_entries;
12191b1076c4SVincenzo Maffione 	assert(csb_size > 0);
12201b1076c4SVincenzo Maffione 	if (ctx->csb) {
12211b1076c4SVincenzo Maffione 		free(ctx->csb);
12221b1076c4SVincenzo Maffione 	}
12231b1076c4SVincenzo Maffione 	ret = posix_memalign(&ctx->csb, sizeof(struct nm_csb_atok), csb_size);
12241b1076c4SVincenzo Maffione 	if (ret != 0) {
12251b1076c4SVincenzo Maffione 		printf("Failed to allocate CSB memory\n");
12261b1076c4SVincenzo Maffione 		exit(EXIT_FAILURE);
12271b1076c4SVincenzo Maffione 	}
12281b1076c4SVincenzo Maffione 
12291b1076c4SVincenzo Maffione 	memset(opt, 0, sizeof(*opt));
12301b1076c4SVincenzo Maffione 	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
12311b1076c4SVincenzo Maffione 	opt->csb_atok            = (uintptr_t)ctx->csb;
12321b1076c4SVincenzo Maffione 	opt->csb_ktoa            = (uintptr_t)(((uint8_t *)ctx->csb) +
12331b1076c4SVincenzo Maffione                                     sizeof(struct nm_csb_atok) * num_entries);
12341b1076c4SVincenzo Maffione 
12351b1076c4SVincenzo Maffione 	printf("Pushing option NETMAP_REQ_OPT_CSB\n");
12361b1076c4SVincenzo Maffione 	push_option(&opt->nro_opt, ctx);
12371b1076c4SVincenzo Maffione 
12381b1076c4SVincenzo Maffione 	return 0;
12391b1076c4SVincenzo Maffione }
12401b1076c4SVincenzo Maffione 
12411b1076c4SVincenzo Maffione static int
csb_mode(struct TestContext * ctx)12421b1076c4SVincenzo Maffione csb_mode(struct TestContext *ctx)
12431b1076c4SVincenzo Maffione {
12441b1076c4SVincenzo Maffione 	struct nmreq_opt_csb opt;
12451b1076c4SVincenzo Maffione 	int ret;
12461b1076c4SVincenzo Maffione 
12471b1076c4SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
12481b1076c4SVincenzo Maffione 	if (ret != 0) {
12491b1076c4SVincenzo Maffione 		return ret;
12501b1076c4SVincenzo Maffione 	}
12511b1076c4SVincenzo Maffione 
12521b1076c4SVincenzo Maffione 	ret = port_register_hwall(ctx);
12531b1076c4SVincenzo Maffione 	clear_options(ctx);
12541b1076c4SVincenzo Maffione 
12551b1076c4SVincenzo Maffione 	return ret;
12561b1076c4SVincenzo Maffione }
12571b1076c4SVincenzo Maffione 
12581b1076c4SVincenzo Maffione static int
csb_mode_invalid_memory(struct TestContext * ctx)12591b1076c4SVincenzo Maffione csb_mode_invalid_memory(struct TestContext *ctx)
12601b1076c4SVincenzo Maffione {
12611b1076c4SVincenzo Maffione 	struct nmreq_opt_csb opt;
12621b1076c4SVincenzo Maffione 	int ret;
12631b1076c4SVincenzo Maffione 
12641b1076c4SVincenzo Maffione 	memset(&opt, 0, sizeof(opt));
12651b1076c4SVincenzo Maffione 	opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
12661b1076c4SVincenzo Maffione 	opt.csb_atok            = (uintptr_t)0x10;
12671b1076c4SVincenzo Maffione 	opt.csb_ktoa            = (uintptr_t)0x800;
12681b1076c4SVincenzo Maffione 	push_option(&opt.nro_opt, ctx);
12691b1076c4SVincenzo Maffione 
12701b1076c4SVincenzo Maffione 	ctx->nr_flags = NR_EXCLUSIVE;
12711b1076c4SVincenzo Maffione 	ret           = port_register_hwall(ctx);
12721b1076c4SVincenzo Maffione 	clear_options(ctx);
12731b1076c4SVincenzo Maffione 
12741b1076c4SVincenzo Maffione 	return (ret < 0) ? 0 : -1;
12751b1076c4SVincenzo Maffione }
12761b1076c4SVincenzo Maffione 
12771b1076c4SVincenzo Maffione static int
sync_kloop_stop(struct TestContext * ctx)12781b1076c4SVincenzo Maffione sync_kloop_stop(struct TestContext *ctx)
12791b1076c4SVincenzo Maffione {
12801b1076c4SVincenzo Maffione 	struct nmreq_header hdr;
12811b1076c4SVincenzo Maffione 	int ret;
12821b1076c4SVincenzo Maffione 
12837c72d869SVincenzo Maffione 	printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname_ext);
12841b1076c4SVincenzo Maffione 
12857c72d869SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
12861b1076c4SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
12871b1076c4SVincenzo Maffione 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
12881b1076c4SVincenzo Maffione 	if (ret != 0) {
12891b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
12901b1076c4SVincenzo Maffione 	}
12911b1076c4SVincenzo Maffione 
12921b1076c4SVincenzo Maffione 	return ret;
12931b1076c4SVincenzo Maffione }
12941b1076c4SVincenzo Maffione 
12951b1076c4SVincenzo Maffione static void *
sync_kloop_worker(void * opaque)12961b1076c4SVincenzo Maffione sync_kloop_worker(void *opaque)
12971b1076c4SVincenzo Maffione {
12981b1076c4SVincenzo Maffione 	struct TestContext *ctx = opaque;
12991b1076c4SVincenzo Maffione 	struct nmreq_sync_kloop_start req;
13001b1076c4SVincenzo Maffione 	struct nmreq_header hdr;
13011b1076c4SVincenzo Maffione 	int ret;
13021b1076c4SVincenzo Maffione 
13037c72d869SVincenzo Maffione 	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname_ext);
13041b1076c4SVincenzo Maffione 
13057c72d869SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
13061b1076c4SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
13071b1076c4SVincenzo Maffione 	hdr.nr_body    = (uintptr_t)&req;
13081b1076c4SVincenzo Maffione 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
13091b1076c4SVincenzo Maffione 	memset(&req, 0, sizeof(req));
13101b1076c4SVincenzo Maffione 	req.sleep_us = 500;
13111b1076c4SVincenzo Maffione 	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
13121b1076c4SVincenzo Maffione 	if (ret != 0) {
13131b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
13141b1076c4SVincenzo Maffione 	}
13151b1076c4SVincenzo Maffione 
13161b1076c4SVincenzo Maffione 	if (ctx->sem) {
13171b1076c4SVincenzo Maffione 		sem_post(ctx->sem);
13181b1076c4SVincenzo Maffione 	}
13191b1076c4SVincenzo Maffione 
13201b1076c4SVincenzo Maffione 	pthread_exit(ret ? (void *)THRET_FAILURE : (void *)THRET_SUCCESS);
13211b1076c4SVincenzo Maffione }
13221b1076c4SVincenzo Maffione 
13231b1076c4SVincenzo Maffione static int
sync_kloop_start_stop(struct TestContext * ctx)13241b1076c4SVincenzo Maffione sync_kloop_start_stop(struct TestContext *ctx)
13251b1076c4SVincenzo Maffione {
13261b1076c4SVincenzo Maffione 	pthread_t th;
13271b1076c4SVincenzo Maffione 	void *thret = THRET_FAILURE;
13281b1076c4SVincenzo Maffione 	int ret;
13291b1076c4SVincenzo Maffione 
13301b1076c4SVincenzo Maffione 	ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
13311b1076c4SVincenzo Maffione 	if (ret != 0) {
13321b1076c4SVincenzo Maffione 		printf("pthread_create(kloop): %s\n", strerror(ret));
13331b1076c4SVincenzo Maffione 		return -1;
13341b1076c4SVincenzo Maffione 	}
13351b1076c4SVincenzo Maffione 
13361b1076c4SVincenzo Maffione 	ret = sync_kloop_stop(ctx);
13371b1076c4SVincenzo Maffione 	if (ret != 0) {
13381b1076c4SVincenzo Maffione 		return ret;
13391b1076c4SVincenzo Maffione 	}
13401b1076c4SVincenzo Maffione 
13411b1076c4SVincenzo Maffione 	ret = pthread_join(th, &thret);
13421b1076c4SVincenzo Maffione 	if (ret != 0) {
13431b1076c4SVincenzo Maffione 		printf("pthread_join(kloop): %s\n", strerror(ret));
13441b1076c4SVincenzo Maffione 	}
13451b1076c4SVincenzo Maffione 
13461b1076c4SVincenzo Maffione 	return thret == THRET_SUCCESS ? 0 : -1;
13471b1076c4SVincenzo Maffione }
13481b1076c4SVincenzo Maffione 
13491b1076c4SVincenzo Maffione static int
sync_kloop(struct TestContext * ctx)13501b1076c4SVincenzo Maffione sync_kloop(struct TestContext *ctx)
13511b1076c4SVincenzo Maffione {
13521b1076c4SVincenzo Maffione 	int ret;
13531b1076c4SVincenzo Maffione 
13541b1076c4SVincenzo Maffione 	ret = csb_mode(ctx);
13551b1076c4SVincenzo Maffione 	if (ret != 0) {
13561b1076c4SVincenzo Maffione 		return ret;
13571b1076c4SVincenzo Maffione 	}
13581b1076c4SVincenzo Maffione 
13591b1076c4SVincenzo Maffione 	return sync_kloop_start_stop(ctx);
13601b1076c4SVincenzo Maffione }
13611b1076c4SVincenzo Maffione 
13621b1076c4SVincenzo Maffione static int
sync_kloop_eventfds(struct TestContext * ctx)13631b1076c4SVincenzo Maffione sync_kloop_eventfds(struct TestContext *ctx)
13641b1076c4SVincenzo Maffione {
13657af42e83SVincenzo Maffione 	struct nmreq_opt_sync_kloop_eventfds *evopt = NULL;
13667af42e83SVincenzo Maffione 	struct nmreq_opt_sync_kloop_mode modeopt;
13677af42e83SVincenzo Maffione 	struct nmreq_option evsave;
13681b1076c4SVincenzo Maffione 	int num_entries;
13691b1076c4SVincenzo Maffione 	size_t opt_size;
13701b1076c4SVincenzo Maffione 	int ret, i;
13711b1076c4SVincenzo Maffione 
13727af42e83SVincenzo Maffione 	memset(&modeopt, 0, sizeof(modeopt));
13737af42e83SVincenzo Maffione 	modeopt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_MODE;
13747af42e83SVincenzo Maffione 	modeopt.mode = ctx->sync_kloop_mode;
13757af42e83SVincenzo Maffione 	push_option(&modeopt.nro_opt, ctx);
13767af42e83SVincenzo Maffione 
13771b1076c4SVincenzo Maffione 	num_entries = num_registered_rings(ctx);
13787af42e83SVincenzo Maffione 	opt_size    = sizeof(*evopt) + num_entries * sizeof(evopt->eventfds[0]);
13797af42e83SVincenzo Maffione 	evopt = calloc(1, opt_size);
13807af42e83SVincenzo Maffione 	evopt->nro_opt.nro_next    = 0;
13817af42e83SVincenzo Maffione 	evopt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
13827af42e83SVincenzo Maffione 	evopt->nro_opt.nro_status  = 0;
13837af42e83SVincenzo Maffione 	evopt->nro_opt.nro_size    = opt_size;
13841b1076c4SVincenzo Maffione 	for (i = 0; i < num_entries; i++) {
13851b1076c4SVincenzo Maffione 		int efd = eventfd(0, 0);
13861b1076c4SVincenzo Maffione 
13877af42e83SVincenzo Maffione 		evopt->eventfds[i].ioeventfd = efd;
13881b1076c4SVincenzo Maffione 		efd                        = eventfd(0, 0);
13897af42e83SVincenzo Maffione 		evopt->eventfds[i].irqfd = efd;
13901b1076c4SVincenzo Maffione 	}
13911b1076c4SVincenzo Maffione 
13927af42e83SVincenzo Maffione 	push_option(&evopt->nro_opt, ctx);
13937af42e83SVincenzo Maffione 	evsave = evopt->nro_opt;
13941b1076c4SVincenzo Maffione 
13951b1076c4SVincenzo Maffione 	ret = sync_kloop_start_stop(ctx);
13961b1076c4SVincenzo Maffione 	if (ret != 0) {
13977af42e83SVincenzo Maffione 		free(evopt);
13981b1076c4SVincenzo Maffione 		clear_options(ctx);
13991b1076c4SVincenzo Maffione 		return ret;
14001b1076c4SVincenzo Maffione 	}
14011b1076c4SVincenzo Maffione #ifdef __linux__
14027af42e83SVincenzo Maffione 	evsave.nro_status = 0;
14031b1076c4SVincenzo Maffione #else  /* !__linux__ */
14047af42e83SVincenzo Maffione 	evsave.nro_status = EOPNOTSUPP;
14051b1076c4SVincenzo Maffione #endif /* !__linux__ */
14061b1076c4SVincenzo Maffione 
14077af42e83SVincenzo Maffione 	ret = checkoption(&evopt->nro_opt, &evsave);
14087af42e83SVincenzo Maffione 	free(evopt);
14091b1076c4SVincenzo Maffione 	clear_options(ctx);
14101b1076c4SVincenzo Maffione 
14111b1076c4SVincenzo Maffione 	return ret;
14121b1076c4SVincenzo Maffione }
14131b1076c4SVincenzo Maffione 
14141b1076c4SVincenzo Maffione static int
sync_kloop_eventfds_all_mode(struct TestContext * ctx,uint32_t sync_kloop_mode)14157af42e83SVincenzo Maffione sync_kloop_eventfds_all_mode(struct TestContext *ctx,
14167af42e83SVincenzo Maffione 			     uint32_t sync_kloop_mode)
14171b1076c4SVincenzo Maffione {
14181b1076c4SVincenzo Maffione 	int ret;
14191b1076c4SVincenzo Maffione 
14201b1076c4SVincenzo Maffione 	ret = csb_mode(ctx);
14211b1076c4SVincenzo Maffione 	if (ret != 0) {
14221b1076c4SVincenzo Maffione 		return ret;
14231b1076c4SVincenzo Maffione 	}
14241b1076c4SVincenzo Maffione 
14257af42e83SVincenzo Maffione 	ctx->sync_kloop_mode = sync_kloop_mode;
14267af42e83SVincenzo Maffione 
14271b1076c4SVincenzo Maffione 	return sync_kloop_eventfds(ctx);
14281b1076c4SVincenzo Maffione }
14291b1076c4SVincenzo Maffione 
14301b1076c4SVincenzo Maffione static int
sync_kloop_eventfds_all(struct TestContext * ctx)14317af42e83SVincenzo Maffione sync_kloop_eventfds_all(struct TestContext *ctx)
14327af42e83SVincenzo Maffione {
14337af42e83SVincenzo Maffione 	return sync_kloop_eventfds_all_mode(ctx, 0);
14347af42e83SVincenzo Maffione }
14357af42e83SVincenzo Maffione 
14367af42e83SVincenzo Maffione static int
sync_kloop_eventfds_all_tx(struct TestContext * ctx)14371b1076c4SVincenzo Maffione sync_kloop_eventfds_all_tx(struct TestContext *ctx)
14381b1076c4SVincenzo Maffione {
14391b1076c4SVincenzo Maffione 	struct nmreq_opt_csb opt;
14401b1076c4SVincenzo Maffione 	int ret;
14411b1076c4SVincenzo Maffione 
14421b1076c4SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
14431b1076c4SVincenzo Maffione 	if (ret != 0) {
14441b1076c4SVincenzo Maffione 		return ret;
14451b1076c4SVincenzo Maffione 	}
14461b1076c4SVincenzo Maffione 
14471b1076c4SVincenzo Maffione 	ret = port_register_hwall_tx(ctx);
14481b1076c4SVincenzo Maffione 	if (ret != 0) {
14491b1076c4SVincenzo Maffione 		return ret;
14501b1076c4SVincenzo Maffione 	}
14511b1076c4SVincenzo Maffione 	clear_options(ctx);
14521b1076c4SVincenzo Maffione 
14531b1076c4SVincenzo Maffione 	return sync_kloop_eventfds(ctx);
14541b1076c4SVincenzo Maffione }
14551b1076c4SVincenzo Maffione 
14561b1076c4SVincenzo Maffione static int
sync_kloop_eventfds_all_direct(struct TestContext * ctx)14577af42e83SVincenzo Maffione sync_kloop_eventfds_all_direct(struct TestContext *ctx)
14587af42e83SVincenzo Maffione {
14597af42e83SVincenzo Maffione 	return sync_kloop_eventfds_all_mode(ctx,
14607af42e83SVincenzo Maffione 	    NM_OPT_SYNC_KLOOP_DIRECT_TX | NM_OPT_SYNC_KLOOP_DIRECT_RX);
14617af42e83SVincenzo Maffione }
14627af42e83SVincenzo Maffione 
14637af42e83SVincenzo Maffione static int
sync_kloop_eventfds_all_direct_tx(struct TestContext * ctx)14647af42e83SVincenzo Maffione sync_kloop_eventfds_all_direct_tx(struct TestContext *ctx)
14657af42e83SVincenzo Maffione {
14667af42e83SVincenzo Maffione 	return sync_kloop_eventfds_all_mode(ctx,
14677af42e83SVincenzo Maffione 	    NM_OPT_SYNC_KLOOP_DIRECT_TX);
14687af42e83SVincenzo Maffione }
14697af42e83SVincenzo Maffione 
14707af42e83SVincenzo Maffione static int
sync_kloop_eventfds_all_direct_rx(struct TestContext * ctx)14717af42e83SVincenzo Maffione sync_kloop_eventfds_all_direct_rx(struct TestContext *ctx)
14727af42e83SVincenzo Maffione {
14737af42e83SVincenzo Maffione 	return sync_kloop_eventfds_all_mode(ctx,
14747af42e83SVincenzo Maffione 	    NM_OPT_SYNC_KLOOP_DIRECT_RX);
14757af42e83SVincenzo Maffione }
14767af42e83SVincenzo Maffione 
14777af42e83SVincenzo Maffione static int
sync_kloop_nocsb(struct TestContext * ctx)14781b1076c4SVincenzo Maffione sync_kloop_nocsb(struct TestContext *ctx)
14791b1076c4SVincenzo Maffione {
14801b1076c4SVincenzo Maffione 	int ret;
14811b1076c4SVincenzo Maffione 
14821b1076c4SVincenzo Maffione 	ret = port_register_hwall(ctx);
14831b1076c4SVincenzo Maffione 	if (ret != 0) {
14841b1076c4SVincenzo Maffione 		return ret;
14851b1076c4SVincenzo Maffione 	}
14861b1076c4SVincenzo Maffione 
14871b1076c4SVincenzo Maffione 	/* Sync kloop must fail because we did not use
14881b1076c4SVincenzo Maffione 	 * NETMAP_REQ_CSB_ENABLE. */
14891b1076c4SVincenzo Maffione 	return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
14901b1076c4SVincenzo Maffione }
14911b1076c4SVincenzo Maffione 
14921b1076c4SVincenzo Maffione static int
csb_enable(struct TestContext * ctx)14931b1076c4SVincenzo Maffione csb_enable(struct TestContext *ctx)
14941b1076c4SVincenzo Maffione {
14951b1076c4SVincenzo Maffione 	struct nmreq_option saveopt;
14961b1076c4SVincenzo Maffione 	struct nmreq_opt_csb opt;
14971b1076c4SVincenzo Maffione 	struct nmreq_header hdr;
14981b1076c4SVincenzo Maffione 	int ret;
14991b1076c4SVincenzo Maffione 
15001b1076c4SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
15011b1076c4SVincenzo Maffione 	if (ret != 0) {
15021b1076c4SVincenzo Maffione 		return ret;
15031b1076c4SVincenzo Maffione 	}
15041b1076c4SVincenzo Maffione 	saveopt = opt.nro_opt;
15051b1076c4SVincenzo Maffione 	saveopt.nro_status = 0;
15061b1076c4SVincenzo Maffione 
15077c72d869SVincenzo Maffione 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
15081b1076c4SVincenzo Maffione 	hdr.nr_reqtype = NETMAP_REQ_CSB_ENABLE;
15091b1076c4SVincenzo Maffione 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
15101b1076c4SVincenzo Maffione 	hdr.nr_body = (uintptr_t)NULL;
15111b1076c4SVincenzo Maffione 
15127c72d869SVincenzo Maffione 	printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname_ext);
15131b1076c4SVincenzo Maffione 
15141b1076c4SVincenzo Maffione 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
15151b1076c4SVincenzo Maffione 	if (ret != 0) {
15161b1076c4SVincenzo Maffione 		perror("ioctl(/dev/netmap, NIOCCTRL, CSB_ENABLE)");
15171b1076c4SVincenzo Maffione 		return ret;
15181b1076c4SVincenzo Maffione 	}
15191b1076c4SVincenzo Maffione 
15201b1076c4SVincenzo Maffione 	ret = checkoption(&opt.nro_opt, &saveopt);
15211b1076c4SVincenzo Maffione 	clear_options(ctx);
15221b1076c4SVincenzo Maffione 
15231b1076c4SVincenzo Maffione 	return ret;
15241b1076c4SVincenzo Maffione }
15251b1076c4SVincenzo Maffione 
15261b1076c4SVincenzo Maffione static int
sync_kloop_csb_enable(struct TestContext * ctx)15271b1076c4SVincenzo Maffione sync_kloop_csb_enable(struct TestContext *ctx)
15281b1076c4SVincenzo Maffione {
15291b1076c4SVincenzo Maffione 	int ret;
15301b1076c4SVincenzo Maffione 
15311b1076c4SVincenzo Maffione 	ctx->nr_flags |= NR_EXCLUSIVE;
15321b1076c4SVincenzo Maffione 	ret = port_register_hwall(ctx);
15331b1076c4SVincenzo Maffione 	if (ret != 0) {
15341b1076c4SVincenzo Maffione 		return ret;
15351b1076c4SVincenzo Maffione 	}
15361b1076c4SVincenzo Maffione 
15371b1076c4SVincenzo Maffione 	ret = csb_enable(ctx);
15381b1076c4SVincenzo Maffione 	if (ret != 0) {
15391b1076c4SVincenzo Maffione 		return ret;
15401b1076c4SVincenzo Maffione 	}
15411b1076c4SVincenzo Maffione 
15421b1076c4SVincenzo Maffione 	return sync_kloop_start_stop(ctx);
15431b1076c4SVincenzo Maffione }
15441b1076c4SVincenzo Maffione 
15451b1076c4SVincenzo Maffione static int
sync_kloop_conflict(struct TestContext * ctx)15461b1076c4SVincenzo Maffione sync_kloop_conflict(struct TestContext *ctx)
15471b1076c4SVincenzo Maffione {
15481b1076c4SVincenzo Maffione 	struct nmreq_opt_csb opt;
15491b1076c4SVincenzo Maffione 	pthread_t th1, th2;
15501b1076c4SVincenzo Maffione 	void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
15511b1076c4SVincenzo Maffione 	struct timespec to;
15521b1076c4SVincenzo Maffione 	sem_t sem;
15531b1076c4SVincenzo Maffione 	int err = 0;
15541b1076c4SVincenzo Maffione 	int ret;
15551b1076c4SVincenzo Maffione 
15561b1076c4SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
15571b1076c4SVincenzo Maffione 	if (ret != 0) {
15581b1076c4SVincenzo Maffione 		return ret;
15591b1076c4SVincenzo Maffione 	}
15601b1076c4SVincenzo Maffione 
15611b1076c4SVincenzo Maffione 	ret = port_register_hwall(ctx);
15621b1076c4SVincenzo Maffione 	if (ret != 0) {
15631b1076c4SVincenzo Maffione 		return ret;
15641b1076c4SVincenzo Maffione 	}
15651b1076c4SVincenzo Maffione 	clear_options(ctx);
15661b1076c4SVincenzo Maffione 
15671b1076c4SVincenzo Maffione 	ret = sem_init(&sem, 0, 0);
15681b1076c4SVincenzo Maffione 	if (ret != 0) {
15691b1076c4SVincenzo Maffione 		printf("sem_init() failed: %s\n", strerror(ret));
15701b1076c4SVincenzo Maffione 		return ret;
15711b1076c4SVincenzo Maffione 	}
15721b1076c4SVincenzo Maffione 	ctx->sem = &sem;
15731b1076c4SVincenzo Maffione 
15741b1076c4SVincenzo Maffione 	ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
15751b1076c4SVincenzo Maffione 	err |= ret;
15761b1076c4SVincenzo Maffione 	if (ret != 0) {
15771b1076c4SVincenzo Maffione 		printf("pthread_create(kloop1): %s\n", strerror(ret));
15781b1076c4SVincenzo Maffione 	}
15791b1076c4SVincenzo Maffione 
15801b1076c4SVincenzo Maffione 	ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
15811b1076c4SVincenzo Maffione 	err |= ret;
15821b1076c4SVincenzo Maffione 	if (ret != 0) {
15831b1076c4SVincenzo Maffione 		printf("pthread_create(kloop2): %s\n", strerror(ret));
15841b1076c4SVincenzo Maffione 	}
15851b1076c4SVincenzo Maffione 
15861b1076c4SVincenzo Maffione 	/* Wait for one of the two threads to fail to start the kloop, to
15871b1076c4SVincenzo Maffione 	 * avoid a race condition where th1 starts the loop and stops,
15881b1076c4SVincenzo Maffione 	 * and after that th2 starts the loop successfully. */
15891b1076c4SVincenzo Maffione 	clock_gettime(CLOCK_REALTIME, &to);
15901b1076c4SVincenzo Maffione 	to.tv_sec += 2;
15911b1076c4SVincenzo Maffione 	ret = sem_timedwait(&sem, &to);
15921b1076c4SVincenzo Maffione 	err |= ret;
15931b1076c4SVincenzo Maffione 	if (ret != 0) {
15941b1076c4SVincenzo Maffione 		printf("sem_timedwait() failed: %s\n", strerror(errno));
15951b1076c4SVincenzo Maffione 	}
15961b1076c4SVincenzo Maffione 
15971b1076c4SVincenzo Maffione 	err |= sync_kloop_stop(ctx);
15981b1076c4SVincenzo Maffione 
15991b1076c4SVincenzo Maffione 	ret = pthread_join(th1, &thret1);
16001b1076c4SVincenzo Maffione 	err |= ret;
16011b1076c4SVincenzo Maffione 	if (ret != 0) {
16021b1076c4SVincenzo Maffione 		printf("pthread_join(kloop1): %s\n", strerror(ret));
16031b1076c4SVincenzo Maffione 	}
16041b1076c4SVincenzo Maffione 
16051b1076c4SVincenzo Maffione 	ret = pthread_join(th2, &thret2);
16061b1076c4SVincenzo Maffione 	err |= ret;
16071b1076c4SVincenzo Maffione 	if (ret != 0) {
16081b1076c4SVincenzo Maffione 		printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
16091b1076c4SVincenzo Maffione 	}
16101b1076c4SVincenzo Maffione 
16111b1076c4SVincenzo Maffione 	sem_destroy(&sem);
16121b1076c4SVincenzo Maffione 	ctx->sem = NULL;
16131b1076c4SVincenzo Maffione 	if (err) {
16141b1076c4SVincenzo Maffione 		return err;
16151b1076c4SVincenzo Maffione 	}
16161b1076c4SVincenzo Maffione 
16171b1076c4SVincenzo Maffione 	/* Check that one of the two failed, while the other one succeeded. */
16181b1076c4SVincenzo Maffione 	return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
16191b1076c4SVincenzo Maffione 			(thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
16201b1076c4SVincenzo Maffione 	               ? 0
16211b1076c4SVincenzo Maffione 	               : -1;
16221b1076c4SVincenzo Maffione }
16231b1076c4SVincenzo Maffione 
16241b1076c4SVincenzo Maffione static int
sync_kloop_eventfds_mismatch(struct TestContext * ctx)16251b1076c4SVincenzo Maffione sync_kloop_eventfds_mismatch(struct TestContext *ctx)
16261b1076c4SVincenzo Maffione {
16271b1076c4SVincenzo Maffione 	struct nmreq_opt_csb opt;
16281b1076c4SVincenzo Maffione 	int ret;
16291b1076c4SVincenzo Maffione 
16301b1076c4SVincenzo Maffione 	ret = push_csb_option(ctx, &opt);
16311b1076c4SVincenzo Maffione 	if (ret != 0) {
16321b1076c4SVincenzo Maffione 		return ret;
16331b1076c4SVincenzo Maffione 	}
16341b1076c4SVincenzo Maffione 
16351b1076c4SVincenzo Maffione 	ret = port_register_hwall_rx(ctx);
16361b1076c4SVincenzo Maffione 	if (ret != 0) {
16371b1076c4SVincenzo Maffione 		return ret;
16381b1076c4SVincenzo Maffione 	}
16391b1076c4SVincenzo Maffione 	clear_options(ctx);
16401b1076c4SVincenzo Maffione 
16411b1076c4SVincenzo Maffione 	/* Deceive num_registered_rings() to trigger a failure of
16421b1076c4SVincenzo Maffione 	 * sync_kloop_eventfds(). The latter will think that all the
16431b1076c4SVincenzo Maffione 	 * rings were registered, and allocate the wrong number of
16441b1076c4SVincenzo Maffione 	 * eventfds. */
16451b1076c4SVincenzo Maffione 	ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
16461b1076c4SVincenzo Maffione 
16471b1076c4SVincenzo Maffione 	return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
16481b1076c4SVincenzo Maffione }
16491b1076c4SVincenzo Maffione 
16501b1076c4SVincenzo Maffione static int
null_port(struct TestContext * ctx)16511b1076c4SVincenzo Maffione null_port(struct TestContext *ctx)
16521b1076c4SVincenzo Maffione {
16531b1076c4SVincenzo Maffione 	int ret;
16541b1076c4SVincenzo Maffione 
16551b1076c4SVincenzo Maffione 	ctx->nr_mem_id = 1;
16561b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_NULL;
16571b1076c4SVincenzo Maffione 	ctx->nr_tx_rings = 10;
16581b1076c4SVincenzo Maffione 	ctx->nr_rx_rings = 5;
16591b1076c4SVincenzo Maffione 	ctx->nr_tx_slots = 256;
16601b1076c4SVincenzo Maffione 	ctx->nr_rx_slots = 100;
16611b1076c4SVincenzo Maffione 	ret = port_register(ctx);
16621b1076c4SVincenzo Maffione 	if (ret != 0) {
16631b1076c4SVincenzo Maffione 		return ret;
16641b1076c4SVincenzo Maffione 	}
16651b1076c4SVincenzo Maffione 	return 0;
16661b1076c4SVincenzo Maffione }
16671b1076c4SVincenzo Maffione 
16681b1076c4SVincenzo Maffione static int
null_port_all_zero(struct TestContext * ctx)16691b1076c4SVincenzo Maffione null_port_all_zero(struct TestContext *ctx)
16701b1076c4SVincenzo Maffione {
16711b1076c4SVincenzo Maffione 	int ret;
16721b1076c4SVincenzo Maffione 
16731b1076c4SVincenzo Maffione 	ctx->nr_mem_id = 1;
16741b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_NULL;
16751b1076c4SVincenzo Maffione 	ctx->nr_tx_rings = 0;
16761b1076c4SVincenzo Maffione 	ctx->nr_rx_rings = 0;
16771b1076c4SVincenzo Maffione 	ctx->nr_tx_slots = 0;
16781b1076c4SVincenzo Maffione 	ctx->nr_rx_slots = 0;
16791b1076c4SVincenzo Maffione 	ret = port_register(ctx);
16801b1076c4SVincenzo Maffione 	if (ret != 0) {
16811b1076c4SVincenzo Maffione 		return ret;
16821b1076c4SVincenzo Maffione 	}
16831b1076c4SVincenzo Maffione 	return 0;
16841b1076c4SVincenzo Maffione }
16851b1076c4SVincenzo Maffione 
16861b1076c4SVincenzo Maffione static int
null_port_sync(struct TestContext * ctx)16871b1076c4SVincenzo Maffione null_port_sync(struct TestContext *ctx)
16881b1076c4SVincenzo Maffione {
16891b1076c4SVincenzo Maffione 	int ret;
16901b1076c4SVincenzo Maffione 
16911b1076c4SVincenzo Maffione 	ctx->nr_mem_id = 1;
16921b1076c4SVincenzo Maffione 	ctx->nr_mode = NR_REG_NULL;
16931b1076c4SVincenzo Maffione 	ctx->nr_tx_rings = 10;
16941b1076c4SVincenzo Maffione 	ctx->nr_rx_rings = 5;
16951b1076c4SVincenzo Maffione 	ctx->nr_tx_slots = 256;
16961b1076c4SVincenzo Maffione 	ctx->nr_rx_slots = 100;
16971b1076c4SVincenzo Maffione 	ret = port_register(ctx);
16981b1076c4SVincenzo Maffione 	if (ret != 0) {
16991b1076c4SVincenzo Maffione 		return ret;
17001b1076c4SVincenzo Maffione 	}
17011b1076c4SVincenzo Maffione 	ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
17021b1076c4SVincenzo Maffione 	if (ret != 0) {
17031b1076c4SVincenzo Maffione 		return ret;
17041b1076c4SVincenzo Maffione 	}
17051b1076c4SVincenzo Maffione 	return 0;
17061b1076c4SVincenzo Maffione }
17071b1076c4SVincenzo Maffione 
17081b1076c4SVincenzo Maffione static void
usage(const char * prog)17091b1076c4SVincenzo Maffione usage(const char *prog)
17101b1076c4SVincenzo Maffione {
17111b1076c4SVincenzo Maffione 	printf("%s -i IFNAME\n"
17121b1076c4SVincenzo Maffione 	       "[-j TEST_NUM1[-[TEST_NUM2]] | -[TEST_NUM_2]]\n"
17131b1076c4SVincenzo Maffione 	       "[-l (list test cases)]\n",
17141b1076c4SVincenzo Maffione 	       prog);
17151b1076c4SVincenzo Maffione }
17161b1076c4SVincenzo Maffione 
17171b1076c4SVincenzo Maffione struct mytest {
17181b1076c4SVincenzo Maffione 	testfunc_t test;
17191b1076c4SVincenzo Maffione 	const char *name;
17201b1076c4SVincenzo Maffione };
17211b1076c4SVincenzo Maffione 
17221b1076c4SVincenzo Maffione #define decltest(f)                                                            \
17231b1076c4SVincenzo Maffione 	{                                                                      \
17241b1076c4SVincenzo Maffione 		.test = f, .name = #f                                          \
17251b1076c4SVincenzo Maffione 	}
17261b1076c4SVincenzo Maffione 
17271b1076c4SVincenzo Maffione static struct mytest tests[] = {
17281b1076c4SVincenzo Maffione 	decltest(port_info_get),
17291b1076c4SVincenzo Maffione 	decltest(port_register_hwall_host),
17301b1076c4SVincenzo Maffione 	decltest(port_register_hwall),
1731*06a67b22SVincenzo Maffione 	decltest(port_register_hostall),
1732*06a67b22SVincenzo Maffione 	decltest(port_register_single_hw_pair),
1733*06a67b22SVincenzo Maffione 	decltest(port_register_single_host_pair),
1734*06a67b22SVincenzo Maffione 	decltest(port_register_hostall_many),
17351b1076c4SVincenzo Maffione 	decltest(vale_attach_detach),
17361b1076c4SVincenzo Maffione 	decltest(vale_attach_detach_host_rings),
17371b1076c4SVincenzo Maffione 	decltest(vale_ephemeral_port_hdr_manipulation),
17381b1076c4SVincenzo Maffione 	decltest(vale_persistent_port),
17391b1076c4SVincenzo Maffione 	decltest(pools_info_get_and_register),
17401b1076c4SVincenzo Maffione 	decltest(pools_info_get_empty_ifname),
17411b1076c4SVincenzo Maffione 	decltest(pipe_master),
17421b1076c4SVincenzo Maffione 	decltest(pipe_slave),
17431b1076c4SVincenzo Maffione 	decltest(pipe_port_info_get),
17441b1076c4SVincenzo Maffione 	decltest(pipe_pools_info_get),
17451b1076c4SVincenzo Maffione 	decltest(vale_polling_enable_disable),
17461b1076c4SVincenzo Maffione 	decltest(unsupported_option),
17471b1076c4SVincenzo Maffione 	decltest(infinite_options),
17481b1076c4SVincenzo Maffione #ifdef CONFIG_NETMAP_EXTMEM
17491b1076c4SVincenzo Maffione 	decltest(extmem_option),
17501b1076c4SVincenzo Maffione 	decltest(bad_extmem_option),
17511b1076c4SVincenzo Maffione 	decltest(duplicate_extmem_options),
17521b1076c4SVincenzo Maffione #endif /* CONFIG_NETMAP_EXTMEM */
17531b1076c4SVincenzo Maffione 	decltest(csb_mode),
17541b1076c4SVincenzo Maffione 	decltest(csb_mode_invalid_memory),
17551b1076c4SVincenzo Maffione 	decltest(sync_kloop),
17561b1076c4SVincenzo Maffione 	decltest(sync_kloop_eventfds_all),
17571b1076c4SVincenzo Maffione 	decltest(sync_kloop_eventfds_all_tx),
17587af42e83SVincenzo Maffione 	decltest(sync_kloop_eventfds_all_direct),
17597af42e83SVincenzo Maffione 	decltest(sync_kloop_eventfds_all_direct_tx),
17607af42e83SVincenzo Maffione 	decltest(sync_kloop_eventfds_all_direct_rx),
17611b1076c4SVincenzo Maffione 	decltest(sync_kloop_nocsb),
17621b1076c4SVincenzo Maffione 	decltest(sync_kloop_csb_enable),
17631b1076c4SVincenzo Maffione 	decltest(sync_kloop_conflict),
17641b1076c4SVincenzo Maffione 	decltest(sync_kloop_eventfds_mismatch),
17651b1076c4SVincenzo Maffione 	decltest(null_port),
17661b1076c4SVincenzo Maffione 	decltest(null_port_all_zero),
17671b1076c4SVincenzo Maffione 	decltest(null_port_sync),
17681b1076c4SVincenzo Maffione 	decltest(legacy_regif_default),
17691b1076c4SVincenzo Maffione 	decltest(legacy_regif_all_nic),
17701b1076c4SVincenzo Maffione 	decltest(legacy_regif_12),
17711b1076c4SVincenzo Maffione 	decltest(legacy_regif_sw),
17721b1076c4SVincenzo Maffione 	decltest(legacy_regif_future),
17731b1076c4SVincenzo Maffione 	decltest(legacy_regif_extra_bufs),
17741b1076c4SVincenzo Maffione 	decltest(legacy_regif_extra_bufs_pipe),
17751b1076c4SVincenzo Maffione 	decltest(legacy_regif_extra_bufs_pipe_vale),
17761b1076c4SVincenzo Maffione };
17771b1076c4SVincenzo Maffione 
17781b1076c4SVincenzo Maffione static void
context_cleanup(struct TestContext * ctx)17791b1076c4SVincenzo Maffione context_cleanup(struct TestContext *ctx)
17801b1076c4SVincenzo Maffione {
17811b1076c4SVincenzo Maffione 	if (ctx->csb) {
17821b1076c4SVincenzo Maffione 		free(ctx->csb);
17831b1076c4SVincenzo Maffione 		ctx->csb = NULL;
17841b1076c4SVincenzo Maffione 	}
17851b1076c4SVincenzo Maffione 
17861b1076c4SVincenzo Maffione 	close(ctx->fd);
17871b1076c4SVincenzo Maffione 	ctx->fd = -1;
17881b1076c4SVincenzo Maffione }
17891b1076c4SVincenzo Maffione 
17901b1076c4SVincenzo Maffione static int
parse_interval(const char * arg,int * j,int * k)17911b1076c4SVincenzo Maffione parse_interval(const char *arg, int *j, int *k)
17921b1076c4SVincenzo Maffione {
17931b1076c4SVincenzo Maffione 	const char *scan = arg;
17941b1076c4SVincenzo Maffione 	char *rest;
17951b1076c4SVincenzo Maffione 
17961b1076c4SVincenzo Maffione 	*j = 0;
17971b1076c4SVincenzo Maffione 	*k = -1;
17981b1076c4SVincenzo Maffione 	if (*scan == '-') {
17991b1076c4SVincenzo Maffione 		scan++;
18001b1076c4SVincenzo Maffione 		goto get_k;
18011b1076c4SVincenzo Maffione 	}
18021b1076c4SVincenzo Maffione 	if (!isdigit(*scan))
18031b1076c4SVincenzo Maffione 		goto err;
18041b1076c4SVincenzo Maffione 	*k = strtol(scan, &rest, 10);
18051b1076c4SVincenzo Maffione 	*j = *k - 1;
18061b1076c4SVincenzo Maffione 	scan = rest;
18071b1076c4SVincenzo Maffione 	if (*scan == '-') {
18081b1076c4SVincenzo Maffione 		*k = -1;
18091b1076c4SVincenzo Maffione 		scan++;
18101b1076c4SVincenzo Maffione 	}
18111b1076c4SVincenzo Maffione get_k:
18121b1076c4SVincenzo Maffione 	if (*scan == '\0')
18131b1076c4SVincenzo Maffione 		return 0;
18141b1076c4SVincenzo Maffione 	if (!isdigit(*scan))
18151b1076c4SVincenzo Maffione 		goto err;
18161b1076c4SVincenzo Maffione 	*k = strtol(scan, &rest, 10);
18171b1076c4SVincenzo Maffione 	scan = rest;
18181b1076c4SVincenzo Maffione 	if (!(*scan == '\0'))
18191b1076c4SVincenzo Maffione 		goto err;
18201b1076c4SVincenzo Maffione 
18211b1076c4SVincenzo Maffione 	return 0;
18221b1076c4SVincenzo Maffione 
18231b1076c4SVincenzo Maffione err:
18241b1076c4SVincenzo Maffione 	fprintf(stderr, "syntax error in '%s', must be num[-[num]] or -[num]\n", arg);
18251b1076c4SVincenzo Maffione 	return -1;
18261b1076c4SVincenzo Maffione }
18271b1076c4SVincenzo Maffione 
18281b1076c4SVincenzo Maffione #define ARGV_APPEND(_av, _ac, _x)\
18291b1076c4SVincenzo Maffione 	do {\
18301b1076c4SVincenzo Maffione 		assert((int)(_ac) < (int)(sizeof(_av)/sizeof((_av)[0])));\
18311b1076c4SVincenzo Maffione 		(_av)[(_ac)++] = _x;\
18321b1076c4SVincenzo Maffione 	} while (0)
18331b1076c4SVincenzo Maffione 
18341b1076c4SVincenzo Maffione static void
tap_cleanup(int signo)18351b1076c4SVincenzo Maffione tap_cleanup(int signo)
18361b1076c4SVincenzo Maffione {
18371b1076c4SVincenzo Maffione 	const char *av[8];
18381b1076c4SVincenzo Maffione 	int ac = 0;
18391b1076c4SVincenzo Maffione 
18401b1076c4SVincenzo Maffione 	(void)signo;
18411b1076c4SVincenzo Maffione #ifdef __FreeBSD__
18421b1076c4SVincenzo Maffione 	ARGV_APPEND(av, ac, "ifconfig");
18431b1076c4SVincenzo Maffione 	ARGV_APPEND(av, ac, ctx_.ifname);
18441b1076c4SVincenzo Maffione 	ARGV_APPEND(av, ac, "destroy");
18451b1076c4SVincenzo Maffione #else
18461b1076c4SVincenzo Maffione 	ARGV_APPEND(av, ac, "ip");
18471b1076c4SVincenzo Maffione 	ARGV_APPEND(av, ac, "link");
18481b1076c4SVincenzo Maffione 	ARGV_APPEND(av, ac, "del");
18491b1076c4SVincenzo Maffione 	ARGV_APPEND(av, ac, ctx_.ifname);
18501b1076c4SVincenzo Maffione #endif
18511b1076c4SVincenzo Maffione 	ARGV_APPEND(av, ac, NULL);
18521b1076c4SVincenzo Maffione 	if (exec_command(ac, av)) {
18531b1076c4SVincenzo Maffione 		printf("Failed to destroy tap interface\n");
18541b1076c4SVincenzo Maffione 	}
18551b1076c4SVincenzo Maffione }
18561b1076c4SVincenzo Maffione 
18571b1076c4SVincenzo Maffione int
main(int argc,char ** argv)18581b1076c4SVincenzo Maffione main(int argc, char **argv)
18591b1076c4SVincenzo Maffione {
18601b1076c4SVincenzo Maffione 	int create_tap = 1;
18611b1076c4SVincenzo Maffione 	int num_tests;
18621b1076c4SVincenzo Maffione 	int ret  = 0;
18631b1076c4SVincenzo Maffione 	int j    = 0;
18641b1076c4SVincenzo Maffione 	int k    = -1;
18651b1076c4SVincenzo Maffione 	int list = 0;
18661b1076c4SVincenzo Maffione 	int opt;
18671b1076c4SVincenzo Maffione 	int i;
18681b1076c4SVincenzo Maffione 
186905e2b301SEnji Cooper #ifdef __FreeBSD__
187005e2b301SEnji Cooper 	PLAIN_REQUIRE_KERNEL_MODULE("if_tap", 0);
187105e2b301SEnji Cooper 	PLAIN_REQUIRE_KERNEL_MODULE("netmap", 0);
187205e2b301SEnji Cooper #endif
187305e2b301SEnji Cooper 
18741b1076c4SVincenzo Maffione 	memset(&ctx_, 0, sizeof(ctx_));
18751b1076c4SVincenzo Maffione 
18761b1076c4SVincenzo Maffione 	{
18771b1076c4SVincenzo Maffione 		struct timespec t;
18781b1076c4SVincenzo Maffione 		int idx;
18791b1076c4SVincenzo Maffione 
18801b1076c4SVincenzo Maffione 		clock_gettime(CLOCK_REALTIME, &t);
18811b1076c4SVincenzo Maffione 		srand((unsigned int)t.tv_nsec);
18821b1076c4SVincenzo Maffione 		idx = rand() % 8000 + 100;
18831b1076c4SVincenzo Maffione 		snprintf(ctx_.ifname, sizeof(ctx_.ifname), "tap%d", idx);
18841b1076c4SVincenzo Maffione 		idx = rand() % 800 + 100;
18851b1076c4SVincenzo Maffione 		snprintf(ctx_.bdgname, sizeof(ctx_.bdgname), "vale%d", idx);
18861b1076c4SVincenzo Maffione 	}
18871b1076c4SVincenzo Maffione 
18881b1076c4SVincenzo Maffione 	while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
18891b1076c4SVincenzo Maffione 		switch (opt) {
18901b1076c4SVincenzo Maffione 		case 'h':
18911b1076c4SVincenzo Maffione 			usage(argv[0]);
18921b1076c4SVincenzo Maffione 			return 0;
18931b1076c4SVincenzo Maffione 
18941b1076c4SVincenzo Maffione 		case 'i':
18951b1076c4SVincenzo Maffione 			strncpy(ctx_.ifname, optarg, sizeof(ctx_.ifname) - 1);
18961b1076c4SVincenzo Maffione 			create_tap = 0;
18971b1076c4SVincenzo Maffione 			break;
18981b1076c4SVincenzo Maffione 
18991b1076c4SVincenzo Maffione 		case 'j':
19001b1076c4SVincenzo Maffione 			if (parse_interval(optarg, &j, &k) < 0) {
19011b1076c4SVincenzo Maffione 				usage(argv[0]);
19021b1076c4SVincenzo Maffione 				return -1;
19031b1076c4SVincenzo Maffione 			}
19041b1076c4SVincenzo Maffione 			break;
19051b1076c4SVincenzo Maffione 
19061b1076c4SVincenzo Maffione 		case 'l':
19071b1076c4SVincenzo Maffione 			list = 1;
19081b1076c4SVincenzo Maffione 			create_tap = 0;
19091b1076c4SVincenzo Maffione 			break;
19101b1076c4SVincenzo Maffione 
19111b1076c4SVincenzo Maffione 		default:
19121b1076c4SVincenzo Maffione 			printf("    Unrecognized option %c\n", opt);
19131b1076c4SVincenzo Maffione 			usage(argv[0]);
19141b1076c4SVincenzo Maffione 			return -1;
19151b1076c4SVincenzo Maffione 		}
19161b1076c4SVincenzo Maffione 	}
19171b1076c4SVincenzo Maffione 
19181b1076c4SVincenzo Maffione 	num_tests = sizeof(tests) / sizeof(tests[0]);
19191b1076c4SVincenzo Maffione 
19201b1076c4SVincenzo Maffione 	if (j < 0 || j >= num_tests || k > num_tests) {
19211b1076c4SVincenzo Maffione 		fprintf(stderr, "Test interval %d-%d out of range (%d-%d)\n",
19221b1076c4SVincenzo Maffione 				j + 1, k, 1, num_tests + 1);
19231b1076c4SVincenzo Maffione 		return -1;
19241b1076c4SVincenzo Maffione 	}
19251b1076c4SVincenzo Maffione 
19261b1076c4SVincenzo Maffione 	if (k < 0)
19271b1076c4SVincenzo Maffione 		k = num_tests;
19281b1076c4SVincenzo Maffione 
19291b1076c4SVincenzo Maffione 	if (list) {
19301b1076c4SVincenzo Maffione 		printf("Available tests:\n");
19311b1076c4SVincenzo Maffione 		for (i = 0; i < num_tests; i++) {
19321b1076c4SVincenzo Maffione 			printf("#%03d: %s\n", i + 1, tests[i].name);
19331b1076c4SVincenzo Maffione 		}
19341b1076c4SVincenzo Maffione 		return 0;
19351b1076c4SVincenzo Maffione 	}
19361b1076c4SVincenzo Maffione 
19371b1076c4SVincenzo Maffione 	if (create_tap) {
19381b1076c4SVincenzo Maffione 		struct sigaction sa;
19391b1076c4SVincenzo Maffione 		const char *av[8];
19401b1076c4SVincenzo Maffione 		int ac = 0;
19411b1076c4SVincenzo Maffione #ifdef __FreeBSD__
19421b1076c4SVincenzo Maffione 		ARGV_APPEND(av, ac, "ifconfig");
19431b1076c4SVincenzo Maffione 		ARGV_APPEND(av, ac, ctx_.ifname);
19441b1076c4SVincenzo Maffione 		ARGV_APPEND(av, ac, "create");
19451b1076c4SVincenzo Maffione 		ARGV_APPEND(av, ac, "up");
19461b1076c4SVincenzo Maffione #else
19471b1076c4SVincenzo Maffione 		ARGV_APPEND(av, ac, "ip");
19481b1076c4SVincenzo Maffione 		ARGV_APPEND(av, ac, "tuntap");
19491b1076c4SVincenzo Maffione 		ARGV_APPEND(av, ac, "add");
19501b1076c4SVincenzo Maffione 		ARGV_APPEND(av, ac, "mode");
19511b1076c4SVincenzo Maffione 		ARGV_APPEND(av, ac, "tap");
19521b1076c4SVincenzo Maffione 		ARGV_APPEND(av, ac, "name");
19531b1076c4SVincenzo Maffione 		ARGV_APPEND(av, ac, ctx_.ifname);
19541b1076c4SVincenzo Maffione #endif
19551b1076c4SVincenzo Maffione 		ARGV_APPEND(av, ac, NULL);
19561b1076c4SVincenzo Maffione 		if (exec_command(ac, av)) {
19571b1076c4SVincenzo Maffione 			printf("Failed to create tap interface\n");
19581b1076c4SVincenzo Maffione 			return -1;
19591b1076c4SVincenzo Maffione 		}
19601b1076c4SVincenzo Maffione 
19611b1076c4SVincenzo Maffione 		sa.sa_handler = tap_cleanup;
19621b1076c4SVincenzo Maffione 		sigemptyset(&sa.sa_mask);
19631b1076c4SVincenzo Maffione 		sa.sa_flags = SA_RESTART;
19641b1076c4SVincenzo Maffione 		ret         = sigaction(SIGINT, &sa, NULL);
19651b1076c4SVincenzo Maffione 		if (ret) {
19661b1076c4SVincenzo Maffione 			perror("sigaction(SIGINT)");
19671b1076c4SVincenzo Maffione 			goto out;
19681b1076c4SVincenzo Maffione 		}
19691b1076c4SVincenzo Maffione 		ret = sigaction(SIGTERM, &sa, NULL);
19701b1076c4SVincenzo Maffione 		if (ret) {
19711b1076c4SVincenzo Maffione 			perror("sigaction(SIGTERM)");
19721b1076c4SVincenzo Maffione 			goto out;
19731b1076c4SVincenzo Maffione 		}
19741b1076c4SVincenzo Maffione 	}
19751b1076c4SVincenzo Maffione 
19761b1076c4SVincenzo Maffione 	for (i = j; i < k; i++) {
19771b1076c4SVincenzo Maffione 		struct TestContext ctxcopy;
19781b1076c4SVincenzo Maffione 		int fd;
19791b1076c4SVincenzo Maffione 		printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
19801b1076c4SVincenzo Maffione 		fd = open("/dev/netmap", O_RDWR);
19811b1076c4SVincenzo Maffione 		if (fd < 0) {
19821b1076c4SVincenzo Maffione 			perror("open(/dev/netmap)");
19831b1076c4SVincenzo Maffione 			ret = fd;
19841b1076c4SVincenzo Maffione 			goto out;
19851b1076c4SVincenzo Maffione 		}
19861b1076c4SVincenzo Maffione 		memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
19871b1076c4SVincenzo Maffione 		ctxcopy.fd = fd;
19887c72d869SVincenzo Maffione 		memcpy(ctxcopy.ifname_ext, ctxcopy.ifname,
19897c72d869SVincenzo Maffione 			sizeof(ctxcopy.ifname));
19901b1076c4SVincenzo Maffione 		ret        = tests[i].test(&ctxcopy);
19911b1076c4SVincenzo Maffione 		if (ret != 0) {
19921b1076c4SVincenzo Maffione 			printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
19931b1076c4SVincenzo Maffione 			goto out;
19941b1076c4SVincenzo Maffione 		}
19951b1076c4SVincenzo Maffione 		printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
19961b1076c4SVincenzo Maffione 		context_cleanup(&ctxcopy);
19971b1076c4SVincenzo Maffione 	}
19981b1076c4SVincenzo Maffione out:
19991b1076c4SVincenzo Maffione 	tap_cleanup(0);
20001b1076c4SVincenzo Maffione 
20011b1076c4SVincenzo Maffione 	return ret;
20021b1076c4SVincenzo Maffione }
2003