1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2017 6WIND S.A.
3 * Copyright 2017 Mellanox Technologies, Ltd
9 #include <linux/sockios.h>
10 #include <linux/netlink.h>
11 #include <linux/rtnetlink.h>
13 #include <net/if_arp.h>
14 #include <netinet/ip.h>
21 #include <sys/ioctl.h>
22 #include <sys/queue.h>
23 #include <sys/socket.h>
26 #include <rte_alarm.h>
28 #include <rte_bus_vdev.h>
29 #include <rte_common.h>
30 #include <rte_config.h>
32 #include <rte_errno.h>
33 #include <rte_ethdev.h>
34 #include <rte_ether.h>
35 #include <rte_hypervisor.h>
36 #include <rte_kvargs.h>
38 #include <rte_string_fns.h>
40 #define VDEV_NETVSC_DRIVER net_vdev_netvsc
41 #define VDEV_NETVSC_DRIVER_NAME RTE_STR(VDEV_NETVSC_DRIVER)
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
48 #define NETVSC_CLASS_ID "{f8615163-df3e-46c5-913f-f2d2f965ed0e}"
49 #define NETVSC_MAX_ROUTE_LINE_SIZE 300
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__,)))
58 /** Driver-specific log messages type. */
59 static int vdev_netvsc_logtype;
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 ether_addr if_addr; /**< NetVSC MAC address. */
71 int pipe[2]; /**< Fail-safe communication pipe. */
72 char yield[256]; /**< PCI sub-device arguments. */
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);
79 /** Number of entries in context list. */
80 static unsigned int vdev_netvsc_ctx_count;
82 /** Number of driver instances relying on context list. */
83 static unsigned int vdev_netvsc_ctx_inst;
86 * Destroy a vdev_netvsc context instance.
92 vdev_netvsc_ctx_destroy(struct vdev_netvsc_ctx *ctx)
94 if (ctx->pipe[0] != -1)
96 if (ctx->pipe[1] != -1)
102 * Determine if a network interface is NetVSC.
105 * Pointer to netdevice description structure (name and index).
108 * A nonzero value when interface is detected as NetVSC. In case of error,
109 * rte_errno is updated and 0 returned.
112 vdev_netvsc_iface_is_netvsc(const struct if_nameindex *iface)
114 static const char temp[] = "/sys/class/net/%s/device/class_id";
115 char path[sizeof(temp) + IF_NAMESIZE];
120 ret = snprintf(path, sizeof(path), temp, iface->if_name);
121 if (ret == -1 || (size_t)ret >= sizeof(path)) {
125 f = fopen(path, "r");
130 ret = fscanf(f, NETVSC_CLASS_ID "%n", &len);
133 ret = len == (int)strlen(NETVSC_CLASS_ID);
139 * Iterate over system network interfaces.
141 * This function runs a given callback function for each netdevice found on
145 * Callback function pointer. List traversal is aborted when this function
146 * returns a nonzero value.
148 * Indicates the device type to iterate - netvsc or non-netvsc.
150 * Variable parameter list passed as @p va_list to @p func.
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.
158 vdev_netvsc_foreach_iface(int (*func)(const struct if_nameindex *iface,
159 const struct ether_addr *eth_addr,
160 va_list ap), int is_netvsc, ...)
162 struct if_nameindex *iface = if_nameindex();
163 int s = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
169 DRV_LOG(ERR, "cannot retrieve system network interfaces");
174 DRV_LOG(ERR, "cannot open socket: %s", rte_strerror(errno));
177 for (i = 0; iface[i].if_name; ++i) {
180 struct ether_addr eth_addr;
183 is_netvsc_ret = vdev_netvsc_iface_is_netvsc(&iface[i]) ? 1 : 0;
184 if (is_netvsc ^ is_netvsc_ret)
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));
193 if (req.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
194 DRV_LOG(DEBUG, "interface %s is non-ethernet device",
198 memcpy(eth_addr.addr_bytes, req.ifr_hwaddr.sa_data,
199 RTE_DIM(eth_addr.addr_bytes));
200 va_start(ap, is_netvsc);
201 ret = func(&iface[i], ð_addr, ap);
210 if_freenameindex(iface);
215 * Determine if a network interface has a route.
218 * Network device name.
220 * Address family: AF_INET for IPv4 or AF_INET6 for IPv6.
223 * 1 when interface has a route, negative errno value in case of error and
227 vdev_netvsc_has_route(const struct if_nameindex *iface,
228 const unsigned char family)
231 * The implementation can be simpler by getifaddrs() function usage but
232 * it works for IPv6 only starting from glibc 2.3.3.
239 struct nlmsghdr *retmsg = (struct nlmsghdr *)buf;
240 struct sockaddr_nl sa;
242 struct nlmsghdr nlhdr;
243 struct ifaddrmsg addrmsg;
246 if (!iface || (family != AF_INET && family != AF_INET6)) {
247 DRV_LOG(ERR, "%s", rte_strerror(EINVAL));
250 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
252 DRV_LOG(ERR, "cannot open socket: %s", rte_strerror(errno));
255 memset(&sa, 0, sizeof(sa));
256 sa.nl_family = AF_NETLINK;
257 sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
258 res = bind(sock, (struct sockaddr *)&sa, sizeof(sa));
261 DRV_LOG(ERR, "cannot bind socket: %s", rte_strerror(errno));
264 memset(&msg, 0, sizeof(msg));
265 msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
266 msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
267 msg.nlhdr.nlmsg_type = RTM_GETADDR;
268 msg.nlhdr.nlmsg_pid = getpid();
269 msg.addrmsg.ifa_family = family;
270 msg.addrmsg.ifa_index = iface->if_index;
271 res = send(sock, &msg, msg.nlhdr.nlmsg_len, 0);
274 DRV_LOG(ERR, "cannot send socket message: %s",
275 rte_strerror(errno));
278 memset(buf, 0, sizeof(buf));
279 len = recv(sock, buf, sizeof(buf), 0);
282 DRV_LOG(ERR, "cannot receive socket message: %s",
283 rte_strerror(errno));
286 while (NLMSG_OK(retmsg, (unsigned int)len)) {
287 struct ifaddrmsg *retaddr =
288 (struct ifaddrmsg *)NLMSG_DATA(retmsg);
290 if (retaddr->ifa_family == family &&
291 retaddr->ifa_index == iface->if_index) {
292 struct rtattr *retrta = IFA_RTA(retaddr);
293 int attlen = IFA_PAYLOAD(retmsg);
295 while (RTA_OK(retrta, attlen)) {
296 if (retrta->rta_type == IFA_ADDRESS) {
298 DRV_LOG(DEBUG, "interface %s has IP",
302 retrta = RTA_NEXT(retrta, attlen);
305 retmsg = NLMSG_NEXT(retmsg, len);
313 * Retrieve network interface data from sysfs symbolic link.
316 * Output data buffer.
318 * Output buffer size.
322 * Symbolic link path relative to netdevice sysfs entry.
325 * 0 on success, a negative error code otherwise.
328 vdev_netvsc_sysfs_readlink(char *buf, size_t size, const char *if_name,
331 struct vdev_netvsc_ctx *ctx;
332 char in[RTE_MAX(sizeof(ctx->yield), 256u)];
335 ret = snprintf(in, sizeof(in) - 1, "/sys/class/net/%s/%s",
337 if (ret == -1 || (size_t)ret >= sizeof(in))
339 ret = readlink(in, buf, size);
342 if ((size_t)ret >= size - 1)
349 * Probe a network interface to associate with vdev_netvsc context.
351 * This function determines if the network device matches the properties of
352 * the NetVSC interface associated with the vdev_netvsc context and
353 * communicates its bus address to the fail-safe PMD instance if so.
355 * It is normally used with vdev_netvsc_foreach_iface().
358 * Pointer to netdevice description structure (name and index).
359 * @param[in] eth_addr
360 * MAC address associated with @p iface.
362 * Variable arguments list comprising:
364 * - struct vdev_netvsc_ctx *ctx:
365 * Context to associate network interface with.
368 * A nonzero value when interface matches, 0 otherwise or in case of
372 vdev_netvsc_device_probe(const struct if_nameindex *iface,
373 const struct ether_addr *eth_addr,
376 struct vdev_netvsc_ctx *ctx = va_arg(ap, struct vdev_netvsc_ctx *);
377 char buf[RTE_MAX(sizeof(ctx->yield), 256u)];
382 /* Skip non-matching or unwanted NetVSC interfaces. */
383 if (ctx->if_index == iface->if_index) {
384 if (!strcmp(ctx->if_name, iface->if_name))
387 "NetVSC interface \"%s\" (index %u) renamed \"%s\"",
388 ctx->if_name, ctx->if_index, iface->if_name);
389 strlcpy(ctx->if_name, iface->if_name, sizeof(ctx->if_name));
392 if (!is_same_ether_addr(eth_addr, &ctx->if_addr))
394 /* Look for associated PCI device. */
395 ret = vdev_netvsc_sysfs_readlink(buf, sizeof(buf), iface->if_name,
399 addr = strrchr(buf, '/');
400 addr = addr ? addr + 1 : buf;
401 if (strcmp(addr, "pci"))
403 ret = vdev_netvsc_sysfs_readlink(buf, sizeof(buf), iface->if_name,
407 addr = strrchr(buf, '/');
408 addr = addr ? addr + 1 : buf;
412 /* Send PCI device argument to fail-safe PMD instance. */
413 if (strcmp(addr, ctx->yield))
414 DRV_LOG(DEBUG, "associating PCI device \"%s\" with NetVSC"
415 " interface \"%s\" (index %u)", addr, ctx->if_name,
417 memmove(buf, addr, len + 1);
420 ret = write(ctx->pipe[1], addr, len + 1);
423 if (errno == EINTR || errno == EAGAIN)
425 DRV_LOG(WARNING, "cannot associate PCI device name \"%s\" with"
426 " interface \"%s\": %s", addr, ctx->if_name,
427 rte_strerror(errno));
430 if ((size_t)ret != len + 1) {
432 * Attempt to override previous partial write, no need to
433 * recover if that fails.
435 ret = write(ctx->pipe[1], "\n", 1);
440 memcpy(ctx->yield, addr, len + 1);
445 * Alarm callback that regularly probes system network interfaces.
447 * This callback runs at a frequency determined by VDEV_NETVSC_PROBE_MS as
448 * long as an vdev_netvsc context instance exists.
454 vdev_netvsc_alarm(__rte_unused void *arg)
456 struct vdev_netvsc_ctx *ctx;
459 LIST_FOREACH(ctx, &vdev_netvsc_ctx_list, entry) {
460 ret = vdev_netvsc_foreach_iface(vdev_netvsc_device_probe, 0,
465 if (!vdev_netvsc_ctx_count)
467 ret = rte_eal_alarm_set(VDEV_NETVSC_PROBE_MS * 1000,
468 vdev_netvsc_alarm, NULL);
470 DRV_LOG(ERR, "unable to reschedule alarm callback: %s",
476 * Probe a NetVSC interface to generate a vdev_netvsc context from.
478 * This function instantiates vdev_netvsc contexts either for all NetVSC
479 * devices found on the system or only a subset provided as device
482 * It is normally used with vdev_netvsc_foreach_iface().
485 * Pointer to netdevice description structure (name and index).
486 * @param[in] eth_addr
487 * MAC address associated with @p iface.
489 * Variable arguments list comprising:
491 * - const char *name:
492 * Name associated with current driver instance.
494 * - struct rte_kvargs *kvargs:
495 * Device arguments provided to current driver instance.
498 * Accept specified interface even if not detected as NetVSC.
500 * - unsigned int specified:
501 * Number of specific netdevices provided as device arguments.
503 * - unsigned int *matched:
504 * The number of specified netdevices matched by this function.
507 * A nonzero value when interface matches, 0 otherwise or in case of
511 vdev_netvsc_netvsc_probe(const struct if_nameindex *iface,
512 const struct ether_addr *eth_addr,
515 const char *name = va_arg(ap, const char *);
516 struct rte_kvargs *kvargs = va_arg(ap, struct rte_kvargs *);
517 unsigned int specified = va_arg(ap, unsigned int);
518 unsigned int *matched = va_arg(ap, unsigned int *);
520 struct vdev_netvsc_ctx *ctx;
523 /* Probe all interfaces when none are specified. */
525 for (i = 0; i != kvargs->count; ++i) {
526 const struct rte_kvargs_pair *pair = &kvargs->pairs[i];
528 if (!strcmp(pair->key, VDEV_NETVSC_ARG_IFACE)) {
529 if (!strcmp(pair->value, iface->if_name))
531 } else if (!strcmp(pair->key, VDEV_NETVSC_ARG_MAC)) {
532 struct ether_addr tmp;
534 if (sscanf(pair->value,
535 "%" SCNx8 ":%" SCNx8 ":%" SCNx8 ":"
536 "%" SCNx8 ":%" SCNx8 ":%" SCNx8,
542 &tmp.addr_bytes[5]) != 6) {
544 "invalid MAC address format"
549 if (is_same_ether_addr(eth_addr, &tmp))
553 if (i == kvargs->count)
557 /* Weed out interfaces already handled. */
558 LIST_FOREACH(ctx, &vdev_netvsc_ctx_list, entry)
559 if (ctx->if_index == iface->if_index)
565 "interface \"%s\" (index %u) is already handled,"
567 iface->if_name, iface->if_index);
570 /* Routed NetVSC should not be probed. */
571 if (vdev_netvsc_has_route(iface, AF_INET) ||
572 vdev_netvsc_has_route(iface, AF_INET6)) {
575 DRV_LOG(WARNING, "probably using routed NetVSC interface \"%s\""
576 " (index %u)", iface->if_name, iface->if_index);
578 /* Create interface context. */
579 ctx = calloc(1, sizeof(*ctx));
582 DRV_LOG(ERR, "cannot allocate context for interface \"%s\": %s",
583 iface->if_name, rte_strerror(errno));
586 ctx->id = vdev_netvsc_ctx_count;
587 strlcpy(ctx->if_name, iface->if_name, sizeof(ctx->if_name));
588 ctx->if_index = iface->if_index;
589 ctx->if_addr = *eth_addr;
592 ctx->yield[0] = '\0';
593 if (pipe(ctx->pipe) == -1) {
596 "cannot allocate control pipe for interface \"%s\": %s",
597 ctx->if_name, rte_strerror(errno));
600 for (i = 0; i != RTE_DIM(ctx->pipe); ++i) {
601 int flf = fcntl(ctx->pipe[i], F_GETFL);
604 fcntl(ctx->pipe[i], F_SETFL, flf | O_NONBLOCK) != -1)
607 DRV_LOG(ERR, "cannot toggle non-blocking flag on control file"
608 " descriptor #%u (%d): %s", i, ctx->pipe[i],
609 rte_strerror(errno));
612 /* Generate virtual device name and arguments. */
614 ret = snprintf(ctx->name, sizeof(ctx->name), "%s_id%u",
616 if (ret == -1 || (size_t)ret >= sizeof(ctx->name))
618 ret = snprintf(ctx->devname, sizeof(ctx->devname), "net_failsafe_vsc%u",
620 if (ret == -1 || (size_t)ret >= sizeof(ctx->devname))
622 ret = snprintf(ctx->devargs, sizeof(ctx->devargs),
623 "fd(%d),dev(net_tap_vsc%u,remote=%s)",
624 ctx->pipe[0], ctx->id, ctx->if_name);
625 if (ret == -1 || (size_t)ret >= sizeof(ctx->devargs))
629 DRV_LOG(ERR, "generated virtual device name or argument list"
630 " too long for interface \"%s\"", ctx->if_name);
633 /* Request virtual device generation. */
634 DRV_LOG(DEBUG, "generating virtual device \"%s\" with arguments \"%s\"",
635 ctx->devname, ctx->devargs);
636 vdev_netvsc_foreach_iface(vdev_netvsc_device_probe, 0, ctx);
637 ret = rte_eal_hotplug_add("vdev", ctx->devname, ctx->devargs);
640 LIST_INSERT_HEAD(&vdev_netvsc_ctx_list, ctx, entry);
641 ++vdev_netvsc_ctx_count;
642 DRV_LOG(DEBUG, "added NetVSC interface \"%s\" to context list",
647 vdev_netvsc_ctx_destroy(ctx);
652 * Probe NetVSC interfaces.
654 * This function probes system netdevices according to the specified device
655 * arguments and starts a periodic alarm callback to notify the resulting
656 * fail-safe PMD instances of their sub-devices whereabouts.
659 * Virtual device context for driver instance.
662 * Always 0, even in case of errors.
665 vdev_netvsc_vdev_probe(struct rte_vdev_device *dev)
667 static const char *const vdev_netvsc_arg[] = {
668 VDEV_NETVSC_ARG_IFACE,
670 VDEV_NETVSC_ARG_FORCE,
671 VDEV_NETVSC_ARG_IGNORE,
674 const char *name = rte_vdev_device_name(dev);
675 const char *args = rte_vdev_device_args(dev);
676 struct rte_kvargs *kvargs = rte_kvargs_parse(args ? args : "",
678 unsigned int specified = 0;
679 unsigned int matched = 0;
685 DRV_LOG(DEBUG, "invoked as \"%s\", using arguments \"%s\"", name, args);
687 DRV_LOG(ERR, "cannot parse arguments list");
690 for (i = 0; i != kvargs->count; ++i) {
691 const struct rte_kvargs_pair *pair = &kvargs->pairs[i];
693 if (!strcmp(pair->key, VDEV_NETVSC_ARG_FORCE))
694 force = !!atoi(pair->value);
695 else if (!strcmp(pair->key, VDEV_NETVSC_ARG_IGNORE))
696 ignore = !!atoi(pair->value);
697 else if (!strcmp(pair->key, VDEV_NETVSC_ARG_IFACE) ||
698 !strcmp(pair->key, VDEV_NETVSC_ARG_MAC))
703 rte_kvargs_free(kvargs);
707 DRV_LOG(ERR, "More than one way used to specify the netvsc"
711 rte_eal_alarm_cancel(vdev_netvsc_alarm, NULL);
712 /* Gather interfaces. */
713 ret = vdev_netvsc_foreach_iface(vdev_netvsc_netvsc_probe, 1, name,
714 kvargs, specified, &matched);
717 if (specified && matched < specified) {
719 DRV_LOG(ERR, "Cannot find the specified netvsc device");
722 /* Try to force probing on non-netvsc specified device. */
723 if (vdev_netvsc_foreach_iface(vdev_netvsc_netvsc_probe, 0, name,
724 kvargs, specified, &matched) < 0)
726 if (matched < specified) {
727 DRV_LOG(ERR, "Cannot find the specified device");
730 DRV_LOG(WARNING, "non-netvsc device was probed as netvsc");
732 ret = rte_eal_alarm_set(VDEV_NETVSC_PROBE_MS * 1000,
733 vdev_netvsc_alarm, NULL);
735 DRV_LOG(ERR, "unable to schedule alarm callback: %s",
741 rte_kvargs_free(kvargs);
742 ++vdev_netvsc_ctx_inst;
747 * Remove driver instance.
749 * The alarm callback and underlying vdev_netvsc context instances are only
750 * destroyed after the last PMD instance is removed.
753 * Virtual device context for driver instance.
759 vdev_netvsc_vdev_remove(__rte_unused struct rte_vdev_device *dev)
761 if (--vdev_netvsc_ctx_inst)
763 rte_eal_alarm_cancel(vdev_netvsc_alarm, NULL);
764 while (!LIST_EMPTY(&vdev_netvsc_ctx_list)) {
765 struct vdev_netvsc_ctx *ctx = LIST_FIRST(&vdev_netvsc_ctx_list);
767 LIST_REMOVE(ctx, entry);
768 --vdev_netvsc_ctx_count;
769 vdev_netvsc_ctx_destroy(ctx);
774 /** Virtual device descriptor. */
775 static struct rte_vdev_driver vdev_netvsc_vdev = {
776 .probe = vdev_netvsc_vdev_probe,
777 .remove = vdev_netvsc_vdev_remove,
780 RTE_PMD_REGISTER_VDEV(VDEV_NETVSC_DRIVER, vdev_netvsc_vdev);
781 RTE_PMD_REGISTER_ALIAS(VDEV_NETVSC_DRIVER, eth_vdev_netvsc);
782 RTE_PMD_REGISTER_PARAM_STRING(net_vdev_netvsc,
783 VDEV_NETVSC_ARG_IFACE "=<string> "
784 VDEV_NETVSC_ARG_MAC "=<string> "
785 VDEV_NETVSC_ARG_FORCE "=<int> "
786 VDEV_NETVSC_ARG_IGNORE "=<int>");
788 /** Initialize driver log type. */
789 RTE_INIT(vdev_netvsc_init_log)
791 vdev_netvsc_logtype = rte_log_register("pmd.vdev_netvsc");
792 if (vdev_netvsc_logtype >= 0)
793 rte_log_set_level(vdev_netvsc_logtype, RTE_LOG_NOTICE);
796 /** Compare function for vdev find device operation. */
798 vdev_netvsc_cmp_rte_device(const struct rte_device *dev1,
799 __rte_unused const void *_dev2)
801 return strcmp(dev1->devargs->name, VDEV_NETVSC_DRIVER_NAME);
805 * A callback called by vdev bus scan function to ensure this driver probing
806 * automatically in Hyper-V VM system unless it already exists in the
810 vdev_netvsc_scan_callback(__rte_unused void *arg)
812 struct rte_vdev_device *dev;
813 struct rte_devargs *devargs;
814 struct rte_bus *vbus = rte_bus_find_by_name("vdev");
816 RTE_EAL_DEVARGS_FOREACH("vdev", devargs)
817 if (!strcmp(devargs->name, VDEV_NETVSC_DRIVER_NAME))
819 dev = (struct rte_vdev_device *)vbus->find_device(NULL,
820 vdev_netvsc_cmp_rte_device, VDEV_NETVSC_DRIVER_NAME);
823 if (rte_devargs_add(RTE_DEVTYPE_VIRTUAL, VDEV_NETVSC_DRIVER_NAME))
824 DRV_LOG(ERR, "unable to add netvsc devargs.");
827 /** Initialize the custom scan. */
828 RTE_INIT(vdev_netvsc_custom_scan_add)
830 if (rte_hypervisor_get() == RTE_HYPERVISOR_HYPERV)
831 rte_vdev_add_custom_scan(vdev_netvsc_scan_callback, NULL);