1edbed86dSXiaolong Ye /* SPDX-License-Identifier: BSD-3-Clause 2edbed86dSXiaolong Ye * Copyright(c) 2018 Intel Corporation 3edbed86dSXiaolong Ye */ 4edbed86dSXiaolong Ye 5edbed86dSXiaolong Ye #include <getopt.h> 6edbed86dSXiaolong Ye #include <signal.h> 7edbed86dSXiaolong Ye #include <stdint.h> 8edbed86dSXiaolong Ye #include <string.h> 9edbed86dSXiaolong Ye #include <unistd.h> 10edbed86dSXiaolong Ye 11edbed86dSXiaolong Ye #include <rte_ethdev.h> 12edbed86dSXiaolong Ye #include <rte_malloc.h> 13edbed86dSXiaolong Ye #include <rte_vhost.h> 14edbed86dSXiaolong Ye #include <rte_vdpa.h> 15edbed86dSXiaolong Ye #include <rte_pci.h> 16edbed86dSXiaolong Ye #include <rte_string_fns.h> 17edbed86dSXiaolong Ye 18edbed86dSXiaolong Ye #include <cmdline_parse.h> 19edbed86dSXiaolong Ye #include <cmdline_socket.h> 20edbed86dSXiaolong Ye #include <cmdline_parse_string.h> 216505865aSMatan Azrad #include <cmdline_parse_num.h> 22edbed86dSXiaolong Ye #include <cmdline.h> 23edbed86dSXiaolong Ye 24edbed86dSXiaolong Ye #define MAX_PATH_LEN 128 25edbed86dSXiaolong Ye #define MAX_VDPA_SAMPLE_PORTS 1024 26edbed86dSXiaolong Ye #define RTE_LOGTYPE_VDPA RTE_LOGTYPE_USER1 27edbed86dSXiaolong Ye 28edbed86dSXiaolong Ye struct vdpa_port { 29edbed86dSXiaolong Ye char ifname[MAX_PATH_LEN]; 300f700f90SMaxime Coquelin struct rte_vdpa_device *dev; 31edbed86dSXiaolong Ye int vid; 32edbed86dSXiaolong Ye uint64_t flags; 336505865aSMatan Azrad int stats_n; 346505865aSMatan Azrad struct rte_vdpa_stat_name *stats_names; 356505865aSMatan Azrad struct rte_vdpa_stat *stats; 36edbed86dSXiaolong Ye }; 37edbed86dSXiaolong Ye 38edbed86dSXiaolong Ye static struct vdpa_port vports[MAX_VDPA_SAMPLE_PORTS]; 39edbed86dSXiaolong Ye 40edbed86dSXiaolong Ye static char iface[MAX_PATH_LEN]; 41edbed86dSXiaolong Ye static int devcnt; 42edbed86dSXiaolong Ye static int interactive; 43edbed86dSXiaolong Ye static int client_mode; 44edbed86dSXiaolong Ye 45edbed86dSXiaolong Ye /* display usage */ 46edbed86dSXiaolong Ye static void 47edbed86dSXiaolong Ye vdpa_usage(const char *prgname) 48edbed86dSXiaolong Ye { 49edbed86dSXiaolong Ye printf("Usage: %s [EAL options] -- " 50edbed86dSXiaolong Ye " --interactive|-i: run in interactive mode.\n" 51edbed86dSXiaolong Ye " --iface <path>: specify the path prefix of the socket files, e.g. /tmp/vhost-user-.\n" 52edbed86dSXiaolong Ye " --client: register a vhost-user socket as client mode.\n", 53edbed86dSXiaolong Ye prgname); 54edbed86dSXiaolong Ye } 55edbed86dSXiaolong Ye 56edbed86dSXiaolong Ye static int 57edbed86dSXiaolong Ye parse_args(int argc, char **argv) 58edbed86dSXiaolong Ye { 59edbed86dSXiaolong Ye static const char *short_option = "i"; 60edbed86dSXiaolong Ye static struct option long_option[] = { 61edbed86dSXiaolong Ye {"iface", required_argument, NULL, 0}, 62edbed86dSXiaolong Ye {"interactive", no_argument, &interactive, 1}, 63edbed86dSXiaolong Ye {"client", no_argument, &client_mode, 1}, 64edbed86dSXiaolong Ye {NULL, 0, 0, 0}, 65edbed86dSXiaolong Ye }; 66edbed86dSXiaolong Ye int opt, idx; 67edbed86dSXiaolong Ye char *prgname = argv[0]; 68edbed86dSXiaolong Ye 69edbed86dSXiaolong Ye while ((opt = getopt_long(argc, argv, short_option, long_option, &idx)) 70edbed86dSXiaolong Ye != EOF) { 71edbed86dSXiaolong Ye switch (opt) { 72edbed86dSXiaolong Ye case 'i': 73edbed86dSXiaolong Ye printf("Interactive-mode selected\n"); 74edbed86dSXiaolong Ye interactive = 1; 75edbed86dSXiaolong Ye break; 76edbed86dSXiaolong Ye /* long options */ 77edbed86dSXiaolong Ye case 0: 78edbed86dSXiaolong Ye if (strncmp(long_option[idx].name, "iface", 79edbed86dSXiaolong Ye MAX_PATH_LEN) == 0) { 80edbed86dSXiaolong Ye rte_strscpy(iface, optarg, MAX_PATH_LEN); 81edbed86dSXiaolong Ye printf("iface %s\n", iface); 82edbed86dSXiaolong Ye } 83edbed86dSXiaolong Ye if (!strcmp(long_option[idx].name, "interactive")) { 84edbed86dSXiaolong Ye printf("Interactive-mode selected\n"); 85edbed86dSXiaolong Ye interactive = 1; 86edbed86dSXiaolong Ye } 87edbed86dSXiaolong Ye break; 88edbed86dSXiaolong Ye 89edbed86dSXiaolong Ye default: 90edbed86dSXiaolong Ye vdpa_usage(prgname); 91edbed86dSXiaolong Ye return -1; 92edbed86dSXiaolong Ye } 93edbed86dSXiaolong Ye } 94edbed86dSXiaolong Ye 95edbed86dSXiaolong Ye if (iface[0] == '\0' && interactive == 0) { 96edbed86dSXiaolong Ye vdpa_usage(prgname); 97edbed86dSXiaolong Ye return -1; 98edbed86dSXiaolong Ye } 99edbed86dSXiaolong Ye 100edbed86dSXiaolong Ye return 0; 101edbed86dSXiaolong Ye } 102edbed86dSXiaolong Ye 103edbed86dSXiaolong Ye static int 104edbed86dSXiaolong Ye new_device(int vid) 105edbed86dSXiaolong Ye { 106edbed86dSXiaolong Ye char ifname[MAX_PATH_LEN]; 1070f700f90SMaxime Coquelin struct rte_device *dev; 108edbed86dSXiaolong Ye int i; 109edbed86dSXiaolong Ye 110edbed86dSXiaolong Ye rte_vhost_get_ifname(vid, ifname, sizeof(ifname)); 111edbed86dSXiaolong Ye for (i = 0; i < MAX_VDPA_SAMPLE_PORTS; i++) { 1120f700f90SMaxime Coquelin if (strncmp(ifname, vports[i].ifname, MAX_PATH_LEN)) 1130f700f90SMaxime Coquelin continue; 1140f700f90SMaxime Coquelin 1150f700f90SMaxime Coquelin dev = rte_vdpa_get_rte_device(vports[i].dev); 1160f700f90SMaxime Coquelin if (!dev) { 1170f700f90SMaxime Coquelin RTE_LOG(ERR, VDPA, 1180f700f90SMaxime Coquelin "Failed to get generic device for port %d\n", i); 1190f700f90SMaxime Coquelin continue; 1200f700f90SMaxime Coquelin } 1210f700f90SMaxime Coquelin printf("\nnew port %s, device : %s\n", ifname, dev->name); 122edbed86dSXiaolong Ye vports[i].vid = vid; 123edbed86dSXiaolong Ye break; 124edbed86dSXiaolong Ye } 125edbed86dSXiaolong Ye 126edbed86dSXiaolong Ye if (i >= MAX_VDPA_SAMPLE_PORTS) 127edbed86dSXiaolong Ye return -1; 128edbed86dSXiaolong Ye 129edbed86dSXiaolong Ye return 0; 130edbed86dSXiaolong Ye } 131edbed86dSXiaolong Ye 132edbed86dSXiaolong Ye static void 133edbed86dSXiaolong Ye destroy_device(int vid) 134edbed86dSXiaolong Ye { 1350f700f90SMaxime Coquelin struct rte_device *dev; 136edbed86dSXiaolong Ye char ifname[MAX_PATH_LEN]; 137edbed86dSXiaolong Ye int i; 138edbed86dSXiaolong Ye 139edbed86dSXiaolong Ye rte_vhost_get_ifname(vid, ifname, sizeof(ifname)); 140edbed86dSXiaolong Ye for (i = 0; i < MAX_VDPA_SAMPLE_PORTS; i++) { 1410f700f90SMaxime Coquelin if (strncmp(ifname, vports[i].ifname, MAX_PATH_LEN)) 1420f700f90SMaxime Coquelin continue; 1430f700f90SMaxime Coquelin 1440f700f90SMaxime Coquelin dev = rte_vdpa_get_rte_device(vports[i].dev); 1450f700f90SMaxime Coquelin if (!dev) { 1460f700f90SMaxime Coquelin RTE_LOG(ERR, VDPA, 1470f700f90SMaxime Coquelin "Failed to get generic device for port %d\n", i); 1480f700f90SMaxime Coquelin continue; 149edbed86dSXiaolong Ye } 1500f700f90SMaxime Coquelin 1510f700f90SMaxime Coquelin printf("\ndestroy port %s, device: %s\n", ifname, dev->name); 1520f700f90SMaxime Coquelin break; 153edbed86dSXiaolong Ye } 154edbed86dSXiaolong Ye } 155edbed86dSXiaolong Ye 156edbed86dSXiaolong Ye static const struct vhost_device_ops vdpa_sample_devops = { 157edbed86dSXiaolong Ye .new_device = new_device, 158edbed86dSXiaolong Ye .destroy_device = destroy_device, 159edbed86dSXiaolong Ye }; 160edbed86dSXiaolong Ye 161edbed86dSXiaolong Ye static int 162edbed86dSXiaolong Ye start_vdpa(struct vdpa_port *vport) 163edbed86dSXiaolong Ye { 164edbed86dSXiaolong Ye int ret; 165edbed86dSXiaolong Ye char *socket_path = vport->ifname; 166edbed86dSXiaolong Ye 167edbed86dSXiaolong Ye if (client_mode) 168edbed86dSXiaolong Ye vport->flags |= RTE_VHOST_USER_CLIENT; 169edbed86dSXiaolong Ye 170edbed86dSXiaolong Ye if (access(socket_path, F_OK) != -1 && !client_mode) { 171edbed86dSXiaolong Ye RTE_LOG(ERR, VDPA, 172edbed86dSXiaolong Ye "%s exists, please remove it or specify another file and try again.\n", 173edbed86dSXiaolong Ye socket_path); 174edbed86dSXiaolong Ye return -1; 175edbed86dSXiaolong Ye } 176edbed86dSXiaolong Ye ret = rte_vhost_driver_register(socket_path, vport->flags); 177edbed86dSXiaolong Ye if (ret != 0) 178edbed86dSXiaolong Ye rte_exit(EXIT_FAILURE, 179edbed86dSXiaolong Ye "register driver failed: %s\n", 180edbed86dSXiaolong Ye socket_path); 181edbed86dSXiaolong Ye 182edbed86dSXiaolong Ye ret = rte_vhost_driver_callback_register(socket_path, 183edbed86dSXiaolong Ye &vdpa_sample_devops); 184edbed86dSXiaolong Ye if (ret != 0) 185edbed86dSXiaolong Ye rte_exit(EXIT_FAILURE, 186edbed86dSXiaolong Ye "register driver ops failed: %s\n", 187edbed86dSXiaolong Ye socket_path); 188edbed86dSXiaolong Ye 1890f700f90SMaxime Coquelin ret = rte_vhost_driver_attach_vdpa_device(socket_path, vport->dev); 190edbed86dSXiaolong Ye if (ret != 0) 191edbed86dSXiaolong Ye rte_exit(EXIT_FAILURE, 192edbed86dSXiaolong Ye "attach vdpa device failed: %s\n", 193edbed86dSXiaolong Ye socket_path); 194edbed86dSXiaolong Ye 195edbed86dSXiaolong Ye if (rte_vhost_driver_start(socket_path) < 0) 196edbed86dSXiaolong Ye rte_exit(EXIT_FAILURE, 197edbed86dSXiaolong Ye "start vhost driver failed: %s\n", 198edbed86dSXiaolong Ye socket_path); 199edbed86dSXiaolong Ye return 0; 200edbed86dSXiaolong Ye } 201edbed86dSXiaolong Ye 202edbed86dSXiaolong Ye static void 203edbed86dSXiaolong Ye close_vdpa(struct vdpa_port *vport) 204edbed86dSXiaolong Ye { 205edbed86dSXiaolong Ye int ret; 206edbed86dSXiaolong Ye char *socket_path = vport->ifname; 207edbed86dSXiaolong Ye 208edbed86dSXiaolong Ye ret = rte_vhost_driver_detach_vdpa_device(socket_path); 209edbed86dSXiaolong Ye if (ret != 0) 210edbed86dSXiaolong Ye RTE_LOG(ERR, VDPA, 211edbed86dSXiaolong Ye "detach vdpa device failed: %s\n", 212edbed86dSXiaolong Ye socket_path); 213edbed86dSXiaolong Ye 214edbed86dSXiaolong Ye ret = rte_vhost_driver_unregister(socket_path); 215edbed86dSXiaolong Ye if (ret != 0) 216edbed86dSXiaolong Ye RTE_LOG(ERR, VDPA, 217edbed86dSXiaolong Ye "Fail to unregister vhost driver for %s.\n", 218edbed86dSXiaolong Ye socket_path); 2196505865aSMatan Azrad if (vport->stats_names) { 2206505865aSMatan Azrad rte_free(vport->stats_names); 2216505865aSMatan Azrad vport->stats_names = NULL; 2226505865aSMatan Azrad } 223edbed86dSXiaolong Ye } 224edbed86dSXiaolong Ye 225edbed86dSXiaolong Ye static void 226edbed86dSXiaolong Ye vdpa_sample_quit(void) 227edbed86dSXiaolong Ye { 228edbed86dSXiaolong Ye int i; 229*fbe6be6eSMaxime Coquelin for (i = 0; i < RTE_MIN(MAX_VDPA_SAMPLE_PORTS, devcnt); i++) { 230edbed86dSXiaolong Ye if (vports[i].ifname[0] != '\0') 231edbed86dSXiaolong Ye close_vdpa(&vports[i]); 232edbed86dSXiaolong Ye } 233edbed86dSXiaolong Ye } 234edbed86dSXiaolong Ye 235edbed86dSXiaolong Ye static void 236edbed86dSXiaolong Ye signal_handler(int signum) 237edbed86dSXiaolong Ye { 238edbed86dSXiaolong Ye if (signum == SIGINT || signum == SIGTERM) { 239edbed86dSXiaolong Ye printf("\nSignal %d received, preparing to exit...\n", signum); 240edbed86dSXiaolong Ye vdpa_sample_quit(); 241edbed86dSXiaolong Ye exit(0); 242edbed86dSXiaolong Ye } 243edbed86dSXiaolong Ye } 244edbed86dSXiaolong Ye 245edbed86dSXiaolong Ye /* interactive cmds */ 246edbed86dSXiaolong Ye 247edbed86dSXiaolong Ye /* *** Help command with introduction. *** */ 248edbed86dSXiaolong Ye struct cmd_help_result { 249edbed86dSXiaolong Ye cmdline_fixed_string_t help; 250edbed86dSXiaolong Ye }; 251edbed86dSXiaolong Ye 252f2fc83b4SThomas Monjalon static void cmd_help_parsed(__rte_unused void *parsed_result, 253edbed86dSXiaolong Ye struct cmdline *cl, 254f2fc83b4SThomas Monjalon __rte_unused void *data) 255edbed86dSXiaolong Ye { 256edbed86dSXiaolong Ye cmdline_printf( 257edbed86dSXiaolong Ye cl, 258edbed86dSXiaolong Ye "\n" 259edbed86dSXiaolong Ye "The following commands are currently available:\n\n" 260edbed86dSXiaolong Ye "Control:\n" 261edbed86dSXiaolong Ye " help : Show interactive instructions.\n" 262edbed86dSXiaolong Ye " list : list all available vdpa devices.\n" 263edbed86dSXiaolong Ye " create <socket file> <vdev addr> : create a new vdpa port.\n" 2646505865aSMatan Azrad " stats <device ID> <virtio queue ID> : show statistics of virtio queue, 0xffff for all.\n" 265edbed86dSXiaolong Ye " quit : exit vdpa sample app.\n" 266edbed86dSXiaolong Ye ); 267edbed86dSXiaolong Ye } 268edbed86dSXiaolong Ye 269edbed86dSXiaolong Ye cmdline_parse_token_string_t cmd_help_help = 270edbed86dSXiaolong Ye TOKEN_STRING_INITIALIZER(struct cmd_help_result, help, "help"); 271edbed86dSXiaolong Ye 272edbed86dSXiaolong Ye cmdline_parse_inst_t cmd_help = { 273edbed86dSXiaolong Ye .f = cmd_help_parsed, 274edbed86dSXiaolong Ye .data = NULL, 275edbed86dSXiaolong Ye .help_str = "show help", 276edbed86dSXiaolong Ye .tokens = { 277edbed86dSXiaolong Ye (void *)&cmd_help_help, 278edbed86dSXiaolong Ye NULL, 279edbed86dSXiaolong Ye }, 280edbed86dSXiaolong Ye }; 281edbed86dSXiaolong Ye 282edbed86dSXiaolong Ye /* *** List all available vdpa devices *** */ 283edbed86dSXiaolong Ye struct cmd_list_result { 284edbed86dSXiaolong Ye cmdline_fixed_string_t action; 285edbed86dSXiaolong Ye }; 286edbed86dSXiaolong Ye 287edbed86dSXiaolong Ye static void cmd_list_vdpa_devices_parsed( 288f2fc83b4SThomas Monjalon __rte_unused void *parsed_result, 289edbed86dSXiaolong Ye struct cmdline *cl, 290f2fc83b4SThomas Monjalon __rte_unused void *data) 291edbed86dSXiaolong Ye { 292edbed86dSXiaolong Ye uint32_t queue_num; 293edbed86dSXiaolong Ye uint64_t features; 294edbed86dSXiaolong Ye struct rte_vdpa_device *vdev; 29538f8ab0bSMaxime Coquelin struct rte_device *dev; 29638f8ab0bSMaxime Coquelin struct rte_dev_iterator dev_iter; 297edbed86dSXiaolong Ye 2980f700f90SMaxime Coquelin cmdline_printf(cl, "device name\tqueue num\tsupported features\n"); 29938f8ab0bSMaxime Coquelin RTE_DEV_FOREACH(dev, "class=vdpa", &dev_iter) { 3000f700f90SMaxime Coquelin vdev = rte_vdpa_find_device_by_name(dev->name); 301edbed86dSXiaolong Ye if (!vdev) 302edbed86dSXiaolong Ye continue; 30371296e7bSMaxime Coquelin if (rte_vdpa_get_queue_num(vdev, &queue_num) < 0) { 304edbed86dSXiaolong Ye RTE_LOG(ERR, VDPA, 305edbed86dSXiaolong Ye "failed to get vdpa queue number " 3060f700f90SMaxime Coquelin "for device %s.\n", dev->name); 307edbed86dSXiaolong Ye continue; 308edbed86dSXiaolong Ye } 30971296e7bSMaxime Coquelin if (rte_vdpa_get_features(vdev, &features) < 0) { 310edbed86dSXiaolong Ye RTE_LOG(ERR, VDPA, 311edbed86dSXiaolong Ye "failed to get vdpa features " 3120f700f90SMaxime Coquelin "for device %s.\n", dev->name); 313edbed86dSXiaolong Ye continue; 314edbed86dSXiaolong Ye } 3150f700f90SMaxime Coquelin cmdline_printf(cl, "%s\t\t%" PRIu32 "\t\t0x%" PRIx64 "\n", 3160f700f90SMaxime Coquelin dev->name, queue_num, features); 317edbed86dSXiaolong Ye } 318edbed86dSXiaolong Ye } 319edbed86dSXiaolong Ye 320edbed86dSXiaolong Ye cmdline_parse_token_string_t cmd_action_list = 321edbed86dSXiaolong Ye TOKEN_STRING_INITIALIZER(struct cmd_list_result, action, "list"); 322edbed86dSXiaolong Ye 323edbed86dSXiaolong Ye cmdline_parse_inst_t cmd_list_vdpa_devices = { 324edbed86dSXiaolong Ye .f = cmd_list_vdpa_devices_parsed, 325edbed86dSXiaolong Ye .data = NULL, 326edbed86dSXiaolong Ye .help_str = "list all available vdpa devices", 327edbed86dSXiaolong Ye .tokens = { 328edbed86dSXiaolong Ye (void *)&cmd_action_list, 329edbed86dSXiaolong Ye NULL, 330edbed86dSXiaolong Ye }, 331edbed86dSXiaolong Ye }; 332edbed86dSXiaolong Ye 333edbed86dSXiaolong Ye /* *** Create new vdpa port *** */ 334edbed86dSXiaolong Ye struct cmd_create_result { 335edbed86dSXiaolong Ye cmdline_fixed_string_t action; 336edbed86dSXiaolong Ye cmdline_fixed_string_t socket_path; 337edbed86dSXiaolong Ye cmdline_fixed_string_t bdf; 338edbed86dSXiaolong Ye }; 339edbed86dSXiaolong Ye 340edbed86dSXiaolong Ye static void cmd_create_vdpa_port_parsed(void *parsed_result, 341edbed86dSXiaolong Ye struct cmdline *cl, 342f2fc83b4SThomas Monjalon __rte_unused void *data) 343edbed86dSXiaolong Ye { 3440f700f90SMaxime Coquelin struct rte_vdpa_device *dev; 345edbed86dSXiaolong Ye struct cmd_create_result *res = parsed_result; 346edbed86dSXiaolong Ye 347edbed86dSXiaolong Ye rte_strscpy(vports[devcnt].ifname, res->socket_path, MAX_PATH_LEN); 3480f700f90SMaxime Coquelin dev = rte_vdpa_find_device_by_name(res->bdf); 3490f700f90SMaxime Coquelin if (dev == NULL) { 35038f8ab0bSMaxime Coquelin cmdline_printf(cl, "Unable to find vdpa device id for %s.\n", 35138f8ab0bSMaxime Coquelin res->bdf); 352edbed86dSXiaolong Ye return; 353edbed86dSXiaolong Ye } 354edbed86dSXiaolong Ye 3550f700f90SMaxime Coquelin vports[devcnt].dev = dev; 356edbed86dSXiaolong Ye 357edbed86dSXiaolong Ye if (start_vdpa(&vports[devcnt]) == 0) 358edbed86dSXiaolong Ye devcnt++; 359edbed86dSXiaolong Ye } 360edbed86dSXiaolong Ye 361edbed86dSXiaolong Ye cmdline_parse_token_string_t cmd_action_create = 362edbed86dSXiaolong Ye TOKEN_STRING_INITIALIZER(struct cmd_create_result, action, "create"); 363edbed86dSXiaolong Ye cmdline_parse_token_string_t cmd_socket_path = 364edbed86dSXiaolong Ye TOKEN_STRING_INITIALIZER(struct cmd_create_result, socket_path, NULL); 365edbed86dSXiaolong Ye cmdline_parse_token_string_t cmd_bdf = 366edbed86dSXiaolong Ye TOKEN_STRING_INITIALIZER(struct cmd_create_result, bdf, NULL); 367edbed86dSXiaolong Ye 368edbed86dSXiaolong Ye cmdline_parse_inst_t cmd_create_vdpa_port = { 369edbed86dSXiaolong Ye .f = cmd_create_vdpa_port_parsed, 370edbed86dSXiaolong Ye .data = NULL, 371edbed86dSXiaolong Ye .help_str = "create a new vdpa port", 372edbed86dSXiaolong Ye .tokens = { 373edbed86dSXiaolong Ye (void *)&cmd_action_create, 374edbed86dSXiaolong Ye (void *)&cmd_socket_path, 375edbed86dSXiaolong Ye (void *)&cmd_bdf, 376edbed86dSXiaolong Ye NULL, 377edbed86dSXiaolong Ye }, 378edbed86dSXiaolong Ye }; 379edbed86dSXiaolong Ye 3806505865aSMatan Azrad /* *** STATS *** */ 3816505865aSMatan Azrad struct cmd_stats_result { 3826505865aSMatan Azrad cmdline_fixed_string_t stats; 3830f700f90SMaxime Coquelin cmdline_fixed_string_t bdf; 3846505865aSMatan Azrad uint16_t qid; 3856505865aSMatan Azrad }; 3866505865aSMatan Azrad 3876505865aSMatan Azrad static void cmd_device_stats_parsed(void *parsed_result, struct cmdline *cl, 3886505865aSMatan Azrad __rte_unused void *data) 3896505865aSMatan Azrad { 3906505865aSMatan Azrad struct cmd_stats_result *res = parsed_result; 3910f700f90SMaxime Coquelin struct rte_vdpa_device *vdev = rte_vdpa_find_device_by_name(res->bdf); 3926505865aSMatan Azrad struct vdpa_port *vport = NULL; 3936505865aSMatan Azrad uint32_t first, last; 3946505865aSMatan Azrad int i; 3956505865aSMatan Azrad 3966505865aSMatan Azrad if (!vdev) { 3970f700f90SMaxime Coquelin RTE_LOG(ERR, VDPA, "Invalid device: %s.\n", 3980f700f90SMaxime Coquelin res->bdf); 3996505865aSMatan Azrad return; 4006505865aSMatan Azrad } 401*fbe6be6eSMaxime Coquelin for (i = 0; i < RTE_MIN(MAX_VDPA_SAMPLE_PORTS, devcnt); i++) { 4020f700f90SMaxime Coquelin if (vports[i].dev == vdev) { 4036505865aSMatan Azrad vport = &vports[i]; 4046505865aSMatan Azrad break; 4056505865aSMatan Azrad } 4066505865aSMatan Azrad } 4076505865aSMatan Azrad if (!vport) { 4080f700f90SMaxime Coquelin RTE_LOG(ERR, VDPA, "Device %s was not created.\n", res->bdf); 4096505865aSMatan Azrad return; 4106505865aSMatan Azrad } 4116505865aSMatan Azrad if (res->qid == 0xFFFF) { 4126505865aSMatan Azrad first = 0; 4136505865aSMatan Azrad last = rte_vhost_get_vring_num(vport->vid); 4146505865aSMatan Azrad if (last == 0) { 4156505865aSMatan Azrad RTE_LOG(ERR, VDPA, "Failed to get num of actual virtqs" 4160f700f90SMaxime Coquelin " for device %s.\n", res->bdf); 4176505865aSMatan Azrad return; 4186505865aSMatan Azrad } 4196505865aSMatan Azrad last--; 4206505865aSMatan Azrad } else { 4216505865aSMatan Azrad first = res->qid; 4226505865aSMatan Azrad last = res->qid; 4236505865aSMatan Azrad } 4246505865aSMatan Azrad if (!vport->stats_names) { 4250f700f90SMaxime Coquelin vport->stats_n = rte_vdpa_get_stats_names(vport->dev, NULL, 0); 4266505865aSMatan Azrad if (vport->stats_n <= 0) { 4276505865aSMatan Azrad RTE_LOG(ERR, VDPA, "Failed to get names number of " 4280f700f90SMaxime Coquelin "device %s stats.\n", res->bdf); 4296505865aSMatan Azrad return; 4306505865aSMatan Azrad } 4316505865aSMatan Azrad vport->stats_names = rte_zmalloc(NULL, 4326505865aSMatan Azrad (sizeof(*vport->stats_names) + sizeof(*vport->stats)) * 4336505865aSMatan Azrad vport->stats_n, 0); 4346505865aSMatan Azrad if (!vport->stats_names) { 4356505865aSMatan Azrad RTE_LOG(ERR, VDPA, "Failed to allocate memory for stat" 4360f700f90SMaxime Coquelin " names of device %s.\n", res->bdf); 4376505865aSMatan Azrad return; 4386505865aSMatan Azrad } 4390f700f90SMaxime Coquelin i = rte_vdpa_get_stats_names(vport->dev, vport->stats_names, 4406505865aSMatan Azrad vport->stats_n); 4416505865aSMatan Azrad if (vport->stats_n != i) { 4420f700f90SMaxime Coquelin RTE_LOG(ERR, VDPA, "Failed to get names of device %s " 4430f700f90SMaxime Coquelin "stats.\n", res->bdf); 4446505865aSMatan Azrad return; 4456505865aSMatan Azrad } 4466505865aSMatan Azrad vport->stats = (struct rte_vdpa_stat *) 4476505865aSMatan Azrad (vport->stats_names + vport->stats_n); 4486505865aSMatan Azrad } 4490f700f90SMaxime Coquelin cmdline_printf(cl, "\nDevice %s:\n", res->bdf); 4506505865aSMatan Azrad for (; first <= last; first++) { 4516505865aSMatan Azrad memset(vport->stats, 0, sizeof(*vport->stats) * vport->stats_n); 4520f700f90SMaxime Coquelin if (rte_vdpa_get_stats(vport->dev, (int)first, vport->stats, 4536505865aSMatan Azrad vport->stats_n) <= 0) { 4546505865aSMatan Azrad RTE_LOG(ERR, VDPA, "Failed to get vdpa queue statistics" 4550f700f90SMaxime Coquelin " for device %s qid %d.\n", res->bdf, 4566505865aSMatan Azrad (int)first); 4576505865aSMatan Azrad return; 4586505865aSMatan Azrad } 4596505865aSMatan Azrad cmdline_printf(cl, "\tVirtq %" PRIu32 ":\n", first); 4606505865aSMatan Azrad for (i = 0; i < vport->stats_n; ++i) { 4616505865aSMatan Azrad cmdline_printf(cl, "\t\t%-*s %-16" PRIu64 "\n", 4626505865aSMatan Azrad RTE_VDPA_STATS_NAME_SIZE, 4636505865aSMatan Azrad vport->stats_names[vport->stats[i].id].name, 4646505865aSMatan Azrad vport->stats[i].value); 4656505865aSMatan Azrad } 4666505865aSMatan Azrad } 4676505865aSMatan Azrad } 4686505865aSMatan Azrad 4696505865aSMatan Azrad cmdline_parse_token_string_t cmd_device_stats_ = 4706505865aSMatan Azrad TOKEN_STRING_INITIALIZER(struct cmd_stats_result, stats, "stats"); 4710f700f90SMaxime Coquelin cmdline_parse_token_string_t cmd_device_bdf = 4720f700f90SMaxime Coquelin TOKEN_STRING_INITIALIZER(struct cmd_stats_result, bdf, NULL); 4736505865aSMatan Azrad cmdline_parse_token_num_t cmd_queue_id = 4746505865aSMatan Azrad TOKEN_NUM_INITIALIZER(struct cmd_stats_result, qid, UINT32); 4756505865aSMatan Azrad 4766505865aSMatan Azrad cmdline_parse_inst_t cmd_device_stats = { 4776505865aSMatan Azrad .f = cmd_device_stats_parsed, 4786505865aSMatan Azrad .data = NULL, 4796505865aSMatan Azrad .help_str = "stats: show device statistics", 4806505865aSMatan Azrad .tokens = { 4816505865aSMatan Azrad (void *)&cmd_device_stats_, 4820f700f90SMaxime Coquelin (void *)&cmd_device_bdf, 4836505865aSMatan Azrad (void *)&cmd_queue_id, 4846505865aSMatan Azrad NULL, 4856505865aSMatan Azrad }, 4866505865aSMatan Azrad }; 4876505865aSMatan Azrad 488edbed86dSXiaolong Ye /* *** QUIT *** */ 489edbed86dSXiaolong Ye struct cmd_quit_result { 490edbed86dSXiaolong Ye cmdline_fixed_string_t quit; 491edbed86dSXiaolong Ye }; 492edbed86dSXiaolong Ye 493f2fc83b4SThomas Monjalon static void cmd_quit_parsed(__rte_unused void *parsed_result, 494edbed86dSXiaolong Ye struct cmdline *cl, 495f2fc83b4SThomas Monjalon __rte_unused void *data) 496edbed86dSXiaolong Ye { 497edbed86dSXiaolong Ye vdpa_sample_quit(); 498edbed86dSXiaolong Ye cmdline_quit(cl); 499edbed86dSXiaolong Ye } 500edbed86dSXiaolong Ye 501edbed86dSXiaolong Ye cmdline_parse_token_string_t cmd_quit_quit = 502edbed86dSXiaolong Ye TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit"); 503edbed86dSXiaolong Ye 504edbed86dSXiaolong Ye cmdline_parse_inst_t cmd_quit = { 505edbed86dSXiaolong Ye .f = cmd_quit_parsed, 506edbed86dSXiaolong Ye .data = NULL, 507edbed86dSXiaolong Ye .help_str = "quit: exit application", 508edbed86dSXiaolong Ye .tokens = { 509edbed86dSXiaolong Ye (void *)&cmd_quit_quit, 510edbed86dSXiaolong Ye NULL, 511edbed86dSXiaolong Ye }, 512edbed86dSXiaolong Ye }; 513edbed86dSXiaolong Ye cmdline_parse_ctx_t main_ctx[] = { 514edbed86dSXiaolong Ye (cmdline_parse_inst_t *)&cmd_help, 515edbed86dSXiaolong Ye (cmdline_parse_inst_t *)&cmd_list_vdpa_devices, 516edbed86dSXiaolong Ye (cmdline_parse_inst_t *)&cmd_create_vdpa_port, 5176505865aSMatan Azrad (cmdline_parse_inst_t *)&cmd_device_stats, 518edbed86dSXiaolong Ye (cmdline_parse_inst_t *)&cmd_quit, 519edbed86dSXiaolong Ye NULL, 520edbed86dSXiaolong Ye }; 521edbed86dSXiaolong Ye 522edbed86dSXiaolong Ye int 523edbed86dSXiaolong Ye main(int argc, char *argv[]) 524edbed86dSXiaolong Ye { 525edbed86dSXiaolong Ye char ch; 526edbed86dSXiaolong Ye int ret; 527edbed86dSXiaolong Ye struct cmdline *cl; 5280f700f90SMaxime Coquelin struct rte_vdpa_device *vdev; 52938f8ab0bSMaxime Coquelin struct rte_device *dev; 53038f8ab0bSMaxime Coquelin struct rte_dev_iterator dev_iter; 531edbed86dSXiaolong Ye 532edbed86dSXiaolong Ye ret = rte_eal_init(argc, argv); 533edbed86dSXiaolong Ye if (ret < 0) 534edbed86dSXiaolong Ye rte_exit(EXIT_FAILURE, "eal init failed\n"); 535edbed86dSXiaolong Ye argc -= ret; 536edbed86dSXiaolong Ye argv += ret; 537edbed86dSXiaolong Ye 538edbed86dSXiaolong Ye signal(SIGINT, signal_handler); 539edbed86dSXiaolong Ye signal(SIGTERM, signal_handler); 540edbed86dSXiaolong Ye 541edbed86dSXiaolong Ye ret = parse_args(argc, argv); 542edbed86dSXiaolong Ye if (ret < 0) 543edbed86dSXiaolong Ye rte_exit(EXIT_FAILURE, "invalid argument\n"); 544edbed86dSXiaolong Ye 545edbed86dSXiaolong Ye if (interactive == 1) { 546edbed86dSXiaolong Ye cl = cmdline_stdin_new(main_ctx, "vdpa> "); 547edbed86dSXiaolong Ye if (cl == NULL) 548edbed86dSXiaolong Ye rte_panic("Cannot create cmdline instance\n"); 549edbed86dSXiaolong Ye cmdline_interact(cl); 550edbed86dSXiaolong Ye cmdline_stdin_exit(cl); 551edbed86dSXiaolong Ye } else { 55238f8ab0bSMaxime Coquelin RTE_DEV_FOREACH(dev, "class=vdpa", &dev_iter) { 5530f700f90SMaxime Coquelin vdev = rte_vdpa_find_device_by_name(dev->name); 5540f700f90SMaxime Coquelin if (vdev == NULL) { 5550f700f90SMaxime Coquelin rte_panic("Failed to find vDPA dev for %s\n", 55638f8ab0bSMaxime Coquelin dev->name); 55738f8ab0bSMaxime Coquelin } 5580f700f90SMaxime Coquelin vports[devcnt].dev = vdev; 55938f8ab0bSMaxime Coquelin snprintf(vports[devcnt].ifname, MAX_PATH_LEN, "%s%d", 56038f8ab0bSMaxime Coquelin iface, devcnt); 561edbed86dSXiaolong Ye 56238f8ab0bSMaxime Coquelin start_vdpa(&vports[devcnt]); 56338f8ab0bSMaxime Coquelin devcnt++; 564edbed86dSXiaolong Ye } 565edbed86dSXiaolong Ye 566edbed86dSXiaolong Ye printf("enter \'q\' to quit\n"); 567edbed86dSXiaolong Ye while (scanf("%c", &ch)) { 568edbed86dSXiaolong Ye if (ch == 'q') 569edbed86dSXiaolong Ye break; 570edbed86dSXiaolong Ye while (ch != '\n') { 571edbed86dSXiaolong Ye if (scanf("%c", &ch)) 572edbed86dSXiaolong Ye printf("%c", ch); 573edbed86dSXiaolong Ye } 574edbed86dSXiaolong Ye printf("enter \'q\' to quit\n"); 575edbed86dSXiaolong Ye } 576edbed86dSXiaolong Ye vdpa_sample_quit(); 577edbed86dSXiaolong Ye } 578edbed86dSXiaolong Ye 579edbed86dSXiaolong Ye return 0; 580edbed86dSXiaolong Ye } 581