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