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