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