X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fvdev_netvsc%2Fvdev_netvsc.c;h=ef02fdcddccbe410c045cf04e17bbd77aa615cc5;hb=6d13ea8e8e49ab957deae2bba5ecf4a4bfe747d1;hp=a8a1a7fe4e90a233bafdc77d56e9d68d4f47e480;hpb=56252de779a68df5f49c04a49b404fa693719d01;p=dpdk.git diff --git a/drivers/net/vdev_netvsc/vdev_netvsc.c b/drivers/net/vdev_netvsc/vdev_netvsc.c index a8a1a7fe4e..ef02fdcddc 100644 --- a/drivers/net/vdev_netvsc/vdev_netvsc.c +++ b/drivers/net/vdev_netvsc/vdev_netvsc.c @@ -1,12 +1,14 @@ /* SPDX-License-Identifier: BSD-3-Clause * Copyright 2017 6WIND S.A. - * Copyright 2017 Mellanox Technologies, Ltd. + * Copyright 2017 Mellanox Technologies, Ltd */ #include #include #include #include +#include +#include #include #include #include @@ -33,9 +35,11 @@ #include #include #include +#include #define VDEV_NETVSC_DRIVER net_vdev_netvsc #define VDEV_NETVSC_DRIVER_NAME RTE_STR(VDEV_NETVSC_DRIVER) +#define VDEV_NETVSC_DRIVER_NAME_LEN 15 #define VDEV_NETVSC_ARG_IFACE "iface" #define VDEV_NETVSC_ARG_MAC "mac" #define VDEV_NETVSC_ARG_FORCE "force" @@ -64,7 +68,7 @@ struct vdev_netvsc_ctx { char devargs[256]; /**< Fail-safe device arguments. */ char if_name[IF_NAMESIZE]; /**< NetVSC netdevice name. */ unsigned int if_index; /**< NetVSC netdevice index. */ - struct ether_addr if_addr; /**< NetVSC MAC address. */ + struct rte_ether_addr if_addr; /**< NetVSC MAC address. */ int pipe[2]; /**< Fail-safe communication pipe. */ char yield[256]; /**< PCI sub-device arguments. */ }; @@ -95,6 +99,43 @@ vdev_netvsc_ctx_destroy(struct vdev_netvsc_ctx *ctx) free(ctx); } +/** + * Determine if a network interface is NetVSC. + * + * @param[in] iface + * Pointer to netdevice description structure (name and index). + * + * @return + * A nonzero value when interface is detected as NetVSC. In case of error, + * rte_errno is updated and 0 returned. + */ +static int +vdev_netvsc_iface_is_netvsc(const struct if_nameindex *iface) +{ + static const char temp[] = "/sys/class/net/%s/device/class_id"; + char path[sizeof(temp) + IF_NAMESIZE]; + FILE *f; + int ret; + int len = 0; + + ret = snprintf(path, sizeof(path), temp, iface->if_name); + if (ret == -1 || (size_t)ret >= sizeof(path)) { + rte_errno = ENOBUFS; + return 0; + } + f = fopen(path, "r"); + if (!f) { + rte_errno = errno; + return 0; + } + ret = fscanf(f, NETVSC_CLASS_ID "%n", &len); + if (ret == EOF) + rte_errno = errno; + ret = len == (int)strlen(NETVSC_CLASS_ID); + fclose(f); + return ret; +} + /** * Iterate over system network interfaces. * @@ -104,6 +145,8 @@ vdev_netvsc_ctx_destroy(struct vdev_netvsc_ctx *ctx) * @param func * Callback function pointer. List traversal is aborted when this function * returns a nonzero value. + * @param is_netvsc + * Indicates the device type to iterate - netvsc or non-netvsc. * @param ... * Variable parameter list passed as @p va_list to @p func. * @@ -114,8 +157,8 @@ vdev_netvsc_ctx_destroy(struct vdev_netvsc_ctx *ctx) */ static int vdev_netvsc_foreach_iface(int (*func)(const struct if_nameindex *iface, - const struct ether_addr *eth_addr, - va_list ap), ...) + const struct rte_ether_addr *eth_addr, + va_list ap), int is_netvsc, ...) { struct if_nameindex *iface = if_nameindex(); int s = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); @@ -133,25 +176,26 @@ vdev_netvsc_foreach_iface(int (*func)(const struct if_nameindex *iface, goto error; } for (i = 0; iface[i].if_name; ++i) { + int is_netvsc_ret; struct ifreq req; - struct ether_addr eth_addr; + struct rte_ether_addr eth_addr; va_list ap; - strncpy(req.ifr_name, iface[i].if_name, sizeof(req.ifr_name)); + is_netvsc_ret = vdev_netvsc_iface_is_netvsc(&iface[i]) ? 1 : 0; + if (is_netvsc ^ is_netvsc_ret) + continue; + strlcpy(req.ifr_name, iface[i].if_name, sizeof(req.ifr_name)); if (ioctl(s, SIOCGIFHWADDR, &req) == -1) { DRV_LOG(WARNING, "cannot retrieve information about" " interface \"%s\": %s", req.ifr_name, rte_strerror(errno)); continue; } - if (req.ifr_hwaddr.sa_family != ARPHRD_ETHER) { - DRV_LOG(DEBUG, "interface %s is non-ethernet device", - req.ifr_name); + if (req.ifr_hwaddr.sa_family != ARPHRD_ETHER) continue; - } memcpy(eth_addr.addr_bytes, req.ifr_hwaddr.sa_data, RTE_DIM(eth_addr.addr_bytes)); - va_start(ap, func); + va_start(ap, is_netvsc); ret = func(&iface[i], ð_addr, ap); va_end(ap); if (ret) @@ -165,78 +209,101 @@ error: return ret; } -/** - * Determine if a network interface is NetVSC. - * - * @param[in] iface - * Pointer to netdevice description structure (name and index). - * - * @return - * A nonzero value when interface is detected as NetVSC. In case of error, - * rte_errno is updated and 0 returned. - */ -static int -vdev_netvsc_iface_is_netvsc(const struct if_nameindex *iface) -{ - static const char temp[] = "/sys/class/net/%s/device/class_id"; - char path[sizeof(temp) + IF_NAMESIZE]; - FILE *f; - int ret; - int len = 0; - - ret = snprintf(path, sizeof(path), temp, iface->if_name); - if (ret == -1 || (size_t)ret >= sizeof(path)) { - rte_errno = ENOBUFS; - return 0; - } - f = fopen(path, "r"); - if (!f) { - rte_errno = errno; - return 0; - } - ret = fscanf(f, NETVSC_CLASS_ID "%n", &len); - if (ret == EOF) - rte_errno = errno; - ret = len == (int)strlen(NETVSC_CLASS_ID); - fclose(f); - return ret; -} - /** * Determine if a network interface has a route. * * @param[in] name * Network device name. + * @param[in] family + * Address family: AF_INET for IPv4 or AF_INET6 for IPv6. * * @return - * A nonzero value when interface has an route. In case of error, - * rte_errno is updated and 0 returned. + * 1 when interface has a route, negative errno value in case of error and + * 0 otherwise. */ static int -vdev_netvsc_has_route(const char *name) +vdev_netvsc_has_route(const struct if_nameindex *iface, + const unsigned char family) { - FILE *fp; + /* + * The implementation can be simpler by getifaddrs() function usage but + * it works for IPv6 only starting from glibc 2.3.3. + */ + char buf[4096]; + int len; int ret = 0; - char route[NETVSC_MAX_ROUTE_LINE_SIZE]; - char *netdev; - - fp = fopen("/proc/net/route", "r"); - if (!fp) { - rte_errno = errno; - return 0; + int res; + int sock; + struct nlmsghdr *retmsg = (struct nlmsghdr *)buf; + struct sockaddr_nl sa; + struct { + struct nlmsghdr nlhdr; + struct ifaddrmsg addrmsg; + } msg; + + if (!iface || (family != AF_INET && family != AF_INET6)) { + DRV_LOG(ERR, "%s", rte_strerror(EINVAL)); + return -EINVAL; } - while (fgets(route, NETVSC_MAX_ROUTE_LINE_SIZE, fp) != NULL) { - netdev = strtok(route, "\t"); - if (strcmp(netdev, name) == 0) { - ret = 1; - break; + sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (sock == -1) { + DRV_LOG(ERR, "cannot open socket: %s", rte_strerror(errno)); + return -errno; + } + memset(&sa, 0, sizeof(sa)); + sa.nl_family = AF_NETLINK; + sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR; + res = bind(sock, (struct sockaddr *)&sa, sizeof(sa)); + if (res == -1) { + ret = -errno; + DRV_LOG(ERR, "cannot bind socket: %s", rte_strerror(errno)); + goto close; + } + memset(&msg, 0, sizeof(msg)); + msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + msg.nlhdr.nlmsg_type = RTM_GETADDR; + msg.nlhdr.nlmsg_pid = getpid(); + msg.addrmsg.ifa_family = family; + msg.addrmsg.ifa_index = iface->if_index; + res = send(sock, &msg, msg.nlhdr.nlmsg_len, 0); + if (res == -1) { + ret = -errno; + DRV_LOG(ERR, "cannot send socket message: %s", + rte_strerror(errno)); + goto close; + } + memset(buf, 0, sizeof(buf)); + len = recv(sock, buf, sizeof(buf), 0); + if (len == -1) { + ret = -errno; + DRV_LOG(ERR, "cannot receive socket message: %s", + rte_strerror(errno)); + goto close; + } + while (NLMSG_OK(retmsg, (unsigned int)len)) { + struct ifaddrmsg *retaddr = + (struct ifaddrmsg *)NLMSG_DATA(retmsg); + + if (retaddr->ifa_family == family && + retaddr->ifa_index == iface->if_index) { + struct rtattr *retrta = IFA_RTA(retaddr); + int attlen = IFA_PAYLOAD(retmsg); + + while (RTA_OK(retrta, attlen)) { + if (retrta->rta_type == IFA_ADDRESS) { + ret = 1; + DRV_LOG(DEBUG, "interface %s has IP", + iface->if_name); + goto close; + } + retrta = RTA_NEXT(retrta, attlen); + } } - /* Move file pointer to the next line. */ - while (strchr(route, '\n') == NULL && - fgets(route, NETVSC_MAX_ROUTE_LINE_SIZE, fp) != NULL) - ; + retmsg = NLMSG_NEXT(retmsg, len); } - fclose(fp); +close: + close(sock); return ret; } @@ -259,12 +326,15 @@ static int vdev_netvsc_sysfs_readlink(char *buf, size_t size, const char *if_name, const char *relpath) { + struct vdev_netvsc_ctx *ctx; + char in[RTE_MAX(sizeof(ctx->yield), 256u)]; int ret; - ret = snprintf(buf, size, "/sys/class/net/%s/%s", if_name, relpath); - if (ret == -1 || (size_t)ret >= size) + ret = snprintf(in, sizeof(in) - 1, "/sys/class/net/%s/%s", + if_name, relpath); + if (ret == -1 || (size_t)ret >= sizeof(in)) return -ENOBUFS; - ret = readlink(buf, buf, size); + ret = readlink(in, buf, size); if (ret == -1) return -errno; if ((size_t)ret >= size - 1) @@ -298,7 +368,7 @@ vdev_netvsc_sysfs_readlink(char *buf, size_t size, const char *if_name, */ static int vdev_netvsc_device_probe(const struct if_nameindex *iface, - const struct ether_addr *eth_addr, + const struct rte_ether_addr *eth_addr, va_list ap) { struct vdev_netvsc_ctx *ctx = va_arg(ap, struct vdev_netvsc_ctx *); @@ -314,11 +384,9 @@ vdev_netvsc_device_probe(const struct if_nameindex *iface, DRV_LOG(DEBUG, "NetVSC interface \"%s\" (index %u) renamed \"%s\"", ctx->if_name, ctx->if_index, iface->if_name); - strncpy(ctx->if_name, iface->if_name, sizeof(ctx->if_name)); + strlcpy(ctx->if_name, iface->if_name, sizeof(ctx->if_name)); return 0; } - if (vdev_netvsc_iface_is_netvsc(iface)) - return 0; if (!is_same_ether_addr(eth_addr, &ctx->if_addr)) return 0; /* Look for associated PCI device. */ @@ -387,8 +455,9 @@ vdev_netvsc_alarm(__rte_unused void *arg) int ret; LIST_FOREACH(ctx, &vdev_netvsc_ctx_list, entry) { - ret = vdev_netvsc_foreach_iface(vdev_netvsc_device_probe, ctx); - if (ret) + ret = vdev_netvsc_foreach_iface(vdev_netvsc_device_probe, 0, + ctx); + if (ret < 0) break; } if (!vdev_netvsc_ctx_count) @@ -438,12 +507,11 @@ vdev_netvsc_alarm(__rte_unused void *arg) */ static int vdev_netvsc_netvsc_probe(const struct if_nameindex *iface, - const struct ether_addr *eth_addr, + const struct rte_ether_addr *eth_addr, va_list ap) { const char *name = va_arg(ap, const char *); struct rte_kvargs *kvargs = va_arg(ap, struct rte_kvargs *); - int force = va_arg(ap, int); unsigned int specified = va_arg(ap, unsigned int); unsigned int *matched = va_arg(ap, unsigned int *); unsigned int i; @@ -459,7 +527,7 @@ vdev_netvsc_netvsc_probe(const struct if_nameindex *iface, if (!strcmp(pair->value, iface->if_name)) break; } else if (!strcmp(pair->key, VDEV_NETVSC_ARG_MAC)) { - struct ether_addr tmp; + struct rte_ether_addr tmp; if (sscanf(pair->value, "%" SCNx8 ":%" SCNx8 ":%" SCNx8 ":" @@ -497,18 +565,12 @@ vdev_netvsc_netvsc_probe(const struct if_nameindex *iface, iface->if_name, iface->if_index); return 0; } - if (!vdev_netvsc_iface_is_netvsc(iface)) { - if (!specified || !force) - return 0; - DRV_LOG(WARNING, - "using non-NetVSC interface \"%s\" (index %u)", - iface->if_name, iface->if_index); - } /* Routed NetVSC should not be probed. */ - if (vdev_netvsc_has_route(iface->if_name)) { - if (!specified || !force) + if (vdev_netvsc_has_route(iface, AF_INET) || + vdev_netvsc_has_route(iface, AF_INET6)) { + if (!specified) return 0; - DRV_LOG(WARNING, "using routed NetVSC interface \"%s\"" + DRV_LOG(WARNING, "probably using routed NetVSC interface \"%s\"" " (index %u)", iface->if_name, iface->if_index); } /* Create interface context. */ @@ -520,7 +582,7 @@ vdev_netvsc_netvsc_probe(const struct if_nameindex *iface, goto error; } ctx->id = vdev_netvsc_ctx_count; - strncpy(ctx->if_name, iface->if_name, sizeof(ctx->if_name)); + strlcpy(ctx->if_name, iface->if_name, sizeof(ctx->if_name)); ctx->if_index = iface->if_index; ctx->if_addr = *eth_addr; ctx->pipe[0] = -1; @@ -551,13 +613,13 @@ vdev_netvsc_netvsc_probe(const struct if_nameindex *iface, name, ctx->id); if (ret == -1 || (size_t)ret >= sizeof(ctx->name)) ++i; - ret = snprintf(ctx->devname, sizeof(ctx->devname), "net_failsafe_%s", - ctx->name); + ret = snprintf(ctx->devname, sizeof(ctx->devname), "net_failsafe_vsc%u", + ctx->id); if (ret == -1 || (size_t)ret >= sizeof(ctx->devname)) ++i; ret = snprintf(ctx->devargs, sizeof(ctx->devargs), - "fd(%d),dev(net_tap_%s,remote=%s)", - ctx->pipe[0], ctx->name, ctx->if_name); + "fd(%d),dev(net_tap_vsc%u,remote=%s)", + ctx->pipe[0], ctx->id, ctx->if_name); if (ret == -1 || (size_t)ret >= sizeof(ctx->devargs)) ++i; if (i) { @@ -569,7 +631,7 @@ vdev_netvsc_netvsc_probe(const struct if_nameindex *iface, /* Request virtual device generation. */ DRV_LOG(DEBUG, "generating virtual device \"%s\" with arguments \"%s\"", ctx->devname, ctx->devargs); - vdev_netvsc_foreach_iface(vdev_netvsc_device_probe, ctx); + vdev_netvsc_foreach_iface(vdev_netvsc_device_probe, 0, ctx); ret = rte_eal_hotplug_add("vdev", ctx->devname, ctx->devargs); if (ret) goto error; @@ -639,16 +701,32 @@ vdev_netvsc_vdev_probe(struct rte_vdev_device *dev) rte_kvargs_free(kvargs); return 0; } + if (specified > 1) { + DRV_LOG(ERR, "More than one way used to specify the netvsc" + " device."); + goto error; + } rte_eal_alarm_cancel(vdev_netvsc_alarm, NULL); /* Gather interfaces. */ - ret = vdev_netvsc_foreach_iface(vdev_netvsc_netvsc_probe, name, kvargs, - force, specified, &matched); + ret = vdev_netvsc_foreach_iface(vdev_netvsc_netvsc_probe, 1, name, + kvargs, specified, &matched); if (ret < 0) goto error; - if (matched < specified) - DRV_LOG(WARNING, - "some of the specified parameters did not match" - " recognized network interfaces"); + if (specified && matched < specified) { + if (!force) { + DRV_LOG(ERR, "Cannot find the specified netvsc device"); + goto error; + } + /* Try to force probing on non-netvsc specified device. */ + if (vdev_netvsc_foreach_iface(vdev_netvsc_netvsc_probe, 0, name, + kvargs, specified, &matched) < 0) + goto error; + if (matched < specified) { + DRV_LOG(ERR, "Cannot find the specified device"); + goto error; + } + DRV_LOG(WARNING, "non-netvsc device was probed as netvsc"); + } ret = rte_eal_alarm_set(VDEV_NETVSC_PROBE_MS * 1000, vdev_netvsc_alarm, NULL); if (ret < 0) { @@ -708,7 +786,7 @@ RTE_PMD_REGISTER_PARAM_STRING(net_vdev_netvsc, /** Initialize driver log type. */ RTE_INIT(vdev_netvsc_init_log) { - vdev_netvsc_logtype = rte_log_register("pmd.vdev_netvsc"); + vdev_netvsc_logtype = rte_log_register("pmd.net.vdev_netvsc"); if (vdev_netvsc_logtype >= 0) rte_log_set_level(vdev_netvsc_logtype, RTE_LOG_NOTICE); } @@ -718,7 +796,8 @@ static int vdev_netvsc_cmp_rte_device(const struct rte_device *dev1, __rte_unused const void *_dev2) { - return strcmp(dev1->devargs->name, VDEV_NETVSC_DRIVER_NAME); + return strncmp(dev1->devargs->name, VDEV_NETVSC_DRIVER_NAME, + VDEV_NETVSC_DRIVER_NAME_LEN); } /** @@ -729,18 +808,20 @@ vdev_netvsc_cmp_rte_device(const struct rte_device *dev1, static void vdev_netvsc_scan_callback(__rte_unused void *arg) { - struct rte_vdev_device *dev; + struct rte_device *dev; struct rte_devargs *devargs; struct rte_bus *vbus = rte_bus_find_by_name("vdev"); - TAILQ_FOREACH(devargs, &devargs_list, next) - if (!strcmp(devargs->name, VDEV_NETVSC_DRIVER_NAME)) + RTE_EAL_DEVARGS_FOREACH("vdev", devargs) + if (!strncmp(devargs->name, VDEV_NETVSC_DRIVER_NAME, + VDEV_NETVSC_DRIVER_NAME_LEN)) return; - dev = (struct rte_vdev_device *)vbus->find_device(NULL, - vdev_netvsc_cmp_rte_device, VDEV_NETVSC_DRIVER_NAME); + + dev = vbus->find_device(NULL, vdev_netvsc_cmp_rte_device, + VDEV_NETVSC_DRIVER_NAME); if (dev) return; - if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, VDEV_NETVSC_DRIVER_NAME)) + if (rte_devargs_add(RTE_DEVTYPE_VIRTUAL, VDEV_NETVSC_DRIVER_NAME)) DRV_LOG(ERR, "unable to add netvsc devargs."); }