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