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