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