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