2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (C) 2018 Vincenzo Maffione
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
30 #include <sys/ioctl.h>
40 #include <net/netmap.h>
42 #include <semaphore.h>
52 #include <sys/eventfd.h>
55 eventfd(int x __unused, int y __unused)
60 #endif /* __linux__ */
63 exec_command(int argc, const char *const argv[])
70 printf("Executing command: ");
71 for (i = 0; i < argc - 1; i++) {
73 /* Invalid argument. */
79 printf("%s", argv[i]);
88 /* Child process. Redirect stdin, stdout
90 for (i = 0; i < 3; i++) {
92 fds[i] = open("/dev/null", O_RDONLY);
94 for (i--; i >= 0; i--) {
101 /* Make a copy of the arguments, passing them to execvp. */
102 av = calloc(argc, sizeof(av[0]));
106 for (i = 0; i < argc - 1; i++) {
107 av[i] = strdup(argv[i]);
117 wret = waitpid(child_pid, &child_status, 0);
119 fprintf(stderr, "waitpid() failed: %s\n", strerror(errno));
122 if (WIFEXITED(child_status)) {
123 return WEXITSTATUS(child_status);
130 #define THRET_SUCCESS ((void *)128)
131 #define THRET_FAILURE ((void *)0)
135 char ifname_ext[128];
137 uint32_t nr_tx_slots; /* slots in tx rings */
138 uint32_t nr_rx_slots; /* slots in rx rings */
139 uint16_t nr_tx_rings; /* number of tx rings */
140 uint16_t nr_rx_rings; /* number of rx rings */
141 uint16_t nr_mem_id; /* id of the memory allocator */
142 uint16_t nr_ringid; /* ring(s) we care about */
143 uint32_t nr_mode; /* specify NR_REG_* modes */
144 uint32_t nr_extra_bufs; /* number of requested extra buffers */
145 uint64_t nr_flags; /* additional flags (see below) */
146 uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
147 uint32_t nr_first_cpu_id; /* vale polling */
148 uint32_t nr_num_polling_cpus; /* vale polling */
149 int fd; /* netmap file descriptor */
151 void *csb; /* CSB entries (atok and ktoa) */
152 struct nmreq_option *nr_opt; /* list of options */
153 sem_t *sem; /* for thread synchronization */
154 struct nmport_d *nmport; /* nmport descriptor from libnetmap */
157 static struct TestContext ctx_;
159 typedef int (*testfunc_t)(struct TestContext *ctx);
162 nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
164 memset(hdr, 0, sizeof(*hdr));
165 hdr->nr_version = NETMAP_API;
166 strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name) - 1);
169 /* Single NETMAP_REQ_PORT_INFO_GET. */
171 port_info_get(struct TestContext *ctx)
173 struct nmreq_port_info_get req;
174 struct nmreq_header hdr;
178 printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname_ext);
180 nmreq_hdr_init(&hdr, ctx->ifname_ext);
181 hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
182 hdr.nr_body = (uintptr_t)&req;
183 memset(&req, 0, sizeof(req));
184 req.nr_mem_id = ctx->nr_mem_id;
185 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
187 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
190 printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
191 printf("nr_tx_slots %u\n", req.nr_tx_slots);
192 printf("nr_rx_slots %u\n", req.nr_rx_slots);
193 printf("nr_tx_rings %u\n", req.nr_tx_rings);
194 printf("nr_rx_rings %u\n", req.nr_rx_rings);
195 printf("nr_mem_id %u\n", req.nr_mem_id);
197 success = req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
198 req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings;
203 /* Write back results to the context structure. */
204 ctx->nr_tx_slots = req.nr_tx_slots;
205 ctx->nr_rx_slots = req.nr_rx_slots;
206 ctx->nr_tx_rings = req.nr_tx_rings;
207 ctx->nr_rx_rings = req.nr_rx_rings;
208 ctx->nr_mem_id = req.nr_mem_id;
213 /* Single NETMAP_REQ_REGISTER, no use. */
215 port_register(struct TestContext *ctx)
217 struct nmreq_register req;
218 struct nmreq_header hdr;
222 printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
223 "flags=0x%llx) on '%s'\n",
224 ctx->nr_mode, ctx->nr_ringid, (unsigned long long)ctx->nr_flags,
227 nmreq_hdr_init(&hdr, ctx->ifname_ext);
228 hdr.nr_reqtype = NETMAP_REQ_REGISTER;
229 hdr.nr_body = (uintptr_t)&req;
230 hdr.nr_options = (uintptr_t)ctx->nr_opt;
231 memset(&req, 0, sizeof(req));
232 req.nr_mem_id = ctx->nr_mem_id;
233 req.nr_mode = ctx->nr_mode;
234 req.nr_ringid = ctx->nr_ringid;
235 req.nr_flags = ctx->nr_flags;
236 req.nr_tx_slots = ctx->nr_tx_slots;
237 req.nr_rx_slots = ctx->nr_rx_slots;
238 req.nr_tx_rings = ctx->nr_tx_rings;
239 req.nr_rx_rings = ctx->nr_rx_rings;
240 req.nr_extra_bufs = ctx->nr_extra_bufs;
241 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
243 perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
246 printf("nr_offset 0x%llx\n", (unsigned long long)req.nr_offset);
247 printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
248 printf("nr_tx_slots %u\n", req.nr_tx_slots);
249 printf("nr_rx_slots %u\n", req.nr_rx_slots);
250 printf("nr_tx_rings %u\n", req.nr_tx_rings);
251 printf("nr_rx_rings %u\n", req.nr_rx_rings);
252 printf("nr_mem_id %u\n", req.nr_mem_id);
253 printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
255 success = req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
256 (ctx->nr_ringid == req.nr_ringid) &&
257 (ctx->nr_flags == req.nr_flags) &&
258 ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
259 (ctx->nr_tx_slots == req.nr_tx_slots)) &&
260 ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
261 (ctx->nr_rx_slots == req.nr_rx_slots)) &&
262 ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
263 (ctx->nr_tx_rings == req.nr_tx_rings)) &&
264 ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
265 (ctx->nr_rx_rings == req.nr_rx_rings)) &&
266 ((!ctx->nr_mem_id && req.nr_mem_id) ||
267 (ctx->nr_mem_id == req.nr_mem_id)) &&
268 (ctx->nr_extra_bufs == req.nr_extra_bufs);
273 /* Write back results to the context structure.*/
274 ctx->nr_tx_slots = req.nr_tx_slots;
275 ctx->nr_rx_slots = req.nr_rx_slots;
276 ctx->nr_tx_rings = req.nr_tx_rings;
277 ctx->nr_rx_rings = req.nr_rx_rings;
278 ctx->nr_mem_id = req.nr_mem_id;
279 ctx->nr_extra_bufs = req.nr_extra_bufs;
285 niocregif(struct TestContext *ctx, int netmap_api)
291 printf("Testing legacy NIOCREGIF on '%s'\n", ctx->ifname_ext);
293 memset(&req, 0, sizeof(req));
294 memcpy(req.nr_name, ctx->ifname_ext, sizeof(req.nr_name));
295 req.nr_name[sizeof(req.nr_name) - 1] = '\0';
296 req.nr_version = netmap_api;
297 req.nr_ringid = ctx->nr_ringid;
298 req.nr_flags = ctx->nr_mode | ctx->nr_flags;
299 req.nr_tx_slots = ctx->nr_tx_slots;
300 req.nr_rx_slots = ctx->nr_rx_slots;
301 req.nr_tx_rings = ctx->nr_tx_rings;
302 req.nr_rx_rings = ctx->nr_rx_rings;
303 req.nr_arg2 = ctx->nr_mem_id;
304 req.nr_arg3 = ctx->nr_extra_bufs;
306 ret = ioctl(ctx->fd, NIOCREGIF, &req);
308 perror("ioctl(/dev/netmap, NIOCREGIF)");
312 printf("nr_offset 0x%x\n", req.nr_offset);
313 printf("nr_memsize %u\n", req.nr_memsize);
314 printf("nr_tx_slots %u\n", req.nr_tx_slots);
315 printf("nr_rx_slots %u\n", req.nr_rx_slots);
316 printf("nr_tx_rings %u\n", req.nr_tx_rings);
317 printf("nr_rx_rings %u\n", req.nr_rx_rings);
318 printf("nr_version %d\n", req.nr_version);
319 printf("nr_ringid %x\n", req.nr_ringid);
320 printf("nr_flags %x\n", req.nr_flags);
321 printf("nr_arg2 %u\n", req.nr_arg2);
322 printf("nr_arg3 %u\n", req.nr_arg3);
324 success = req.nr_memsize &&
325 (ctx->nr_ringid == req.nr_ringid) &&
326 ((ctx->nr_mode | ctx->nr_flags) == req.nr_flags) &&
327 ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
328 (ctx->nr_tx_slots == req.nr_tx_slots)) &&
329 ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
330 (ctx->nr_rx_slots == req.nr_rx_slots)) &&
331 ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
332 (ctx->nr_tx_rings == req.nr_tx_rings)) &&
333 ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
334 (ctx->nr_rx_rings == req.nr_rx_rings)) &&
335 ((!ctx->nr_mem_id && req.nr_arg2) ||
336 (ctx->nr_mem_id == req.nr_arg2)) &&
337 (ctx->nr_extra_bufs == req.nr_arg3);
342 /* Write back results to the context structure.*/
343 ctx->nr_tx_slots = req.nr_tx_slots;
344 ctx->nr_rx_slots = req.nr_rx_slots;
345 ctx->nr_tx_rings = req.nr_tx_rings;
346 ctx->nr_rx_rings = req.nr_rx_rings;
347 ctx->nr_mem_id = req.nr_arg2;
348 ctx->nr_extra_bufs = req.nr_arg3;
353 /* The 11 ABI is the one right before the introduction of the new NIOCCTRL
354 * ABI. The 11 ABI is useful to perform tests with legacy applications
355 * (which use the 11 ABI) and new kernel (which uses 12, or higher). */
356 #define NETMAP_API_NIOCREGIF 11
359 legacy_regif_default(struct TestContext *ctx)
361 return niocregif(ctx, NETMAP_API_NIOCREGIF);
365 legacy_regif_all_nic(struct TestContext *ctx)
367 ctx->nr_mode = NR_REG_ALL_NIC;
368 return niocregif(ctx, NETMAP_API);
372 legacy_regif_12(struct TestContext *ctx)
374 ctx->nr_mode = NR_REG_ALL_NIC;
375 return niocregif(ctx, NETMAP_API_NIOCREGIF+1);
379 legacy_regif_sw(struct TestContext *ctx)
381 ctx->nr_mode = NR_REG_SW;
382 return niocregif(ctx, NETMAP_API_NIOCREGIF);
386 legacy_regif_future(struct TestContext *ctx)
388 ctx->nr_mode = NR_REG_NIC_SW;
389 /* Test forward compatibility for the legacy ABI. This means
390 * using an older kernel (with ABI 12 or higher) and a newer
391 * application (with ABI greater than NETMAP_API). */
392 return niocregif(ctx, NETMAP_API+2);
396 legacy_regif_extra_bufs(struct TestContext *ctx)
398 ctx->nr_mode = NR_REG_ALL_NIC;
399 ctx->nr_extra_bufs = 20; /* arbitrary number of extra bufs */
400 return niocregif(ctx, NETMAP_API_NIOCREGIF);
404 legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
406 strncat(ctx->ifname_ext, "{pipeexbuf", sizeof(ctx->ifname_ext));
407 ctx->nr_mode = NR_REG_ALL_NIC;
408 ctx->nr_extra_bufs = 58; /* arbitrary number of extra bufs */
410 return niocregif(ctx, NETMAP_API_NIOCREGIF);
414 legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
416 strncpy(ctx->ifname_ext, "valeX1:Y4", sizeof(ctx->ifname_ext));
417 return legacy_regif_extra_bufs_pipe(ctx);
420 /* Only valid after a successful port_register(). */
422 num_registered_rings(struct TestContext *ctx)
424 if (ctx->nr_flags & NR_TX_RINGS_ONLY) {
425 return ctx->nr_tx_rings;
427 if (ctx->nr_flags & NR_RX_RINGS_ONLY) {
428 return ctx->nr_rx_rings;
431 return ctx->nr_tx_rings + ctx->nr_rx_rings;
435 port_register_hwall_host(struct TestContext *ctx)
437 ctx->nr_mode = NR_REG_NIC_SW;
438 return port_register(ctx);
442 port_register_host(struct TestContext *ctx)
444 ctx->nr_mode = NR_REG_SW;
445 return port_register(ctx);
449 port_register_hwall(struct TestContext *ctx)
451 ctx->nr_mode = NR_REG_ALL_NIC;
452 return port_register(ctx);
456 port_register_single_ring_couple(struct TestContext *ctx)
458 ctx->nr_mode = NR_REG_ONE_NIC;
460 return port_register(ctx);
464 port_register_hwall_tx(struct TestContext *ctx)
466 ctx->nr_mode = NR_REG_ALL_NIC;
467 ctx->nr_flags |= NR_TX_RINGS_ONLY;
468 return port_register(ctx);
472 port_register_hwall_rx(struct TestContext *ctx)
474 ctx->nr_mode = NR_REG_ALL_NIC;
475 ctx->nr_flags |= NR_RX_RINGS_ONLY;
476 return port_register(ctx);
479 /* NETMAP_REQ_VALE_ATTACH */
481 vale_attach(struct TestContext *ctx)
483 struct nmreq_vale_attach req;
484 struct nmreq_header hdr;
485 char vpname[sizeof(ctx->bdgname) + 1 + sizeof(ctx->ifname_ext)];
488 snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
490 printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
491 nmreq_hdr_init(&hdr, vpname);
492 hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
493 hdr.nr_body = (uintptr_t)&req;
494 memset(&req, 0, sizeof(req));
495 req.reg.nr_mem_id = ctx->nr_mem_id;
496 if (ctx->nr_mode == 0) {
497 ctx->nr_mode = NR_REG_ALL_NIC; /* default */
499 req.reg.nr_mode = ctx->nr_mode;
500 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
502 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
505 printf("nr_mem_id %u\n", req.reg.nr_mem_id);
507 return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
508 (ctx->nr_mem_id == req.reg.nr_mem_id)) &&
509 (ctx->nr_flags == req.reg.nr_flags)
514 /* NETMAP_REQ_VALE_DETACH */
516 vale_detach(struct TestContext *ctx)
518 struct nmreq_header hdr;
519 struct nmreq_vale_detach req;
523 snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
525 printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
526 nmreq_hdr_init(&hdr, vpname);
527 hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
528 hdr.nr_body = (uintptr_t)&req;
529 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
531 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
538 /* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
540 vale_attach_detach(struct TestContext *ctx)
544 if ((ret = vale_attach(ctx)) != 0) {
548 return vale_detach(ctx);
552 vale_attach_detach_host_rings(struct TestContext *ctx)
554 ctx->nr_mode = NR_REG_NIC_SW;
555 return vale_attach_detach(ctx);
558 /* First NETMAP_REQ_PORT_HDR_SET and the NETMAP_REQ_PORT_HDR_GET
559 * to check that we get the same value. */
561 port_hdr_set_and_get(struct TestContext *ctx)
563 struct nmreq_port_hdr req;
564 struct nmreq_header hdr;
567 printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname_ext);
569 nmreq_hdr_init(&hdr, ctx->ifname_ext);
570 hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
571 hdr.nr_body = (uintptr_t)&req;
572 memset(&req, 0, sizeof(req));
573 req.nr_hdr_len = ctx->nr_hdr_len;
574 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
576 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
580 if (req.nr_hdr_len != ctx->nr_hdr_len) {
584 printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname_ext);
585 hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
587 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
589 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
592 printf("nr_hdr_len %u\n", req.nr_hdr_len);
594 return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
598 * Possible lengths for the VirtIO network header, as specified by
600 * http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html
602 #define VIRTIO_NET_HDR_LEN 10
603 #define VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS 12
606 vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
610 strncpy(ctx->ifname_ext, "vale:eph0", sizeof(ctx->ifname_ext));
611 ctx->nr_mode = NR_REG_ALL_NIC;
612 if ((ret = port_register(ctx))) {
615 /* Try to set and get all the acceptable values. */
616 ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS;
617 if ((ret = port_hdr_set_and_get(ctx))) {
621 if ((ret = port_hdr_set_and_get(ctx))) {
624 ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN;
625 if ((ret = port_hdr_set_and_get(ctx))) {
632 vale_persistent_port(struct TestContext *ctx)
634 struct nmreq_vale_newif req;
635 struct nmreq_header hdr;
639 strncpy(ctx->ifname_ext, "per4", sizeof(ctx->ifname_ext));
641 printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname_ext);
643 nmreq_hdr_init(&hdr, ctx->ifname_ext);
644 hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
645 hdr.nr_body = (uintptr_t)&req;
646 memset(&req, 0, sizeof(req));
647 req.nr_mem_id = ctx->nr_mem_id;
648 req.nr_tx_slots = ctx->nr_tx_slots;
649 req.nr_rx_slots = ctx->nr_rx_slots;
650 req.nr_tx_rings = ctx->nr_tx_rings;
651 req.nr_rx_rings = ctx->nr_rx_rings;
652 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
654 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
658 /* Attach the persistent VALE port to a switch and then detach. */
659 result = vale_attach_detach(ctx);
661 printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname_ext);
662 hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
663 hdr.nr_body = (uintptr_t)NULL;
664 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
666 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
675 /* Single NETMAP_REQ_POOLS_INFO_GET. */
677 pools_info_get(struct TestContext *ctx)
679 struct nmreq_pools_info req;
680 struct nmreq_header hdr;
683 printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname_ext);
685 nmreq_hdr_init(&hdr, ctx->ifname_ext);
686 hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
687 hdr.nr_body = (uintptr_t)&req;
688 memset(&req, 0, sizeof(req));
689 req.nr_mem_id = ctx->nr_mem_id;
690 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
692 perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
695 printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
696 printf("nr_mem_id %u\n", req.nr_mem_id);
697 printf("nr_if_pool_offset 0x%llx\n",
698 (unsigned long long)req.nr_if_pool_offset);
699 printf("nr_if_pool_objtotal %u\n", req.nr_if_pool_objtotal);
700 printf("nr_if_pool_objsize %u\n", req.nr_if_pool_objsize);
701 printf("nr_ring_pool_offset 0x%llx\n",
702 (unsigned long long)req.nr_if_pool_offset);
703 printf("nr_ring_pool_objtotal %u\n", req.nr_ring_pool_objtotal);
704 printf("nr_ring_pool_objsize %u\n", req.nr_ring_pool_objsize);
705 printf("nr_buf_pool_offset 0x%llx\n",
706 (unsigned long long)req.nr_buf_pool_offset);
707 printf("nr_buf_pool_objtotal %u\n", req.nr_buf_pool_objtotal);
708 printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
710 return req.nr_memsize && req.nr_if_pool_objtotal &&
711 req.nr_if_pool_objsize &&
712 req.nr_ring_pool_objtotal &&
713 req.nr_ring_pool_objsize &&
714 req.nr_buf_pool_objtotal &&
715 req.nr_buf_pool_objsize
721 pools_info_get_and_register(struct TestContext *ctx)
725 /* Check that we can get pools info before we register
726 * a netmap interface. */
727 ret = pools_info_get(ctx);
732 ctx->nr_mode = NR_REG_ONE_NIC;
733 ret = port_register(ctx);
739 /* Check that we can get pools info also after we register. */
740 return pools_info_get(ctx);
744 pools_info_get_empty_ifname(struct TestContext *ctx)
746 strncpy(ctx->ifname_ext, "", sizeof(ctx->ifname_ext));
747 return pools_info_get(ctx) != 0 ? 0 : -1;
751 pipe_master(struct TestContext *ctx)
753 strncat(ctx->ifname_ext, "{pipeid1", sizeof(ctx->ifname_ext));
754 ctx->nr_mode = NR_REG_NIC_SW;
756 if (port_register(ctx) == 0) {
757 printf("pipes should not accept NR_REG_NIC_SW\n");
760 ctx->nr_mode = NR_REG_ALL_NIC;
762 return port_register(ctx);
766 pipe_slave(struct TestContext *ctx)
768 strncat(ctx->ifname_ext, "}pipeid2", sizeof(ctx->ifname_ext));
769 ctx->nr_mode = NR_REG_ALL_NIC;
771 return port_register(ctx);
774 /* Test PORT_INFO_GET and POOLS_INFO_GET on a pipe. This is useful to test the
775 * registration request used internall by netmap. */
777 pipe_port_info_get(struct TestContext *ctx)
779 strncat(ctx->ifname_ext, "}pipeid3", sizeof(ctx->ifname_ext));
781 return port_info_get(ctx);
785 pipe_pools_info_get(struct TestContext *ctx)
787 strncat(ctx->ifname_ext, "{xid", sizeof(ctx->ifname_ext));
789 return pools_info_get(ctx);
792 /* NETMAP_REQ_VALE_POLLING_ENABLE */
794 vale_polling_enable(struct TestContext *ctx)
796 struct nmreq_vale_polling req;
797 struct nmreq_header hdr;
801 snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
802 printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
804 nmreq_hdr_init(&hdr, vpname);
805 hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
806 hdr.nr_body = (uintptr_t)&req;
807 memset(&req, 0, sizeof(req));
808 req.nr_mode = ctx->nr_mode;
809 req.nr_first_cpu_id = ctx->nr_first_cpu_id;
810 req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
811 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
813 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
817 return (req.nr_mode == ctx->nr_mode &&
818 req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
819 req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
824 /* NETMAP_REQ_VALE_POLLING_DISABLE */
826 vale_polling_disable(struct TestContext *ctx)
828 struct nmreq_vale_polling req;
829 struct nmreq_header hdr;
833 snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
834 printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
836 nmreq_hdr_init(&hdr, vpname);
837 hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
838 hdr.nr_body = (uintptr_t)&req;
839 memset(&req, 0, sizeof(req));
840 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
842 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
850 vale_polling_enable_disable(struct TestContext *ctx)
854 if ((ret = vale_attach(ctx)) != 0) {
858 ctx->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
859 ctx->nr_num_polling_cpus = 1;
860 ctx->nr_first_cpu_id = 0;
861 if ((ret = vale_polling_enable(ctx))) {
864 /* NETMAP_REQ_VALE_POLLING_DISABLE is disabled on FreeBSD,
865 * because it is currently broken. We are happy to see that
873 if ((ret = vale_polling_disable(ctx))) {
878 return vale_detach(ctx);
882 push_option(struct nmreq_option *opt, struct TestContext *ctx)
884 opt->nro_next = (uintptr_t)ctx->nr_opt;
889 clear_options(struct TestContext *ctx)
895 checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
897 if (opt->nro_next != exp->nro_next) {
898 printf("nro_next %p expected %p\n",
899 (void *)(uintptr_t)opt->nro_next,
900 (void *)(uintptr_t)exp->nro_next);
903 if (opt->nro_reqtype != exp->nro_reqtype) {
904 printf("nro_reqtype %u expected %u\n", opt->nro_reqtype,
908 if (opt->nro_status != exp->nro_status) {
909 printf("nro_status %u expected %u\n", opt->nro_status,
917 unsupported_option(struct TestContext *ctx)
919 struct nmreq_option opt, save;
921 printf("Testing unsupported option on %s\n", ctx->ifname_ext);
923 memset(&opt, 0, sizeof(opt));
924 opt.nro_reqtype = 1234;
925 push_option(&opt, ctx);
928 if (port_register_hwall(ctx) >= 0)
932 save.nro_status = EOPNOTSUPP;
933 return checkoption(&opt, &save);
937 infinite_options(struct TestContext *ctx)
939 struct nmreq_option opt;
941 printf("Testing infinite list of options on %s\n", ctx->ifname_ext);
943 opt.nro_reqtype = 1234;
944 push_option(&opt, ctx);
945 opt.nro_next = (uintptr_t)&opt;
946 if (port_register_hwall(ctx) >= 0)
949 return (errno == EMSGSIZE ? 0 : -1);
952 #ifdef CONFIG_NETMAP_EXTMEM
954 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
957 char param[256] = "/sys/module/netmap/parameters/";
961 strncat(param, pname, sizeof(param) - 1);
963 f = fopen(param, "r+");
968 if (fscanf(f, "%ld", &oldv) != 1) {
976 if (fprintf(f, "%ld\n", newv) < 0) {
982 printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
983 #endif /* __linux__ */
988 push_extmem_option(struct TestContext *ctx, const struct nmreq_pools_info *pi,
989 struct nmreq_opt_extmem *e)
993 addr = mmap(NULL, pi->nr_memsize, PROT_READ | PROT_WRITE,
994 MAP_ANONYMOUS | MAP_SHARED, -1, 0);
995 if (addr == MAP_FAILED) {
1000 memset(e, 0, sizeof(*e));
1001 e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
1003 e->nro_usrptr = (uintptr_t)addr;
1005 push_option(&e->nro_opt, ctx);
1011 pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
1013 struct nmreq_opt_extmem *e;
1016 e = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
1017 ctx->nr_opt = (struct nmreq_option *)(uintptr_t)ctx->nr_opt->nro_next;
1019 if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
1023 if (e->nro_usrptr != exp->nro_usrptr) {
1024 printf("usrptr %" PRIu64 " expected %" PRIu64 "\n",
1025 e->nro_usrptr, exp->nro_usrptr);
1028 if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
1029 printf("memsize %" PRIu64 " expected %" PRIu64 "\n",
1030 e->nro_info.nr_memsize, exp->nro_info.nr_memsize);
1034 if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr,
1035 e->nro_info.nr_memsize)))
1042 _extmem_option(struct TestContext *ctx,
1043 const struct nmreq_pools_info *pi)
1045 struct nmreq_opt_extmem e, save;
1048 if ((ret = push_extmem_option(ctx, pi, &e)) < 0)
1053 strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
1054 ctx->nr_tx_slots = 16;
1055 ctx->nr_rx_slots = 16;
1057 if ((ret = port_register_hwall(ctx)))
1060 ret = pop_extmem_option(ctx, &save);
1066 pools_info_min_memsize(const struct nmreq_pools_info *pi)
1070 tot += pi->nr_if_pool_objtotal * pi->nr_if_pool_objsize;
1071 tot += pi->nr_ring_pool_objtotal * pi->nr_ring_pool_objsize;
1072 tot += pi->nr_buf_pool_objtotal * pi->nr_buf_pool_objsize;
1078 * Fill the specification of a netmap memory allocator to be
1079 * used with the 'struct nmreq_opt_extmem' option. Arbitrary
1080 * values are used for the parameters, but with enough netmap
1081 * rings, netmap ifs, and buffers to support a VALE port.
1084 pools_info_fill(struct nmreq_pools_info *pi)
1086 pi->nr_if_pool_objtotal = 2;
1087 pi->nr_if_pool_objsize = 1024;
1088 pi->nr_ring_pool_objtotal = 64;
1089 pi->nr_ring_pool_objsize = 512;
1090 pi->nr_buf_pool_objtotal = 4096;
1091 pi->nr_buf_pool_objsize = 2048;
1092 pi->nr_memsize = pools_info_min_memsize(pi);
1096 extmem_option(struct TestContext *ctx)
1098 struct nmreq_pools_info pools_info;
1100 pools_info_fill(&pools_info);
1102 printf("Testing extmem option on vale0:0\n");
1103 return _extmem_option(ctx, &pools_info);
1107 bad_extmem_option(struct TestContext *ctx)
1109 struct nmreq_pools_info pools_info;
1111 printf("Testing bad extmem option on vale0:0\n");
1113 pools_info_fill(&pools_info);
1114 /* Request a large ring size, to make sure that the kernel
1115 * rejects our request. */
1116 pools_info.nr_ring_pool_objsize = (1 << 16);
1118 return _extmem_option(ctx, &pools_info) < 0 ? 0 : -1;
1122 duplicate_extmem_options(struct TestContext *ctx)
1124 struct nmreq_opt_extmem e1, save1, e2, save2;
1125 struct nmreq_pools_info pools_info;
1128 printf("Testing duplicate extmem option on vale0:0\n");
1130 pools_info_fill(&pools_info);
1132 if ((ret = push_extmem_option(ctx, &pools_info, &e1)) < 0)
1135 if ((ret = push_extmem_option(ctx, &pools_info, &e2)) < 0) {
1143 ret = port_register_hwall(ctx);
1145 printf("duplicate option not detected\n");
1149 save2.nro_opt.nro_status = EINVAL;
1150 if ((ret = pop_extmem_option(ctx, &save2)))
1153 save1.nro_opt.nro_status = EINVAL;
1154 if ((ret = pop_extmem_option(ctx, &save1)))
1159 #endif /* CONFIG_NETMAP_EXTMEM */
1162 push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
1168 ctx->nr_flags |= NR_EXCLUSIVE;
1170 /* Get port info in order to use num_registered_rings(). */
1171 ret = port_info_get(ctx);
1175 num_entries = num_registered_rings(ctx);
1177 csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
1179 assert(csb_size > 0);
1183 ret = posix_memalign(&ctx->csb, sizeof(struct nm_csb_atok), csb_size);
1185 printf("Failed to allocate CSB memory\n");
1189 memset(opt, 0, sizeof(*opt));
1190 opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1191 opt->csb_atok = (uintptr_t)ctx->csb;
1192 opt->csb_ktoa = (uintptr_t)(((uint8_t *)ctx->csb) +
1193 sizeof(struct nm_csb_atok) * num_entries);
1195 printf("Pushing option NETMAP_REQ_OPT_CSB\n");
1196 push_option(&opt->nro_opt, ctx);
1202 csb_mode(struct TestContext *ctx)
1204 struct nmreq_opt_csb opt;
1207 ret = push_csb_option(ctx, &opt);
1212 ret = port_register_hwall(ctx);
1219 csb_mode_invalid_memory(struct TestContext *ctx)
1221 struct nmreq_opt_csb opt;
1224 memset(&opt, 0, sizeof(opt));
1225 opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1226 opt.csb_atok = (uintptr_t)0x10;
1227 opt.csb_ktoa = (uintptr_t)0x800;
1228 push_option(&opt.nro_opt, ctx);
1230 ctx->nr_flags = NR_EXCLUSIVE;
1231 ret = port_register_hwall(ctx);
1234 return (ret < 0) ? 0 : -1;
1238 sync_kloop_stop(struct TestContext *ctx)
1240 struct nmreq_header hdr;
1243 printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname_ext);
1245 nmreq_hdr_init(&hdr, ctx->ifname_ext);
1246 hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
1247 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1249 perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
1256 sync_kloop_worker(void *opaque)
1258 struct TestContext *ctx = opaque;
1259 struct nmreq_sync_kloop_start req;
1260 struct nmreq_header hdr;
1263 printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname_ext);
1265 nmreq_hdr_init(&hdr, ctx->ifname_ext);
1266 hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
1267 hdr.nr_body = (uintptr_t)&req;
1268 hdr.nr_options = (uintptr_t)ctx->nr_opt;
1269 memset(&req, 0, sizeof(req));
1271 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1273 perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
1280 pthread_exit(ret ? (void *)THRET_FAILURE : (void *)THRET_SUCCESS);
1284 sync_kloop_start_stop(struct TestContext *ctx)
1287 void *thret = THRET_FAILURE;
1290 ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
1292 printf("pthread_create(kloop): %s\n", strerror(ret));
1296 ret = sync_kloop_stop(ctx);
1301 ret = pthread_join(th, &thret);
1303 printf("pthread_join(kloop): %s\n", strerror(ret));
1306 return thret == THRET_SUCCESS ? 0 : -1;
1310 sync_kloop(struct TestContext *ctx)
1314 ret = csb_mode(ctx);
1319 return sync_kloop_start_stop(ctx);
1323 sync_kloop_eventfds(struct TestContext *ctx)
1325 struct nmreq_opt_sync_kloop_eventfds *opt = NULL;
1326 struct nmreq_option save;
1331 num_entries = num_registered_rings(ctx);
1332 opt_size = sizeof(*opt) + num_entries * sizeof(opt->eventfds[0]);
1333 opt = calloc(1, opt_size);
1334 opt->nro_opt.nro_next = 0;
1335 opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
1336 opt->nro_opt.nro_status = 0;
1337 opt->nro_opt.nro_size = opt_size;
1338 for (i = 0; i < num_entries; i++) {
1339 int efd = eventfd(0, 0);
1341 opt->eventfds[i].ioeventfd = efd;
1342 efd = eventfd(0, 0);
1343 opt->eventfds[i].irqfd = efd;
1346 push_option(&opt->nro_opt, ctx);
1347 save = opt->nro_opt;
1349 ret = sync_kloop_start_stop(ctx);
1356 save.nro_status = 0;
1357 #else /* !__linux__ */
1358 save.nro_status = EOPNOTSUPP;
1359 #endif /* !__linux__ */
1361 ret = checkoption(&opt->nro_opt, &save);
1369 sync_kloop_eventfds_all(struct TestContext *ctx)
1373 ret = csb_mode(ctx);
1378 return sync_kloop_eventfds(ctx);
1382 sync_kloop_eventfds_all_tx(struct TestContext *ctx)
1384 struct nmreq_opt_csb opt;
1387 ret = push_csb_option(ctx, &opt);
1392 ret = port_register_hwall_tx(ctx);
1398 return sync_kloop_eventfds(ctx);
1402 sync_kloop_nocsb(struct TestContext *ctx)
1406 ret = port_register_hwall(ctx);
1411 /* Sync kloop must fail because we did not use
1412 * NETMAP_REQ_CSB_ENABLE. */
1413 return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
1417 csb_enable(struct TestContext *ctx)
1419 struct nmreq_option saveopt;
1420 struct nmreq_opt_csb opt;
1421 struct nmreq_header hdr;
1424 ret = push_csb_option(ctx, &opt);
1428 saveopt = opt.nro_opt;
1429 saveopt.nro_status = 0;
1431 nmreq_hdr_init(&hdr, ctx->ifname_ext);
1432 hdr.nr_reqtype = NETMAP_REQ_CSB_ENABLE;
1433 hdr.nr_options = (uintptr_t)ctx->nr_opt;
1434 hdr.nr_body = (uintptr_t)NULL;
1436 printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname_ext);
1438 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1440 perror("ioctl(/dev/netmap, NIOCCTRL, CSB_ENABLE)");
1444 ret = checkoption(&opt.nro_opt, &saveopt);
1451 sync_kloop_csb_enable(struct TestContext *ctx)
1455 ctx->nr_flags |= NR_EXCLUSIVE;
1456 ret = port_register_hwall(ctx);
1461 ret = csb_enable(ctx);
1466 return sync_kloop_start_stop(ctx);
1470 sync_kloop_conflict(struct TestContext *ctx)
1472 struct nmreq_opt_csb opt;
1474 void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
1480 ret = push_csb_option(ctx, &opt);
1485 ret = port_register_hwall(ctx);
1491 ret = sem_init(&sem, 0, 0);
1493 printf("sem_init() failed: %s\n", strerror(ret));
1498 ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
1501 printf("pthread_create(kloop1): %s\n", strerror(ret));
1504 ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
1507 printf("pthread_create(kloop2): %s\n", strerror(ret));
1510 /* Wait for one of the two threads to fail to start the kloop, to
1511 * avoid a race condition where th1 starts the loop and stops,
1512 * and after that th2 starts the loop successfully. */
1513 clock_gettime(CLOCK_REALTIME, &to);
1515 ret = sem_timedwait(&sem, &to);
1518 printf("sem_timedwait() failed: %s\n", strerror(errno));
1521 err |= sync_kloop_stop(ctx);
1523 ret = pthread_join(th1, &thret1);
1526 printf("pthread_join(kloop1): %s\n", strerror(ret));
1529 ret = pthread_join(th2, &thret2);
1532 printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
1541 /* Check that one of the two failed, while the other one succeeded. */
1542 return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
1543 (thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
1549 sync_kloop_eventfds_mismatch(struct TestContext *ctx)
1551 struct nmreq_opt_csb opt;
1554 ret = push_csb_option(ctx, &opt);
1559 ret = port_register_hwall_rx(ctx);
1565 /* Deceive num_registered_rings() to trigger a failure of
1566 * sync_kloop_eventfds(). The latter will think that all the
1567 * rings were registered, and allocate the wrong number of
1569 ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
1571 return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
1575 null_port(struct TestContext *ctx)
1580 ctx->nr_mode = NR_REG_NULL;
1581 ctx->nr_tx_rings = 10;
1582 ctx->nr_rx_rings = 5;
1583 ctx->nr_tx_slots = 256;
1584 ctx->nr_rx_slots = 100;
1585 ret = port_register(ctx);
1593 null_port_all_zero(struct TestContext *ctx)
1598 ctx->nr_mode = NR_REG_NULL;
1599 ctx->nr_tx_rings = 0;
1600 ctx->nr_rx_rings = 0;
1601 ctx->nr_tx_slots = 0;
1602 ctx->nr_rx_slots = 0;
1603 ret = port_register(ctx);
1611 null_port_sync(struct TestContext *ctx)
1616 ctx->nr_mode = NR_REG_NULL;
1617 ctx->nr_tx_rings = 10;
1618 ctx->nr_rx_rings = 5;
1619 ctx->nr_tx_slots = 256;
1620 ctx->nr_rx_slots = 100;
1621 ret = port_register(ctx);
1625 ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
1633 usage(const char *prog)
1635 printf("%s -i IFNAME\n"
1636 "[-j TEST_NUM1[-[TEST_NUM2]] | -[TEST_NUM_2]]\n"
1637 "[-l (list test cases)]\n",
1646 #define decltest(f) \
1648 .test = f, .name = #f \
1651 static struct mytest tests[] = {
1652 decltest(port_info_get),
1653 decltest(port_register_hwall_host),
1654 decltest(port_register_hwall),
1655 decltest(port_register_host),
1656 decltest(port_register_single_ring_couple),
1657 decltest(vale_attach_detach),
1658 decltest(vale_attach_detach_host_rings),
1659 decltest(vale_ephemeral_port_hdr_manipulation),
1660 decltest(vale_persistent_port),
1661 decltest(pools_info_get_and_register),
1662 decltest(pools_info_get_empty_ifname),
1663 decltest(pipe_master),
1664 decltest(pipe_slave),
1665 decltest(pipe_port_info_get),
1666 decltest(pipe_pools_info_get),
1667 decltest(vale_polling_enable_disable),
1668 decltest(unsupported_option),
1669 decltest(infinite_options),
1670 #ifdef CONFIG_NETMAP_EXTMEM
1671 decltest(extmem_option),
1672 decltest(bad_extmem_option),
1673 decltest(duplicate_extmem_options),
1674 #endif /* CONFIG_NETMAP_EXTMEM */
1676 decltest(csb_mode_invalid_memory),
1677 decltest(sync_kloop),
1678 decltest(sync_kloop_eventfds_all),
1679 decltest(sync_kloop_eventfds_all_tx),
1680 decltest(sync_kloop_nocsb),
1681 decltest(sync_kloop_csb_enable),
1682 decltest(sync_kloop_conflict),
1683 decltest(sync_kloop_eventfds_mismatch),
1684 decltest(null_port),
1685 decltest(null_port_all_zero),
1686 decltest(null_port_sync),
1687 decltest(legacy_regif_default),
1688 decltest(legacy_regif_all_nic),
1689 decltest(legacy_regif_12),
1690 decltest(legacy_regif_sw),
1691 decltest(legacy_regif_future),
1692 decltest(legacy_regif_extra_bufs),
1693 decltest(legacy_regif_extra_bufs_pipe),
1694 decltest(legacy_regif_extra_bufs_pipe_vale),
1698 context_cleanup(struct TestContext *ctx)
1710 parse_interval(const char *arg, int *j, int *k)
1712 const char *scan = arg;
1721 if (!isdigit(*scan))
1723 *k = strtol(scan, &rest, 10);
1733 if (!isdigit(*scan))
1735 *k = strtol(scan, &rest, 10);
1737 if (!(*scan == '\0'))
1743 fprintf(stderr, "syntax error in '%s', must be num[-[num]] or -[num]\n", arg);
1747 #define ARGV_APPEND(_av, _ac, _x)\
1749 assert((int)(_ac) < (int)(sizeof(_av)/sizeof((_av)[0])));\
1750 (_av)[(_ac)++] = _x;\
1754 tap_cleanup(int signo)
1761 ARGV_APPEND(av, ac, "ifconfig");
1762 ARGV_APPEND(av, ac, ctx_.ifname);
1763 ARGV_APPEND(av, ac, "destroy");
1765 ARGV_APPEND(av, ac, "ip");
1766 ARGV_APPEND(av, ac, "link");
1767 ARGV_APPEND(av, ac, "del");
1768 ARGV_APPEND(av, ac, ctx_.ifname);
1770 ARGV_APPEND(av, ac, NULL);
1771 if (exec_command(ac, av)) {
1772 printf("Failed to destroy tap interface\n");
1777 main(int argc, char **argv)
1788 memset(&ctx_, 0, sizeof(ctx_));
1794 clock_gettime(CLOCK_REALTIME, &t);
1795 srand((unsigned int)t.tv_nsec);
1796 idx = rand() % 8000 + 100;
1797 snprintf(ctx_.ifname, sizeof(ctx_.ifname), "tap%d", idx);
1798 idx = rand() % 800 + 100;
1799 snprintf(ctx_.bdgname, sizeof(ctx_.bdgname), "vale%d", idx);
1802 while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
1809 strncpy(ctx_.ifname, optarg, sizeof(ctx_.ifname) - 1);
1814 if (parse_interval(optarg, &j, &k) < 0) {
1826 printf(" Unrecognized option %c\n", opt);
1832 num_tests = sizeof(tests) / sizeof(tests[0]);
1834 if (j < 0 || j >= num_tests || k > num_tests) {
1835 fprintf(stderr, "Test interval %d-%d out of range (%d-%d)\n",
1836 j + 1, k, 1, num_tests + 1);
1844 printf("Available tests:\n");
1845 for (i = 0; i < num_tests; i++) {
1846 printf("#%03d: %s\n", i + 1, tests[i].name);
1852 struct sigaction sa;
1856 ARGV_APPEND(av, ac, "ifconfig");
1857 ARGV_APPEND(av, ac, ctx_.ifname);
1858 ARGV_APPEND(av, ac, "create");
1859 ARGV_APPEND(av, ac, "up");
1861 ARGV_APPEND(av, ac, "ip");
1862 ARGV_APPEND(av, ac, "tuntap");
1863 ARGV_APPEND(av, ac, "add");
1864 ARGV_APPEND(av, ac, "mode");
1865 ARGV_APPEND(av, ac, "tap");
1866 ARGV_APPEND(av, ac, "name");
1867 ARGV_APPEND(av, ac, ctx_.ifname);
1869 ARGV_APPEND(av, ac, NULL);
1870 if (exec_command(ac, av)) {
1871 printf("Failed to create tap interface\n");
1875 sa.sa_handler = tap_cleanup;
1876 sigemptyset(&sa.sa_mask);
1877 sa.sa_flags = SA_RESTART;
1878 ret = sigaction(SIGINT, &sa, NULL);
1880 perror("sigaction(SIGINT)");
1883 ret = sigaction(SIGTERM, &sa, NULL);
1885 perror("sigaction(SIGTERM)");
1890 for (i = j; i < k; i++) {
1891 struct TestContext ctxcopy;
1893 printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
1894 fd = open("/dev/netmap", O_RDWR);
1896 perror("open(/dev/netmap)");
1900 memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
1902 memcpy(ctxcopy.ifname_ext, ctxcopy.ifname,
1903 sizeof(ctxcopy.ifname));
1904 ret = tests[i].test(&ctxcopy);
1906 printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
1909 printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
1910 context_cleanup(&ctxcopy);