X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=examples%2Fvdpa%2Fmain.c;h=7e11ef4e26eb121bb7a1beed86949d19ed385e1e;hb=68629be3a622ee53cd5b40c8447ae9b083ff3f6c;hp=d9a9112b161420a1d4a03a280ace0ec70e130b07;hpb=0265a1980f7b2752b0cba9c476eb6c670b8ad778;p=dpdk.git diff --git a/examples/vdpa/main.c b/examples/vdpa/main.c index d9a9112b16..7e11ef4e26 100644 --- a/examples/vdpa/main.c +++ b/examples/vdpa/main.c @@ -18,7 +18,9 @@ #include #include #include +#include #include +#include "vdpa_blk_compact.h" #define MAX_PATH_LEN 128 #define MAX_VDPA_SAMPLE_PORTS 1024 @@ -26,15 +28,17 @@ struct vdpa_port { char ifname[MAX_PATH_LEN]; - int did; + struct rte_vdpa_device *dev; int vid; uint64_t flags; + int stats_n; + struct rte_vdpa_stat_name *stats_names; + struct rte_vdpa_stat *stats; }; static struct vdpa_port vports[MAX_VDPA_SAMPLE_PORTS]; static char iface[MAX_PATH_LEN]; -static int dev_total; static int devcnt; static int interactive; static int client_mode; @@ -101,16 +105,23 @@ static int new_device(int vid) { char ifname[MAX_PATH_LEN]; + struct rte_device *dev; int i; rte_vhost_get_ifname(vid, ifname, sizeof(ifname)); for (i = 0; i < MAX_VDPA_SAMPLE_PORTS; i++) { - if (strncmp(ifname, vports[i].ifname, MAX_PATH_LEN) == 0) { - printf("\nnew port %s, did: %d\n", - ifname, vports[i].did); - vports[i].vid = vid; - break; + if (strncmp(ifname, vports[i].ifname, MAX_PATH_LEN)) + continue; + + dev = rte_vdpa_get_rte_device(vports[i].dev); + if (!dev) { + RTE_LOG(ERR, VDPA, + "Failed to get generic device for port %d\n", i); + continue; } + printf("\nnew port %s, device : %s\n", ifname, dev->name); + vports[i].vid = vid; + break; } if (i >= MAX_VDPA_SAMPLE_PORTS) @@ -122,30 +133,82 @@ new_device(int vid) static void destroy_device(int vid) { + struct rte_device *dev; char ifname[MAX_PATH_LEN]; int i; rte_vhost_get_ifname(vid, ifname, sizeof(ifname)); for (i = 0; i < MAX_VDPA_SAMPLE_PORTS; i++) { - if (strcmp(ifname, vports[i].ifname) == 0) { - printf("\ndestroy port %s, did: %d\n", - ifname, vports[i].did); - break; + if (strncmp(ifname, vports[i].ifname, MAX_PATH_LEN)) + continue; + + dev = rte_vdpa_get_rte_device(vports[i].dev); + if (!dev) { + RTE_LOG(ERR, VDPA, + "Failed to get generic device for port %d\n", i); + continue; } + + printf("\ndestroy port %s, device: %s\n", ifname, dev->name); + break; } } -static const struct vhost_device_ops vdpa_sample_devops = { +static const struct rte_vhost_device_ops vdpa_sample_devops = { .new_device = new_device, .destroy_device = destroy_device, }; +static int +vdpa_blk_device_set_features_and_protocol(const char *path) +{ + uint64_t protocol_features = 0; + int ret; + + ret = rte_vhost_driver_set_features(path, VHOST_BLK_FEATURES); + if (ret != 0) { + RTE_LOG(ERR, VDPA, + "rte_vhost_driver_set_features for %s failed.\n", + path); + goto out; + } + + ret = rte_vhost_driver_disable_features(path, + VHOST_BLK_DISABLED_FEATURES); + if (ret != 0) { + RTE_LOG(ERR, VDPA, + "rte_vhost_driver_disable_features for %s failed.\n", + path); + goto out; + } + + ret = rte_vhost_driver_get_protocol_features(path, &protocol_features); + if (ret != 0) { + RTE_LOG(ERR, VDPA, + "rte_vhost_driver_get_protocol_features for %s failed.\n", + path); + goto out; + } + + protocol_features |= VHOST_BLK_PROTOCOL_FEATURES; + + ret = rte_vhost_driver_set_protocol_features(path, protocol_features); + if (ret != 0) { + RTE_LOG(ERR, VDPA, + "rte_vhost_driver_set_protocol_features for %s failed.\n", + path); + } + +out: + return ret; +} + static int start_vdpa(struct vdpa_port *vport) { + uint32_t device_type = 0; int ret; char *socket_path = vport->ifname; - int did = vport->did; if (client_mode) vport->flags |= RTE_VHOST_USER_CLIENT; @@ -169,12 +232,22 @@ start_vdpa(struct vdpa_port *vport) "register driver ops failed: %s\n", socket_path); - ret = rte_vhost_driver_attach_vdpa_device(socket_path, did); + ret = rte_vhost_driver_attach_vdpa_device(socket_path, vport->dev); if (ret != 0) rte_exit(EXIT_FAILURE, "attach vdpa device failed: %s\n", socket_path); + ret = rte_vhost_driver_get_vdpa_dev_type(socket_path, &device_type); + if (ret == 0 && device_type == RTE_VHOST_VDPA_DEVICE_TYPE_BLK) { + RTE_LOG(NOTICE, VDPA, "%s is a blk device\n", socket_path); + ret = vdpa_blk_device_set_features_and_protocol(socket_path); + if (ret != 0) + rte_exit(EXIT_FAILURE, + "set vhost blk driver features and protocol features failed: %s\n", + socket_path); + } + if (rte_vhost_driver_start(socket_path) < 0) rte_exit(EXIT_FAILURE, "start vhost driver failed: %s\n", @@ -199,13 +272,17 @@ close_vdpa(struct vdpa_port *vport) RTE_LOG(ERR, VDPA, "Fail to unregister vhost driver for %s.\n", socket_path); + if (vport->stats_names) { + rte_free(vport->stats_names); + vport->stats_names = NULL; + } } static void vdpa_sample_quit(void) { int i; - for (i = 0; i < RTE_MIN(MAX_VDPA_SAMPLE_PORTS, dev_total); i++) { + for (i = 0; i < RTE_MIN(MAX_VDPA_SAMPLE_PORTS, devcnt); i++) { if (vports[i].ifname[0] != '\0') close_vdpa(&vports[i]); } @@ -240,6 +317,7 @@ static void cmd_help_parsed(__rte_unused void *parsed_result, " help : Show interactive instructions.\n" " list : list all available vdpa devices.\n" " create : create a new vdpa port.\n" + " stats : show statistics of virtio queue, 0xffff for all.\n" " quit : exit vdpa sample app.\n" ); } @@ -267,34 +345,31 @@ static void cmd_list_vdpa_devices_parsed( struct cmdline *cl, __rte_unused void *data) { - int did; uint32_t queue_num; uint64_t features; struct rte_vdpa_device *vdev; - struct rte_pci_addr addr; + struct rte_device *dev; + struct rte_dev_iterator dev_iter; - cmdline_printf(cl, "device id\tdevice address\tqueue num\tsupported features\n"); - for (did = 0; did < dev_total; did++) { - vdev = rte_vdpa_get_device(did); + cmdline_printf(cl, "device name\tqueue num\tsupported features\n"); + RTE_DEV_FOREACH(dev, "class=vdpa", &dev_iter) { + vdev = rte_vdpa_find_device_by_name(dev->name); if (!vdev) continue; - if (vdev->ops->get_queue_num(did, &queue_num) < 0) { + if (rte_vdpa_get_queue_num(vdev, &queue_num) < 0) { RTE_LOG(ERR, VDPA, "failed to get vdpa queue number " - "for device id %d.\n", did); + "for device %s.\n", dev->name); continue; } - if (vdev->ops->get_features(did, &features) < 0) { + if (rte_vdpa_get_features(vdev, &features) < 0) { RTE_LOG(ERR, VDPA, "failed to get vdpa features " - "for device id %d.\n", did); + "for device %s.\n", dev->name); continue; } - addr = vdev->addr.pci_addr; - cmdline_printf(cl, - "%d\t\t" PCI_PRI_FMT "\t%" PRIu32 "\t\t0x%" PRIx64 "\n", - did, addr.domain, addr.bus, addr.devid, - addr.function, queue_num, features); + cmdline_printf(cl, "%s\t\t%" PRIu32 "\t\t0x%" PRIx64 "\n", + dev->name, queue_num, features); } } @@ -322,23 +397,18 @@ static void cmd_create_vdpa_port_parsed(void *parsed_result, struct cmdline *cl, __rte_unused void *data) { - int did; + struct rte_vdpa_device *dev; struct cmd_create_result *res = parsed_result; - struct rte_vdpa_dev_addr addr; rte_strscpy(vports[devcnt].ifname, res->socket_path, MAX_PATH_LEN); - if (rte_pci_addr_parse(res->bdf, &addr.pci_addr) != 0) { - cmdline_printf(cl, "Unable to parse the given bdf.\n"); - return; - } - addr.type = VDPA_ADDR_PCI; - did = rte_vdpa_find_device_id(&addr); - if (did < 0) { - cmdline_printf(cl, "Unable to find vdpa device id.\n"); + dev = rte_vdpa_find_device_by_name(res->bdf); + if (dev == NULL) { + cmdline_printf(cl, "Unable to find vdpa device id for %s.\n", + res->bdf); return; } - vports[devcnt].did = did; + vports[devcnt].dev = dev; if (start_vdpa(&vports[devcnt]) == 0) devcnt++; @@ -363,6 +433,114 @@ cmdline_parse_inst_t cmd_create_vdpa_port = { }, }; +/* *** STATS *** */ +struct cmd_stats_result { + cmdline_fixed_string_t stats; + cmdline_fixed_string_t bdf; + uint16_t qid; +}; + +static void cmd_device_stats_parsed(void *parsed_result, struct cmdline *cl, + __rte_unused void *data) +{ + struct cmd_stats_result *res = parsed_result; + struct rte_vdpa_device *vdev = rte_vdpa_find_device_by_name(res->bdf); + struct vdpa_port *vport = NULL; + uint32_t first, last; + int i; + + if (!vdev) { + RTE_LOG(ERR, VDPA, "Invalid device: %s.\n", + res->bdf); + return; + } + for (i = 0; i < RTE_MIN(MAX_VDPA_SAMPLE_PORTS, devcnt); i++) { + if (vports[i].dev == vdev) { + vport = &vports[i]; + break; + } + } + if (!vport) { + RTE_LOG(ERR, VDPA, "Device %s was not created.\n", res->bdf); + return; + } + if (res->qid == 0xFFFF) { + first = 0; + last = rte_vhost_get_vring_num(vport->vid); + if (last == 0) { + RTE_LOG(ERR, VDPA, "Failed to get num of actual virtqs" + " for device %s.\n", res->bdf); + return; + } + last--; + } else { + first = res->qid; + last = res->qid; + } + if (!vport->stats_names) { + vport->stats_n = rte_vdpa_get_stats_names(vport->dev, NULL, 0); + if (vport->stats_n <= 0) { + RTE_LOG(ERR, VDPA, "Failed to get names number of " + "device %s stats.\n", res->bdf); + return; + } + vport->stats_names = rte_zmalloc(NULL, + (sizeof(*vport->stats_names) + sizeof(*vport->stats)) * + vport->stats_n, 0); + if (!vport->stats_names) { + RTE_LOG(ERR, VDPA, "Failed to allocate memory for stat" + " names of device %s.\n", res->bdf); + return; + } + i = rte_vdpa_get_stats_names(vport->dev, vport->stats_names, + vport->stats_n); + if (vport->stats_n != i) { + RTE_LOG(ERR, VDPA, "Failed to get names of device %s " + "stats.\n", res->bdf); + return; + } + vport->stats = (struct rte_vdpa_stat *) + (vport->stats_names + vport->stats_n); + } + cmdline_printf(cl, "\nDevice %s:\n", res->bdf); + for (; first <= last; first++) { + memset(vport->stats, 0, sizeof(*vport->stats) * vport->stats_n); + if (rte_vdpa_get_stats(vport->dev, (int)first, vport->stats, + vport->stats_n) <= 0) { + RTE_LOG(ERR, VDPA, "Failed to get vdpa queue statistics" + " for device %s qid %d.\n", res->bdf, + (int)first); + return; + } + cmdline_printf(cl, "\tVirtq %" PRIu32 ":\n", first); + for (i = 0; i < vport->stats_n; ++i) { + cmdline_printf(cl, "\t\t%-*s %-16" PRIu64 "\n", + RTE_VDPA_STATS_NAME_SIZE, + vport->stats_names[vport->stats[i].id].name, + vport->stats[i].value); + } + } +} + +cmdline_parse_token_string_t cmd_device_stats_ = + TOKEN_STRING_INITIALIZER(struct cmd_stats_result, stats, "stats"); +cmdline_parse_token_string_t cmd_device_bdf = + TOKEN_STRING_INITIALIZER(struct cmd_stats_result, bdf, NULL); +cmdline_parse_token_num_t cmd_queue_id = + TOKEN_NUM_INITIALIZER(struct cmd_stats_result, qid, RTE_UINT32); + +cmdline_parse_inst_t cmd_device_stats = { + .f = cmd_device_stats_parsed, + .data = NULL, + .help_str = "stats: show device statistics", + .tokens = { + (void *)&cmd_device_stats_, + (void *)&cmd_device_bdf, + (void *)&cmd_queue_id, + NULL, + }, +}; + /* *** QUIT *** */ struct cmd_quit_result { cmdline_fixed_string_t quit; @@ -392,6 +570,7 @@ cmdline_parse_ctx_t main_ctx[] = { (cmdline_parse_inst_t *)&cmd_help, (cmdline_parse_inst_t *)&cmd_list_vdpa_devices, (cmdline_parse_inst_t *)&cmd_create_vdpa_port, + (cmdline_parse_inst_t *)&cmd_device_stats, (cmdline_parse_inst_t *)&cmd_quit, NULL, }; @@ -400,9 +579,11 @@ int main(int argc, char *argv[]) { char ch; - int i; int ret; struct cmdline *cl; + struct rte_vdpa_device *vdev; + struct rte_device *dev; + struct rte_dev_iterator dev_iter; ret = rte_eal_init(argc, argv); if (ret < 0) @@ -410,10 +591,6 @@ main(int argc, char *argv[]) argc -= ret; argv += ret; - dev_total = rte_vdpa_get_device_num(); - if (dev_total <= 0) - rte_exit(EXIT_FAILURE, "No available vdpa device found\n"); - signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); @@ -428,13 +605,18 @@ main(int argc, char *argv[]) cmdline_interact(cl); cmdline_stdin_exit(cl); } else { - for (i = 0; i < RTE_MIN(MAX_VDPA_SAMPLE_PORTS, dev_total); - i++) { - vports[i].did = i; - snprintf(vports[i].ifname, MAX_PATH_LEN, "%s%d", - iface, i); + RTE_DEV_FOREACH(dev, "class=vdpa", &dev_iter) { + vdev = rte_vdpa_find_device_by_name(dev->name); + if (vdev == NULL) { + rte_panic("Failed to find vDPA dev for %s\n", + dev->name); + } + vports[devcnt].dev = vdev; + snprintf(vports[devcnt].ifname, MAX_PATH_LEN, "%s%d", + iface, devcnt); - start_vdpa(&vports[i]); + start_vdpa(&vports[devcnt]); + devcnt++; } printf("enter \'q\' to quit\n"); @@ -450,5 +632,8 @@ main(int argc, char *argv[]) vdpa_sample_quit(); } + /* clean up the EAL */ + rte_eal_cleanup(); + return 0; }