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