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