1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2017 6WIND S.A. 3 * Copyright 2017 Mellanox Technologies, Ltd. 4 */ 5 6 #include <errno.h> 7 #include <fcntl.h> 8 #include <inttypes.h> 9 #include <linux/sockios.h> 10 #include <net/if.h> 11 #include <net/if_arp.h> 12 #include <netinet/ip.h> 13 #include <stdarg.h> 14 #include <stddef.h> 15 #include <stdlib.h> 16 #include <stdint.h> 17 #include <stdio.h> 18 #include <string.h> 19 #include <sys/ioctl.h> 20 #include <sys/queue.h> 21 #include <sys/socket.h> 22 #include <unistd.h> 23 24 #include <rte_alarm.h> 25 #include <rte_bus.h> 26 #include <rte_bus_vdev.h> 27 #include <rte_common.h> 28 #include <rte_config.h> 29 #include <rte_dev.h> 30 #include <rte_errno.h> 31 #include <rte_ethdev.h> 32 #include <rte_ether.h> 33 #include <rte_hypervisor.h> 34 #include <rte_kvargs.h> 35 #include <rte_log.h> 36 37 #define VDEV_NETVSC_DRIVER net_vdev_netvsc 38 #define VDEV_NETVSC_DRIVER_NAME RTE_STR(VDEV_NETVSC_DRIVER) 39 #define VDEV_NETVSC_ARG_IFACE "iface" 40 #define VDEV_NETVSC_ARG_MAC "mac" 41 #define VDEV_NETVSC_ARG_FORCE "force" 42 #define VDEV_NETVSC_ARG_IGNORE "ignore" 43 #define VDEV_NETVSC_PROBE_MS 1000 44 45 #define NETVSC_CLASS_ID "{f8615163-df3e-46c5-913f-f2d2f965ed0e}" 46 #define NETVSC_MAX_ROUTE_LINE_SIZE 300 47 48 #define DRV_LOG(level, ...) \ 49 rte_log(RTE_LOG_ ## level, \ 50 vdev_netvsc_logtype, \ 51 RTE_FMT(VDEV_NETVSC_DRIVER_NAME ": " \ 52 RTE_FMT_HEAD(__VA_ARGS__,) "\n", \ 53 RTE_FMT_TAIL(__VA_ARGS__,))) 54 55 /** Driver-specific log messages type. */ 56 static int vdev_netvsc_logtype; 57 58 /** Context structure for a vdev_netvsc instance. */ 59 struct vdev_netvsc_ctx { 60 LIST_ENTRY(vdev_netvsc_ctx) entry; /**< Next entry in list. */ 61 unsigned int id; /**< Unique ID. */ 62 char name[64]; /**< Unique name. */ 63 char devname[64]; /**< Fail-safe instance name. */ 64 char devargs[256]; /**< Fail-safe device arguments. */ 65 char if_name[IF_NAMESIZE]; /**< NetVSC netdevice name. */ 66 unsigned int if_index; /**< NetVSC netdevice index. */ 67 struct ether_addr if_addr; /**< NetVSC MAC address. */ 68 int pipe[2]; /**< Fail-safe communication pipe. */ 69 char yield[256]; /**< PCI sub-device arguments. */ 70 }; 71 72 /** Context list is common to all driver instances. */ 73 static LIST_HEAD(, vdev_netvsc_ctx) vdev_netvsc_ctx_list = 74 LIST_HEAD_INITIALIZER(vdev_netvsc_ctx_list); 75 76 /** Number of entries in context list. */ 77 static unsigned int vdev_netvsc_ctx_count; 78 79 /** Number of driver instances relying on context list. */ 80 static unsigned int vdev_netvsc_ctx_inst; 81 82 /** 83 * Destroy a vdev_netvsc context instance. 84 * 85 * @param ctx 86 * Context to destroy. 87 */ 88 static void 89 vdev_netvsc_ctx_destroy(struct vdev_netvsc_ctx *ctx) 90 { 91 if (ctx->pipe[0] != -1) 92 close(ctx->pipe[0]); 93 if (ctx->pipe[1] != -1) 94 close(ctx->pipe[1]); 95 free(ctx); 96 } 97 98 /** 99 * Iterate over system network interfaces. 100 * 101 * This function runs a given callback function for each netdevice found on 102 * the system. 103 * 104 * @param func 105 * Callback function pointer. List traversal is aborted when this function 106 * returns a nonzero value. 107 * @param ... 108 * Variable parameter list passed as @p va_list to @p func. 109 * 110 * @return 111 * 0 when the entire list is traversed successfully, a negative error code 112 * in case or failure, or the nonzero value returned by @p func when list 113 * traversal is aborted. 114 */ 115 static int 116 vdev_netvsc_foreach_iface(int (*func)(const struct if_nameindex *iface, 117 const struct ether_addr *eth_addr, 118 va_list ap), ...) 119 { 120 struct if_nameindex *iface = if_nameindex(); 121 int s = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); 122 unsigned int i; 123 int ret = 0; 124 125 if (!iface) { 126 ret = -ENOBUFS; 127 DRV_LOG(ERR, "cannot retrieve system network interfaces"); 128 goto error; 129 } 130 if (s == -1) { 131 ret = -errno; 132 DRV_LOG(ERR, "cannot open socket: %s", rte_strerror(errno)); 133 goto error; 134 } 135 for (i = 0; iface[i].if_name; ++i) { 136 struct ifreq req; 137 struct ether_addr eth_addr; 138 va_list ap; 139 140 strncpy(req.ifr_name, iface[i].if_name, sizeof(req.ifr_name)); 141 if (ioctl(s, SIOCGIFHWADDR, &req) == -1) { 142 DRV_LOG(WARNING, "cannot retrieve information about" 143 " interface \"%s\": %s", 144 req.ifr_name, rte_strerror(errno)); 145 continue; 146 } 147 if (req.ifr_hwaddr.sa_family != ARPHRD_ETHER) { 148 DRV_LOG(DEBUG, "interface %s is non-ethernet device", 149 req.ifr_name); 150 continue; 151 } 152 memcpy(eth_addr.addr_bytes, req.ifr_hwaddr.sa_data, 153 RTE_DIM(eth_addr.addr_bytes)); 154 va_start(ap, func); 155 ret = func(&iface[i], ð_addr, ap); 156 va_end(ap); 157 if (ret) 158 break; 159 } 160 error: 161 if (s != -1) 162 close(s); 163 if (iface) 164 if_freenameindex(iface); 165 return ret; 166 } 167 168 /** 169 * Determine if a network interface is NetVSC. 170 * 171 * @param[in] iface 172 * Pointer to netdevice description structure (name and index). 173 * 174 * @return 175 * A nonzero value when interface is detected as NetVSC. In case of error, 176 * rte_errno is updated and 0 returned. 177 */ 178 static int 179 vdev_netvsc_iface_is_netvsc(const struct if_nameindex *iface) 180 { 181 static const char temp[] = "/sys/class/net/%s/device/class_id"; 182 char path[sizeof(temp) + IF_NAMESIZE]; 183 FILE *f; 184 int ret; 185 int len = 0; 186 187 ret = snprintf(path, sizeof(path), temp, iface->if_name); 188 if (ret == -1 || (size_t)ret >= sizeof(path)) { 189 rte_errno = ENOBUFS; 190 return 0; 191 } 192 f = fopen(path, "r"); 193 if (!f) { 194 rte_errno = errno; 195 return 0; 196 } 197 ret = fscanf(f, NETVSC_CLASS_ID "%n", &len); 198 if (ret == EOF) 199 rte_errno = errno; 200 ret = len == (int)strlen(NETVSC_CLASS_ID); 201 fclose(f); 202 return ret; 203 } 204 205 /** 206 * Determine if a network interface has a route. 207 * 208 * @param[in] name 209 * Network device name. 210 * 211 * @return 212 * A nonzero value when interface has an route. In case of error, 213 * rte_errno is updated and 0 returned. 214 */ 215 static int 216 vdev_netvsc_has_route(const char *name) 217 { 218 FILE *fp; 219 int ret = 0; 220 char route[NETVSC_MAX_ROUTE_LINE_SIZE]; 221 char *netdev; 222 223 fp = fopen("/proc/net/route", "r"); 224 if (!fp) { 225 rte_errno = errno; 226 return 0; 227 } 228 while (fgets(route, NETVSC_MAX_ROUTE_LINE_SIZE, fp) != NULL) { 229 netdev = strtok(route, "\t"); 230 if (strcmp(netdev, name) == 0) { 231 ret = 1; 232 break; 233 } 234 /* Move file pointer to the next line. */ 235 while (strchr(route, '\n') == NULL && 236 fgets(route, NETVSC_MAX_ROUTE_LINE_SIZE, fp) != NULL) 237 ; 238 } 239 fclose(fp); 240 return ret; 241 } 242 243 /** 244 * Retrieve network interface data from sysfs symbolic link. 245 * 246 * @param[out] buf 247 * Output data buffer. 248 * @param size 249 * Output buffer size. 250 * @param[in] if_name 251 * Netdevice name. 252 * @param[in] relpath 253 * Symbolic link path relative to netdevice sysfs entry. 254 * 255 * @return 256 * 0 on success, a negative error code otherwise. 257 */ 258 static int 259 vdev_netvsc_sysfs_readlink(char *buf, size_t size, const char *if_name, 260 const char *relpath) 261 { 262 int ret; 263 264 ret = snprintf(buf, size, "/sys/class/net/%s/%s", if_name, relpath); 265 if (ret == -1 || (size_t)ret >= size) 266 return -ENOBUFS; 267 ret = readlink(buf, buf, size); 268 if (ret == -1) 269 return -errno; 270 if ((size_t)ret >= size - 1) 271 return -ENOBUFS; 272 buf[ret] = '\0'; 273 return 0; 274 } 275 276 /** 277 * Probe a network interface to associate with vdev_netvsc context. 278 * 279 * This function determines if the network device matches the properties of 280 * the NetVSC interface associated with the vdev_netvsc context and 281 * communicates its bus address to the fail-safe PMD instance if so. 282 * 283 * It is normally used with vdev_netvsc_foreach_iface(). 284 * 285 * @param[in] iface 286 * Pointer to netdevice description structure (name and index). 287 * @param[in] eth_addr 288 * MAC address associated with @p iface. 289 * @param ap 290 * Variable arguments list comprising: 291 * 292 * - struct vdev_netvsc_ctx *ctx: 293 * Context to associate network interface with. 294 * 295 * @return 296 * A nonzero value when interface matches, 0 otherwise or in case of 297 * error. 298 */ 299 static int 300 vdev_netvsc_device_probe(const struct if_nameindex *iface, 301 const struct ether_addr *eth_addr, 302 va_list ap) 303 { 304 struct vdev_netvsc_ctx *ctx = va_arg(ap, struct vdev_netvsc_ctx *); 305 char buf[RTE_MAX(sizeof(ctx->yield), 256u)]; 306 const char *addr; 307 size_t len; 308 int ret; 309 310 /* Skip non-matching or unwanted NetVSC interfaces. */ 311 if (ctx->if_index == iface->if_index) { 312 if (!strcmp(ctx->if_name, iface->if_name)) 313 return 0; 314 DRV_LOG(DEBUG, 315 "NetVSC interface \"%s\" (index %u) renamed \"%s\"", 316 ctx->if_name, ctx->if_index, iface->if_name); 317 strncpy(ctx->if_name, iface->if_name, sizeof(ctx->if_name)); 318 return 0; 319 } 320 if (vdev_netvsc_iface_is_netvsc(iface)) 321 return 0; 322 if (!is_same_ether_addr(eth_addr, &ctx->if_addr)) 323 return 0; 324 /* Look for associated PCI device. */ 325 ret = vdev_netvsc_sysfs_readlink(buf, sizeof(buf), iface->if_name, 326 "device/subsystem"); 327 if (ret) 328 return 0; 329 addr = strrchr(buf, '/'); 330 addr = addr ? addr + 1 : buf; 331 if (strcmp(addr, "pci")) 332 return 0; 333 ret = vdev_netvsc_sysfs_readlink(buf, sizeof(buf), iface->if_name, 334 "device"); 335 if (ret) 336 return 0; 337 addr = strrchr(buf, '/'); 338 addr = addr ? addr + 1 : buf; 339 len = strlen(addr); 340 if (!len) 341 return 0; 342 /* Send PCI device argument to fail-safe PMD instance. */ 343 if (strcmp(addr, ctx->yield)) 344 DRV_LOG(DEBUG, "associating PCI device \"%s\" with NetVSC" 345 " interface \"%s\" (index %u)", addr, ctx->if_name, 346 ctx->if_index); 347 memmove(buf, addr, len + 1); 348 addr = buf; 349 buf[len] = '\n'; 350 ret = write(ctx->pipe[1], addr, len + 1); 351 buf[len] = '\0'; 352 if (ret == -1) { 353 if (errno == EINTR || errno == EAGAIN) 354 return 1; 355 DRV_LOG(WARNING, "cannot associate PCI device name \"%s\" with" 356 " interface \"%s\": %s", addr, ctx->if_name, 357 rte_strerror(errno)); 358 return 1; 359 } 360 if ((size_t)ret != len + 1) { 361 /* 362 * Attempt to override previous partial write, no need to 363 * recover if that fails. 364 */ 365 ret = write(ctx->pipe[1], "\n", 1); 366 (void)ret; 367 return 1; 368 } 369 fsync(ctx->pipe[1]); 370 memcpy(ctx->yield, addr, len + 1); 371 return 1; 372 } 373 374 /** 375 * Alarm callback that regularly probes system network interfaces. 376 * 377 * This callback runs at a frequency determined by VDEV_NETVSC_PROBE_MS as 378 * long as an vdev_netvsc context instance exists. 379 * 380 * @param arg 381 * Ignored. 382 */ 383 static void 384 vdev_netvsc_alarm(__rte_unused void *arg) 385 { 386 struct vdev_netvsc_ctx *ctx; 387 int ret; 388 389 LIST_FOREACH(ctx, &vdev_netvsc_ctx_list, entry) { 390 ret = vdev_netvsc_foreach_iface(vdev_netvsc_device_probe, ctx); 391 if (ret) 392 break; 393 } 394 if (!vdev_netvsc_ctx_count) 395 return; 396 ret = rte_eal_alarm_set(VDEV_NETVSC_PROBE_MS * 1000, 397 vdev_netvsc_alarm, NULL); 398 if (ret < 0) { 399 DRV_LOG(ERR, "unable to reschedule alarm callback: %s", 400 rte_strerror(-ret)); 401 } 402 } 403 404 /** 405 * Probe a NetVSC interface to generate a vdev_netvsc context from. 406 * 407 * This function instantiates vdev_netvsc contexts either for all NetVSC 408 * devices found on the system or only a subset provided as device 409 * arguments. 410 * 411 * It is normally used with vdev_netvsc_foreach_iface(). 412 * 413 * @param[in] iface 414 * Pointer to netdevice description structure (name and index). 415 * @param[in] eth_addr 416 * MAC address associated with @p iface. 417 * @param ap 418 * Variable arguments list comprising: 419 * 420 * - const char *name: 421 * Name associated with current driver instance. 422 * 423 * - struct rte_kvargs *kvargs: 424 * Device arguments provided to current driver instance. 425 * 426 * - int force: 427 * Accept specified interface even if not detected as NetVSC. 428 * 429 * - unsigned int specified: 430 * Number of specific netdevices provided as device arguments. 431 * 432 * - unsigned int *matched: 433 * The number of specified netdevices matched by this function. 434 * 435 * @return 436 * A nonzero value when interface matches, 0 otherwise or in case of 437 * error. 438 */ 439 static int 440 vdev_netvsc_netvsc_probe(const struct if_nameindex *iface, 441 const struct ether_addr *eth_addr, 442 va_list ap) 443 { 444 const char *name = va_arg(ap, const char *); 445 struct rte_kvargs *kvargs = va_arg(ap, struct rte_kvargs *); 446 int force = va_arg(ap, int); 447 unsigned int specified = va_arg(ap, unsigned int); 448 unsigned int *matched = va_arg(ap, unsigned int *); 449 unsigned int i; 450 struct vdev_netvsc_ctx *ctx; 451 int ret; 452 453 /* Probe all interfaces when none are specified. */ 454 if (specified) { 455 for (i = 0; i != kvargs->count; ++i) { 456 const struct rte_kvargs_pair *pair = &kvargs->pairs[i]; 457 458 if (!strcmp(pair->key, VDEV_NETVSC_ARG_IFACE)) { 459 if (!strcmp(pair->value, iface->if_name)) 460 break; 461 } else if (!strcmp(pair->key, VDEV_NETVSC_ARG_MAC)) { 462 struct ether_addr tmp; 463 464 if (sscanf(pair->value, 465 "%" SCNx8 ":%" SCNx8 ":%" SCNx8 ":" 466 "%" SCNx8 ":%" SCNx8 ":%" SCNx8, 467 &tmp.addr_bytes[0], 468 &tmp.addr_bytes[1], 469 &tmp.addr_bytes[2], 470 &tmp.addr_bytes[3], 471 &tmp.addr_bytes[4], 472 &tmp.addr_bytes[5]) != 6) { 473 DRV_LOG(ERR, 474 "invalid MAC address format" 475 " \"%s\"", 476 pair->value); 477 return -EINVAL; 478 } 479 if (is_same_ether_addr(eth_addr, &tmp)) 480 break; 481 } 482 } 483 if (i == kvargs->count) 484 return 0; 485 ++(*matched); 486 } 487 /* Weed out interfaces already handled. */ 488 LIST_FOREACH(ctx, &vdev_netvsc_ctx_list, entry) 489 if (ctx->if_index == iface->if_index) 490 break; 491 if (ctx) { 492 if (!specified) 493 return 0; 494 DRV_LOG(WARNING, 495 "interface \"%s\" (index %u) is already handled," 496 " skipping", 497 iface->if_name, iface->if_index); 498 return 0; 499 } 500 if (!vdev_netvsc_iface_is_netvsc(iface)) { 501 if (!specified || !force) 502 return 0; 503 DRV_LOG(WARNING, 504 "using non-NetVSC interface \"%s\" (index %u)", 505 iface->if_name, iface->if_index); 506 } 507 /* Routed NetVSC should not be probed. */ 508 if (vdev_netvsc_has_route(iface->if_name)) { 509 if (!specified || !force) 510 return 0; 511 DRV_LOG(WARNING, "using routed NetVSC interface \"%s\"" 512 " (index %u)", iface->if_name, iface->if_index); 513 } 514 /* Create interface context. */ 515 ctx = calloc(1, sizeof(*ctx)); 516 if (!ctx) { 517 ret = -errno; 518 DRV_LOG(ERR, "cannot allocate context for interface \"%s\": %s", 519 iface->if_name, rte_strerror(errno)); 520 goto error; 521 } 522 ctx->id = vdev_netvsc_ctx_count; 523 strncpy(ctx->if_name, iface->if_name, sizeof(ctx->if_name)); 524 ctx->if_index = iface->if_index; 525 ctx->if_addr = *eth_addr; 526 ctx->pipe[0] = -1; 527 ctx->pipe[1] = -1; 528 ctx->yield[0] = '\0'; 529 if (pipe(ctx->pipe) == -1) { 530 ret = -errno; 531 DRV_LOG(ERR, 532 "cannot allocate control pipe for interface \"%s\": %s", 533 ctx->if_name, rte_strerror(errno)); 534 goto error; 535 } 536 for (i = 0; i != RTE_DIM(ctx->pipe); ++i) { 537 int flf = fcntl(ctx->pipe[i], F_GETFL); 538 539 if (flf != -1 && 540 fcntl(ctx->pipe[i], F_SETFL, flf | O_NONBLOCK) != -1) 541 continue; 542 ret = -errno; 543 DRV_LOG(ERR, "cannot toggle non-blocking flag on control file" 544 " descriptor #%u (%d): %s", i, ctx->pipe[i], 545 rte_strerror(errno)); 546 goto error; 547 } 548 /* Generate virtual device name and arguments. */ 549 i = 0; 550 ret = snprintf(ctx->name, sizeof(ctx->name), "%s_id%u", 551 name, ctx->id); 552 if (ret == -1 || (size_t)ret >= sizeof(ctx->name)) 553 ++i; 554 ret = snprintf(ctx->devname, sizeof(ctx->devname), "net_failsafe_%s", 555 ctx->name); 556 if (ret == -1 || (size_t)ret >= sizeof(ctx->devname)) 557 ++i; 558 ret = snprintf(ctx->devargs, sizeof(ctx->devargs), 559 "fd(%d),dev(net_tap_%s,remote=%s)", 560 ctx->pipe[0], ctx->name, ctx->if_name); 561 if (ret == -1 || (size_t)ret >= sizeof(ctx->devargs)) 562 ++i; 563 if (i) { 564 ret = -ENOBUFS; 565 DRV_LOG(ERR, "generated virtual device name or argument list" 566 " too long for interface \"%s\"", ctx->if_name); 567 goto error; 568 } 569 /* Request virtual device generation. */ 570 DRV_LOG(DEBUG, "generating virtual device \"%s\" with arguments \"%s\"", 571 ctx->devname, ctx->devargs); 572 vdev_netvsc_foreach_iface(vdev_netvsc_device_probe, ctx); 573 ret = rte_eal_hotplug_add("vdev", ctx->devname, ctx->devargs); 574 if (ret) 575 goto error; 576 LIST_INSERT_HEAD(&vdev_netvsc_ctx_list, ctx, entry); 577 ++vdev_netvsc_ctx_count; 578 DRV_LOG(DEBUG, "added NetVSC interface \"%s\" to context list", 579 ctx->if_name); 580 return 0; 581 error: 582 if (ctx) 583 vdev_netvsc_ctx_destroy(ctx); 584 return ret; 585 } 586 587 /** 588 * Probe NetVSC interfaces. 589 * 590 * This function probes system netdevices according to the specified device 591 * arguments and starts a periodic alarm callback to notify the resulting 592 * fail-safe PMD instances of their sub-devices whereabouts. 593 * 594 * @param dev 595 * Virtual device context for driver instance. 596 * 597 * @return 598 * Always 0, even in case of errors. 599 */ 600 static int 601 vdev_netvsc_vdev_probe(struct rte_vdev_device *dev) 602 { 603 static const char *const vdev_netvsc_arg[] = { 604 VDEV_NETVSC_ARG_IFACE, 605 VDEV_NETVSC_ARG_MAC, 606 VDEV_NETVSC_ARG_FORCE, 607 VDEV_NETVSC_ARG_IGNORE, 608 NULL, 609 }; 610 const char *name = rte_vdev_device_name(dev); 611 const char *args = rte_vdev_device_args(dev); 612 struct rte_kvargs *kvargs = rte_kvargs_parse(args ? args : "", 613 vdev_netvsc_arg); 614 unsigned int specified = 0; 615 unsigned int matched = 0; 616 int force = 0; 617 int ignore = 0; 618 unsigned int i; 619 int ret; 620 621 DRV_LOG(DEBUG, "invoked as \"%s\", using arguments \"%s\"", name, args); 622 if (!kvargs) { 623 DRV_LOG(ERR, "cannot parse arguments list"); 624 goto error; 625 } 626 for (i = 0; i != kvargs->count; ++i) { 627 const struct rte_kvargs_pair *pair = &kvargs->pairs[i]; 628 629 if (!strcmp(pair->key, VDEV_NETVSC_ARG_FORCE)) 630 force = !!atoi(pair->value); 631 else if (!strcmp(pair->key, VDEV_NETVSC_ARG_IGNORE)) 632 ignore = !!atoi(pair->value); 633 else if (!strcmp(pair->key, VDEV_NETVSC_ARG_IFACE) || 634 !strcmp(pair->key, VDEV_NETVSC_ARG_MAC)) 635 ++specified; 636 } 637 if (ignore) { 638 if (kvargs) 639 rte_kvargs_free(kvargs); 640 return 0; 641 } 642 rte_eal_alarm_cancel(vdev_netvsc_alarm, NULL); 643 /* Gather interfaces. */ 644 ret = vdev_netvsc_foreach_iface(vdev_netvsc_netvsc_probe, name, kvargs, 645 force, specified, &matched); 646 if (ret < 0) 647 goto error; 648 if (matched < specified) 649 DRV_LOG(WARNING, 650 "some of the specified parameters did not match" 651 " recognized network interfaces"); 652 ret = rte_eal_alarm_set(VDEV_NETVSC_PROBE_MS * 1000, 653 vdev_netvsc_alarm, NULL); 654 if (ret < 0) { 655 DRV_LOG(ERR, "unable to schedule alarm callback: %s", 656 rte_strerror(-ret)); 657 goto error; 658 } 659 error: 660 if (kvargs) 661 rte_kvargs_free(kvargs); 662 ++vdev_netvsc_ctx_inst; 663 return 0; 664 } 665 666 /** 667 * Remove driver instance. 668 * 669 * The alarm callback and underlying vdev_netvsc context instances are only 670 * destroyed after the last PMD instance is removed. 671 * 672 * @param dev 673 * Virtual device context for driver instance. 674 * 675 * @return 676 * Always 0. 677 */ 678 static int 679 vdev_netvsc_vdev_remove(__rte_unused struct rte_vdev_device *dev) 680 { 681 if (--vdev_netvsc_ctx_inst) 682 return 0; 683 rte_eal_alarm_cancel(vdev_netvsc_alarm, NULL); 684 while (!LIST_EMPTY(&vdev_netvsc_ctx_list)) { 685 struct vdev_netvsc_ctx *ctx = LIST_FIRST(&vdev_netvsc_ctx_list); 686 687 LIST_REMOVE(ctx, entry); 688 --vdev_netvsc_ctx_count; 689 vdev_netvsc_ctx_destroy(ctx); 690 } 691 return 0; 692 } 693 694 /** Virtual device descriptor. */ 695 static struct rte_vdev_driver vdev_netvsc_vdev = { 696 .probe = vdev_netvsc_vdev_probe, 697 .remove = vdev_netvsc_vdev_remove, 698 }; 699 700 RTE_PMD_REGISTER_VDEV(VDEV_NETVSC_DRIVER, vdev_netvsc_vdev); 701 RTE_PMD_REGISTER_ALIAS(VDEV_NETVSC_DRIVER, eth_vdev_netvsc); 702 RTE_PMD_REGISTER_PARAM_STRING(net_vdev_netvsc, 703 VDEV_NETVSC_ARG_IFACE "=<string> " 704 VDEV_NETVSC_ARG_MAC "=<string> " 705 VDEV_NETVSC_ARG_FORCE "=<int> " 706 VDEV_NETVSC_ARG_IGNORE "=<int>"); 707 708 /** Initialize driver log type. */ 709 RTE_INIT(vdev_netvsc_init_log) 710 { 711 vdev_netvsc_logtype = rte_log_register("pmd.vdev_netvsc"); 712 if (vdev_netvsc_logtype >= 0) 713 rte_log_set_level(vdev_netvsc_logtype, RTE_LOG_NOTICE); 714 } 715 716 /** Compare function for vdev find device operation. */ 717 static int 718 vdev_netvsc_cmp_rte_device(const struct rte_device *dev1, 719 __rte_unused const void *_dev2) 720 { 721 return strcmp(dev1->devargs->name, VDEV_NETVSC_DRIVER_NAME); 722 } 723 724 /** 725 * A callback called by vdev bus scan function to ensure this driver probing 726 * automatically in Hyper-V VM system unless it already exists in the 727 * devargs list. 728 */ 729 static void 730 vdev_netvsc_scan_callback(__rte_unused void *arg) 731 { 732 struct rte_vdev_device *dev; 733 struct rte_devargs *devargs; 734 struct rte_bus *vbus = rte_bus_find_by_name("vdev"); 735 736 TAILQ_FOREACH(devargs, &devargs_list, next) 737 if (!strcmp(devargs->name, VDEV_NETVSC_DRIVER_NAME)) 738 return; 739 dev = (struct rte_vdev_device *)vbus->find_device(NULL, 740 vdev_netvsc_cmp_rte_device, VDEV_NETVSC_DRIVER_NAME); 741 if (dev) 742 return; 743 if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, VDEV_NETVSC_DRIVER_NAME)) 744 DRV_LOG(ERR, "unable to add netvsc devargs."); 745 } 746 747 /** Initialize the custom scan. */ 748 RTE_INIT(vdev_netvsc_custom_scan_add) 749 { 750 if (rte_hypervisor_get() == RTE_HYPERVISOR_HYPERV) 751 rte_vdev_add_custom_scan(vdev_netvsc_scan_callback, NULL); 752 } 753