xref: /freebsd/tests/sys/netmap/ctrl-api-test.c (revision ee5804da116f2107451c8b4376b69b3a64a630e8)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (C) 2018 Vincenzo Maffione
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *   1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *   2. Redistributions in binary form must reproduce the above copyright
12  *      notice, this list of conditions and the following disclaimer in the
13  *      documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 /*
29  * This program contains a suite of unit tests for the netmap control device.
30  *
31  * On FreeBSD, you can run these tests with Kyua once installed in the system:
32  *     # kyua test -k /usr/tests/sys/netmap/Kyuafile
33  *
34  * On Linux, you can run them directly:
35  *     # ./ctrl-api-test
36  */
37 
38 #include <sys/ioctl.h>
39 #include <sys/mman.h>
40 #include <sys/wait.h>
41 
42 #include <assert.h>
43 #include <ctype.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <inttypes.h>
47 #include <libnetmap.h>
48 #include <net/if.h>
49 #include <net/netmap.h>
50 #include <pthread.h>
51 #include <semaphore.h>
52 #include <stdint.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <time.h>
57 #include <unistd.h>
58 #include <signal.h>
59 #include <stddef.h>
60 
61 #ifdef __FreeBSD__
62 #include "freebsd_test_suite/macros.h"
63 
64 static int
eventfd(int x __unused,int y __unused)65 eventfd(int x __unused, int y __unused)
66 {
67 	errno = ENODEV;
68 	return -1;
69 }
70 #else /* __linux__ */
71 #include <sys/eventfd.h>
72 #endif
73 
74 #define NM_IFNAMSZ 64
75 
76 static int
exec_command(int argc,const char * const argv[])77 exec_command(int argc, const char *const argv[])
78 {
79 	pid_t child_pid;
80 	pid_t wret;
81 	int child_status;
82 	int i;
83 
84 	printf("Executing command: ");
85 	for (i = 0; i < argc - 1; i++) {
86 		if (!argv[i]) {
87 			/* Invalid argument. */
88 			return -1;
89 		}
90 		if (i > 0) {
91 			putchar(' ');
92 		}
93 		printf("%s", argv[i]);
94 	}
95 	putchar('\n');
96 
97 	child_pid = fork();
98 	if (child_pid == 0) {
99 		char **av;
100 		int fds[3];
101 
102 		/* Child process. Redirect stdin, stdout
103 		 * and stderr. */
104 		for (i = 0; i < 3; i++) {
105 			close(i);
106 			fds[i] = open("/dev/null", O_RDONLY);
107 			if (fds[i] < 0) {
108 				for (i--; i >= 0; i--) {
109 					close(fds[i]);
110 				}
111 				return -1;
112 			}
113 		}
114 
115 		/* Make a copy of the arguments, passing them to execvp. */
116 		av = calloc(argc, sizeof(av[0]));
117 		if (!av) {
118 			exit(EXIT_FAILURE);
119 		}
120 		for (i = 0; i < argc - 1; i++) {
121 			av[i] = strdup(argv[i]);
122 			if (!av[i]) {
123 				exit(EXIT_FAILURE);
124 			}
125 		}
126 		execvp(av[0], av);
127 		perror("execvp()");
128 		exit(EXIT_FAILURE);
129 	}
130 
131 	wret = waitpid(child_pid, &child_status, 0);
132 	if (wret < 0) {
133 		fprintf(stderr, "waitpid() failed: %s\n", strerror(errno));
134 		return wret;
135 	}
136 	if (WIFEXITED(child_status)) {
137 		return WEXITSTATUS(child_status);
138 	}
139 
140 	return -1;
141 }
142 
143 
144 #define THRET_SUCCESS	((void *)128)
145 #define THRET_FAILURE	((void *)0)
146 
147 struct TestContext {
148 	char ifname[NM_IFNAMSZ];
149 	char ifname_ext[NM_IFNAMSZ];
150 	char bdgname[NM_IFNAMSZ];
151 	uint32_t nr_tx_slots;   /* slots in tx rings */
152 	uint32_t nr_rx_slots;   /* slots in rx rings */
153 	uint16_t nr_tx_rings;   /* number of tx rings */
154 	uint16_t nr_rx_rings;   /* number of rx rings */
155 	uint16_t nr_host_tx_rings;   /* number of host tx rings */
156 	uint16_t nr_host_rx_rings;   /* number of host rx rings */
157 	uint16_t nr_mem_id;     /* id of the memory allocator */
158 	uint16_t nr_ringid;     /* ring(s) we care about */
159 	uint32_t nr_mode;       /* specify NR_REG_* modes */
160 	uint32_t nr_extra_bufs; /* number of requested extra buffers */
161 	uint64_t nr_flags;      /* additional flags (see below) */
162 	uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
163 	uint32_t nr_first_cpu_id;     /* vale polling */
164 	uint32_t nr_num_polling_cpus; /* vale polling */
165 	uint32_t sync_kloop_mode; /* sync-kloop */
166 	int fd; /* netmap file descriptor */
167 
168 	void *csb;                    /* CSB entries (atok and ktoa) */
169 	struct nmreq_option *nr_opt;  /* list of options */
170 	sem_t *sem;	/* for thread synchronization */
171 
172 	struct nmctx *nmctx;
173 	const char *ifparse;
174 	struct nmport_d *nmport;      /* nmport descriptor from libnetmap */
175 };
176 
177 static struct TestContext ctx_;
178 
179 typedef int (*testfunc_t)(struct TestContext *ctx);
180 
181 static void
nmreq_hdr_init(struct nmreq_header * hdr,const char * ifname)182 nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
183 {
184 	memset(hdr, 0, sizeof(*hdr));
185 	hdr->nr_version = NETMAP_API;
186 	assert(strlen(ifname) < NM_IFNAMSZ);
187 	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name));
188 }
189 
190 /* Single NETMAP_REQ_PORT_INFO_GET. */
191 static int
port_info_get(struct TestContext * ctx)192 port_info_get(struct TestContext *ctx)
193 {
194 	struct nmreq_port_info_get req;
195 	struct nmreq_header hdr;
196 	int success;
197 	int ret;
198 
199 	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname_ext);
200 
201 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
202 	hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
203 	hdr.nr_body    = (uintptr_t)&req;
204 	memset(&req, 0, sizeof(req));
205 	req.nr_mem_id = ctx->nr_mem_id;
206 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
207 	if (ret != 0) {
208 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
209 		return ret;
210 	}
211 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
212 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
213 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
214 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
215 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
216 	printf("nr_mem_id %u\n", req.nr_mem_id);
217 
218 	success = req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
219 	          req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings;
220 	if (!success) {
221 		return -1;
222 	}
223 
224 	/* Write back results to the context structure. */
225 	ctx->nr_tx_slots = req.nr_tx_slots;
226 	ctx->nr_rx_slots = req.nr_rx_slots;
227 	ctx->nr_tx_rings = req.nr_tx_rings;
228 	ctx->nr_rx_rings = req.nr_rx_rings;
229 	ctx->nr_mem_id   = req.nr_mem_id;
230 
231 	return 0;
232 }
233 
234 /* Single NETMAP_REQ_REGISTER, no use. */
235 static int
port_register(struct TestContext * ctx)236 port_register(struct TestContext *ctx)
237 {
238 	struct nmreq_register req;
239 	struct nmreq_header hdr;
240 	int success;
241 	int ret;
242 
243 	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
244 	       "flags=0x%llx) on '%s'\n",
245 	       ctx->nr_mode, ctx->nr_ringid, (unsigned long long)ctx->nr_flags,
246 	       ctx->ifname_ext);
247 
248 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
249 	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
250 	hdr.nr_body    = (uintptr_t)&req;
251 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
252 	memset(&req, 0, sizeof(req));
253 	req.nr_mem_id     = ctx->nr_mem_id;
254 	req.nr_mode       = ctx->nr_mode;
255 	req.nr_ringid     = ctx->nr_ringid;
256 	req.nr_flags      = ctx->nr_flags;
257 	req.nr_tx_slots   = ctx->nr_tx_slots;
258 	req.nr_rx_slots   = ctx->nr_rx_slots;
259 	req.nr_tx_rings   = ctx->nr_tx_rings;
260 	req.nr_host_tx_rings = ctx->nr_host_tx_rings;
261 	req.nr_host_rx_rings = ctx->nr_host_rx_rings;
262 	req.nr_rx_rings   = ctx->nr_rx_rings;
263 	req.nr_extra_bufs = ctx->nr_extra_bufs;
264 	ret               = ioctl(ctx->fd, NIOCCTRL, &hdr);
265 	if (ret != 0) {
266 		perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
267 		return ret;
268 	}
269 	printf("nr_offset 0x%llx\n", (unsigned long long)req.nr_offset);
270 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
271 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
272 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
273 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
274 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
275 	printf("nr_host_tx_rings %u\n", req.nr_host_tx_rings);
276 	printf("nr_host_rx_rings %u\n", req.nr_host_rx_rings);
277 	printf("nr_mem_id %u\n", req.nr_mem_id);
278 	printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
279 
280 	success = req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
281 		       (ctx->nr_ringid == req.nr_ringid) &&
282 		       (ctx->nr_flags == req.nr_flags) &&
283 		       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
284 			(ctx->nr_tx_slots == req.nr_tx_slots)) &&
285 		       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
286 			(ctx->nr_rx_slots == req.nr_rx_slots)) &&
287 		       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
288 			(ctx->nr_tx_rings == req.nr_tx_rings)) &&
289 		       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
290 			(ctx->nr_rx_rings == req.nr_rx_rings)) &&
291 		       ((!ctx->nr_host_tx_rings && req.nr_host_tx_rings) ||
292 			(ctx->nr_host_tx_rings == req.nr_host_tx_rings)) &&
293 		       ((!ctx->nr_host_rx_rings && req.nr_host_rx_rings) ||
294 			(ctx->nr_host_rx_rings == req.nr_host_rx_rings)) &&
295 		       ((!ctx->nr_mem_id && req.nr_mem_id) ||
296 			(ctx->nr_mem_id == req.nr_mem_id)) &&
297 		       (ctx->nr_extra_bufs == req.nr_extra_bufs);
298 	if (!success) {
299 		return -1;
300 	}
301 
302 	/* Write back results to the context structure.*/
303 	ctx->nr_tx_slots   = req.nr_tx_slots;
304 	ctx->nr_rx_slots   = req.nr_rx_slots;
305 	ctx->nr_tx_rings   = req.nr_tx_rings;
306 	ctx->nr_rx_rings   = req.nr_rx_rings;
307 	ctx->nr_host_tx_rings = req.nr_host_tx_rings;
308 	ctx->nr_host_rx_rings = req.nr_host_rx_rings;
309 	ctx->nr_mem_id     = req.nr_mem_id;
310 	ctx->nr_extra_bufs = req.nr_extra_bufs;
311 
312 	return 0;
313 }
314 
315 static int
niocregif(struct TestContext * ctx,int netmap_api)316 niocregif(struct TestContext *ctx, int netmap_api)
317 {
318 	struct nmreq req;
319 	int success;
320 	int ret;
321 
322 	printf("Testing legacy NIOCREGIF on '%s'\n", ctx->ifname_ext);
323 
324 	memset(&req, 0, sizeof(req));
325 	memcpy(req.nr_name, ctx->ifname_ext, sizeof(req.nr_name));
326 	req.nr_name[sizeof(req.nr_name) - 1] = '\0';
327 	req.nr_version = netmap_api;
328 	req.nr_ringid     = ctx->nr_ringid;
329 	req.nr_flags      = ctx->nr_mode | ctx->nr_flags;
330 	req.nr_tx_slots   = ctx->nr_tx_slots;
331 	req.nr_rx_slots   = ctx->nr_rx_slots;
332 	req.nr_tx_rings   = ctx->nr_tx_rings;
333 	req.nr_rx_rings   = ctx->nr_rx_rings;
334 	req.nr_arg2     = ctx->nr_mem_id;
335 	req.nr_arg3 = ctx->nr_extra_bufs;
336 
337 	ret = ioctl(ctx->fd, NIOCREGIF, &req);
338 	if (ret != 0) {
339 		perror("ioctl(/dev/netmap, NIOCREGIF)");
340 		return ret;
341 	}
342 
343 	printf("nr_offset 0x%x\n", req.nr_offset);
344 	printf("nr_memsize  %u\n", req.nr_memsize);
345 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
346 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
347 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
348 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
349 	printf("nr_version  %d\n", req.nr_version);
350 	printf("nr_ringid   %x\n", req.nr_ringid);
351 	printf("nr_flags    %x\n", req.nr_flags);
352 	printf("nr_arg2     %u\n", req.nr_arg2);
353 	printf("nr_arg3     %u\n", req.nr_arg3);
354 
355 	success = req.nr_memsize &&
356 	       (ctx->nr_ringid == req.nr_ringid) &&
357 	       ((ctx->nr_mode | ctx->nr_flags) == req.nr_flags) &&
358 	       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
359 		(ctx->nr_tx_slots == req.nr_tx_slots)) &&
360 	       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
361 		(ctx->nr_rx_slots == req.nr_rx_slots)) &&
362 	       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
363 		(ctx->nr_tx_rings == req.nr_tx_rings)) &&
364 	       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
365 		(ctx->nr_rx_rings == req.nr_rx_rings)) &&
366 	       ((!ctx->nr_mem_id && req.nr_arg2) ||
367 		(ctx->nr_mem_id == req.nr_arg2)) &&
368 	       (ctx->nr_extra_bufs == req.nr_arg3);
369 	if (!success) {
370 		return -1;
371 	}
372 
373 	/* Write back results to the context structure.*/
374 	ctx->nr_tx_slots   = req.nr_tx_slots;
375 	ctx->nr_rx_slots   = req.nr_rx_slots;
376 	ctx->nr_tx_rings   = req.nr_tx_rings;
377 	ctx->nr_rx_rings   = req.nr_rx_rings;
378 	ctx->nr_mem_id     = req.nr_arg2;
379 	ctx->nr_extra_bufs = req.nr_arg3;
380 
381 	return ret;
382 }
383 
384 /* The 11 ABI is the one right before the introduction of the new NIOCCTRL
385  * ABI. The 11 ABI is useful to perform tests with legacy applications
386  * (which use the 11 ABI) and new kernel (which uses 12, or higher).
387  * However, version 14 introduced a change in the layout of struct netmap_if,
388  * so that binary backward compatibility to 11 is not supported anymore.
389  */
390 #define NETMAP_API_NIOCREGIF	14
391 
392 static int
legacy_regif_default(struct TestContext * ctx)393 legacy_regif_default(struct TestContext *ctx)
394 {
395 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
396 }
397 
398 static int
legacy_regif_all_nic(struct TestContext * ctx)399 legacy_regif_all_nic(struct TestContext *ctx)
400 {
401 	ctx->nr_mode = NR_REG_ALL_NIC;
402 	return niocregif(ctx, NETMAP_API);
403 }
404 
405 static int
legacy_regif_12(struct TestContext * ctx)406 legacy_regif_12(struct TestContext *ctx)
407 {
408 	ctx->nr_mode = NR_REG_ALL_NIC;
409 	return niocregif(ctx, NETMAP_API_NIOCREGIF+1);
410 }
411 
412 static int
legacy_regif_sw(struct TestContext * ctx)413 legacy_regif_sw(struct TestContext *ctx)
414 {
415 	ctx->nr_mode = NR_REG_SW;
416 	return niocregif(ctx,  NETMAP_API_NIOCREGIF);
417 }
418 
419 static int
legacy_regif_future(struct TestContext * ctx)420 legacy_regif_future(struct TestContext *ctx)
421 {
422 	ctx->nr_mode = NR_REG_NIC_SW;
423 	/* Test forward compatibility for the legacy ABI. This means
424 	 * using an older kernel (with ABI 12 or higher) and a newer
425 	 * application (with ABI greater than NETMAP_API). */
426 	return niocregif(ctx, NETMAP_API+2);
427 }
428 
429 static int
legacy_regif_extra_bufs(struct TestContext * ctx)430 legacy_regif_extra_bufs(struct TestContext *ctx)
431 {
432 	ctx->nr_mode = NR_REG_ALL_NIC;
433 	ctx->nr_extra_bufs = 20;	/* arbitrary number of extra bufs */
434 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
435 }
436 
437 static int
legacy_regif_extra_bufs_pipe(struct TestContext * ctx)438 legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
439 {
440 	strncat(ctx->ifname_ext, "{pipeexbuf", sizeof(ctx->ifname_ext));
441 	ctx->nr_mode = NR_REG_ALL_NIC;
442 	ctx->nr_extra_bufs = 58;	/* arbitrary number of extra bufs */
443 
444 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
445 }
446 
447 static int
legacy_regif_extra_bufs_pipe_vale(struct TestContext * ctx)448 legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
449 {
450 	strncpy(ctx->ifname_ext, "valeX1:Y4", sizeof(ctx->ifname_ext));
451 	return legacy_regif_extra_bufs_pipe(ctx);
452 }
453 
454 /* Only valid after a successful port_register(). */
455 static int
num_registered_rings(struct TestContext * ctx)456 num_registered_rings(struct TestContext *ctx)
457 {
458 	if (ctx->nr_flags & NR_TX_RINGS_ONLY) {
459 		return ctx->nr_tx_rings;
460 	}
461 	if (ctx->nr_flags & NR_RX_RINGS_ONLY) {
462 		return ctx->nr_rx_rings;
463 	}
464 
465 	return ctx->nr_tx_rings + ctx->nr_rx_rings;
466 }
467 
468 static int
port_register_hwall_host(struct TestContext * ctx)469 port_register_hwall_host(struct TestContext *ctx)
470 {
471 	ctx->nr_mode = NR_REG_NIC_SW;
472 	return port_register(ctx);
473 }
474 
475 static int
port_register_hostall(struct TestContext * ctx)476 port_register_hostall(struct TestContext *ctx)
477 {
478 	ctx->nr_mode = NR_REG_SW;
479 	return port_register(ctx);
480 }
481 
482 static int
port_register_hwall(struct TestContext * ctx)483 port_register_hwall(struct TestContext *ctx)
484 {
485 	ctx->nr_mode = NR_REG_ALL_NIC;
486 	return port_register(ctx);
487 }
488 
489 static int
port_register_single_hw_pair(struct TestContext * ctx)490 port_register_single_hw_pair(struct TestContext *ctx)
491 {
492 	ctx->nr_mode   = NR_REG_ONE_NIC;
493 	ctx->nr_ringid = 0;
494 	return port_register(ctx);
495 }
496 
497 static int
port_register_single_host_pair(struct TestContext * ctx)498 port_register_single_host_pair(struct TestContext *ctx)
499 {
500 	ctx->nr_mode   = NR_REG_ONE_SW;
501 	ctx->nr_host_tx_rings = 2;
502 	ctx->nr_host_rx_rings = 2;
503 	ctx->nr_ringid = 1;
504 	return port_register(ctx);
505 }
506 
507 static int
port_register_hostall_many(struct TestContext * ctx)508 port_register_hostall_many(struct TestContext *ctx)
509 {
510 	ctx->nr_mode   = NR_REG_SW;
511 	ctx->nr_host_tx_rings = 5;
512 	ctx->nr_host_rx_rings = 4;
513 	return port_register(ctx);
514 }
515 
516 static int
port_register_hwall_tx(struct TestContext * ctx)517 port_register_hwall_tx(struct TestContext *ctx)
518 {
519 	ctx->nr_mode = NR_REG_ALL_NIC;
520 	ctx->nr_flags |= NR_TX_RINGS_ONLY;
521 	return port_register(ctx);
522 }
523 
524 static int
port_register_hwall_rx(struct TestContext * ctx)525 port_register_hwall_rx(struct TestContext *ctx)
526 {
527 	ctx->nr_mode = NR_REG_ALL_NIC;
528 	ctx->nr_flags |= NR_RX_RINGS_ONLY;
529 	return port_register(ctx);
530 }
531 
532 
533 static int
vale_mkname(char * vpname,struct TestContext * ctx)534 vale_mkname(char *vpname, struct TestContext *ctx)
535 {
536 	if (snprintf(vpname, NM_IFNAMSZ, "%s:%s", ctx->bdgname, ctx->ifname_ext) >= NM_IFNAMSZ) {
537 		fprintf(stderr, "%s:%s too long (max %d chars)\n", ctx->bdgname, ctx->ifname_ext,
538 				NM_IFNAMSZ - 1);
539 		return -1;
540 	}
541 	return 0;
542 }
543 
544 
545 /* NETMAP_REQ_VALE_ATTACH */
546 static int
vale_attach(struct TestContext * ctx)547 vale_attach(struct TestContext *ctx)
548 {
549 	struct nmreq_vale_attach req;
550 	struct nmreq_header hdr;
551 	char vpname[NM_IFNAMSZ];
552 	int ret;
553 
554 	if (vale_mkname(vpname, ctx) < 0)
555 		return -1;
556 
557 	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
558 	nmreq_hdr_init(&hdr, vpname);
559 	hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
560 	hdr.nr_body    = (uintptr_t)&req;
561 	memset(&req, 0, sizeof(req));
562 	req.reg.nr_mem_id = ctx->nr_mem_id;
563 	if (ctx->nr_mode == 0) {
564 		ctx->nr_mode = NR_REG_ALL_NIC; /* default */
565 	}
566 	req.reg.nr_mode = ctx->nr_mode;
567 	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
568 	if (ret != 0) {
569 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
570 		return ret;
571 	}
572 	printf("nr_mem_id %u\n", req.reg.nr_mem_id);
573 
574 	return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
575 	        (ctx->nr_mem_id == req.reg.nr_mem_id)) &&
576 	                       (ctx->nr_flags == req.reg.nr_flags)
577 	               ? 0
578 	               : -1;
579 }
580 
581 /* NETMAP_REQ_VALE_DETACH */
582 static int
vale_detach(struct TestContext * ctx)583 vale_detach(struct TestContext *ctx)
584 {
585 	struct nmreq_header hdr;
586 	struct nmreq_vale_detach req;
587 	char vpname[NM_IFNAMSZ];
588 	int ret;
589 
590 	if (vale_mkname(vpname, ctx) < 0)
591 		return -1;
592 
593 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
594 	nmreq_hdr_init(&hdr, vpname);
595 	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
596 	hdr.nr_body    = (uintptr_t)&req;
597 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
598 	if (ret != 0) {
599 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
600 		return ret;
601 	}
602 
603 	return 0;
604 }
605 
606 /* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
607 static int
vale_attach_detach(struct TestContext * ctx)608 vale_attach_detach(struct TestContext *ctx)
609 {
610 	int ret;
611 
612 	if ((ret = vale_attach(ctx)) != 0) {
613 		return ret;
614 	}
615 
616 	return vale_detach(ctx);
617 }
618 
619 static int
vale_attach_detach_host_rings(struct TestContext * ctx)620 vale_attach_detach_host_rings(struct TestContext *ctx)
621 {
622 	ctx->nr_mode = NR_REG_NIC_SW;
623 	return vale_attach_detach(ctx);
624 }
625 
626 /* First NETMAP_REQ_PORT_HDR_SET and the NETMAP_REQ_PORT_HDR_GET
627  * to check that we get the same value. */
628 static int
port_hdr_set_and_get(struct TestContext * ctx)629 port_hdr_set_and_get(struct TestContext *ctx)
630 {
631 	struct nmreq_port_hdr req;
632 	struct nmreq_header hdr;
633 	int ret;
634 
635 	printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname_ext);
636 
637 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
638 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
639 	hdr.nr_body    = (uintptr_t)&req;
640 	memset(&req, 0, sizeof(req));
641 	req.nr_hdr_len = ctx->nr_hdr_len;
642 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
643 	if (ret != 0) {
644 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
645 		return ret;
646 	}
647 
648 	if (req.nr_hdr_len != ctx->nr_hdr_len) {
649 		return -1;
650 	}
651 
652 	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname_ext);
653 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
654 	req.nr_hdr_len = 0;
655 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
656 	if (ret != 0) {
657 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
658 		return ret;
659 	}
660 	printf("nr_hdr_len %u\n", req.nr_hdr_len);
661 
662 	return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
663 }
664 
665 /*
666  * Possible lengths for the VirtIO network header, as specified by
667  * the standard:
668  *    http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html
669  */
670 #define VIRTIO_NET_HDR_LEN				10
671 #define VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS	12
672 
673 static int
vale_ephemeral_port_hdr_manipulation(struct TestContext * ctx)674 vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
675 {
676 	int ret;
677 
678 	strncpy(ctx->ifname_ext, "vale:eph0", sizeof(ctx->ifname_ext));
679 	ctx->nr_mode = NR_REG_ALL_NIC;
680 	if ((ret = port_register(ctx))) {
681 		return ret;
682 	}
683 	/* Try to set and get all the acceptable values. */
684 	ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS;
685 	if ((ret = port_hdr_set_and_get(ctx))) {
686 		return ret;
687 	}
688 	ctx->nr_hdr_len = 0;
689 	if ((ret = port_hdr_set_and_get(ctx))) {
690 		return ret;
691 	}
692 	ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN;
693 	if ((ret = port_hdr_set_and_get(ctx))) {
694 		return ret;
695 	}
696 	return 0;
697 }
698 
699 static int
vale_persistent_port(struct TestContext * ctx)700 vale_persistent_port(struct TestContext *ctx)
701 {
702 	struct nmreq_vale_newif req;
703 	struct nmreq_header hdr;
704 	int result;
705 	int ret;
706 
707 	strncpy(ctx->ifname_ext, "per4", sizeof(ctx->ifname_ext));
708 
709 	printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname_ext);
710 
711 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
712 	hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
713 	hdr.nr_body    = (uintptr_t)&req;
714 	memset(&req, 0, sizeof(req));
715 	req.nr_mem_id   = ctx->nr_mem_id;
716 	req.nr_tx_slots = ctx->nr_tx_slots;
717 	req.nr_rx_slots = ctx->nr_rx_slots;
718 	req.nr_tx_rings = ctx->nr_tx_rings;
719 	req.nr_rx_rings = ctx->nr_rx_rings;
720 	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
721 	if (ret != 0) {
722 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
723 		return ret;
724 	}
725 
726 	/* Attach the persistent VALE port to a switch and then detach. */
727 	result = vale_attach_detach(ctx);
728 
729 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname_ext);
730 	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
731 	hdr.nr_body    = (uintptr_t)NULL;
732 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
733 	if (ret != 0) {
734 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
735 		if (result == 0) {
736 			result = ret;
737 		}
738 	}
739 
740 	return result;
741 }
742 
743 /* Single NETMAP_REQ_POOLS_INFO_GET. */
744 static int
pools_info_get(struct TestContext * ctx)745 pools_info_get(struct TestContext *ctx)
746 {
747 	struct nmreq_pools_info req;
748 	struct nmreq_header hdr;
749 	int ret;
750 
751 	printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname_ext);
752 
753 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
754 	hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
755 	hdr.nr_body    = (uintptr_t)&req;
756 	memset(&req, 0, sizeof(req));
757 	req.nr_mem_id = ctx->nr_mem_id;
758 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
759 	if (ret != 0) {
760 		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
761 		return ret;
762 	}
763 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
764 	printf("nr_mem_id %u\n", req.nr_mem_id);
765 	printf("nr_if_pool_offset 0x%llx\n",
766 		(unsigned long long)req.nr_if_pool_offset);
767 	printf("nr_if_pool_objtotal %u\n", req.nr_if_pool_objtotal);
768 	printf("nr_if_pool_objsize %u\n", req.nr_if_pool_objsize);
769 	printf("nr_ring_pool_offset 0x%llx\n",
770 		(unsigned long long)req.nr_if_pool_offset);
771 	printf("nr_ring_pool_objtotal %u\n", req.nr_ring_pool_objtotal);
772 	printf("nr_ring_pool_objsize %u\n", req.nr_ring_pool_objsize);
773 	printf("nr_buf_pool_offset 0x%llx\n",
774 		(unsigned long long)req.nr_buf_pool_offset);
775 	printf("nr_buf_pool_objtotal %u\n", req.nr_buf_pool_objtotal);
776 	printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
777 
778 	return req.nr_memsize && req.nr_if_pool_objtotal &&
779 	                       req.nr_if_pool_objsize &&
780 	                       req.nr_ring_pool_objtotal &&
781 	                       req.nr_ring_pool_objsize &&
782 	                       req.nr_buf_pool_objtotal &&
783 	                       req.nr_buf_pool_objsize
784 	               ? 0
785 	               : -1;
786 }
787 
788 static int
pools_info_get_and_register(struct TestContext * ctx)789 pools_info_get_and_register(struct TestContext *ctx)
790 {
791 	int ret;
792 
793 	/* Check that we can get pools info before we register
794 	 * a netmap interface. */
795 	ret = pools_info_get(ctx);
796 	if (ret != 0) {
797 		return ret;
798 	}
799 
800 	ctx->nr_mode = NR_REG_ONE_NIC;
801 	ret          = port_register(ctx);
802 	if (ret != 0) {
803 		return ret;
804 	}
805 	ctx->nr_mem_id = 1;
806 
807 	/* Check that we can get pools info also after we register. */
808 	return pools_info_get(ctx);
809 }
810 
811 static int
pools_info_get_empty_ifname(struct TestContext * ctx)812 pools_info_get_empty_ifname(struct TestContext *ctx)
813 {
814 	strncpy(ctx->ifname_ext, "", sizeof(ctx->ifname_ext));
815 	return pools_info_get(ctx) != 0 ? 0 : -1;
816 }
817 
818 static int
pipe_master(struct TestContext * ctx)819 pipe_master(struct TestContext *ctx)
820 {
821 	strncat(ctx->ifname_ext, "{pipeid1", sizeof(ctx->ifname_ext));
822 	ctx->nr_mode = NR_REG_NIC_SW;
823 
824 	if (port_register(ctx) == 0) {
825 		printf("pipes should not accept NR_REG_NIC_SW\n");
826 		return -1;
827 	}
828 	ctx->nr_mode = NR_REG_ALL_NIC;
829 
830 	return port_register(ctx);
831 }
832 
833 static int
pipe_slave(struct TestContext * ctx)834 pipe_slave(struct TestContext *ctx)
835 {
836 	strncat(ctx->ifname_ext, "}pipeid2", sizeof(ctx->ifname_ext));
837 	ctx->nr_mode = NR_REG_ALL_NIC;
838 
839 	return port_register(ctx);
840 }
841 
842 /* Test PORT_INFO_GET and POOLS_INFO_GET on a pipe. This is useful to test the
843  * registration request used internally by netmap. */
844 static int
pipe_port_info_get(struct TestContext * ctx)845 pipe_port_info_get(struct TestContext *ctx)
846 {
847 	strncat(ctx->ifname_ext, "}pipeid3", sizeof(ctx->ifname_ext));
848 
849 	return port_info_get(ctx);
850 }
851 
852 static int
pipe_pools_info_get(struct TestContext * ctx)853 pipe_pools_info_get(struct TestContext *ctx)
854 {
855 	strncat(ctx->ifname_ext, "{xid", sizeof(ctx->ifname_ext));
856 
857 	return pools_info_get(ctx);
858 }
859 
860 /* NETMAP_REQ_VALE_POLLING_ENABLE */
861 static int
vale_polling_enable(struct TestContext * ctx)862 vale_polling_enable(struct TestContext *ctx)
863 {
864 	struct nmreq_vale_polling req;
865 	struct nmreq_header hdr;
866 	char vpname[NM_IFNAMSZ];
867 	int ret;
868 
869 	if (vale_mkname(vpname, ctx) < 0)
870 		return -1;
871 
872 	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
873 
874 	nmreq_hdr_init(&hdr, vpname);
875 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
876 	hdr.nr_body    = (uintptr_t)&req;
877 	memset(&req, 0, sizeof(req));
878 	req.nr_mode             = ctx->nr_mode;
879 	req.nr_first_cpu_id     = ctx->nr_first_cpu_id;
880 	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
881 	ret                     = ioctl(ctx->fd, NIOCCTRL, &hdr);
882 	if (ret != 0) {
883 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
884 		return ret;
885 	}
886 
887 	return (req.nr_mode == ctx->nr_mode &&
888 	        req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
889 	        req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
890 	               ? 0
891 	               : -1;
892 }
893 
894 /* NETMAP_REQ_VALE_POLLING_DISABLE */
895 static int
vale_polling_disable(struct TestContext * ctx)896 vale_polling_disable(struct TestContext *ctx)
897 {
898 	struct nmreq_vale_polling req;
899 	struct nmreq_header hdr;
900 	char vpname[NM_IFNAMSZ];
901 	int ret;
902 
903 	if (vale_mkname(vpname, ctx) < 0)
904 		return -1;
905 
906 	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
907 
908 	nmreq_hdr_init(&hdr, vpname);
909 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
910 	hdr.nr_body    = (uintptr_t)&req;
911 	memset(&req, 0, sizeof(req));
912 	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
913 	if (ret != 0) {
914 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
915 		return ret;
916 	}
917 
918 	return 0;
919 }
920 
921 static int
vale_polling_enable_disable(struct TestContext * ctx)922 vale_polling_enable_disable(struct TestContext *ctx)
923 {
924 	int ret = 0;
925 
926 	if ((ret = vale_attach(ctx)) != 0) {
927 		return ret;
928 	}
929 
930 	ctx->nr_mode             = NETMAP_POLLING_MODE_SINGLE_CPU;
931 	ctx->nr_num_polling_cpus = 1;
932 	ctx->nr_first_cpu_id     = 0;
933 	if ((ret = vale_polling_enable(ctx))) {
934 		vale_detach(ctx);
935 #ifdef __FreeBSD__
936 		/* NETMAP_REQ_VALE_POLLING_DISABLE is disabled on FreeBSD,
937 		 * because it is currently broken. We are happy to see that
938 		 * it fails. */
939 		return 0;
940 #else
941 		return ret;
942 #endif
943 	}
944 
945 	if ((ret = vale_polling_disable(ctx))) {
946 		vale_detach(ctx);
947 		return ret;
948 	}
949 
950 	return vale_detach(ctx);
951 }
952 
953 static void
push_option(struct nmreq_option * opt,struct TestContext * ctx)954 push_option(struct nmreq_option *opt, struct TestContext *ctx)
955 {
956 	opt->nro_next = (uintptr_t)ctx->nr_opt;
957 	ctx->nr_opt   = opt;
958 }
959 
960 static void
clear_options(struct TestContext * ctx)961 clear_options(struct TestContext *ctx)
962 {
963 	ctx->nr_opt = NULL;
964 }
965 
966 static int
checkoption(struct nmreq_option * opt,struct nmreq_option * exp)967 checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
968 {
969 	if (opt->nro_next != exp->nro_next) {
970 		printf("nro_next %p expected %p\n",
971 		       (void *)(uintptr_t)opt->nro_next,
972 		       (void *)(uintptr_t)exp->nro_next);
973 		return -1;
974 	}
975 	if (opt->nro_reqtype != exp->nro_reqtype) {
976 		printf("nro_reqtype %u expected %u\n", opt->nro_reqtype,
977 		       exp->nro_reqtype);
978 		return -1;
979 	}
980 	if (opt->nro_status != exp->nro_status) {
981 		printf("nro_status %u expected %u\n", opt->nro_status,
982 		       exp->nro_status);
983 		return -1;
984 	}
985 	return 0;
986 }
987 
988 static int
unsupported_option(struct TestContext * ctx)989 unsupported_option(struct TestContext *ctx)
990 {
991 	struct nmreq_option opt, save;
992 
993 	printf("Testing unsupported option on %s\n", ctx->ifname_ext);
994 
995 	memset(&opt, 0, sizeof(opt));
996 	opt.nro_reqtype = 1234;
997 	push_option(&opt, ctx);
998 	save = opt;
999 
1000 	if (port_register_hwall(ctx) >= 0)
1001 		return -1;
1002 
1003 	clear_options(ctx);
1004 	save.nro_status = EOPNOTSUPP;
1005 	return checkoption(&opt, &save);
1006 }
1007 
1008 static int
infinite_options(struct TestContext * ctx)1009 infinite_options(struct TestContext *ctx)
1010 {
1011 	struct nmreq_option opt;
1012 
1013 	printf("Testing infinite list of options on %s (invalid options)\n", ctx->ifname_ext);
1014 
1015 	memset(&opt, 0, sizeof(opt));
1016 	opt.nro_reqtype = NETMAP_REQ_OPT_MAX + 1;
1017 	push_option(&opt, ctx);
1018 	opt.nro_next = (uintptr_t)&opt;
1019 	if (port_register_hwall(ctx) >= 0)
1020 		return -1;
1021 	clear_options(ctx);
1022 	return (errno == EMSGSIZE ? 0 : -1);
1023 }
1024 
1025 static int
infinite_options2(struct TestContext * ctx)1026 infinite_options2(struct TestContext *ctx)
1027 {
1028 	struct nmreq_option opt;
1029 
1030 	printf("Testing infinite list of options on %s (valid options)\n", ctx->ifname_ext);
1031 
1032 	memset(&opt, 0, sizeof(opt));
1033 	opt.nro_reqtype = NETMAP_REQ_OPT_OFFSETS;
1034 	push_option(&opt, ctx);
1035 	opt.nro_next = (uintptr_t)&opt;
1036 	if (port_register_hwall(ctx) >= 0)
1037 		return -1;
1038 	clear_options(ctx);
1039 	return (errno == EINVAL ? 0 : -1);
1040 }
1041 
1042 #ifdef CONFIG_NETMAP_EXTMEM
1043 int
change_param(const char * pname,unsigned long newv,unsigned long * poldv)1044 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
1045 {
1046 #ifdef __linux__
1047 	char param[256] = "/sys/module/netmap/parameters/";
1048 	unsigned long oldv;
1049 	FILE *f;
1050 
1051 	strncat(param, pname, sizeof(param) - 1);
1052 
1053 	f = fopen(param, "r+");
1054 	if (f == NULL) {
1055 		perror(param);
1056 		return -1;
1057 	}
1058 	if (fscanf(f, "%ld", &oldv) != 1) {
1059 		perror(param);
1060 		fclose(f);
1061 		return -1;
1062 	}
1063 	if (poldv)
1064 		*poldv = oldv;
1065 	rewind(f);
1066 	if (fprintf(f, "%ld\n", newv) < 0) {
1067 		perror(param);
1068 		fclose(f);
1069 		return -1;
1070 	}
1071 	fclose(f);
1072 	printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
1073 #endif /* __linux__ */
1074 	return 0;
1075 }
1076 
1077 static int
push_extmem_option(struct TestContext * ctx,const struct nmreq_pools_info * pi,struct nmreq_opt_extmem * e)1078 push_extmem_option(struct TestContext *ctx, const struct nmreq_pools_info *pi,
1079 		struct nmreq_opt_extmem *e)
1080 {
1081 	void *addr;
1082 
1083 	addr = mmap(NULL, pi->nr_memsize, PROT_READ | PROT_WRITE,
1084 	            MAP_ANONYMOUS | MAP_SHARED, -1, 0);
1085 	if (addr == MAP_FAILED) {
1086 		perror("mmap");
1087 		return -1;
1088 	}
1089 
1090 	memset(e, 0, sizeof(*e));
1091 	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
1092 	e->nro_info = *pi;
1093 	e->nro_usrptr          = (uintptr_t)addr;
1094 
1095 	push_option(&e->nro_opt, ctx);
1096 
1097 	return 0;
1098 }
1099 
1100 static int
pop_extmem_option(struct TestContext * ctx,struct nmreq_opt_extmem * exp)1101 pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
1102 {
1103 	struct nmreq_opt_extmem *e;
1104 	int ret;
1105 
1106 	e           = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
1107 	ctx->nr_opt = (struct nmreq_option *)(uintptr_t)ctx->nr_opt->nro_next;
1108 
1109 	if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
1110 		return ret;
1111 	}
1112 
1113 	if (e->nro_usrptr != exp->nro_usrptr) {
1114 		printf("usrptr %" PRIu64 " expected %" PRIu64 "\n",
1115 		       e->nro_usrptr, exp->nro_usrptr);
1116 		return -1;
1117 	}
1118 	if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
1119 		printf("memsize %" PRIu64 " expected %" PRIu64 "\n",
1120 		       e->nro_info.nr_memsize, exp->nro_info.nr_memsize);
1121 		return -1;
1122 	}
1123 
1124 	if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr,
1125 	                  e->nro_info.nr_memsize)))
1126 		return ret;
1127 
1128 	return 0;
1129 }
1130 
1131 static int
_extmem_option(struct TestContext * ctx,const struct nmreq_pools_info * pi)1132 _extmem_option(struct TestContext *ctx,
1133 		const struct nmreq_pools_info *pi)
1134 {
1135 	struct nmreq_opt_extmem e, save;
1136 	int ret;
1137 
1138 	if ((ret = push_extmem_option(ctx, pi, &e)) < 0)
1139 		return ret;
1140 
1141 	save = e;
1142 
1143 	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
1144 	ctx->nr_tx_slots = 16;
1145 	ctx->nr_rx_slots = 16;
1146 
1147 	if ((ret = port_register_hwall(ctx)))
1148 		return ret;
1149 
1150 	ret = pop_extmem_option(ctx, &save);
1151 
1152 	return ret;
1153 }
1154 
1155 static size_t
pools_info_min_memsize(const struct nmreq_pools_info * pi)1156 pools_info_min_memsize(const struct nmreq_pools_info *pi)
1157 {
1158 	size_t tot = 0;
1159 
1160 	tot += pi->nr_if_pool_objtotal * pi->nr_if_pool_objsize;
1161 	tot += pi->nr_ring_pool_objtotal * pi->nr_ring_pool_objsize;
1162 	tot += pi->nr_buf_pool_objtotal * pi->nr_buf_pool_objsize;
1163 
1164 	return tot;
1165 }
1166 
1167 /*
1168  * Fill the specification of a netmap memory allocator to be
1169  * used with the 'struct nmreq_opt_extmem' option. Arbitrary
1170  * values are used for the parameters, but with enough netmap
1171  * rings, netmap ifs, and buffers to support a VALE port.
1172  */
1173 static void
pools_info_fill(struct nmreq_pools_info * pi)1174 pools_info_fill(struct nmreq_pools_info *pi)
1175 {
1176 	pi->nr_if_pool_objtotal = 2;
1177 	pi->nr_if_pool_objsize = 1024;
1178 	pi->nr_ring_pool_objtotal = 64;
1179 	pi->nr_ring_pool_objsize = 512;
1180 	pi->nr_buf_pool_objtotal = 4096;
1181 	pi->nr_buf_pool_objsize = 2048;
1182 	pi->nr_memsize = pools_info_min_memsize(pi);
1183 }
1184 
1185 static int
extmem_option(struct TestContext * ctx)1186 extmem_option(struct TestContext *ctx)
1187 {
1188 	struct nmreq_pools_info	pools_info;
1189 
1190 	pools_info_fill(&pools_info);
1191 
1192 	printf("Testing extmem option on vale0:0\n");
1193 	return _extmem_option(ctx, &pools_info);
1194 }
1195 
1196 static int
bad_extmem_option(struct TestContext * ctx)1197 bad_extmem_option(struct TestContext *ctx)
1198 {
1199 	struct nmreq_pools_info	pools_info;
1200 
1201 	printf("Testing bad extmem option on vale0:0\n");
1202 
1203 	pools_info_fill(&pools_info);
1204 	/* Request a large ring size, to make sure that the kernel
1205 	 * rejects our request. */
1206 	pools_info.nr_ring_pool_objsize = (1 << 20);
1207 
1208 	return _extmem_option(ctx, &pools_info) < 0 ? 0 : -1;
1209 }
1210 
1211 static int
duplicate_extmem_options(struct TestContext * ctx)1212 duplicate_extmem_options(struct TestContext *ctx)
1213 {
1214 	struct nmreq_opt_extmem e1, save1, e2, save2;
1215 	struct nmreq_pools_info	pools_info;
1216 	int ret;
1217 
1218 	printf("Testing duplicate extmem option on vale0:0\n");
1219 
1220 	pools_info_fill(&pools_info);
1221 
1222 	if ((ret = push_extmem_option(ctx, &pools_info, &e1)) < 0)
1223 		return ret;
1224 
1225 	if ((ret = push_extmem_option(ctx, &pools_info, &e2)) < 0) {
1226 		clear_options(ctx);
1227 		return ret;
1228 	}
1229 
1230 	save1 = e1;
1231 	save2 = e2;
1232 
1233 	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
1234 	ctx->nr_tx_slots = 16;
1235 	ctx->nr_rx_slots = 16;
1236 
1237 	ret = port_register_hwall(ctx);
1238 	if (ret >= 0) {
1239 		printf("duplicate option not detected\n");
1240 		return -1;
1241 	}
1242 
1243 	save2.nro_opt.nro_status = EINVAL;
1244 	if ((ret = pop_extmem_option(ctx, &save2)))
1245 		return ret;
1246 
1247 	save1.nro_opt.nro_status = EINVAL;
1248 	if ((ret = pop_extmem_option(ctx, &save1)))
1249 		return ret;
1250 
1251 	return 0;
1252 }
1253 #endif /* CONFIG_NETMAP_EXTMEM */
1254 
1255 static int
push_csb_option(struct TestContext * ctx,struct nmreq_opt_csb * opt)1256 push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
1257 {
1258 	size_t csb_size;
1259 	int num_entries;
1260 	int ret;
1261 
1262 	ctx->nr_flags |= NR_EXCLUSIVE;
1263 
1264 	/* Get port info in order to use num_registered_rings(). */
1265 	ret = port_info_get(ctx);
1266 	if (ret != 0) {
1267 		return ret;
1268 	}
1269 	num_entries = num_registered_rings(ctx);
1270 
1271 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
1272 	           num_entries;
1273 	assert(csb_size > 0);
1274 	if (ctx->csb) {
1275 		free(ctx->csb);
1276 	}
1277 	ret = posix_memalign(&ctx->csb, sizeof(struct nm_csb_atok), csb_size);
1278 	if (ret != 0) {
1279 		printf("Failed to allocate CSB memory\n");
1280 		exit(EXIT_FAILURE);
1281 	}
1282 
1283 	memset(opt, 0, sizeof(*opt));
1284 	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1285 	opt->csb_atok            = (uintptr_t)ctx->csb;
1286 	opt->csb_ktoa            = (uintptr_t)(((uint8_t *)ctx->csb) +
1287                                     sizeof(struct nm_csb_atok) * num_entries);
1288 
1289 	printf("Pushing option NETMAP_REQ_OPT_CSB\n");
1290 	push_option(&opt->nro_opt, ctx);
1291 
1292 	return 0;
1293 }
1294 
1295 static int
csb_mode(struct TestContext * ctx)1296 csb_mode(struct TestContext *ctx)
1297 {
1298 	struct nmreq_opt_csb opt;
1299 	int ret;
1300 
1301 	ret = push_csb_option(ctx, &opt);
1302 	if (ret != 0) {
1303 		return ret;
1304 	}
1305 
1306 	ret = port_register_hwall(ctx);
1307 	clear_options(ctx);
1308 
1309 	return ret;
1310 }
1311 
1312 static int
csb_mode_invalid_memory(struct TestContext * ctx)1313 csb_mode_invalid_memory(struct TestContext *ctx)
1314 {
1315 	struct nmreq_opt_csb opt;
1316 	int ret;
1317 
1318 	memset(&opt, 0, sizeof(opt));
1319 	opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1320 	opt.csb_atok            = (uintptr_t)0x10;
1321 	opt.csb_ktoa            = (uintptr_t)0x800;
1322 	push_option(&opt.nro_opt, ctx);
1323 
1324 	ctx->nr_flags = NR_EXCLUSIVE;
1325 	ret           = port_register_hwall(ctx);
1326 	clear_options(ctx);
1327 
1328 	return (ret < 0) ? 0 : -1;
1329 }
1330 
1331 static int
sync_kloop_stop(struct TestContext * ctx)1332 sync_kloop_stop(struct TestContext *ctx)
1333 {
1334 	struct nmreq_header hdr;
1335 	int ret;
1336 
1337 	printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname_ext);
1338 
1339 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
1340 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
1341 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
1342 	if (ret != 0) {
1343 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
1344 	}
1345 
1346 	return ret;
1347 }
1348 
1349 static void *
sync_kloop_worker(void * opaque)1350 sync_kloop_worker(void *opaque)
1351 {
1352 	struct TestContext *ctx = opaque;
1353 	struct nmreq_sync_kloop_start req;
1354 	struct nmreq_header hdr;
1355 	int ret;
1356 
1357 	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname_ext);
1358 
1359 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
1360 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
1361 	hdr.nr_body    = (uintptr_t)&req;
1362 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
1363 	memset(&req, 0, sizeof(req));
1364 	req.sleep_us = 500;
1365 	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
1366 	if (ret != 0) {
1367 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
1368 	}
1369 
1370 	if (ctx->sem) {
1371 		sem_post(ctx->sem);
1372 	}
1373 
1374 	pthread_exit(ret ? (void *)THRET_FAILURE : (void *)THRET_SUCCESS);
1375 }
1376 
1377 static int
sync_kloop_start_stop(struct TestContext * ctx)1378 sync_kloop_start_stop(struct TestContext *ctx)
1379 {
1380 	pthread_t th;
1381 	void *thret = THRET_FAILURE;
1382 	int ret;
1383 
1384 	ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
1385 	if (ret != 0) {
1386 		printf("pthread_create(kloop): %s\n", strerror(ret));
1387 		return -1;
1388 	}
1389 
1390 	ret = sync_kloop_stop(ctx);
1391 	if (ret != 0) {
1392 		return ret;
1393 	}
1394 
1395 	ret = pthread_join(th, &thret);
1396 	if (ret != 0) {
1397 		printf("pthread_join(kloop): %s\n", strerror(ret));
1398 	}
1399 
1400 	return thret == THRET_SUCCESS ? 0 : -1;
1401 }
1402 
1403 static int
sync_kloop(struct TestContext * ctx)1404 sync_kloop(struct TestContext *ctx)
1405 {
1406 	int ret;
1407 
1408 	ret = csb_mode(ctx);
1409 	if (ret != 0) {
1410 		return ret;
1411 	}
1412 
1413 	return sync_kloop_start_stop(ctx);
1414 }
1415 
1416 static int
sync_kloop_eventfds(struct TestContext * ctx)1417 sync_kloop_eventfds(struct TestContext *ctx)
1418 {
1419 	struct nmreq_opt_sync_kloop_eventfds *evopt = NULL;
1420 	struct nmreq_opt_sync_kloop_mode modeopt;
1421 	struct nmreq_option evsave;
1422 	int num_entries;
1423 	size_t opt_size;
1424 	int ret, i;
1425 
1426 	memset(&modeopt, 0, sizeof(modeopt));
1427 	modeopt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_MODE;
1428 	modeopt.mode = ctx->sync_kloop_mode;
1429 	push_option(&modeopt.nro_opt, ctx);
1430 
1431 	num_entries = num_registered_rings(ctx);
1432 	opt_size    = sizeof(*evopt) + num_entries * sizeof(evopt->eventfds[0]);
1433 	evopt = calloc(1, opt_size);
1434 	evopt->nro_opt.nro_next    = 0;
1435 	evopt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
1436 	evopt->nro_opt.nro_status  = 0;
1437 	evopt->nro_opt.nro_size    = opt_size;
1438 	for (i = 0; i < num_entries; i++) {
1439 		int efd = eventfd(0, 0);
1440 
1441 		evopt->eventfds[i].ioeventfd = efd;
1442 		efd                        = eventfd(0, 0);
1443 		evopt->eventfds[i].irqfd = efd;
1444 	}
1445 
1446 	push_option(&evopt->nro_opt, ctx);
1447 	evsave = evopt->nro_opt;
1448 
1449 	ret = sync_kloop_start_stop(ctx);
1450 	if (ret != 0) {
1451 		free(evopt);
1452 		clear_options(ctx);
1453 		return ret;
1454 	}
1455 #ifdef __linux__
1456 	evsave.nro_status = 0;
1457 #else  /* !__linux__ */
1458 	evsave.nro_status = EOPNOTSUPP;
1459 #endif /* !__linux__ */
1460 
1461 	ret = checkoption(&evopt->nro_opt, &evsave);
1462 	free(evopt);
1463 	clear_options(ctx);
1464 
1465 	return ret;
1466 }
1467 
1468 static int
sync_kloop_eventfds_all_mode(struct TestContext * ctx,uint32_t sync_kloop_mode)1469 sync_kloop_eventfds_all_mode(struct TestContext *ctx,
1470 			     uint32_t sync_kloop_mode)
1471 {
1472 	int ret;
1473 
1474 	ret = csb_mode(ctx);
1475 	if (ret != 0) {
1476 		return ret;
1477 	}
1478 
1479 	ctx->sync_kloop_mode = sync_kloop_mode;
1480 
1481 	return sync_kloop_eventfds(ctx);
1482 }
1483 
1484 static int
sync_kloop_eventfds_all(struct TestContext * ctx)1485 sync_kloop_eventfds_all(struct TestContext *ctx)
1486 {
1487 	return sync_kloop_eventfds_all_mode(ctx, 0);
1488 }
1489 
1490 static int
sync_kloop_eventfds_all_tx(struct TestContext * ctx)1491 sync_kloop_eventfds_all_tx(struct TestContext *ctx)
1492 {
1493 	struct nmreq_opt_csb opt;
1494 	int ret;
1495 
1496 	ret = push_csb_option(ctx, &opt);
1497 	if (ret != 0) {
1498 		return ret;
1499 	}
1500 
1501 	ret = port_register_hwall_tx(ctx);
1502 	if (ret != 0) {
1503 		return ret;
1504 	}
1505 	clear_options(ctx);
1506 
1507 	return sync_kloop_eventfds(ctx);
1508 }
1509 
1510 static int
sync_kloop_eventfds_all_direct(struct TestContext * ctx)1511 sync_kloop_eventfds_all_direct(struct TestContext *ctx)
1512 {
1513 	return sync_kloop_eventfds_all_mode(ctx,
1514 	    NM_OPT_SYNC_KLOOP_DIRECT_TX | NM_OPT_SYNC_KLOOP_DIRECT_RX);
1515 }
1516 
1517 static int
sync_kloop_eventfds_all_direct_tx(struct TestContext * ctx)1518 sync_kloop_eventfds_all_direct_tx(struct TestContext *ctx)
1519 {
1520 	return sync_kloop_eventfds_all_mode(ctx,
1521 	    NM_OPT_SYNC_KLOOP_DIRECT_TX);
1522 }
1523 
1524 static int
sync_kloop_eventfds_all_direct_rx(struct TestContext * ctx)1525 sync_kloop_eventfds_all_direct_rx(struct TestContext *ctx)
1526 {
1527 	return sync_kloop_eventfds_all_mode(ctx,
1528 	    NM_OPT_SYNC_KLOOP_DIRECT_RX);
1529 }
1530 
1531 static int
sync_kloop_nocsb(struct TestContext * ctx)1532 sync_kloop_nocsb(struct TestContext *ctx)
1533 {
1534 	int ret;
1535 
1536 	ret = port_register_hwall(ctx);
1537 	if (ret != 0) {
1538 		return ret;
1539 	}
1540 
1541 	/* Sync kloop must fail because we did not use
1542 	 * NETMAP_REQ_CSB_ENABLE. */
1543 	return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
1544 }
1545 
1546 static int
csb_enable(struct TestContext * ctx)1547 csb_enable(struct TestContext *ctx)
1548 {
1549 	struct nmreq_option saveopt;
1550 	struct nmreq_opt_csb opt;
1551 	struct nmreq_header hdr;
1552 	int ret;
1553 
1554 	ret = push_csb_option(ctx, &opt);
1555 	if (ret != 0) {
1556 		return ret;
1557 	}
1558 	saveopt = opt.nro_opt;
1559 	saveopt.nro_status = 0;
1560 
1561 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
1562 	hdr.nr_reqtype = NETMAP_REQ_CSB_ENABLE;
1563 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
1564 	hdr.nr_body = (uintptr_t)NULL;
1565 
1566 	printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname_ext);
1567 
1568 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
1569 	if (ret != 0) {
1570 		perror("ioctl(/dev/netmap, NIOCCTRL, CSB_ENABLE)");
1571 		return ret;
1572 	}
1573 
1574 	ret = checkoption(&opt.nro_opt, &saveopt);
1575 	clear_options(ctx);
1576 
1577 	return ret;
1578 }
1579 
1580 static int
sync_kloop_csb_enable(struct TestContext * ctx)1581 sync_kloop_csb_enable(struct TestContext *ctx)
1582 {
1583 	int ret;
1584 
1585 	ctx->nr_flags |= NR_EXCLUSIVE;
1586 	ret = port_register_hwall(ctx);
1587 	if (ret != 0) {
1588 		return ret;
1589 	}
1590 
1591 	ret = csb_enable(ctx);
1592 	if (ret != 0) {
1593 		return ret;
1594 	}
1595 
1596 	return sync_kloop_start_stop(ctx);
1597 }
1598 
1599 static int
sync_kloop_conflict(struct TestContext * ctx)1600 sync_kloop_conflict(struct TestContext *ctx)
1601 {
1602 	struct nmreq_opt_csb opt;
1603 	pthread_t th1, th2;
1604 	void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
1605 	struct timespec to;
1606 	sem_t sem;
1607 	int err = 0;
1608 	int ret;
1609 
1610 	ret = push_csb_option(ctx, &opt);
1611 	if (ret != 0) {
1612 		return ret;
1613 	}
1614 
1615 	ret = port_register_hwall(ctx);
1616 	if (ret != 0) {
1617 		return ret;
1618 	}
1619 	clear_options(ctx);
1620 
1621 	ret = sem_init(&sem, 0, 0);
1622 	if (ret != 0) {
1623 		printf("sem_init() failed: %s\n", strerror(ret));
1624 		return ret;
1625 	}
1626 	ctx->sem = &sem;
1627 
1628 	ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
1629 	err |= ret;
1630 	if (ret != 0) {
1631 		printf("pthread_create(kloop1): %s\n", strerror(ret));
1632 	}
1633 
1634 	ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
1635 	err |= ret;
1636 	if (ret != 0) {
1637 		printf("pthread_create(kloop2): %s\n", strerror(ret));
1638 	}
1639 
1640 	/* Wait for one of the two threads to fail to start the kloop, to
1641 	 * avoid a race condition where th1 starts the loop and stops,
1642 	 * and after that th2 starts the loop successfully. */
1643 	clock_gettime(CLOCK_REALTIME, &to);
1644 	to.tv_sec += 2;
1645 	ret = sem_timedwait(&sem, &to);
1646 	err |= ret;
1647 	if (ret != 0) {
1648 		printf("sem_timedwait() failed: %s\n", strerror(errno));
1649 	}
1650 
1651 	err |= sync_kloop_stop(ctx);
1652 
1653 	ret = pthread_join(th1, &thret1);
1654 	err |= ret;
1655 	if (ret != 0) {
1656 		printf("pthread_join(kloop1): %s\n", strerror(ret));
1657 	}
1658 
1659 	ret = pthread_join(th2, &thret2);
1660 	err |= ret;
1661 	if (ret != 0) {
1662 		printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
1663 	}
1664 
1665 	sem_destroy(&sem);
1666 	ctx->sem = NULL;
1667 	if (err) {
1668 		return err;
1669 	}
1670 
1671 	/* Check that one of the two failed, while the other one succeeded. */
1672 	return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
1673 			(thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
1674 	               ? 0
1675 	               : -1;
1676 }
1677 
1678 static int
sync_kloop_eventfds_mismatch(struct TestContext * ctx)1679 sync_kloop_eventfds_mismatch(struct TestContext *ctx)
1680 {
1681 	struct nmreq_opt_csb opt;
1682 	int ret;
1683 
1684 	ret = push_csb_option(ctx, &opt);
1685 	if (ret != 0) {
1686 		return ret;
1687 	}
1688 
1689 	ret = port_register_hwall_rx(ctx);
1690 	if (ret != 0) {
1691 		return ret;
1692 	}
1693 	clear_options(ctx);
1694 
1695 	/* Deceive num_registered_rings() to trigger a failure of
1696 	 * sync_kloop_eventfds(). The latter will think that all the
1697 	 * rings were registered, and allocate the wrong number of
1698 	 * eventfds. */
1699 	ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
1700 
1701 	return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
1702 }
1703 
1704 static int
null_port(struct TestContext * ctx)1705 null_port(struct TestContext *ctx)
1706 {
1707 	int ret;
1708 
1709 	ctx->nr_mem_id = 1;
1710 	ctx->nr_mode = NR_REG_NULL;
1711 	ctx->nr_tx_rings = 10;
1712 	ctx->nr_rx_rings = 5;
1713 	ctx->nr_tx_slots = 256;
1714 	ctx->nr_rx_slots = 100;
1715 	ret = port_register(ctx);
1716 	if (ret != 0) {
1717 		return ret;
1718 	}
1719 	return 0;
1720 }
1721 
1722 static int
null_port_all_zero(struct TestContext * ctx)1723 null_port_all_zero(struct TestContext *ctx)
1724 {
1725 	int ret;
1726 
1727 	ctx->nr_mem_id = 1;
1728 	ctx->nr_mode = NR_REG_NULL;
1729 	ctx->nr_tx_rings = 0;
1730 	ctx->nr_rx_rings = 0;
1731 	ctx->nr_tx_slots = 0;
1732 	ctx->nr_rx_slots = 0;
1733 	ret = port_register(ctx);
1734 	if (ret != 0) {
1735 		return ret;
1736 	}
1737 	return 0;
1738 }
1739 
1740 static int
null_port_sync(struct TestContext * ctx)1741 null_port_sync(struct TestContext *ctx)
1742 {
1743 	int ret;
1744 
1745 	ctx->nr_mem_id = 1;
1746 	ctx->nr_mode = NR_REG_NULL;
1747 	ctx->nr_tx_rings = 10;
1748 	ctx->nr_rx_rings = 5;
1749 	ctx->nr_tx_slots = 256;
1750 	ctx->nr_rx_slots = 100;
1751 	ret = port_register(ctx);
1752 	if (ret != 0) {
1753 		return ret;
1754 	}
1755 	ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
1756 	if (ret != 0) {
1757 		return ret;
1758 	}
1759 	return 0;
1760 }
1761 
1762 struct nmreq_parse_test {
1763 	const char *ifname;
1764 	const char *exp_port;
1765 	const char *exp_suff;
1766 	int exp_error;
1767 	uint32_t exp_mode;
1768 	uint16_t exp_ringid;
1769 	uint64_t exp_flags;
1770 };
1771 
1772 static struct nmreq_parse_test nmreq_parse_tests[] = {
1773 	/* port spec is the input. The expected results are as follows:
1774 	 * - port: what should go into hdr.nr_name
1775 	 * - suff: the trailing part of the input after parsing (NULL means equal to port spec)
1776 	 * - err: the expected return value, interpreted as follows
1777 	 *       err > 0 => nmreq_header_parse should fail with the given error
1778 	 *       err < 0 => nrmeq_header_parse should succeed, but nmreq_register_decode should
1779 	 *       		   fail with error |err|
1780 	 *       err = 0 => should succeed
1781 	 * - mode, ringid flags: what should go into the corresponding nr_* fields in the
1782 	 *   	nmreq_register struct in case of success
1783 	 */
1784 
1785 	/*port spec*/			/*port*/	/*suff*/    /*err*/	/*mode*/    /*ringid*/ /*flags*/
1786 	{ "netmap:eth0",		"eth0",		"",		0, 	NR_REG_ALL_NIC,	0,	0 },
1787 	{ "netmap:eth0-1",		"eth0",		"",		0, 	NR_REG_ONE_NIC, 1,	0 },
1788 	{ "netmap:eth0-",		"eth0",		"-",		-EINVAL,0,		0,	0 },
1789 	{ "netmap:eth0/x",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_EXCLUSIVE },
1790 	{ "netmap:eth0/z",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_ZCOPY_MON },
1791 	{ "netmap:eth0/r",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_MONITOR_RX },
1792 	{ "netmap:eth0/t",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_MONITOR_TX },
1793 	{ "netmap:eth0-2/Tx",		"eth0",		"",		0, 	NR_REG_ONE_NIC, 2,	NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
1794 	{ "netmap:eth0*",		"eth0",		"",		0, 	NR_REG_NIC_SW,  0,	0 },
1795 	{ "netmap:eth0^",		"eth0",		"",		0, 	NR_REG_SW,	0,	0 },
1796 	{ "netmap:eth0@2",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	0 },
1797 	{ "netmap:eth0@2/R",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	NR_RX_RINGS_ONLY },
1798 	{ "netmap:eth0@netmap:lo/R",	"eth0",	        "@netmap:lo/R",	0,	NR_REG_ALL_NIC,	0,	0 },
1799 	{ "netmap:eth0/R@xxx",		"eth0",	        "@xxx",		0,	NR_REG_ALL_NIC,	0,	NR_RX_RINGS_ONLY },
1800 	{ "netmap:eth0@2/R@2",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	NR_RX_RINGS_ONLY },
1801 	{ "netmap:eth0@2/R@3",		"eth0",	        "@2/R@3",	-EINVAL,0,		0,	0 },
1802 	{ "netmap:eth0@",		"eth0",	        "@",		-EINVAL,0,		0,	0 },
1803 	{ "netmap:",			"",		NULL,		EINVAL, 0,		0,	0 },
1804 	{ "netmap:^",			"",		NULL,		EINVAL,	0,		0,	0 },
1805 	{ "netmap:{",			"",		NULL,		EINVAL,	0,		0,	0 },
1806 	{ "eth0",			NULL,		NULL,		EINVAL, 0,		0,	0 },
1807 	{ "vale0:0",			"vale0:0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
1808 	{ "vale:0",			"vale:0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
1809 	{ "valeXXX:YYY",		"valeXXX:YYY",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
1810 	{ "valeXXX:YYY-4",		"valeXXX:YYY",	"",		0,	NR_REG_ONE_NIC, 4,	0 },
1811 	{ "netmapXXX:eth0",		NULL,		NULL,		EINVAL,	0,		0,	0 },
1812 	{ "netmap:14",			"14",		"",		0, 	NR_REG_ALL_NIC,	0,	0 },
1813 	{ "netmap:pipe{0",		"pipe{0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
1814 	{ "netmap:pipe{in",		"pipe{in",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
1815 	{ "netmap:pipe{in-7",		"pipe{in",	"",		0,	NR_REG_ONE_NIC, 7,	0 },
1816 	{ "vale0:0{0",			"vale0:0{0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
1817 	{ "netmap:pipe{1}2",		NULL,		NULL,		EINVAL, 0,		0,	0 },
1818 	{ "vale0:0@opt", 		"vale0:0",	"@opt",		0,	NR_REG_ALL_NIC, 0,	0 },
1819 	{ "vale0:0/Tx@opt", 		"vale0:0",	"@opt",		0,	NR_REG_ALL_NIC, 0,	NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
1820 	{ "vale0:0-3@opt", 		"vale0:0",	"@opt",		0,	NR_REG_ONE_NIC, 3,	0 },
1821 	{ "vale0:0@", 			"vale0:0",	"@",		-EINVAL,0,	        0,	0 },
1822 	{ "",				NULL,		NULL,		EINVAL, 0,		0,	0 },
1823 	{ NULL,				NULL,		NULL,		0, 	0,		0,	0 },
1824 };
1825 
1826 static void
randomize(void * dst,size_t n)1827 randomize(void *dst, size_t n)
1828 {
1829 	size_t i;
1830 	char *dst_ = dst;
1831 
1832 	for (i = 0; i < n; i++)
1833 		dst_[i] = (char)random();
1834 }
1835 
1836 static int
nmreq_hdr_parsing(struct TestContext * ctx,struct nmreq_parse_test * t,struct nmreq_header * hdr)1837 nmreq_hdr_parsing(struct TestContext *ctx,
1838 		struct nmreq_parse_test *t,
1839 		struct nmreq_header *hdr)
1840 {
1841 	const char *save;
1842 	struct nmreq_header orig_hdr;
1843 
1844 	save = ctx->ifparse = t->ifname;
1845 	orig_hdr = *hdr;
1846 
1847 	printf("nmreq_header: \"%s\"\n", ctx->ifparse);
1848 	if (nmreq_header_decode(&ctx->ifparse, hdr, ctx->nmctx) < 0) {
1849 		if (t->exp_error > 0) {
1850 			if (errno != t->exp_error) {
1851 				printf("!!! got errno=%d, want %d\n",
1852 						errno, t->exp_error);
1853 				return -1;
1854 			}
1855 			if (ctx->ifparse != save) {
1856 				printf("!!! parse error, but first arg changed\n");
1857 				return -1;
1858 			}
1859 			if (memcmp(&orig_hdr, hdr, sizeof(*hdr))) {
1860 				printf("!!! parse error, but header changed\n");
1861 				return -1;
1862 			}
1863 			return 0;
1864 		}
1865 		printf ("!!! nmreq_header_decode was expected to succeed, but it failed with error %d\n", errno);
1866 		return -1;
1867 	}
1868 	if (t->exp_error > 0) {
1869 		printf("!!! nmreq_header_decode returns 0, but error %d was expected\n", t->exp_error);
1870 		return -1;
1871 	}
1872 	if (strcmp(t->exp_port, hdr->nr_name) != 0) {
1873 		printf("!!! got '%s', want '%s'\n", hdr->nr_name, t->exp_port);
1874 		return -1;
1875 	}
1876 	if (hdr->nr_reqtype != orig_hdr.nr_reqtype ||
1877 	    hdr->nr_options != orig_hdr.nr_options ||
1878 	    hdr->nr_body    != orig_hdr.nr_body) {
1879 		printf("!!! some fields of the nmreq_header where changed unexpectedly\n");
1880 		return -1;
1881 	}
1882 	return 0;
1883 }
1884 
1885 static int
nmreq_reg_parsing(struct TestContext * ctx,struct nmreq_parse_test * t,struct nmreq_register * reg)1886 nmreq_reg_parsing(struct TestContext *ctx,
1887 		struct nmreq_parse_test *t,
1888 		struct nmreq_register *reg)
1889 {
1890 	const char *save;
1891 	struct nmreq_register orig_reg;
1892 
1893 
1894 	save = ctx->ifparse;
1895 	orig_reg = *reg;
1896 
1897 	printf("nmreq_register: \"%s\"\n", ctx->ifparse);
1898 	if (nmreq_register_decode(&ctx->ifparse, reg, ctx->nmctx) < 0) {
1899 		if (t->exp_error < 0) {
1900 			if (errno != -t->exp_error) {
1901 				printf("!!! got errno=%d, want %d\n",
1902 						errno, -t->exp_error);
1903 				return -1;
1904 			}
1905 			if (ctx->ifparse != save) {
1906 				printf("!!! parse error, but first arg changed\n");
1907 				return -1;
1908 			}
1909 			if (memcmp(&orig_reg, reg, sizeof(*reg))) {
1910 				printf("!!! parse error, but nmreq_register changed\n");
1911 				return -1;
1912 			}
1913 			return 0;
1914 		}
1915 		printf ("!!! parse failed but it should have succeeded\n");
1916 		return -1;
1917 	}
1918 	if (t->exp_error < 0) {
1919 		printf("!!! nmreq_register_decode returns 0, but error %d was expected\n", -t->exp_error);
1920 		return -1;
1921 	}
1922 	if (reg->nr_mode != t->exp_mode) {
1923 		printf("!!! got nr_mode '%d', want '%d'\n", reg->nr_mode, t->exp_mode);
1924 		return -1;
1925 	}
1926 	if (reg->nr_ringid != t->exp_ringid) {
1927 		printf("!!! got nr_ringid '%d', want '%d'\n", reg->nr_ringid, t->exp_ringid);
1928 		return -1;
1929 	}
1930 	if (reg->nr_flags != t->exp_flags) {
1931 		printf("!!! got nm_flags '%llx', want '%llx\n", (unsigned long long)reg->nr_flags,
1932 				(unsigned long long)t->exp_flags);
1933 		return -1;
1934 	}
1935 	if (reg->nr_offset     != orig_reg.nr_offset     ||
1936 	    reg->nr_memsize    != orig_reg.nr_memsize    ||
1937 	    reg->nr_tx_slots   != orig_reg.nr_tx_slots   ||
1938 	    reg->nr_rx_slots   != orig_reg.nr_rx_slots   ||
1939 	    reg->nr_tx_rings   != orig_reg.nr_tx_rings   ||
1940 	    reg->nr_rx_rings   != orig_reg.nr_rx_rings   ||
1941 	    reg->nr_extra_bufs != orig_reg.nr_extra_bufs)
1942 	{
1943 		printf("!!! some fields of the nmreq_register where changed unexpectedly\n");
1944 		return -1;
1945 	}
1946 	return 0;
1947 }
1948 
1949 static void
nmctx_parsing_error(struct nmctx * ctx,const char * msg)1950 nmctx_parsing_error(struct nmctx *ctx, const char *msg)
1951 {
1952 	(void)ctx;
1953 	printf("    got message: %s\n", msg);
1954 }
1955 
1956 static int
nmreq_parsing(struct TestContext * ctx)1957 nmreq_parsing(struct TestContext *ctx)
1958 {
1959 	struct nmreq_parse_test *t;
1960 	struct nmreq_header hdr;
1961 	struct nmreq_register reg;
1962 	struct nmctx test_nmctx, *nmctx;
1963 	int ret = 0;
1964 
1965 	nmctx = nmctx_get();
1966 	if (nmctx == NULL) {
1967 		printf("Failed to acquire nmctx: %s", strerror(errno));
1968 		return -1;
1969 	}
1970 	test_nmctx = *nmctx;
1971 	test_nmctx.error = nmctx_parsing_error;
1972 	ctx->nmctx = &test_nmctx;
1973 	for (t = nmreq_parse_tests; t->ifname != NULL; t++) {
1974 		const char *exp_suff = t->exp_suff != NULL ?
1975 			t->exp_suff : t->ifname;
1976 
1977 		randomize(&hdr, sizeof(hdr));
1978 		randomize(&reg, sizeof(reg));
1979 		reg.nr_mem_id = 0;
1980 		if (nmreq_hdr_parsing(ctx, t, &hdr) < 0) {
1981 			ret = -1;
1982 		} else if (t->exp_error <= 0 && nmreq_reg_parsing(ctx, t, &reg) < 0) {
1983 			ret = -1;
1984 		}
1985 		if (strcmp(ctx->ifparse, exp_suff) != 0) {
1986 			printf("!!! string suffix after parse is '%s', but it should be '%s'\n",
1987 					ctx->ifparse, exp_suff);
1988 			ret = -1;
1989 		}
1990 	}
1991 	ctx->nmctx = NULL;
1992 	return ret;
1993 }
1994 
1995 static int
binarycomp(struct TestContext * ctx)1996 binarycomp(struct TestContext *ctx)
1997 {
1998 #define ckroff(f, o) do {\
1999 	if (offsetof(struct netmap_ring, f) != (o)) {\
2000 		printf("offset of netmap_ring.%s is %zd, but it should be %d",\
2001 				#f, offsetof(struct netmap_ring, f), (o));\
2002 		return -1;\
2003 	}\
2004 } while (0)
2005 
2006 	(void)ctx;
2007 
2008 	ckroff(buf_ofs, 0);
2009 	ckroff(num_slots, 8);
2010 	ckroff(nr_buf_size, 12);
2011 	ckroff(ringid, 16);
2012 	ckroff(dir, 18);
2013 	ckroff(head, 20);
2014 	ckroff(cur, 24);
2015 	ckroff(tail, 28);
2016 	ckroff(flags, 32);
2017 	ckroff(ts, 40);
2018 	ckroff(offset_mask, 56);
2019 	ckroff(buf_align, 64);
2020 	ckroff(sem, 128);
2021 	ckroff(slot, 256);
2022 
2023 	return 0;
2024 }
2025 
2026 static void
usage(const char * prog)2027 usage(const char *prog)
2028 {
2029 	printf("%s -i IFNAME\n"
2030 	       "[-j TEST_NUM1[-[TEST_NUM2]] | -[TEST_NUM_2]]\n"
2031 	       "[-l (list test cases)]\n",
2032 	       prog);
2033 }
2034 
2035 struct mytest {
2036 	testfunc_t test;
2037 	const char *name;
2038 };
2039 
2040 #define decltest(f)                                                            \
2041 	{                                                                      \
2042 		.test = f, .name = #f                                          \
2043 	}
2044 
2045 static struct mytest tests[] = {
2046 	decltest(port_info_get),
2047 	decltest(port_register_hwall_host),
2048 	decltest(port_register_hwall),
2049 	decltest(port_register_hostall),
2050 	decltest(port_register_single_hw_pair),
2051 	decltest(port_register_single_host_pair),
2052 	decltest(port_register_hostall_many),
2053 	decltest(vale_attach_detach),
2054 	decltest(vale_attach_detach_host_rings),
2055 	decltest(vale_ephemeral_port_hdr_manipulation),
2056 	decltest(vale_persistent_port),
2057 	decltest(pools_info_get_and_register),
2058 	decltest(pools_info_get_empty_ifname),
2059 	decltest(pipe_master),
2060 	decltest(pipe_slave),
2061 	decltest(pipe_port_info_get),
2062 	decltest(pipe_pools_info_get),
2063 	decltest(vale_polling_enable_disable),
2064 	decltest(unsupported_option),
2065 	decltest(infinite_options),
2066 	decltest(infinite_options2),
2067 #ifdef CONFIG_NETMAP_EXTMEM
2068 	decltest(extmem_option),
2069 	decltest(bad_extmem_option),
2070 	decltest(duplicate_extmem_options),
2071 #endif /* CONFIG_NETMAP_EXTMEM */
2072 	decltest(csb_mode),
2073 	decltest(csb_mode_invalid_memory),
2074 	decltest(sync_kloop),
2075 	decltest(sync_kloop_eventfds_all),
2076 	decltest(sync_kloop_eventfds_all_tx),
2077 	decltest(sync_kloop_eventfds_all_direct),
2078 	decltest(sync_kloop_eventfds_all_direct_tx),
2079 	decltest(sync_kloop_eventfds_all_direct_rx),
2080 	decltest(sync_kloop_nocsb),
2081 	decltest(sync_kloop_csb_enable),
2082 	decltest(sync_kloop_conflict),
2083 	decltest(sync_kloop_eventfds_mismatch),
2084 	decltest(null_port),
2085 	decltest(null_port_all_zero),
2086 	decltest(null_port_sync),
2087 	decltest(legacy_regif_default),
2088 	decltest(legacy_regif_all_nic),
2089 	decltest(legacy_regif_12),
2090 	decltest(legacy_regif_sw),
2091 	decltest(legacy_regif_future),
2092 	decltest(legacy_regif_extra_bufs),
2093 	decltest(legacy_regif_extra_bufs_pipe),
2094 	decltest(legacy_regif_extra_bufs_pipe_vale),
2095 	decltest(nmreq_parsing),
2096 	decltest(binarycomp),
2097 };
2098 
2099 static void
context_cleanup(struct TestContext * ctx)2100 context_cleanup(struct TestContext *ctx)
2101 {
2102 	if (ctx->csb) {
2103 		free(ctx->csb);
2104 		ctx->csb = NULL;
2105 	}
2106 
2107 	close(ctx->fd);
2108 	ctx->fd = -1;
2109 }
2110 
2111 static int
parse_interval(const char * arg,int * j,int * k)2112 parse_interval(const char *arg, int *j, int *k)
2113 {
2114 	const char *scan = arg;
2115 	char *rest;
2116 
2117 	*j = 0;
2118 	*k = -1;
2119 	if (*scan == '-') {
2120 		scan++;
2121 		goto get_k;
2122 	}
2123 	if (!isdigit(*scan))
2124 		goto err;
2125 	*k = strtol(scan, &rest, 10);
2126 	*j = *k - 1;
2127 	scan = rest;
2128 	if (*scan == '-') {
2129 		*k = -1;
2130 		scan++;
2131 	}
2132 get_k:
2133 	if (*scan == '\0')
2134 		return 0;
2135 	if (!isdigit(*scan))
2136 		goto err;
2137 	*k = strtol(scan, &rest, 10);
2138 	scan = rest;
2139 	if (!(*scan == '\0'))
2140 		goto err;
2141 
2142 	return 0;
2143 
2144 err:
2145 	fprintf(stderr, "syntax error in '%s', must be num[-[num]] or -[num]\n", arg);
2146 	return -1;
2147 }
2148 
2149 #define ARGV_APPEND(_av, _ac, _x)\
2150 	do {\
2151 		assert((int)(_ac) < (int)(sizeof(_av)/sizeof((_av)[0])));\
2152 		(_av)[(_ac)++] = _x;\
2153 	} while (0)
2154 
2155 static void
tap_cleanup(int signo)2156 tap_cleanup(int signo)
2157 {
2158 	const char *av[8];
2159 	int ac = 0;
2160 
2161 	(void)signo;
2162 #ifdef __FreeBSD__
2163 	ARGV_APPEND(av, ac, "ifconfig");
2164 	ARGV_APPEND(av, ac, ctx_.ifname);
2165 	ARGV_APPEND(av, ac, "destroy");
2166 #else
2167 	ARGV_APPEND(av, ac, "ip");
2168 	ARGV_APPEND(av, ac, "link");
2169 	ARGV_APPEND(av, ac, "del");
2170 	ARGV_APPEND(av, ac, ctx_.ifname);
2171 #endif
2172 	ARGV_APPEND(av, ac, NULL);
2173 	if (exec_command(ac, av)) {
2174 		printf("Failed to destroy tap interface\n");
2175 	}
2176 }
2177 
2178 int
main(int argc,char ** argv)2179 main(int argc, char **argv)
2180 {
2181 	int create_tap = 1;
2182 	int num_tests;
2183 	int ret  = 0;
2184 	int j    = 0;
2185 	int k    = -1;
2186 	int list = 0;
2187 	int opt;
2188 	int i;
2189 
2190 #ifdef __FreeBSD__
2191 	PLAIN_REQUIRE_KERNEL_MODULE("if_tap", 0);
2192 	PLAIN_REQUIRE_KERNEL_MODULE("netmap", 0);
2193 #endif
2194 
2195 	memset(&ctx_, 0, sizeof(ctx_));
2196 
2197 	{
2198 		struct timespec t;
2199 		int idx;
2200 
2201 		clock_gettime(CLOCK_REALTIME, &t);
2202 		srand((unsigned int)t.tv_nsec);
2203 		idx = rand() % 8000 + 100;
2204 		snprintf(ctx_.ifname, sizeof(ctx_.ifname), "tap%d", idx);
2205 		idx = rand() % 800 + 100;
2206 		snprintf(ctx_.bdgname, sizeof(ctx_.bdgname), "vale%d", idx);
2207 	}
2208 
2209 	while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
2210 		switch (opt) {
2211 		case 'h':
2212 			usage(argv[0]);
2213 			return 0;
2214 
2215 		case 'i':
2216 			strncpy(ctx_.ifname, optarg, sizeof(ctx_.ifname) - 1);
2217 			create_tap = 0;
2218 			break;
2219 
2220 		case 'j':
2221 			if (parse_interval(optarg, &j, &k) < 0) {
2222 				usage(argv[0]);
2223 				return -1;
2224 			}
2225 			break;
2226 
2227 		case 'l':
2228 			list = 1;
2229 			create_tap = 0;
2230 			break;
2231 
2232 		default:
2233 			printf("    Unrecognized option %c\n", opt);
2234 			usage(argv[0]);
2235 			return -1;
2236 		}
2237 	}
2238 
2239 	num_tests = sizeof(tests) / sizeof(tests[0]);
2240 
2241 	if (j < 0 || j >= num_tests || k > num_tests) {
2242 		fprintf(stderr, "Test interval %d-%d out of range (%d-%d)\n",
2243 				j + 1, k, 1, num_tests + 1);
2244 		return -1;
2245 	}
2246 
2247 	if (k < 0)
2248 		k = num_tests;
2249 
2250 	if (list) {
2251 		printf("Available tests:\n");
2252 		for (i = 0; i < num_tests; i++) {
2253 			printf("#%03d: %s\n", i + 1, tests[i].name);
2254 		}
2255 		return 0;
2256 	}
2257 
2258 	if (create_tap) {
2259 		struct sigaction sa;
2260 		const char *av[8];
2261 		int ac = 0;
2262 #ifdef __FreeBSD__
2263 		ARGV_APPEND(av, ac, "ifconfig");
2264 		ARGV_APPEND(av, ac, ctx_.ifname);
2265 		ARGV_APPEND(av, ac, "create");
2266 		ARGV_APPEND(av, ac, "up");
2267 #else
2268 		ARGV_APPEND(av, ac, "ip");
2269 		ARGV_APPEND(av, ac, "tuntap");
2270 		ARGV_APPEND(av, ac, "add");
2271 		ARGV_APPEND(av, ac, "mode");
2272 		ARGV_APPEND(av, ac, "tap");
2273 		ARGV_APPEND(av, ac, "name");
2274 		ARGV_APPEND(av, ac, ctx_.ifname);
2275 #endif
2276 		ARGV_APPEND(av, ac, NULL);
2277 		if (exec_command(ac, av)) {
2278 			printf("Failed to create tap interface\n");
2279 			return -1;
2280 		}
2281 
2282 		sa.sa_handler = tap_cleanup;
2283 		sigemptyset(&sa.sa_mask);
2284 		sa.sa_flags = SA_RESTART;
2285 		ret         = sigaction(SIGINT, &sa, NULL);
2286 		if (ret) {
2287 			perror("sigaction(SIGINT)");
2288 			goto out;
2289 		}
2290 		ret = sigaction(SIGTERM, &sa, NULL);
2291 		if (ret) {
2292 			perror("sigaction(SIGTERM)");
2293 			goto out;
2294 		}
2295 	}
2296 
2297 	for (i = j; i < k; i++) {
2298 		struct TestContext ctxcopy;
2299 		int fd;
2300 		printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
2301 		fd = open("/dev/netmap", O_RDWR);
2302 		if (fd < 0) {
2303 			perror("open(/dev/netmap)");
2304 			ret = fd;
2305 			goto out;
2306 		}
2307 		memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
2308 		ctxcopy.fd = fd;
2309 		memcpy(ctxcopy.ifname_ext, ctxcopy.ifname,
2310 			sizeof(ctxcopy.ifname));
2311 		ret        = tests[i].test(&ctxcopy);
2312 		if (ret != 0) {
2313 			printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
2314 			goto out;
2315 		}
2316 		printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
2317 		context_cleanup(&ctxcopy);
2318 	}
2319 out:
2320 	tap_cleanup(0);
2321 
2322 	return ret;
2323 }
2324