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