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