<commit_before>/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright 2017 6WIND S.A.
 * Copyright 2017 Mellanox Technologies, Ltd
 */

#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <linux/sockios.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/ip.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <unistd.h>

#include <rte_alarm.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_ether.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 VDEV_NETVSC_ARG_IGNORE "ignore"
#define VDEV_NETVSC_PROBE_MS 1000

#define NETVSC_CLASS_ID "{f8615163-df3e-46c5-913f-f2d2f965ed0e}"
#define NETVSC_MAX_ROUTE_LINE_SIZE 300

#define DRV_LOG(level, ...) \
	rte_log(RTE_LOG_ ## level, \
		vdev_netvsc_logtype, \
		RTE_FMT(VDEV_NETVSC_DRIVER_NAME ": " \
			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. */
	unsigned int id;		   /**< Unique ID. */
	char name[64];			   /**< Unique name. */
	char devname[64];		   /**< Fail-safe instance name. */
	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. */
	int pipe[2];			   /**< Fail-safe communication pipe. */
	char yield[256];		   /**< PCI sub-device arguments. */
};

/** Context list is common to all driver instances. */
static LIST_HEAD(, vdev_netvsc_ctx) vdev_netvsc_ctx_list =
	LIST_HEAD_INITIALIZER(vdev_netvsc_ctx_list);

/** Number of entries in context list. */
static unsigned int vdev_netvsc_ctx_count;

/** Number of driver instances relying on context list. */
static unsigned int vdev_netvsc_ctx_inst;

/**
 * Destroy a vdev_netvsc context instance.
 *
 * @param ctx
 *   Context to destroy.
 */
static void
vdev_netvsc_ctx_destroy(struct vdev_netvsc_ctx *ctx)
{
	if (ctx->pipe[0] != -1)
		close(ctx->pipe[0]);
	if (ctx->pipe[1] != -1)
		close(ctx->pipe[1]);
	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.
 *
 * This function runs a given callback function for each netdevice found on
 * the system.
 *
 * @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.
 *
 * @return
 *   0 when the entire list is traversed successfully, a negative error code
 *   in case or failure, or the nonzero value returned by @p func when list
 *   traversal is aborted.
 */
static int
vdev_netvsc_foreach_iface(int (*func)(const struct if_nameindex *iface,
				      const struct 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);
	unsigned int i;
	int ret = 0;

	if (!iface) {
		ret = -ENOBUFS;
		DRV_LOG(ERR, "cannot retrieve system network interfaces");
		goto error;
	}
	if (s == -1) {
		ret = -errno;
		DRV_LOG(ERR, "cannot open socket: %s", rte_strerror(errno));
		goto error;
	}
	for (i = 0; iface[i].if_name; ++i) {
		int is_netvsc_ret;
		struct ifreq req;
		struct ether_addr eth_addr;
		va_list ap;

		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);
			continue;
		}
		memcpy(eth_addr.addr_bytes, req.ifr_hwaddr.sa_data,
		       RTE_DIM(eth_addr.addr_bytes));
		va_start(ap, is_netvsc);
		ret = func(&iface[i], &eth_addr, ap);
		va_end(ap);
		if (ret)
			break;
	}
error:
	if (s != -1)
		close(s);
	if (iface)
		if_freenameindex(iface);
	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
 *   1 when interface has a route, negative errno value in case of error and
 *   0 otherwise.<commit_msg>net/vdev_netvsc: get rid of unnecessary debug log message<commit_after>/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright 2017 6WIND S.A.
 * Copyright 2017 Mellanox Technologies, Ltd
 */

#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <linux/sockios.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/ip.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <unistd.h>

#include <rte_alarm.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_ether.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 VDEV_NETVSC_ARG_IGNORE "ignore"
#define VDEV_NETVSC_PROBE_MS 1000

#define NETVSC_CLASS_ID "{f8615163-df3e-46c5-913f-f2d2f965ed0e}"
#define NETVSC_MAX_ROUTE_LINE_SIZE 300

#define DRV_LOG(level, ...) \
	rte_log(RTE_LOG_ ## level, \
		vdev_netvsc_logtype, \
		RTE_FMT(VDEV_NETVSC_DRIVER_NAME ": " \
			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. */
	unsigned int id;		   /**< Unique ID. */
	char name[64];			   /**< Unique name. */
	char devname[64];		   /**< Fail-safe instance name. */
	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. */
	int pipe[2];			   /**< Fail-safe communication pipe. */
	char yield[256];		   /**< PCI sub-device arguments. */
};

/** Context list is common to all driver instances. */
static LIST_HEAD(, vdev_netvsc_ctx) vdev_netvsc_ctx_list =
	LIST_HEAD_INITIALIZER(vdev_netvsc_ctx_list);

/** Number of entries in context list. */
static unsigned int vdev_netvsc_ctx_count;

/** Number of driver instances relying on context list. */
static unsigned int vdev_netvsc_ctx_inst;

/**
 * Destroy a vdev_netvsc context instance.
 *
 * @param ctx
 *   Context to destroy.
 */
static void
vdev_netvsc_ctx_destroy(struct vdev_netvsc_ctx *ctx)
{
	if (ctx->pipe[0] != -1)
		close(ctx->pipe[0]);
	if (ctx->pipe[1] != -1)
		close(ctx->pipe[1]);
	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.
 *
 * This function runs a given callback function for each netdevice found on
 * the system.
 *
 * @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.
 *
 * @return
 *   0 when the entire list is traversed successfully, a negative error code
 *   in case or failure, or the nonzero value returned by @p func when list
 *   traversal is aborted.
 */
static int
vdev_netvsc_foreach_iface(int (*func)(const struct if_nameindex *iface,
				      const struct 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);
	unsigned int i;
	int ret = 0;

	if (!iface) {
		ret = -ENOBUFS;
		DRV_LOG(ERR, "cannot retrieve system network interfaces");
		goto error;
	}
	if (s == -1) {
		ret = -errno;
		DRV_LOG(ERR, "cannot open socket: %s", rte_strerror(errno));
		goto error;
	}
	for (i = 0; iface[i].if_name; ++i) {
		int is_netvsc_ret;
		struct ifreq req;
		struct ether_addr eth_addr;
		va_list ap;

		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)
			continue;
		memcpy(eth_addr.addr_bytes, req.ifr_hwaddr.sa_data,
		       RTE_DIM(eth_addr.addr_bytes));
		va_start(ap, is_netvsc);
		ret = func(&iface[i], &eth_addr, ap);
		va_end(ap);
		if (ret)
			break;
	}
error:
	if (s != -1)
		close(s);
	if (iface)
		if_freenameindex(iface);
	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
 *   1 when interface has a route, negative errno value in case of error and
 *   0 otherwise.
{'fraction_non_alphanumeric': 0.13326719576719576, 'fraction_numerical': 0.012235449735449735, 'mean_word_length': 3.9516987310683587, 'pattern_counts': {'":': 4, '<': 87, '<?xml version=': 0, '>': 79, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3295765', 'n_tokens_mistral': 5014, 'n_tokens_neox': 4770, 'n_words': 1199}