Blame vdpa/vdpa.c

Packit Bot 867fae
// SPDX-License-Identifier: GPL-2.0+
Packit Bot 867fae
Packit Bot 867fae
#include <stdio.h>
Packit Bot 867fae
#include <getopt.h>
Packit Bot 867fae
#include <errno.h>
Packit Bot 867fae
#include <linux/genetlink.h>
Packit Bot 867fae
#include <linux/vdpa.h>
Packit Bot 867fae
#include <linux/virtio_ids.h>
Packit Bot 867fae
#include <linux/netlink.h>
Packit Bot 867fae
#include <libmnl/libmnl.h>
Packit Bot 867fae
#include "mnl_utils.h"
Packit Bot 867fae
Packit Bot 867fae
#include "version.h"
Packit Bot 867fae
#include "json_print.h"
Packit Bot 867fae
#include "utils.h"
Packit Bot 867fae
Packit Bot 867fae
#define VDPA_OPT_MGMTDEV_HANDLE		BIT(0)
Packit Bot 867fae
#define VDPA_OPT_VDEV_MGMTDEV_HANDLE	BIT(1)
Packit Bot 867fae
#define VDPA_OPT_VDEV_NAME		BIT(2)
Packit Bot 867fae
#define VDPA_OPT_VDEV_HANDLE		BIT(3)
Packit Bot 867fae
Packit Bot 867fae
struct vdpa_opts {
Packit Bot 867fae
	uint64_t present; /* flags of present items */
Packit Bot 867fae
	char *mdev_bus_name;
Packit Bot 867fae
	char *mdev_name;
Packit Bot 867fae
	const char *vdev_name;
Packit Bot 867fae
	unsigned int device_id;
Packit Bot 867fae
};
Packit Bot 867fae
Packit Bot 867fae
struct vdpa {
Packit Bot 867fae
	struct mnlu_gen_socket nlg;
Packit Bot 867fae
	struct vdpa_opts opts;
Packit Bot 867fae
	bool json_output;
Packit Bot 867fae
	struct indent_mem *indent;
Packit Bot 867fae
};
Packit Bot 867fae
Packit Bot 867fae
static void pr_out_section_start(struct vdpa *vdpa, const char *name)
Packit Bot 867fae
{
Packit Bot 867fae
	open_json_object(NULL);
Packit Bot 867fae
	open_json_object(name);
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void pr_out_section_end(struct vdpa *vdpa)
Packit Bot 867fae
{
Packit Bot 867fae
	close_json_object();
Packit Bot 867fae
	close_json_object();
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void pr_out_array_start(struct vdpa *vdpa, const char *name)
Packit Bot 867fae
{
Packit Bot 867fae
	if (!vdpa->json_output) {
Packit Bot 867fae
		print_nl();
Packit Bot 867fae
		inc_indent(vdpa->indent);
Packit Bot 867fae
		print_indent(vdpa->indent);
Packit Bot 867fae
	}
Packit Bot 867fae
	open_json_array(PRINT_ANY, name);
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void pr_out_array_end(struct vdpa *vdpa)
Packit Bot 867fae
{
Packit Bot 867fae
	close_json_array(PRINT_JSON, NULL);
Packit Bot 867fae
	if (!vdpa->json_output)
Packit Bot 867fae
		dec_indent(vdpa->indent);
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static const enum mnl_attr_data_type vdpa_policy[VDPA_ATTR_MAX + 1] = {
Packit Bot 867fae
	[VDPA_ATTR_MGMTDEV_BUS_NAME] = MNL_TYPE_NUL_STRING,
Packit Bot 867fae
	[VDPA_ATTR_MGMTDEV_DEV_NAME] = MNL_TYPE_NUL_STRING,
Packit Bot 867fae
	[VDPA_ATTR_DEV_NAME] = MNL_TYPE_STRING,
Packit Bot 867fae
	[VDPA_ATTR_DEV_ID] = MNL_TYPE_U32,
Packit Bot 867fae
	[VDPA_ATTR_DEV_VENDOR_ID] = MNL_TYPE_U32,
Packit Bot 867fae
	[VDPA_ATTR_DEV_MAX_VQS] = MNL_TYPE_U32,
Packit Bot 867fae
	[VDPA_ATTR_DEV_MAX_VQ_SIZE] = MNL_TYPE_U16,
Packit Bot 867fae
};
Packit Bot 867fae
Packit Bot 867fae
static int attr_cb(const struct nlattr *attr, void *data)
Packit Bot 867fae
{
Packit Bot 867fae
	const struct nlattr **tb = data;
Packit Bot 867fae
	int type;
Packit Bot 867fae
Packit Bot 867fae
	if (mnl_attr_type_valid(attr, VDPA_ATTR_MAX) < 0)
Packit Bot 867fae
		return MNL_CB_OK;
Packit Bot 867fae
Packit Bot 867fae
	type = mnl_attr_get_type(attr);
Packit Bot 867fae
	if (mnl_attr_validate(attr, vdpa_policy[type]) < 0)
Packit Bot 867fae
		return MNL_CB_ERROR;
Packit Bot 867fae
Packit Bot 867fae
	tb[type] = attr;
Packit Bot 867fae
	return MNL_CB_OK;
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static int vdpa_argv_handle(struct vdpa *vdpa, int argc, char **argv,
Packit Bot 867fae
			    char **p_mdev_bus_name,
Packit Bot 867fae
			    char **p_mdev_name)
Packit Bot 867fae
{
Packit Bot 867fae
	unsigned int slashcount;
Packit Bot 867fae
	char *str;
Packit Bot 867fae
Packit Bot 867fae
	if (argc <= 0 || *argv == NULL) {
Packit Bot 867fae
		fprintf(stderr,
Packit Bot 867fae
			"vdpa identification (\"mgmtdev_bus_name/mgmtdev_name\") expected\n");
Packit Bot 867fae
		return -EINVAL;
Packit Bot 867fae
	}
Packit Bot 867fae
	str = *argv;
Packit Bot 867fae
	slashcount = get_str_char_count(str, '/');
Packit Bot 867fae
	if (slashcount > 1) {
Packit Bot 867fae
		fprintf(stderr,
Packit Bot 867fae
			"Wrong vdpa mgmtdev identification string format\n");
Packit Bot 867fae
		fprintf(stderr, "Expected \"mgmtdev_bus_name/mgmtdev_name\"\n");
Packit Bot 867fae
		fprintf(stderr, "Expected \"mgmtdev_name\"\n");
Packit Bot 867fae
		return -EINVAL;
Packit Bot 867fae
	}
Packit Bot 867fae
	switch (slashcount) {
Packit Bot 867fae
	case 0:
Packit Bot 867fae
		*p_mdev_bus_name = NULL;
Packit Bot 867fae
		*p_mdev_name = str;
Packit Bot 867fae
		return 0;
Packit Bot 867fae
	case 1:
Packit Bot 867fae
		str_split_by_char(str, p_mdev_bus_name, p_mdev_name, '/');
Packit Bot 867fae
		return 0;
Packit Bot 867fae
	default:
Packit Bot 867fae
		return -EINVAL;
Packit Bot 867fae
	}
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static int vdpa_argv_str(struct vdpa *vdpa, int argc, char **argv,
Packit Bot 867fae
			 const char **p_str)
Packit Bot 867fae
{
Packit Bot 867fae
	if (argc <= 0 || *argv == NULL) {
Packit Bot 867fae
		fprintf(stderr, "String parameter expected\n");
Packit Bot 867fae
		return -EINVAL;
Packit Bot 867fae
	}
Packit Bot 867fae
	*p_str = *argv;
Packit Bot 867fae
	return 0;
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
struct vdpa_args_metadata {
Packit Bot 867fae
	uint64_t o_flag;
Packit Bot 867fae
	const char *err_msg;
Packit Bot 867fae
};
Packit Bot 867fae
Packit Bot 867fae
static const struct vdpa_args_metadata vdpa_args_required[] = {
Packit Bot 867fae
	{VDPA_OPT_VDEV_MGMTDEV_HANDLE, "management device handle not set."},
Packit Bot 867fae
	{VDPA_OPT_VDEV_NAME, "device name is not set."},
Packit Bot 867fae
	{VDPA_OPT_VDEV_HANDLE, "device name is not set."},
Packit Bot 867fae
};
Packit Bot 867fae
Packit Bot 867fae
static int vdpa_args_finding_required_validate(uint64_t o_required,
Packit Bot 867fae
					       uint64_t o_found)
Packit Bot 867fae
{
Packit Bot 867fae
	uint64_t o_flag;
Packit Bot 867fae
	int i;
Packit Bot 867fae
Packit Bot 867fae
	for (i = 0; i < ARRAY_SIZE(vdpa_args_required); i++) {
Packit Bot 867fae
		o_flag = vdpa_args_required[i].o_flag;
Packit Bot 867fae
		if ((o_required & o_flag) && !(o_found & o_flag)) {
Packit Bot 867fae
			fprintf(stderr, "%s\n", vdpa_args_required[i].err_msg);
Packit Bot 867fae
			return -EINVAL;
Packit Bot 867fae
		}
Packit Bot 867fae
	}
Packit Bot 867fae
	if (o_required & ~o_found) {
Packit Bot 867fae
		fprintf(stderr,
Packit Bot 867fae
			"BUG: unknown argument required but not found\n");
Packit Bot 867fae
		return -EINVAL;
Packit Bot 867fae
	}
Packit Bot 867fae
	return 0;
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void vdpa_opts_put(struct nlmsghdr *nlh, struct vdpa *vdpa)
Packit Bot 867fae
{
Packit Bot 867fae
	struct vdpa_opts *opts = &vdpa->opts;
Packit Bot 867fae
Packit Bot 867fae
	if ((opts->present & VDPA_OPT_MGMTDEV_HANDLE) ||
Packit Bot 867fae
	    (opts->present & VDPA_OPT_VDEV_MGMTDEV_HANDLE)) {
Packit Bot 867fae
		if (opts->mdev_bus_name)
Packit Bot 867fae
			mnl_attr_put_strz(nlh, VDPA_ATTR_MGMTDEV_BUS_NAME,
Packit Bot 867fae
					  opts->mdev_bus_name);
Packit Bot 867fae
		mnl_attr_put_strz(nlh, VDPA_ATTR_MGMTDEV_DEV_NAME,
Packit Bot 867fae
				  opts->mdev_name);
Packit Bot 867fae
	}
Packit Bot 867fae
	if ((opts->present & VDPA_OPT_VDEV_NAME) ||
Packit Bot 867fae
	    (opts->present & VDPA_OPT_VDEV_HANDLE))
Packit Bot 867fae
		mnl_attr_put_strz(nlh, VDPA_ATTR_DEV_NAME, opts->vdev_name);
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static int vdpa_argv_parse(struct vdpa *vdpa, int argc, char **argv,
Packit Bot 867fae
			   uint64_t o_required)
Packit Bot 867fae
{
Packit Bot 867fae
	struct vdpa_opts *opts = &vdpa->opts;
Packit Bot 867fae
	uint64_t o_all = o_required;
Packit Bot 867fae
	uint64_t o_found = 0;
Packit Bot 867fae
	int err;
Packit Bot 867fae
Packit Bot 867fae
	if (o_required & VDPA_OPT_MGMTDEV_HANDLE) {
Packit Bot 867fae
		err = vdpa_argv_handle(vdpa, argc, argv, &opts->mdev_bus_name,
Packit Bot 867fae
				       &opts->mdev_name);
Packit Bot 867fae
		if (err)
Packit Bot 867fae
			return err;
Packit Bot 867fae
Packit Bot 867fae
		NEXT_ARG_FWD();
Packit Bot 867fae
		o_found |= VDPA_OPT_MGMTDEV_HANDLE;
Packit Bot 867fae
	} else if (o_required & VDPA_OPT_VDEV_HANDLE) {
Packit Bot 867fae
		err = vdpa_argv_str(vdpa, argc, argv, &opts->vdev_name);
Packit Bot 867fae
		if (err)
Packit Bot 867fae
			return err;
Packit Bot 867fae
Packit Bot 867fae
		NEXT_ARG_FWD();
Packit Bot 867fae
		o_found |= VDPA_OPT_VDEV_HANDLE;
Packit Bot 867fae
	}
Packit Bot 867fae
Packit Bot 867fae
	while (NEXT_ARG_OK()) {
Packit Bot 867fae
		if ((matches(*argv, "name") == 0) &&
Packit Bot 867fae
		    (o_all & VDPA_OPT_VDEV_NAME)) {
Packit Bot 867fae
			const char *namestr;
Packit Bot 867fae
Packit Bot 867fae
			NEXT_ARG_FWD();
Packit Bot 867fae
			err = vdpa_argv_str(vdpa, argc, argv, &namestr);
Packit Bot 867fae
			if (err)
Packit Bot 867fae
				return err;
Packit Bot 867fae
			opts->vdev_name = namestr;
Packit Bot 867fae
			NEXT_ARG_FWD();
Packit Bot 867fae
			o_found |= VDPA_OPT_VDEV_NAME;
Packit Bot 867fae
		} else if ((matches(*argv, "mgmtdev")  == 0) &&
Packit Bot 867fae
			   (o_all & VDPA_OPT_VDEV_MGMTDEV_HANDLE)) {
Packit Bot 867fae
			NEXT_ARG_FWD();
Packit Bot 867fae
			err = vdpa_argv_handle(vdpa, argc, argv,
Packit Bot 867fae
					       &opts->mdev_bus_name,
Packit Bot 867fae
					       &opts->mdev_name);
Packit Bot 867fae
			if (err)
Packit Bot 867fae
				return err;
Packit Bot 867fae
Packit Bot 867fae
			NEXT_ARG_FWD();
Packit Bot 867fae
			o_found |= VDPA_OPT_VDEV_MGMTDEV_HANDLE;
Packit Bot 867fae
		} else {
Packit Bot 867fae
			fprintf(stderr, "Unknown option \"%s\"\n", *argv);
Packit Bot 867fae
			return -EINVAL;
Packit Bot 867fae
		}
Packit Bot 867fae
	}
Packit Bot 867fae
Packit Bot 867fae
	opts->present = o_found;
Packit Bot 867fae
Packit Bot 867fae
	return vdpa_args_finding_required_validate(o_required, o_found);
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static int vdpa_argv_parse_put(struct nlmsghdr *nlh, struct vdpa *vdpa,
Packit Bot 867fae
			       int argc, char **argv,
Packit Bot 867fae
			       uint64_t o_required)
Packit Bot 867fae
{
Packit Bot 867fae
	int err;
Packit Bot 867fae
Packit Bot 867fae
	err = vdpa_argv_parse(vdpa, argc, argv, o_required);
Packit Bot 867fae
	if (err)
Packit Bot 867fae
		return err;
Packit Bot 867fae
	vdpa_opts_put(nlh, vdpa);
Packit Bot 867fae
	return 0;
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void cmd_mgmtdev_help(void)
Packit Bot 867fae
{
Packit Bot 867fae
	fprintf(stderr, "Usage: vdpa mgmtdev show [ DEV ]\n");
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void pr_out_handle_start(struct vdpa *vdpa, struct nlattr **tb)
Packit Bot 867fae
{
Packit Bot 867fae
	const char *mdev_bus_name = NULL;
Packit Bot 867fae
	const char *mdev_name;
Packit Bot 867fae
	SPRINT_BUF(buf);
Packit Bot 867fae
Packit Bot 867fae
	mdev_name = mnl_attr_get_str(tb[VDPA_ATTR_MGMTDEV_DEV_NAME]);
Packit Bot 867fae
	if (tb[VDPA_ATTR_MGMTDEV_BUS_NAME]) {
Packit Bot 867fae
		mdev_bus_name = mnl_attr_get_str(tb[VDPA_ATTR_MGMTDEV_BUS_NAME]);
Packit Bot 867fae
		sprintf(buf, "%s/%s", mdev_bus_name, mdev_name);
Packit Bot 867fae
	} else {
Packit Bot 867fae
		sprintf(buf, "%s", mdev_name);
Packit Bot 867fae
	}
Packit Bot 867fae
Packit Bot 867fae
	if (vdpa->json_output)
Packit Bot 867fae
		open_json_object(buf);
Packit Bot 867fae
	else
Packit Bot 867fae
		printf("%s: ", buf);
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void pr_out_handle_end(struct vdpa *vdpa)
Packit Bot 867fae
{
Packit Bot 867fae
	if (vdpa->json_output)
Packit Bot 867fae
		close_json_object();
Packit Bot 867fae
	else
Packit Bot 867fae
		print_nl();
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void __pr_out_vdev_handle_start(struct vdpa *vdpa, const char *vdev_name)
Packit Bot 867fae
{
Packit Bot 867fae
	SPRINT_BUF(buf);
Packit Bot 867fae
Packit Bot 867fae
	sprintf(buf, "%s", vdev_name);
Packit Bot 867fae
	if (vdpa->json_output)
Packit Bot 867fae
		open_json_object(buf);
Packit Bot 867fae
	else
Packit Bot 867fae
		printf("%s: ", buf);
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void pr_out_vdev_handle_start(struct vdpa *vdpa, struct nlattr **tb)
Packit Bot 867fae
{
Packit Bot 867fae
	const char *vdev_name;
Packit Bot 867fae
Packit Bot 867fae
	vdev_name = mnl_attr_get_str(tb[VDPA_ATTR_DEV_NAME]);
Packit Bot 867fae
	__pr_out_vdev_handle_start(vdpa, vdev_name);
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void pr_out_vdev_handle_end(struct vdpa *vdpa)
Packit Bot 867fae
{
Packit Bot 867fae
	if (vdpa->json_output)
Packit Bot 867fae
		close_json_object();
Packit Bot 867fae
	else
Packit Bot 867fae
		print_nl();
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static struct str_num_map class_map[] = {
Packit Bot 867fae
	{ .str = "net", .num = VIRTIO_ID_NET },
Packit Bot 867fae
	{ .str = "block", .num = VIRTIO_ID_BLOCK },
Packit Bot 867fae
	{ .str = NULL, },
Packit Bot 867fae
};
Packit Bot 867fae
Packit Bot 867fae
static const char *parse_class(int num)
Packit Bot 867fae
{
Packit Bot 867fae
	const char *class;
Packit Bot 867fae
Packit Bot 867fae
	class = str_map_lookup_uint(class_map, num);
Packit Bot 867fae
	return class ? class : "< unknown class >";
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void pr_out_mgmtdev_show(struct vdpa *vdpa, const struct nlmsghdr *nlh,
Packit Bot 867fae
				struct nlattr **tb)
Packit Bot 867fae
{
Packit Bot 867fae
	const char *class;
Packit Bot 867fae
	unsigned int i;
Packit Bot 867fae
Packit Bot 867fae
	pr_out_handle_start(vdpa, tb);
Packit Bot 867fae
Packit Bot 867fae
	if (tb[VDPA_ATTR_MGMTDEV_SUPPORTED_CLASSES]) {
Packit Bot 867fae
		uint64_t classes = mnl_attr_get_u64(tb[VDPA_ATTR_MGMTDEV_SUPPORTED_CLASSES]);
Packit Bot 867fae
Packit Bot 867fae
		pr_out_array_start(vdpa, "supported_classes");
Packit Bot 867fae
Packit Bot 867fae
		for (i = 1; i < 64; i++) {
Packit Bot 867fae
			if ((classes & (1ULL << i)) == 0)
Packit Bot 867fae
				continue;
Packit Bot 867fae
Packit Bot 867fae
			class = parse_class(i);
Packit Bot 867fae
			print_string(PRINT_ANY, NULL, " %s", class);
Packit Bot 867fae
		}
Packit Bot 867fae
		pr_out_array_end(vdpa);
Packit Bot 867fae
	}
Packit Bot 867fae
Packit Bot 867fae
	pr_out_handle_end(vdpa);
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static int cmd_mgmtdev_show_cb(const struct nlmsghdr *nlh, void *data)
Packit Bot 867fae
{
Packit Bot 867fae
	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
Packit Bot 867fae
	struct nlattr *tb[VDPA_ATTR_MAX + 1] = {};
Packit Bot 867fae
	struct vdpa *vdpa = data;
Packit Bot 867fae
Packit Bot 867fae
	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
Packit Bot 867fae
Packit Bot 867fae
	if (!tb[VDPA_ATTR_MGMTDEV_DEV_NAME])
Packit Bot 867fae
		return MNL_CB_ERROR;
Packit Bot 867fae
Packit Bot 867fae
	pr_out_mgmtdev_show(vdpa, nlh, tb);
Packit Bot 867fae
Packit Bot 867fae
	return MNL_CB_OK;
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static int cmd_mgmtdev_show(struct vdpa *vdpa, int argc, char **argv)
Packit Bot 867fae
{
Packit Bot 867fae
	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
Packit Bot 867fae
	struct nlmsghdr *nlh;
Packit Bot 867fae
	int err;
Packit Bot 867fae
Packit Bot 867fae
	if (argc == 0)
Packit Bot 867fae
		flags |= NLM_F_DUMP;
Packit Bot 867fae
Packit Bot 867fae
	nlh = mnlu_gen_socket_cmd_prepare(&vdpa->nlg, VDPA_CMD_MGMTDEV_GET,
Packit Bot 867fae
					  flags);
Packit Bot 867fae
	if (argc > 0) {
Packit Bot 867fae
		err = vdpa_argv_parse_put(nlh, vdpa, argc, argv,
Packit Bot 867fae
					  VDPA_OPT_MGMTDEV_HANDLE);
Packit Bot 867fae
		if (err)
Packit Bot 867fae
			return err;
Packit Bot 867fae
	}
Packit Bot 867fae
Packit Bot 867fae
	pr_out_section_start(vdpa, "mgmtdev");
Packit Bot 867fae
	err = mnlu_gen_socket_sndrcv(&vdpa->nlg, nlh, cmd_mgmtdev_show_cb, vdpa);
Packit Bot 867fae
	pr_out_section_end(vdpa);
Packit Bot 867fae
	return err;
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static int cmd_mgmtdev(struct vdpa *vdpa, int argc, char **argv)
Packit Bot 867fae
{
Packit Bot 867fae
	if (!argc || matches(*argv, "help") == 0) {
Packit Bot 867fae
		cmd_mgmtdev_help();
Packit Bot 867fae
		return 0;
Packit Bot 867fae
	} else if (matches(*argv, "show") == 0 ||
Packit Bot 867fae
		   matches(*argv, "list") == 0) {
Packit Bot 867fae
		return cmd_mgmtdev_show(vdpa, argc - 1, argv + 1);
Packit Bot 867fae
	}
Packit Bot 867fae
	fprintf(stderr, "Command \"%s\" not found\n", *argv);
Packit Bot 867fae
	return -ENOENT;
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void cmd_dev_help(void)
Packit Bot 867fae
{
Packit Bot 867fae
	fprintf(stderr, "Usage: vdpa dev show [ DEV ]\n");
Packit Bot 867fae
	fprintf(stderr, "       vdpa dev add name NAME mgmtdev MANAGEMENTDEV\n");
Packit Bot 867fae
	fprintf(stderr, "       vdpa dev del DEV\n");
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static const char *device_type_name(uint32_t type)
Packit Bot 867fae
{
Packit Bot 867fae
	switch (type) {
Packit Bot 867fae
	case 0x1: return "network";
Packit Bot 867fae
	case 0x2: return "block";
Packit Bot 867fae
	default: return "<unknown type>";
Packit Bot 867fae
	}
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void pr_out_dev(struct vdpa *vdpa, struct nlattr **tb)
Packit Bot 867fae
{
Packit Bot 867fae
	const char *mdev_name = mnl_attr_get_str(tb[VDPA_ATTR_MGMTDEV_DEV_NAME]);
Packit Bot 867fae
	uint32_t device_id = mnl_attr_get_u32(tb[VDPA_ATTR_DEV_ID]);
Packit Bot 867fae
	const char *mdev_bus_name = NULL;
Packit Bot 867fae
	char mgmtdev_buf[128];
Packit Bot 867fae
Packit Bot 867fae
	if (tb[VDPA_ATTR_MGMTDEV_BUS_NAME])
Packit Bot 867fae
		mdev_bus_name = mnl_attr_get_str(tb[VDPA_ATTR_MGMTDEV_BUS_NAME]);
Packit Bot 867fae
Packit Bot 867fae
	if (mdev_bus_name)
Packit Bot 867fae
		sprintf(mgmtdev_buf, "%s/%s", mdev_bus_name, mdev_name);
Packit Bot 867fae
	else
Packit Bot 867fae
		sprintf(mgmtdev_buf, "%s", mdev_name);
Packit Bot 867fae
	pr_out_vdev_handle_start(vdpa, tb);
Packit Bot 867fae
	print_string(PRINT_ANY, "type", "type %s", device_type_name(device_id));
Packit Bot 867fae
	print_string(PRINT_ANY, "mgmtdev", " mgmtdev %s", mgmtdev_buf);
Packit Bot 867fae
Packit Bot 867fae
	if (tb[VDPA_ATTR_DEV_VENDOR_ID])
Packit Bot 867fae
		print_uint(PRINT_ANY, "vendor_id", " vendor_id %u",
Packit Bot 867fae
			   mnl_attr_get_u32(tb[VDPA_ATTR_DEV_VENDOR_ID]));
Packit Bot 867fae
	if (tb[VDPA_ATTR_DEV_MAX_VQS])
Packit Bot 867fae
		print_uint(PRINT_ANY, "max_vqs", " max_vqs %u",
Packit Bot 867fae
			   mnl_attr_get_u32(tb[VDPA_ATTR_DEV_MAX_VQS]));
Packit Bot 867fae
	if (tb[VDPA_ATTR_DEV_MAX_VQ_SIZE])
Packit Bot 867fae
		print_uint(PRINT_ANY, "max_vq_size", " max_vq_size %u",
Packit Bot 867fae
			   mnl_attr_get_u16(tb[VDPA_ATTR_DEV_MAX_VQ_SIZE]));
Packit Bot 867fae
	pr_out_vdev_handle_end(vdpa);
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
Packit Bot 867fae
{
Packit Bot 867fae
	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
Packit Bot 867fae
	struct nlattr *tb[VDPA_ATTR_MAX + 1] = {};
Packit Bot 867fae
	struct vdpa *vdpa = data;
Packit Bot 867fae
Packit Bot 867fae
	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
Packit Bot 867fae
	if (!tb[VDPA_ATTR_MGMTDEV_DEV_NAME] ||
Packit Bot 867fae
	    !tb[VDPA_ATTR_DEV_NAME] || !tb[VDPA_ATTR_DEV_ID])
Packit Bot 867fae
		return MNL_CB_ERROR;
Packit Bot 867fae
	pr_out_dev(vdpa, tb);
Packit Bot 867fae
	return MNL_CB_OK;
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static int cmd_dev_show(struct vdpa *vdpa, int argc, char **argv)
Packit Bot 867fae
{
Packit Bot 867fae
	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
Packit Bot 867fae
	struct nlmsghdr *nlh;
Packit Bot 867fae
	int err;
Packit Bot 867fae
Packit Bot 867fae
	if (argc <= 0)
Packit Bot 867fae
		flags |= NLM_F_DUMP;
Packit Bot 867fae
Packit Bot 867fae
	nlh = mnlu_gen_socket_cmd_prepare(&vdpa->nlg, VDPA_CMD_DEV_GET, flags);
Packit Bot 867fae
	if (argc > 0) {
Packit Bot 867fae
		err = vdpa_argv_parse_put(nlh, vdpa, argc, argv,
Packit Bot 867fae
					  VDPA_OPT_VDEV_HANDLE);
Packit Bot 867fae
		if (err)
Packit Bot 867fae
			return err;
Packit Bot 867fae
	}
Packit Bot 867fae
Packit Bot 867fae
	pr_out_section_start(vdpa, "dev");
Packit Bot 867fae
	err = mnlu_gen_socket_sndrcv(&vdpa->nlg, nlh, cmd_dev_show_cb, vdpa);
Packit Bot 867fae
	pr_out_section_end(vdpa);
Packit Bot 867fae
	return err;
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static int cmd_dev_add(struct vdpa *vdpa, int argc, char **argv)
Packit Bot 867fae
{
Packit Bot 867fae
	struct nlmsghdr *nlh;
Packit Bot 867fae
	int err;
Packit Bot 867fae
Packit Bot 867fae
	nlh = mnlu_gen_socket_cmd_prepare(&vdpa->nlg, VDPA_CMD_DEV_NEW,
Packit Bot 867fae
					  NLM_F_REQUEST | NLM_F_ACK);
Packit Bot 867fae
	err = vdpa_argv_parse_put(nlh, vdpa, argc, argv,
Packit Bot 867fae
				  VDPA_OPT_VDEV_MGMTDEV_HANDLE | VDPA_OPT_VDEV_NAME);
Packit Bot 867fae
	if (err)
Packit Bot 867fae
		return err;
Packit Bot 867fae
Packit Bot 867fae
	return mnlu_gen_socket_sndrcv(&vdpa->nlg, nlh, NULL, NULL);
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static int cmd_dev_del(struct vdpa *vdpa,  int argc, char **argv)
Packit Bot 867fae
{
Packit Bot 867fae
	struct nlmsghdr *nlh;
Packit Bot 867fae
	int err;
Packit Bot 867fae
Packit Bot 867fae
	nlh = mnlu_gen_socket_cmd_prepare(&vdpa->nlg, VDPA_CMD_DEV_DEL,
Packit Bot 867fae
					  NLM_F_REQUEST | NLM_F_ACK);
Packit Bot 867fae
	err = vdpa_argv_parse_put(nlh, vdpa, argc, argv, VDPA_OPT_VDEV_HANDLE);
Packit Bot 867fae
	if (err)
Packit Bot 867fae
		return err;
Packit Bot 867fae
Packit Bot 867fae
	return mnlu_gen_socket_sndrcv(&vdpa->nlg, nlh, NULL, NULL);
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static int cmd_dev(struct vdpa *vdpa, int argc, char **argv)
Packit Bot 867fae
{
Packit Bot 867fae
	if (!argc)
Packit Bot 867fae
		return cmd_dev_show(vdpa, argc - 1, argv + 1);
Packit Bot 867fae
Packit Bot 867fae
	if (matches(*argv, "help") == 0) {
Packit Bot 867fae
		cmd_dev_help();
Packit Bot 867fae
		return 0;
Packit Bot 867fae
	} else if (matches(*argv, "show") == 0 ||
Packit Bot 867fae
		   matches(*argv, "list") == 0) {
Packit Bot 867fae
		return cmd_dev_show(vdpa, argc - 1, argv + 1);
Packit Bot 867fae
	} else if (matches(*argv, "add") == 0) {
Packit Bot 867fae
		return cmd_dev_add(vdpa, argc - 1, argv + 1);
Packit Bot 867fae
	} else if (matches(*argv, "del") == 0) {
Packit Bot 867fae
		return cmd_dev_del(vdpa, argc - 1, argv + 1);
Packit Bot 867fae
	}
Packit Bot 867fae
	fprintf(stderr, "Command \"%s\" not found\n", *argv);
Packit Bot 867fae
	return -ENOENT;
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void help(void)
Packit Bot 867fae
{
Packit Bot 867fae
	fprintf(stderr,
Packit Bot 867fae
		"Usage: vdpa [ OPTIONS ] OBJECT { COMMAND | help }\n"
Packit Bot 867fae
		"where  OBJECT := { mgmtdev | dev }\n"
Packit Bot 867fae
		"       OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] }\n");
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static int vdpa_cmd(struct vdpa *vdpa, int argc, char **argv)
Packit Bot 867fae
{
Packit Bot 867fae
	if (!argc || matches(*argv, "help") == 0) {
Packit Bot 867fae
		help();
Packit Bot 867fae
		return 0;
Packit Bot 867fae
	} else if (matches(*argv, "mgmtdev") == 0) {
Packit Bot 867fae
		return cmd_mgmtdev(vdpa, argc - 1, argv + 1);
Packit Bot 867fae
	} else if (matches(*argv, "dev") == 0) {
Packit Bot 867fae
		return cmd_dev(vdpa, argc - 1, argv + 1);
Packit Bot 867fae
	}
Packit Bot 867fae
	fprintf(stderr, "Object \"%s\" not found\n", *argv);
Packit Bot 867fae
	return -ENOENT;
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static int vdpa_init(struct vdpa *vdpa)
Packit Bot 867fae
{
Packit Bot 867fae
	int err;
Packit Bot 867fae
Packit Bot 867fae
	err = mnlu_gen_socket_open(&vdpa->nlg, VDPA_GENL_NAME,
Packit Bot 867fae
				   VDPA_GENL_VERSION);
Packit Bot 867fae
	if (err) {
Packit Bot 867fae
		fprintf(stderr, "Failed to connect to vdpa Netlink\n");
Packit Bot 867fae
		return -errno;
Packit Bot 867fae
	}
Packit Bot 867fae
	new_json_obj_plain(vdpa->json_output);
Packit Bot 867fae
	return 0;
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void vdpa_fini(struct vdpa *vdpa)
Packit Bot 867fae
{
Packit Bot 867fae
	delete_json_obj_plain();
Packit Bot 867fae
	mnlu_gen_socket_close(&vdpa->nlg);
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static struct vdpa *vdpa_alloc(void)
Packit Bot 867fae
{
Packit Bot 867fae
	struct vdpa *vdpa = calloc(1, sizeof(struct vdpa));
Packit Bot 867fae
Packit Bot 867fae
	if (!vdpa)
Packit Bot 867fae
		return NULL;
Packit Bot 867fae
Packit Bot 867fae
	vdpa->indent = alloc_indent_mem();
Packit Bot 867fae
	if (!vdpa->indent)
Packit Bot 867fae
		goto indent_err;
Packit Bot 867fae
Packit Bot 867fae
	return vdpa;
Packit Bot 867fae
Packit Bot 867fae
indent_err:
Packit Bot 867fae
	free(vdpa);
Packit Bot 867fae
	return NULL;
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
static void vdpa_free(struct vdpa *vdpa)
Packit Bot 867fae
{
Packit Bot 867fae
	free_indent_mem(vdpa->indent);
Packit Bot 867fae
	free(vdpa);
Packit Bot 867fae
}
Packit Bot 867fae
Packit Bot 867fae
int main(int argc, char **argv)
Packit Bot 867fae
{
Packit Bot 867fae
	static const struct option long_options[] = {
Packit Bot 867fae
		{ "Version",		no_argument,	NULL, 'V' },
Packit Bot 867fae
		{ "json",		no_argument,	NULL, 'j' },
Packit Bot 867fae
		{ "pretty",		no_argument,	NULL, 'p' },
Packit Bot 867fae
		{ "help",		no_argument,	NULL, 'h' },
Packit Bot 867fae
		{ NULL, 0, NULL, 0 }
Packit Bot 867fae
	};
Packit Bot 867fae
	struct vdpa *vdpa;
Packit Bot 867fae
	int opt;
Packit Bot 867fae
	int err;
Packit Bot 867fae
	int ret;
Packit Bot 867fae
Packit Bot 867fae
	vdpa = vdpa_alloc();
Packit Bot 867fae
	if (!vdpa) {
Packit Bot 867fae
		fprintf(stderr, "Failed to allocate memory for vdpa\n");
Packit Bot 867fae
		return EXIT_FAILURE;
Packit Bot 867fae
	}
Packit Bot 867fae
Packit Bot 867fae
	while ((opt = getopt_long(argc, argv, "Vjpsh", long_options, NULL)) >= 0) {
Packit Bot 867fae
		switch (opt) {
Packit Bot 867fae
		case 'V':
Packit Bot 867fae
			printf("vdpa utility, iproute2-%s\n", version);
Packit Bot 867fae
			ret = EXIT_SUCCESS;
Packit Bot 867fae
			goto vdpa_free;
Packit Bot 867fae
		case 'j':
Packit Bot 867fae
			vdpa->json_output = true;
Packit Bot 867fae
			break;
Packit Bot 867fae
		case 'p':
Packit Bot 867fae
			pretty = true;
Packit Bot 867fae
			break;
Packit Bot 867fae
		case 'h':
Packit Bot 867fae
			help();
Packit Bot 867fae
			ret = EXIT_SUCCESS;
Packit Bot 867fae
			goto vdpa_free;
Packit Bot 867fae
		default:
Packit Bot 867fae
			fprintf(stderr, "Unknown option.\n");
Packit Bot 867fae
			help();
Packit Bot 867fae
			ret = EXIT_FAILURE;
Packit Bot 867fae
			goto vdpa_free;
Packit Bot 867fae
		}
Packit Bot 867fae
	}
Packit Bot 867fae
Packit Bot 867fae
	argc -= optind;
Packit Bot 867fae
	argv += optind;
Packit Bot 867fae
Packit Bot 867fae
	err = vdpa_init(vdpa);
Packit Bot 867fae
	if (err) {
Packit Bot 867fae
		ret = EXIT_FAILURE;
Packit Bot 867fae
		goto vdpa_free;
Packit Bot 867fae
	}
Packit Bot 867fae
Packit Bot 867fae
	err = vdpa_cmd(vdpa, argc, argv);
Packit Bot 867fae
	if (err) {
Packit Bot 867fae
		ret = EXIT_FAILURE;
Packit Bot 867fae
		goto vdpa_fini;
Packit Bot 867fae
	}
Packit Bot 867fae
Packit Bot 867fae
	ret = EXIT_SUCCESS;
Packit Bot 867fae
Packit Bot 867fae
vdpa_fini:
Packit Bot 867fae
	vdpa_fini(vdpa);
Packit Bot 867fae
vdpa_free:
Packit Bot 867fae
	vdpa_free(vdpa);
Packit Bot 867fae
	return ret;
Packit Bot 867fae
}