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