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 "freebsd_test_suite/macros.h"
57 #include <sys/eventfd.h>
61 eventfd(int x __unused, int y __unused)
66 #endif /* __linux__ */
69 exec_command(int argc, const char *const argv[])
76 printf("Executing command: ");
77 for (i = 0; i < argc - 1; i++) {
79 /* Invalid argument. */
85 printf("%s", argv[i]);
94 /* Child process. Redirect stdin, stdout
96 for (i = 0; i < 3; i++) {
98 fds[i] = open("/dev/null", O_RDONLY);
100 for (i--; i >= 0; i--) {
107 /* Make a copy of the arguments, passing them to execvp. */
108 av = calloc(argc, sizeof(av[0]));
112 for (i = 0; i < argc - 1; i++) {
113 av[i] = strdup(argv[i]);
123 wret = waitpid(child_pid, &child_status, 0);
125 fprintf(stderr, "waitpid() failed: %s\n", strerror(errno));
128 if (WIFEXITED(child_status)) {
129 return WEXITSTATUS(child_status);
136 #define THRET_SUCCESS ((void *)128)
137 #define THRET_FAILURE ((void *)0)
141 char ifname_ext[128];
143 uint32_t nr_tx_slots; /* slots in tx rings */
144 uint32_t nr_rx_slots; /* slots in rx rings */
145 uint16_t nr_tx_rings; /* number of tx rings */
146 uint16_t nr_rx_rings; /* number of rx rings */
147 uint16_t nr_mem_id; /* id of the memory allocator */
148 uint16_t nr_ringid; /* ring(s) we care about */
149 uint32_t nr_mode; /* specify NR_REG_* modes */
150 uint32_t nr_extra_bufs; /* number of requested extra buffers */
151 uint64_t nr_flags; /* additional flags (see below) */
152 uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
153 uint32_t nr_first_cpu_id; /* vale polling */
154 uint32_t nr_num_polling_cpus; /* vale polling */
155 int fd; /* netmap file descriptor */
157 void *csb; /* CSB entries (atok and ktoa) */
158 struct nmreq_option *nr_opt; /* list of options */
159 sem_t *sem; /* for thread synchronization */
160 struct nmport_d *nmport; /* nmport descriptor from libnetmap */
163 static struct TestContext ctx_;
165 typedef int (*testfunc_t)(struct TestContext *ctx);
168 nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
170 memset(hdr, 0, sizeof(*hdr));
171 hdr->nr_version = NETMAP_API;
172 strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name) - 1);
175 /* Single NETMAP_REQ_PORT_INFO_GET. */
177 port_info_get(struct TestContext *ctx)
179 struct nmreq_port_info_get req;
180 struct nmreq_header hdr;
184 printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname_ext);
186 nmreq_hdr_init(&hdr, ctx->ifname_ext);
187 hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
188 hdr.nr_body = (uintptr_t)&req;
189 memset(&req, 0, sizeof(req));
190 req.nr_mem_id = ctx->nr_mem_id;
191 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
193 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
196 printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
197 printf("nr_tx_slots %u\n", req.nr_tx_slots);
198 printf("nr_rx_slots %u\n", req.nr_rx_slots);
199 printf("nr_tx_rings %u\n", req.nr_tx_rings);
200 printf("nr_rx_rings %u\n", req.nr_rx_rings);
201 printf("nr_mem_id %u\n", req.nr_mem_id);
203 success = req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
204 req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings;
209 /* Write back results to the context structure. */
210 ctx->nr_tx_slots = req.nr_tx_slots;
211 ctx->nr_rx_slots = req.nr_rx_slots;
212 ctx->nr_tx_rings = req.nr_tx_rings;
213 ctx->nr_rx_rings = req.nr_rx_rings;
214 ctx->nr_mem_id = req.nr_mem_id;
219 /* Single NETMAP_REQ_REGISTER, no use. */
221 port_register(struct TestContext *ctx)
223 struct nmreq_register req;
224 struct nmreq_header hdr;
228 printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
229 "flags=0x%llx) on '%s'\n",
230 ctx->nr_mode, ctx->nr_ringid, (unsigned long long)ctx->nr_flags,
233 nmreq_hdr_init(&hdr, ctx->ifname_ext);
234 hdr.nr_reqtype = NETMAP_REQ_REGISTER;
235 hdr.nr_body = (uintptr_t)&req;
236 hdr.nr_options = (uintptr_t)ctx->nr_opt;
237 memset(&req, 0, sizeof(req));
238 req.nr_mem_id = ctx->nr_mem_id;
239 req.nr_mode = ctx->nr_mode;
240 req.nr_ringid = ctx->nr_ringid;
241 req.nr_flags = ctx->nr_flags;
242 req.nr_tx_slots = ctx->nr_tx_slots;
243 req.nr_rx_slots = ctx->nr_rx_slots;
244 req.nr_tx_rings = ctx->nr_tx_rings;
245 req.nr_rx_rings = ctx->nr_rx_rings;
246 req.nr_extra_bufs = ctx->nr_extra_bufs;
247 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
249 perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
252 printf("nr_offset 0x%llx\n", (unsigned long long)req.nr_offset);
253 printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
254 printf("nr_tx_slots %u\n", req.nr_tx_slots);
255 printf("nr_rx_slots %u\n", req.nr_rx_slots);
256 printf("nr_tx_rings %u\n", req.nr_tx_rings);
257 printf("nr_rx_rings %u\n", req.nr_rx_rings);
258 printf("nr_mem_id %u\n", req.nr_mem_id);
259 printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
261 success = req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
262 (ctx->nr_ringid == req.nr_ringid) &&
263 (ctx->nr_flags == req.nr_flags) &&
264 ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
265 (ctx->nr_tx_slots == req.nr_tx_slots)) &&
266 ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
267 (ctx->nr_rx_slots == req.nr_rx_slots)) &&
268 ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
269 (ctx->nr_tx_rings == req.nr_tx_rings)) &&
270 ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
271 (ctx->nr_rx_rings == req.nr_rx_rings)) &&
272 ((!ctx->nr_mem_id && req.nr_mem_id) ||
273 (ctx->nr_mem_id == req.nr_mem_id)) &&
274 (ctx->nr_extra_bufs == req.nr_extra_bufs);
279 /* Write back results to the context structure.*/
280 ctx->nr_tx_slots = req.nr_tx_slots;
281 ctx->nr_rx_slots = req.nr_rx_slots;
282 ctx->nr_tx_rings = req.nr_tx_rings;
283 ctx->nr_rx_rings = req.nr_rx_rings;
284 ctx->nr_mem_id = req.nr_mem_id;
285 ctx->nr_extra_bufs = req.nr_extra_bufs;
291 niocregif(struct TestContext *ctx, int netmap_api)
297 printf("Testing legacy NIOCREGIF on '%s'\n", ctx->ifname_ext);
299 memset(&req, 0, sizeof(req));
300 memcpy(req.nr_name, ctx->ifname_ext, sizeof(req.nr_name));
301 req.nr_name[sizeof(req.nr_name) - 1] = '\0';
302 req.nr_version = netmap_api;
303 req.nr_ringid = ctx->nr_ringid;
304 req.nr_flags = ctx->nr_mode | ctx->nr_flags;
305 req.nr_tx_slots = ctx->nr_tx_slots;
306 req.nr_rx_slots = ctx->nr_rx_slots;
307 req.nr_tx_rings = ctx->nr_tx_rings;
308 req.nr_rx_rings = ctx->nr_rx_rings;
309 req.nr_arg2 = ctx->nr_mem_id;
310 req.nr_arg3 = ctx->nr_extra_bufs;
312 ret = ioctl(ctx->fd, NIOCREGIF, &req);
314 perror("ioctl(/dev/netmap, NIOCREGIF)");
318 printf("nr_offset 0x%x\n", req.nr_offset);
319 printf("nr_memsize %u\n", req.nr_memsize);
320 printf("nr_tx_slots %u\n", req.nr_tx_slots);
321 printf("nr_rx_slots %u\n", req.nr_rx_slots);
322 printf("nr_tx_rings %u\n", req.nr_tx_rings);
323 printf("nr_rx_rings %u\n", req.nr_rx_rings);
324 printf("nr_version %d\n", req.nr_version);
325 printf("nr_ringid %x\n", req.nr_ringid);
326 printf("nr_flags %x\n", req.nr_flags);
327 printf("nr_arg2 %u\n", req.nr_arg2);
328 printf("nr_arg3 %u\n", req.nr_arg3);
330 success = req.nr_memsize &&
331 (ctx->nr_ringid == req.nr_ringid) &&
332 ((ctx->nr_mode | ctx->nr_flags) == req.nr_flags) &&
333 ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
334 (ctx->nr_tx_slots == req.nr_tx_slots)) &&
335 ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
336 (ctx->nr_rx_slots == req.nr_rx_slots)) &&
337 ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
338 (ctx->nr_tx_rings == req.nr_tx_rings)) &&
339 ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
340 (ctx->nr_rx_rings == req.nr_rx_rings)) &&
341 ((!ctx->nr_mem_id && req.nr_arg2) ||
342 (ctx->nr_mem_id == req.nr_arg2)) &&
343 (ctx->nr_extra_bufs == req.nr_arg3);
348 /* Write back results to the context structure.*/
349 ctx->nr_tx_slots = req.nr_tx_slots;
350 ctx->nr_rx_slots = req.nr_rx_slots;
351 ctx->nr_tx_rings = req.nr_tx_rings;
352 ctx->nr_rx_rings = req.nr_rx_rings;
353 ctx->nr_mem_id = req.nr_arg2;
354 ctx->nr_extra_bufs = req.nr_arg3;
359 /* The 11 ABI is the one right before the introduction of the new NIOCCTRL
360 * ABI. The 11 ABI is useful to perform tests with legacy applications
361 * (which use the 11 ABI) and new kernel (which uses 12, or higher). */
362 #define NETMAP_API_NIOCREGIF 11
365 legacy_regif_default(struct TestContext *ctx)
367 return niocregif(ctx, NETMAP_API_NIOCREGIF);
371 legacy_regif_all_nic(struct TestContext *ctx)
373 ctx->nr_mode = NR_REG_ALL_NIC;
374 return niocregif(ctx, NETMAP_API);
378 legacy_regif_12(struct TestContext *ctx)
380 ctx->nr_mode = NR_REG_ALL_NIC;
381 return niocregif(ctx, NETMAP_API_NIOCREGIF+1);
385 legacy_regif_sw(struct TestContext *ctx)
387 ctx->nr_mode = NR_REG_SW;
388 return niocregif(ctx, NETMAP_API_NIOCREGIF);
392 legacy_regif_future(struct TestContext *ctx)
394 ctx->nr_mode = NR_REG_NIC_SW;
395 /* Test forward compatibility for the legacy ABI. This means
396 * using an older kernel (with ABI 12 or higher) and a newer
397 * application (with ABI greater than NETMAP_API). */
398 return niocregif(ctx, NETMAP_API+2);
402 legacy_regif_extra_bufs(struct TestContext *ctx)
404 ctx->nr_mode = NR_REG_ALL_NIC;
405 ctx->nr_extra_bufs = 20; /* arbitrary number of extra bufs */
406 return niocregif(ctx, NETMAP_API_NIOCREGIF);
410 legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
412 strncat(ctx->ifname_ext, "{pipeexbuf", sizeof(ctx->ifname_ext));
413 ctx->nr_mode = NR_REG_ALL_NIC;
414 ctx->nr_extra_bufs = 58; /* arbitrary number of extra bufs */
416 return niocregif(ctx, NETMAP_API_NIOCREGIF);
420 legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
422 strncpy(ctx->ifname_ext, "valeX1:Y4", sizeof(ctx->ifname_ext));
423 return legacy_regif_extra_bufs_pipe(ctx);
426 /* Only valid after a successful port_register(). */
428 num_registered_rings(struct TestContext *ctx)
430 if (ctx->nr_flags & NR_TX_RINGS_ONLY) {
431 return ctx->nr_tx_rings;
433 if (ctx->nr_flags & NR_RX_RINGS_ONLY) {
434 return ctx->nr_rx_rings;
437 return ctx->nr_tx_rings + ctx->nr_rx_rings;
441 port_register_hwall_host(struct TestContext *ctx)
443 ctx->nr_mode = NR_REG_NIC_SW;
444 return port_register(ctx);
448 port_register_host(struct TestContext *ctx)
450 ctx->nr_mode = NR_REG_SW;
451 return port_register(ctx);
455 port_register_hwall(struct TestContext *ctx)
457 ctx->nr_mode = NR_REG_ALL_NIC;
458 return port_register(ctx);
462 port_register_single_ring_couple(struct TestContext *ctx)
464 ctx->nr_mode = NR_REG_ONE_NIC;
466 return port_register(ctx);
470 port_register_hwall_tx(struct TestContext *ctx)
472 ctx->nr_mode = NR_REG_ALL_NIC;
473 ctx->nr_flags |= NR_TX_RINGS_ONLY;
474 return port_register(ctx);
478 port_register_hwall_rx(struct TestContext *ctx)
480 ctx->nr_mode = NR_REG_ALL_NIC;
481 ctx->nr_flags |= NR_RX_RINGS_ONLY;
482 return port_register(ctx);
485 /* NETMAP_REQ_VALE_ATTACH */
487 vale_attach(struct TestContext *ctx)
489 struct nmreq_vale_attach req;
490 struct nmreq_header hdr;
491 char vpname[sizeof(ctx->bdgname) + 1 + sizeof(ctx->ifname_ext)];
494 snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
496 printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
497 nmreq_hdr_init(&hdr, vpname);
498 hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
499 hdr.nr_body = (uintptr_t)&req;
500 memset(&req, 0, sizeof(req));
501 req.reg.nr_mem_id = ctx->nr_mem_id;
502 if (ctx->nr_mode == 0) {
503 ctx->nr_mode = NR_REG_ALL_NIC; /* default */
505 req.reg.nr_mode = ctx->nr_mode;
506 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
508 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
511 printf("nr_mem_id %u\n", req.reg.nr_mem_id);
513 return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
514 (ctx->nr_mem_id == req.reg.nr_mem_id)) &&
515 (ctx->nr_flags == req.reg.nr_flags)
520 /* NETMAP_REQ_VALE_DETACH */
522 vale_detach(struct TestContext *ctx)
524 struct nmreq_header hdr;
525 struct nmreq_vale_detach req;
529 snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
531 printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
532 nmreq_hdr_init(&hdr, vpname);
533 hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
534 hdr.nr_body = (uintptr_t)&req;
535 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
537 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
544 /* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
546 vale_attach_detach(struct TestContext *ctx)
550 if ((ret = vale_attach(ctx)) != 0) {
554 return vale_detach(ctx);
558 vale_attach_detach_host_rings(struct TestContext *ctx)
560 ctx->nr_mode = NR_REG_NIC_SW;
561 return vale_attach_detach(ctx);
564 /* First NETMAP_REQ_PORT_HDR_SET and the NETMAP_REQ_PORT_HDR_GET
565 * to check that we get the same value. */
567 port_hdr_set_and_get(struct TestContext *ctx)
569 struct nmreq_port_hdr req;
570 struct nmreq_header hdr;
573 printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname_ext);
575 nmreq_hdr_init(&hdr, ctx->ifname_ext);
576 hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
577 hdr.nr_body = (uintptr_t)&req;
578 memset(&req, 0, sizeof(req));
579 req.nr_hdr_len = ctx->nr_hdr_len;
580 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
582 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
586 if (req.nr_hdr_len != ctx->nr_hdr_len) {
590 printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname_ext);
591 hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
593 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
595 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
598 printf("nr_hdr_len %u\n", req.nr_hdr_len);
600 return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
604 * Possible lengths for the VirtIO network header, as specified by
606 * http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html
608 #define VIRTIO_NET_HDR_LEN 10
609 #define VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS 12
612 vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
616 strncpy(ctx->ifname_ext, "vale:eph0", sizeof(ctx->ifname_ext));
617 ctx->nr_mode = NR_REG_ALL_NIC;
618 if ((ret = port_register(ctx))) {
621 /* Try to set and get all the acceptable values. */
622 ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS;
623 if ((ret = port_hdr_set_and_get(ctx))) {
627 if ((ret = port_hdr_set_and_get(ctx))) {
630 ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN;
631 if ((ret = port_hdr_set_and_get(ctx))) {
638 vale_persistent_port(struct TestContext *ctx)
640 struct nmreq_vale_newif req;
641 struct nmreq_header hdr;
645 strncpy(ctx->ifname_ext, "per4", sizeof(ctx->ifname_ext));
647 printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname_ext);
649 nmreq_hdr_init(&hdr, ctx->ifname_ext);
650 hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
651 hdr.nr_body = (uintptr_t)&req;
652 memset(&req, 0, sizeof(req));
653 req.nr_mem_id = ctx->nr_mem_id;
654 req.nr_tx_slots = ctx->nr_tx_slots;
655 req.nr_rx_slots = ctx->nr_rx_slots;
656 req.nr_tx_rings = ctx->nr_tx_rings;
657 req.nr_rx_rings = ctx->nr_rx_rings;
658 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
660 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
664 /* Attach the persistent VALE port to a switch and then detach. */
665 result = vale_attach_detach(ctx);
667 printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname_ext);
668 hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
669 hdr.nr_body = (uintptr_t)NULL;
670 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
672 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
681 /* Single NETMAP_REQ_POOLS_INFO_GET. */
683 pools_info_get(struct TestContext *ctx)
685 struct nmreq_pools_info req;
686 struct nmreq_header hdr;
689 printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname_ext);
691 nmreq_hdr_init(&hdr, ctx->ifname_ext);
692 hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
693 hdr.nr_body = (uintptr_t)&req;
694 memset(&req, 0, sizeof(req));
695 req.nr_mem_id = ctx->nr_mem_id;
696 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
698 perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
701 printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
702 printf("nr_mem_id %u\n", req.nr_mem_id);
703 printf("nr_if_pool_offset 0x%llx\n",
704 (unsigned long long)req.nr_if_pool_offset);
705 printf("nr_if_pool_objtotal %u\n", req.nr_if_pool_objtotal);
706 printf("nr_if_pool_objsize %u\n", req.nr_if_pool_objsize);
707 printf("nr_ring_pool_offset 0x%llx\n",
708 (unsigned long long)req.nr_if_pool_offset);
709 printf("nr_ring_pool_objtotal %u\n", req.nr_ring_pool_objtotal);
710 printf("nr_ring_pool_objsize %u\n", req.nr_ring_pool_objsize);
711 printf("nr_buf_pool_offset 0x%llx\n",
712 (unsigned long long)req.nr_buf_pool_offset);
713 printf("nr_buf_pool_objtotal %u\n", req.nr_buf_pool_objtotal);
714 printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
716 return req.nr_memsize && req.nr_if_pool_objtotal &&
717 req.nr_if_pool_objsize &&
718 req.nr_ring_pool_objtotal &&
719 req.nr_ring_pool_objsize &&
720 req.nr_buf_pool_objtotal &&
721 req.nr_buf_pool_objsize
727 pools_info_get_and_register(struct TestContext *ctx)
731 /* Check that we can get pools info before we register
732 * a netmap interface. */
733 ret = pools_info_get(ctx);
738 ctx->nr_mode = NR_REG_ONE_NIC;
739 ret = port_register(ctx);
745 /* Check that we can get pools info also after we register. */
746 return pools_info_get(ctx);
750 pools_info_get_empty_ifname(struct TestContext *ctx)
752 strncpy(ctx->ifname_ext, "", sizeof(ctx->ifname_ext));
753 return pools_info_get(ctx) != 0 ? 0 : -1;
757 pipe_master(struct TestContext *ctx)
759 strncat(ctx->ifname_ext, "{pipeid1", sizeof(ctx->ifname_ext));
760 ctx->nr_mode = NR_REG_NIC_SW;
762 if (port_register(ctx) == 0) {
763 printf("pipes should not accept NR_REG_NIC_SW\n");
766 ctx->nr_mode = NR_REG_ALL_NIC;
768 return port_register(ctx);
772 pipe_slave(struct TestContext *ctx)
774 strncat(ctx->ifname_ext, "}pipeid2", sizeof(ctx->ifname_ext));
775 ctx->nr_mode = NR_REG_ALL_NIC;
777 return port_register(ctx);
780 /* Test PORT_INFO_GET and POOLS_INFO_GET on a pipe. This is useful to test the
781 * registration request used internall by netmap. */
783 pipe_port_info_get(struct TestContext *ctx)
785 strncat(ctx->ifname_ext, "}pipeid3", sizeof(ctx->ifname_ext));
787 return port_info_get(ctx);
791 pipe_pools_info_get(struct TestContext *ctx)
793 strncat(ctx->ifname_ext, "{xid", sizeof(ctx->ifname_ext));
795 return pools_info_get(ctx);
798 /* NETMAP_REQ_VALE_POLLING_ENABLE */
800 vale_polling_enable(struct TestContext *ctx)
802 struct nmreq_vale_polling req;
803 struct nmreq_header hdr;
807 snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
808 printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
810 nmreq_hdr_init(&hdr, vpname);
811 hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
812 hdr.nr_body = (uintptr_t)&req;
813 memset(&req, 0, sizeof(req));
814 req.nr_mode = ctx->nr_mode;
815 req.nr_first_cpu_id = ctx->nr_first_cpu_id;
816 req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
817 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
819 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
823 return (req.nr_mode == ctx->nr_mode &&
824 req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
825 req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
830 /* NETMAP_REQ_VALE_POLLING_DISABLE */
832 vale_polling_disable(struct TestContext *ctx)
834 struct nmreq_vale_polling req;
835 struct nmreq_header hdr;
839 snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
840 printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
842 nmreq_hdr_init(&hdr, vpname);
843 hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
844 hdr.nr_body = (uintptr_t)&req;
845 memset(&req, 0, sizeof(req));
846 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
848 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
856 vale_polling_enable_disable(struct TestContext *ctx)
860 if ((ret = vale_attach(ctx)) != 0) {
864 ctx->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
865 ctx->nr_num_polling_cpus = 1;
866 ctx->nr_first_cpu_id = 0;
867 if ((ret = vale_polling_enable(ctx))) {
870 /* NETMAP_REQ_VALE_POLLING_DISABLE is disabled on FreeBSD,
871 * because it is currently broken. We are happy to see that
879 if ((ret = vale_polling_disable(ctx))) {
884 return vale_detach(ctx);
888 push_option(struct nmreq_option *opt, struct TestContext *ctx)
890 opt->nro_next = (uintptr_t)ctx->nr_opt;
895 clear_options(struct TestContext *ctx)
901 checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
903 if (opt->nro_next != exp->nro_next) {
904 printf("nro_next %p expected %p\n",
905 (void *)(uintptr_t)opt->nro_next,
906 (void *)(uintptr_t)exp->nro_next);
909 if (opt->nro_reqtype != exp->nro_reqtype) {
910 printf("nro_reqtype %u expected %u\n", opt->nro_reqtype,
914 if (opt->nro_status != exp->nro_status) {
915 printf("nro_status %u expected %u\n", opt->nro_status,
923 unsupported_option(struct TestContext *ctx)
925 struct nmreq_option opt, save;
927 printf("Testing unsupported option on %s\n", ctx->ifname_ext);
929 memset(&opt, 0, sizeof(opt));
930 opt.nro_reqtype = 1234;
931 push_option(&opt, ctx);
934 if (port_register_hwall(ctx) >= 0)
938 save.nro_status = EOPNOTSUPP;
939 return checkoption(&opt, &save);
943 infinite_options(struct TestContext *ctx)
945 struct nmreq_option opt;
947 printf("Testing infinite list of options on %s\n", ctx->ifname_ext);
949 opt.nro_reqtype = 1234;
950 push_option(&opt, ctx);
951 opt.nro_next = (uintptr_t)&opt;
952 if (port_register_hwall(ctx) >= 0)
955 return (errno == EMSGSIZE ? 0 : -1);
958 #ifdef CONFIG_NETMAP_EXTMEM
960 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
963 char param[256] = "/sys/module/netmap/parameters/";
967 strncat(param, pname, sizeof(param) - 1);
969 f = fopen(param, "r+");
974 if (fscanf(f, "%ld", &oldv) != 1) {
982 if (fprintf(f, "%ld\n", newv) < 0) {
988 printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
989 #endif /* __linux__ */
994 push_extmem_option(struct TestContext *ctx, const struct nmreq_pools_info *pi,
995 struct nmreq_opt_extmem *e)
999 addr = mmap(NULL, pi->nr_memsize, PROT_READ | PROT_WRITE,
1000 MAP_ANONYMOUS | MAP_SHARED, -1, 0);
1001 if (addr == MAP_FAILED) {
1006 memset(e, 0, sizeof(*e));
1007 e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
1009 e->nro_usrptr = (uintptr_t)addr;
1011 push_option(&e->nro_opt, ctx);
1017 pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
1019 struct nmreq_opt_extmem *e;
1022 e = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
1023 ctx->nr_opt = (struct nmreq_option *)(uintptr_t)ctx->nr_opt->nro_next;
1025 if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
1029 if (e->nro_usrptr != exp->nro_usrptr) {
1030 printf("usrptr %" PRIu64 " expected %" PRIu64 "\n",
1031 e->nro_usrptr, exp->nro_usrptr);
1034 if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
1035 printf("memsize %" PRIu64 " expected %" PRIu64 "\n",
1036 e->nro_info.nr_memsize, exp->nro_info.nr_memsize);
1040 if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr,
1041 e->nro_info.nr_memsize)))
1048 _extmem_option(struct TestContext *ctx,
1049 const struct nmreq_pools_info *pi)
1051 struct nmreq_opt_extmem e, save;
1054 if ((ret = push_extmem_option(ctx, pi, &e)) < 0)
1059 strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
1060 ctx->nr_tx_slots = 16;
1061 ctx->nr_rx_slots = 16;
1063 if ((ret = port_register_hwall(ctx)))
1066 ret = pop_extmem_option(ctx, &save);
1072 pools_info_min_memsize(const struct nmreq_pools_info *pi)
1076 tot += pi->nr_if_pool_objtotal * pi->nr_if_pool_objsize;
1077 tot += pi->nr_ring_pool_objtotal * pi->nr_ring_pool_objsize;
1078 tot += pi->nr_buf_pool_objtotal * pi->nr_buf_pool_objsize;
1084 * Fill the specification of a netmap memory allocator to be
1085 * used with the 'struct nmreq_opt_extmem' option. Arbitrary
1086 * values are used for the parameters, but with enough netmap
1087 * rings, netmap ifs, and buffers to support a VALE port.
1090 pools_info_fill(struct nmreq_pools_info *pi)
1092 pi->nr_if_pool_objtotal = 2;
1093 pi->nr_if_pool_objsize = 1024;
1094 pi->nr_ring_pool_objtotal = 64;
1095 pi->nr_ring_pool_objsize = 512;
1096 pi->nr_buf_pool_objtotal = 4096;
1097 pi->nr_buf_pool_objsize = 2048;
1098 pi->nr_memsize = pools_info_min_memsize(pi);
1102 extmem_option(struct TestContext *ctx)
1104 struct nmreq_pools_info pools_info;
1106 pools_info_fill(&pools_info);
1108 printf("Testing extmem option on vale0:0\n");
1109 return _extmem_option(ctx, &pools_info);
1113 bad_extmem_option(struct TestContext *ctx)
1115 struct nmreq_pools_info pools_info;
1117 printf("Testing bad extmem option on vale0:0\n");
1119 pools_info_fill(&pools_info);
1120 /* Request a large ring size, to make sure that the kernel
1121 * rejects our request. */
1122 pools_info.nr_ring_pool_objsize = (1 << 16);
1124 return _extmem_option(ctx, &pools_info) < 0 ? 0 : -1;
1128 duplicate_extmem_options(struct TestContext *ctx)
1130 struct nmreq_opt_extmem e1, save1, e2, save2;
1131 struct nmreq_pools_info pools_info;
1134 printf("Testing duplicate extmem option on vale0:0\n");
1136 pools_info_fill(&pools_info);
1138 if ((ret = push_extmem_option(ctx, &pools_info, &e1)) < 0)
1141 if ((ret = push_extmem_option(ctx, &pools_info, &e2)) < 0) {
1149 ret = port_register_hwall(ctx);
1151 printf("duplicate option not detected\n");
1155 save2.nro_opt.nro_status = EINVAL;
1156 if ((ret = pop_extmem_option(ctx, &save2)))
1159 save1.nro_opt.nro_status = EINVAL;
1160 if ((ret = pop_extmem_option(ctx, &save1)))
1165 #endif /* CONFIG_NETMAP_EXTMEM */
1168 push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
1174 ctx->nr_flags |= NR_EXCLUSIVE;
1176 /* Get port info in order to use num_registered_rings(). */
1177 ret = port_info_get(ctx);
1181 num_entries = num_registered_rings(ctx);
1183 csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
1185 assert(csb_size > 0);
1189 ret = posix_memalign(&ctx->csb, sizeof(struct nm_csb_atok), csb_size);
1191 printf("Failed to allocate CSB memory\n");
1195 memset(opt, 0, sizeof(*opt));
1196 opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1197 opt->csb_atok = (uintptr_t)ctx->csb;
1198 opt->csb_ktoa = (uintptr_t)(((uint8_t *)ctx->csb) +
1199 sizeof(struct nm_csb_atok) * num_entries);
1201 printf("Pushing option NETMAP_REQ_OPT_CSB\n");
1202 push_option(&opt->nro_opt, ctx);
1208 csb_mode(struct TestContext *ctx)
1210 struct nmreq_opt_csb opt;
1213 ret = push_csb_option(ctx, &opt);
1218 ret = port_register_hwall(ctx);
1225 csb_mode_invalid_memory(struct TestContext *ctx)
1227 struct nmreq_opt_csb opt;
1230 memset(&opt, 0, sizeof(opt));
1231 opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1232 opt.csb_atok = (uintptr_t)0x10;
1233 opt.csb_ktoa = (uintptr_t)0x800;
1234 push_option(&opt.nro_opt, ctx);
1236 ctx->nr_flags = NR_EXCLUSIVE;
1237 ret = port_register_hwall(ctx);
1240 return (ret < 0) ? 0 : -1;
1244 sync_kloop_stop(struct TestContext *ctx)
1246 struct nmreq_header hdr;
1249 printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname_ext);
1251 nmreq_hdr_init(&hdr, ctx->ifname_ext);
1252 hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
1253 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1255 perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
1262 sync_kloop_worker(void *opaque)
1264 struct TestContext *ctx = opaque;
1265 struct nmreq_sync_kloop_start req;
1266 struct nmreq_header hdr;
1269 printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname_ext);
1271 nmreq_hdr_init(&hdr, ctx->ifname_ext);
1272 hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
1273 hdr.nr_body = (uintptr_t)&req;
1274 hdr.nr_options = (uintptr_t)ctx->nr_opt;
1275 memset(&req, 0, sizeof(req));
1277 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1279 perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
1286 pthread_exit(ret ? (void *)THRET_FAILURE : (void *)THRET_SUCCESS);
1290 sync_kloop_start_stop(struct TestContext *ctx)
1293 void *thret = THRET_FAILURE;
1296 ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
1298 printf("pthread_create(kloop): %s\n", strerror(ret));
1302 ret = sync_kloop_stop(ctx);
1307 ret = pthread_join(th, &thret);
1309 printf("pthread_join(kloop): %s\n", strerror(ret));
1312 return thret == THRET_SUCCESS ? 0 : -1;
1316 sync_kloop(struct TestContext *ctx)
1320 ret = csb_mode(ctx);
1325 return sync_kloop_start_stop(ctx);
1329 sync_kloop_eventfds(struct TestContext *ctx)
1331 struct nmreq_opt_sync_kloop_eventfds *opt = NULL;
1332 struct nmreq_option save;
1337 num_entries = num_registered_rings(ctx);
1338 opt_size = sizeof(*opt) + num_entries * sizeof(opt->eventfds[0]);
1339 opt = calloc(1, opt_size);
1340 opt->nro_opt.nro_next = 0;
1341 opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
1342 opt->nro_opt.nro_status = 0;
1343 opt->nro_opt.nro_size = opt_size;
1344 for (i = 0; i < num_entries; i++) {
1345 int efd = eventfd(0, 0);
1347 opt->eventfds[i].ioeventfd = efd;
1348 efd = eventfd(0, 0);
1349 opt->eventfds[i].irqfd = efd;
1352 push_option(&opt->nro_opt, ctx);
1353 save = opt->nro_opt;
1355 ret = sync_kloop_start_stop(ctx);
1362 save.nro_status = 0;
1363 #else /* !__linux__ */
1364 save.nro_status = EOPNOTSUPP;
1365 #endif /* !__linux__ */
1367 ret = checkoption(&opt->nro_opt, &save);
1375 sync_kloop_eventfds_all(struct TestContext *ctx)
1379 ret = csb_mode(ctx);
1384 return sync_kloop_eventfds(ctx);
1388 sync_kloop_eventfds_all_tx(struct TestContext *ctx)
1390 struct nmreq_opt_csb opt;
1393 ret = push_csb_option(ctx, &opt);
1398 ret = port_register_hwall_tx(ctx);
1404 return sync_kloop_eventfds(ctx);
1408 sync_kloop_nocsb(struct TestContext *ctx)
1412 ret = port_register_hwall(ctx);
1417 /* Sync kloop must fail because we did not use
1418 * NETMAP_REQ_CSB_ENABLE. */
1419 return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
1423 csb_enable(struct TestContext *ctx)
1425 struct nmreq_option saveopt;
1426 struct nmreq_opt_csb opt;
1427 struct nmreq_header hdr;
1430 ret = push_csb_option(ctx, &opt);
1434 saveopt = opt.nro_opt;
1435 saveopt.nro_status = 0;
1437 nmreq_hdr_init(&hdr, ctx->ifname_ext);
1438 hdr.nr_reqtype = NETMAP_REQ_CSB_ENABLE;
1439 hdr.nr_options = (uintptr_t)ctx->nr_opt;
1440 hdr.nr_body = (uintptr_t)NULL;
1442 printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname_ext);
1444 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1446 perror("ioctl(/dev/netmap, NIOCCTRL, CSB_ENABLE)");
1450 ret = checkoption(&opt.nro_opt, &saveopt);
1457 sync_kloop_csb_enable(struct TestContext *ctx)
1461 ctx->nr_flags |= NR_EXCLUSIVE;
1462 ret = port_register_hwall(ctx);
1467 ret = csb_enable(ctx);
1472 return sync_kloop_start_stop(ctx);
1476 sync_kloop_conflict(struct TestContext *ctx)
1478 struct nmreq_opt_csb opt;
1480 void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
1486 ret = push_csb_option(ctx, &opt);
1491 ret = port_register_hwall(ctx);
1497 ret = sem_init(&sem, 0, 0);
1499 printf("sem_init() failed: %s\n", strerror(ret));
1504 ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
1507 printf("pthread_create(kloop1): %s\n", strerror(ret));
1510 ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
1513 printf("pthread_create(kloop2): %s\n", strerror(ret));
1516 /* Wait for one of the two threads to fail to start the kloop, to
1517 * avoid a race condition where th1 starts the loop and stops,
1518 * and after that th2 starts the loop successfully. */
1519 clock_gettime(CLOCK_REALTIME, &to);
1521 ret = sem_timedwait(&sem, &to);
1524 printf("sem_timedwait() failed: %s\n", strerror(errno));
1527 err |= sync_kloop_stop(ctx);
1529 ret = pthread_join(th1, &thret1);
1532 printf("pthread_join(kloop1): %s\n", strerror(ret));
1535 ret = pthread_join(th2, &thret2);
1538 printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
1547 /* Check that one of the two failed, while the other one succeeded. */
1548 return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
1549 (thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
1555 sync_kloop_eventfds_mismatch(struct TestContext *ctx)
1557 struct nmreq_opt_csb opt;
1560 ret = push_csb_option(ctx, &opt);
1565 ret = port_register_hwall_rx(ctx);
1571 /* Deceive num_registered_rings() to trigger a failure of
1572 * sync_kloop_eventfds(). The latter will think that all the
1573 * rings were registered, and allocate the wrong number of
1575 ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
1577 return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
1581 null_port(struct TestContext *ctx)
1586 ctx->nr_mode = NR_REG_NULL;
1587 ctx->nr_tx_rings = 10;
1588 ctx->nr_rx_rings = 5;
1589 ctx->nr_tx_slots = 256;
1590 ctx->nr_rx_slots = 100;
1591 ret = port_register(ctx);
1599 null_port_all_zero(struct TestContext *ctx)
1604 ctx->nr_mode = NR_REG_NULL;
1605 ctx->nr_tx_rings = 0;
1606 ctx->nr_rx_rings = 0;
1607 ctx->nr_tx_slots = 0;
1608 ctx->nr_rx_slots = 0;
1609 ret = port_register(ctx);
1617 null_port_sync(struct TestContext *ctx)
1622 ctx->nr_mode = NR_REG_NULL;
1623 ctx->nr_tx_rings = 10;
1624 ctx->nr_rx_rings = 5;
1625 ctx->nr_tx_slots = 256;
1626 ctx->nr_rx_slots = 100;
1627 ret = port_register(ctx);
1631 ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
1639 usage(const char *prog)
1641 printf("%s -i IFNAME\n"
1642 "[-j TEST_NUM1[-[TEST_NUM2]] | -[TEST_NUM_2]]\n"
1643 "[-l (list test cases)]\n",
1652 #define decltest(f) \
1654 .test = f, .name = #f \
1657 static struct mytest tests[] = {
1658 decltest(port_info_get),
1659 decltest(port_register_hwall_host),
1660 decltest(port_register_hwall),
1661 decltest(port_register_host),
1662 decltest(port_register_single_ring_couple),
1663 decltest(vale_attach_detach),
1664 decltest(vale_attach_detach_host_rings),
1665 decltest(vale_ephemeral_port_hdr_manipulation),
1666 decltest(vale_persistent_port),
1667 decltest(pools_info_get_and_register),
1668 decltest(pools_info_get_empty_ifname),
1669 decltest(pipe_master),
1670 decltest(pipe_slave),
1671 decltest(pipe_port_info_get),
1672 decltest(pipe_pools_info_get),
1673 decltest(vale_polling_enable_disable),
1674 decltest(unsupported_option),
1675 decltest(infinite_options),
1676 #ifdef CONFIG_NETMAP_EXTMEM
1677 decltest(extmem_option),
1678 decltest(bad_extmem_option),
1679 decltest(duplicate_extmem_options),
1680 #endif /* CONFIG_NETMAP_EXTMEM */
1682 decltest(csb_mode_invalid_memory),
1683 decltest(sync_kloop),
1684 decltest(sync_kloop_eventfds_all),
1685 decltest(sync_kloop_eventfds_all_tx),
1686 decltest(sync_kloop_nocsb),
1687 decltest(sync_kloop_csb_enable),
1688 decltest(sync_kloop_conflict),
1689 decltest(sync_kloop_eventfds_mismatch),
1690 decltest(null_port),
1691 decltest(null_port_all_zero),
1692 decltest(null_port_sync),
1693 decltest(legacy_regif_default),
1694 decltest(legacy_regif_all_nic),
1695 decltest(legacy_regif_12),
1696 decltest(legacy_regif_sw),
1697 decltest(legacy_regif_future),
1698 decltest(legacy_regif_extra_bufs),
1699 decltest(legacy_regif_extra_bufs_pipe),
1700 decltest(legacy_regif_extra_bufs_pipe_vale),
1704 context_cleanup(struct TestContext *ctx)
1716 parse_interval(const char *arg, int *j, int *k)
1718 const char *scan = arg;
1727 if (!isdigit(*scan))
1729 *k = strtol(scan, &rest, 10);
1739 if (!isdigit(*scan))
1741 *k = strtol(scan, &rest, 10);
1743 if (!(*scan == '\0'))
1749 fprintf(stderr, "syntax error in '%s', must be num[-[num]] or -[num]\n", arg);
1753 #define ARGV_APPEND(_av, _ac, _x)\
1755 assert((int)(_ac) < (int)(sizeof(_av)/sizeof((_av)[0])));\
1756 (_av)[(_ac)++] = _x;\
1760 tap_cleanup(int signo)
1767 ARGV_APPEND(av, ac, "ifconfig");
1768 ARGV_APPEND(av, ac, ctx_.ifname);
1769 ARGV_APPEND(av, ac, "destroy");
1771 ARGV_APPEND(av, ac, "ip");
1772 ARGV_APPEND(av, ac, "link");
1773 ARGV_APPEND(av, ac, "del");
1774 ARGV_APPEND(av, ac, ctx_.ifname);
1776 ARGV_APPEND(av, ac, NULL);
1777 if (exec_command(ac, av)) {
1778 printf("Failed to destroy tap interface\n");
1783 main(int argc, char **argv)
1795 PLAIN_REQUIRE_KERNEL_MODULE("if_tap", 0);
1796 PLAIN_REQUIRE_KERNEL_MODULE("netmap", 0);
1799 memset(&ctx_, 0, sizeof(ctx_));
1805 clock_gettime(CLOCK_REALTIME, &t);
1806 srand((unsigned int)t.tv_nsec);
1807 idx = rand() % 8000 + 100;
1808 snprintf(ctx_.ifname, sizeof(ctx_.ifname), "tap%d", idx);
1809 idx = rand() % 800 + 100;
1810 snprintf(ctx_.bdgname, sizeof(ctx_.bdgname), "vale%d", idx);
1813 while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
1820 strncpy(ctx_.ifname, optarg, sizeof(ctx_.ifname) - 1);
1825 if (parse_interval(optarg, &j, &k) < 0) {
1837 printf(" Unrecognized option %c\n", opt);
1843 num_tests = sizeof(tests) / sizeof(tests[0]);
1845 if (j < 0 || j >= num_tests || k > num_tests) {
1846 fprintf(stderr, "Test interval %d-%d out of range (%d-%d)\n",
1847 j + 1, k, 1, num_tests + 1);
1855 printf("Available tests:\n");
1856 for (i = 0; i < num_tests; i++) {
1857 printf("#%03d: %s\n", i + 1, tests[i].name);
1863 struct sigaction sa;
1867 ARGV_APPEND(av, ac, "ifconfig");
1868 ARGV_APPEND(av, ac, ctx_.ifname);
1869 ARGV_APPEND(av, ac, "create");
1870 ARGV_APPEND(av, ac, "up");
1872 ARGV_APPEND(av, ac, "ip");
1873 ARGV_APPEND(av, ac, "tuntap");
1874 ARGV_APPEND(av, ac, "add");
1875 ARGV_APPEND(av, ac, "mode");
1876 ARGV_APPEND(av, ac, "tap");
1877 ARGV_APPEND(av, ac, "name");
1878 ARGV_APPEND(av, ac, ctx_.ifname);
1880 ARGV_APPEND(av, ac, NULL);
1881 if (exec_command(ac, av)) {
1882 printf("Failed to create tap interface\n");
1886 sa.sa_handler = tap_cleanup;
1887 sigemptyset(&sa.sa_mask);
1888 sa.sa_flags = SA_RESTART;
1889 ret = sigaction(SIGINT, &sa, NULL);
1891 perror("sigaction(SIGINT)");
1894 ret = sigaction(SIGTERM, &sa, NULL);
1896 perror("sigaction(SIGTERM)");
1901 for (i = j; i < k; i++) {
1902 struct TestContext ctxcopy;
1904 printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
1905 fd = open("/dev/netmap", O_RDWR);
1907 perror("open(/dev/netmap)");
1911 memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
1913 memcpy(ctxcopy.ifname_ext, ctxcopy.ifname,
1914 sizeof(ctxcopy.ifname));
1915 ret = tests[i].test(&ctxcopy);
1917 printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
1920 printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
1921 context_cleanup(&ctxcopy);