/* SPDX-License-Identifier: BSD-3-Clause
* Copyright 2017 6WIND S.A.
- * Copyright 2017 Mellanox Technologies, Ltd.
+ * Copyright 2017 Mellanox Technologies, Ltd
*/
#include <errno.h>
#include <rte_bus.h>
#include <rte_bus_vdev.h>
#include <rte_common.h>
-#include <rte_config.h>
#include <rte_dev.h>
#include <rte_errno.h>
#include <rte_ethdev.h>
#include <rte_hypervisor.h>
#include <rte_kvargs.h>
#include <rte_log.h>
+#include <rte_string_fns.h>
#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"
#define NETVSC_CLASS_ID "{f8615163-df3e-46c5-913f-f2d2f965ed0e}"
#define NETVSC_MAX_ROUTE_LINE_SIZE 300
+RTE_LOG_REGISTER_DEFAULT(vdev_netvsc_logtype, NOTICE);
+
#define DRV_LOG(level, ...) \
rte_log(RTE_LOG_ ## level, \
vdev_netvsc_logtype, \
RTE_FMT_HEAD(__VA_ARGS__,) "\n", \
RTE_FMT_TAIL(__VA_ARGS__,)))
-/** Driver-specific log messages type. */
-static int vdev_netvsc_logtype;
-
/** Context structure for a vdev_netvsc instance. */
struct vdev_netvsc_ctx {
LIST_ENTRY(vdev_netvsc_ctx) entry; /**< Next entry in list. */
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. */
};
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.
*
* @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.
*
*/
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);
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)
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.
*
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), "/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)
*/
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 *);
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))
+ if (!rte_is_same_ether_addr(eth_addr, &ctx->if_addr))
return 0;
/* Look for associated PCI device. */
ret = vdev_netvsc_sysfs_readlink(buf, sizeof(buf), iface->if_name,
int ret;
LIST_FOREACH(ctx, &vdev_netvsc_ctx_list, entry) {
- ret = vdev_netvsc_foreach_iface(vdev_netvsc_device_probe, ctx);
+ ret = vdev_netvsc_foreach_iface(vdev_netvsc_device_probe, 0,
+ ctx);
if (ret < 0)
break;
}
*/
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;
if (!strcmp(pair->value, iface->if_name))
break;
} else if (!strcmp(pair->key, VDEV_NETVSC_ARG_MAC)) {
- struct ether_addr tmp;
-
- if (sscanf(pair->value,
- "%" SCNx8 ":%" SCNx8 ":%" SCNx8 ":"
- "%" SCNx8 ":%" SCNx8 ":%" SCNx8,
- &tmp.addr_bytes[0],
- &tmp.addr_bytes[1],
- &tmp.addr_bytes[2],
- &tmp.addr_bytes[3],
- &tmp.addr_bytes[4],
- &tmp.addr_bytes[5]) != 6) {
+ struct rte_ether_addr tmp;
+
+ if (rte_ether_unformat_addr(pair->value, &tmp) != 0) {
DRV_LOG(ERR,
"invalid MAC address format"
" \"%s\"",
pair->value);
return -EINVAL;
}
- if (is_same_ether_addr(eth_addr, &tmp))
+ if (rte_is_same_ether_addr(eth_addr, &tmp))
break;
}
}
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, AF_INET) ||
vdev_netvsc_has_route(iface, AF_INET6)) {
- if (!specified || !force)
+ if (!specified)
return 0;
DRV_LOG(WARNING, "probably using routed NetVSC interface \"%s\""
" (index %u)", iface->if_name, iface->if_index);
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;
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) {
/* 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)
+ if (ret < 0)
goto error;
LIST_INSERT_HEAD(&vdev_netvsc_ctx_list, ctx, entry);
++vdev_netvsc_ctx_count;
int ret;
DRV_LOG(DEBUG, "invoked as \"%s\", using arguments \"%s\"", name, args);
+ rte_eal_alarm_cancel(vdev_netvsc_alarm, NULL);
if (!kvargs) {
DRV_LOG(ERR, "cannot parse arguments list");
goto error;
!strcmp(pair->key, VDEV_NETVSC_ARG_MAC))
++specified;
}
- if (ignore) {
- if (kvargs)
- rte_kvargs_free(kvargs);
- return 0;
+ if (ignore)
+ goto ignore;
+ 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");
- ret = rte_eal_alarm_set(VDEV_NETVSC_PROBE_MS * 1000,
- vdev_netvsc_alarm, NULL);
- if (ret < 0) {
- DRV_LOG(ERR, "unable to schedule alarm callback: %s",
- rte_strerror(-ret));
- goto error;
+ 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");
}
error:
- if (kvargs)
- rte_kvargs_free(kvargs);
++vdev_netvsc_ctx_inst;
+ignore:
+ rte_kvargs_free(kvargs);
+ /* Reset alarm if there are device context created */
+ if (vdev_netvsc_ctx_count) {
+ ret = rte_eal_alarm_set(VDEV_NETVSC_PROBE_MS * 1000,
+ vdev_netvsc_alarm, NULL);
+ if (ret < 0)
+ DRV_LOG(ERR, "unable to schedule alarm callback: %s",
+ rte_strerror(-ret));
+ }
return 0;
}
VDEV_NETVSC_ARG_FORCE "=<int> "
VDEV_NETVSC_ARG_IGNORE "=<int>");
-/** Initialize driver log type. */
-RTE_INIT(vdev_netvsc_init_log)
-{
- vdev_netvsc_logtype = rte_log_register("pmd.vdev_netvsc");
- if (vdev_netvsc_logtype >= 0)
- rte_log_set_level(vdev_netvsc_logtype, RTE_LOG_NOTICE);
-}
-
/** Compare function for vdev find device operation. */
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);
}
/**
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.");
}