1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Intel Corporation
11 #include <rte_ethdev.h>
12 #include <rte_malloc.h>
13 #include <rte_vhost.h>
16 #include <rte_string_fns.h>
18 #include <cmdline_parse.h>
19 #include <cmdline_socket.h>
20 #include <cmdline_parse_string.h>
23 #define MAX_PATH_LEN 128
24 #define MAX_VDPA_SAMPLE_PORTS 1024
25 #define RTE_LOGTYPE_VDPA RTE_LOGTYPE_USER1
28 char ifname[MAX_PATH_LEN];
34 static struct vdpa_port vports[MAX_VDPA_SAMPLE_PORTS];
36 static char iface[MAX_PATH_LEN];
39 static int interactive;
40 static int client_mode;
44 vdpa_usage(const char *prgname)
46 printf("Usage: %s [EAL options] -- "
47 " --interactive|-i: run in interactive mode.\n"
48 " --iface <path>: specify the path prefix of the socket files, e.g. /tmp/vhost-user-.\n"
49 " --client: register a vhost-user socket as client mode.\n",
54 parse_args(int argc, char **argv)
56 static const char *short_option = "i";
57 static struct option long_option[] = {
58 {"iface", required_argument, NULL, 0},
59 {"interactive", no_argument, &interactive, 1},
60 {"client", no_argument, &client_mode, 1},
64 char *prgname = argv[0];
66 while ((opt = getopt_long(argc, argv, short_option, long_option, &idx))
70 printf("Interactive-mode selected\n");
75 if (strncmp(long_option[idx].name, "iface",
77 rte_strscpy(iface, optarg, MAX_PATH_LEN);
78 printf("iface %s\n", iface);
80 if (!strcmp(long_option[idx].name, "interactive")) {
81 printf("Interactive-mode selected\n");
92 if (iface[0] == '\0' && interactive == 0) {
103 char ifname[MAX_PATH_LEN];
106 rte_vhost_get_ifname(vid, ifname, sizeof(ifname));
107 for (i = 0; i < MAX_VDPA_SAMPLE_PORTS; i++) {
108 if (strncmp(ifname, vports[i].ifname, MAX_PATH_LEN) == 0) {
109 printf("\nnew port %s, did: %d\n",
110 ifname, vports[i].did);
116 if (i >= MAX_VDPA_SAMPLE_PORTS)
123 destroy_device(int vid)
125 char ifname[MAX_PATH_LEN];
128 rte_vhost_get_ifname(vid, ifname, sizeof(ifname));
129 for (i = 0; i < MAX_VDPA_SAMPLE_PORTS; i++) {
130 if (strcmp(ifname, vports[i].ifname) == 0) {
131 printf("\ndestroy port %s, did: %d\n",
132 ifname, vports[i].did);
138 static const struct vhost_device_ops vdpa_sample_devops = {
139 .new_device = new_device,
140 .destroy_device = destroy_device,
144 start_vdpa(struct vdpa_port *vport)
147 char *socket_path = vport->ifname;
148 int did = vport->did;
151 vport->flags |= RTE_VHOST_USER_CLIENT;
153 if (access(socket_path, F_OK) != -1 && !client_mode) {
155 "%s exists, please remove it or specify another file and try again.\n",
159 ret = rte_vhost_driver_register(socket_path, vport->flags);
161 rte_exit(EXIT_FAILURE,
162 "register driver failed: %s\n",
165 ret = rte_vhost_driver_callback_register(socket_path,
166 &vdpa_sample_devops);
168 rte_exit(EXIT_FAILURE,
169 "register driver ops failed: %s\n",
172 ret = rte_vhost_driver_attach_vdpa_device(socket_path, did);
174 rte_exit(EXIT_FAILURE,
175 "attach vdpa device failed: %s\n",
178 if (rte_vhost_driver_start(socket_path) < 0)
179 rte_exit(EXIT_FAILURE,
180 "start vhost driver failed: %s\n",
186 close_vdpa(struct vdpa_port *vport)
189 char *socket_path = vport->ifname;
191 ret = rte_vhost_driver_detach_vdpa_device(socket_path);
194 "detach vdpa device failed: %s\n",
197 ret = rte_vhost_driver_unregister(socket_path);
200 "Fail to unregister vhost driver for %s.\n",
205 vdpa_sample_quit(void)
208 for (i = 0; i < RTE_MIN(MAX_VDPA_SAMPLE_PORTS, dev_total); i++) {
209 if (vports[i].ifname[0] != '\0')
210 close_vdpa(&vports[i]);
215 signal_handler(int signum)
217 if (signum == SIGINT || signum == SIGTERM) {
218 printf("\nSignal %d received, preparing to exit...\n", signum);
224 /* interactive cmds */
226 /* *** Help command with introduction. *** */
227 struct cmd_help_result {
228 cmdline_fixed_string_t help;
231 static void cmd_help_parsed(__attribute__((unused)) void *parsed_result,
233 __attribute__((unused)) void *data)
238 "The following commands are currently available:\n\n"
240 " help : Show interactive instructions.\n"
241 " list : list all available vdpa devices.\n"
242 " create <socket file> <vdev addr> : create a new vdpa port.\n"
243 " quit : exit vdpa sample app.\n"
247 cmdline_parse_token_string_t cmd_help_help =
248 TOKEN_STRING_INITIALIZER(struct cmd_help_result, help, "help");
250 cmdline_parse_inst_t cmd_help = {
251 .f = cmd_help_parsed,
253 .help_str = "show help",
255 (void *)&cmd_help_help,
260 /* *** List all available vdpa devices *** */
261 struct cmd_list_result {
262 cmdline_fixed_string_t action;
265 static void cmd_list_vdpa_devices_parsed(
266 __attribute__((unused)) void *parsed_result,
268 __attribute__((unused)) void *data)
273 struct rte_vdpa_device *vdev;
274 struct rte_pci_addr addr;
276 cmdline_printf(cl, "device id\tdevice address\tqueue num\tsupported features\n");
277 for (did = 0; did < dev_total; did++) {
278 vdev = rte_vdpa_get_device(did);
281 if (vdev->ops->get_queue_num(did, &queue_num) < 0) {
283 "failed to get vdpa queue number "
284 "for device id %d.\n", did);
287 if (vdev->ops->get_features(did, &features) < 0) {
289 "failed to get vdpa features "
290 "for device id %d.\n", did);
293 addr = vdev->addr.pci_addr;
295 "%d\t\t" PCI_PRI_FMT "\t%" PRIu32 "\t\t0x%" PRIx64 "\n",
296 did, addr.domain, addr.bus, addr.devid,
297 addr.function, queue_num, features);
301 cmdline_parse_token_string_t cmd_action_list =
302 TOKEN_STRING_INITIALIZER(struct cmd_list_result, action, "list");
304 cmdline_parse_inst_t cmd_list_vdpa_devices = {
305 .f = cmd_list_vdpa_devices_parsed,
307 .help_str = "list all available vdpa devices",
309 (void *)&cmd_action_list,
314 /* *** Create new vdpa port *** */
315 struct cmd_create_result {
316 cmdline_fixed_string_t action;
317 cmdline_fixed_string_t socket_path;
318 cmdline_fixed_string_t bdf;
321 static void cmd_create_vdpa_port_parsed(void *parsed_result,
323 __attribute__((unused)) void *data)
326 struct cmd_create_result *res = parsed_result;
327 struct rte_vdpa_dev_addr addr;
329 rte_strscpy(vports[devcnt].ifname, res->socket_path, MAX_PATH_LEN);
330 if (rte_pci_addr_parse(res->bdf, &addr.pci_addr) != 0) {
331 cmdline_printf(cl, "Unable to parse the given bdf.\n");
334 addr.type = PCI_ADDR;
335 did = rte_vdpa_find_device_id(&addr);
337 cmdline_printf(cl, "Unable to find vdpa device id.\n");
341 vports[devcnt].did = did;
343 if (start_vdpa(&vports[devcnt]) == 0)
347 cmdline_parse_token_string_t cmd_action_create =
348 TOKEN_STRING_INITIALIZER(struct cmd_create_result, action, "create");
349 cmdline_parse_token_string_t cmd_socket_path =
350 TOKEN_STRING_INITIALIZER(struct cmd_create_result, socket_path, NULL);
351 cmdline_parse_token_string_t cmd_bdf =
352 TOKEN_STRING_INITIALIZER(struct cmd_create_result, bdf, NULL);
354 cmdline_parse_inst_t cmd_create_vdpa_port = {
355 .f = cmd_create_vdpa_port_parsed,
357 .help_str = "create a new vdpa port",
359 (void *)&cmd_action_create,
360 (void *)&cmd_socket_path,
367 struct cmd_quit_result {
368 cmdline_fixed_string_t quit;
371 static void cmd_quit_parsed(__attribute__((unused)) void *parsed_result,
373 __attribute__((unused)) void *data)
379 cmdline_parse_token_string_t cmd_quit_quit =
380 TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit, "quit");
382 cmdline_parse_inst_t cmd_quit = {
383 .f = cmd_quit_parsed,
385 .help_str = "quit: exit application",
387 (void *)&cmd_quit_quit,
391 cmdline_parse_ctx_t main_ctx[] = {
392 (cmdline_parse_inst_t *)&cmd_help,
393 (cmdline_parse_inst_t *)&cmd_list_vdpa_devices,
394 (cmdline_parse_inst_t *)&cmd_create_vdpa_port,
395 (cmdline_parse_inst_t *)&cmd_quit,
400 main(int argc, char *argv[])
407 ret = rte_eal_init(argc, argv);
409 rte_exit(EXIT_FAILURE, "eal init failed\n");
413 dev_total = rte_vdpa_get_device_num();
415 rte_exit(EXIT_FAILURE, "No available vdpa device found\n");
417 signal(SIGINT, signal_handler);
418 signal(SIGTERM, signal_handler);
420 ret = parse_args(argc, argv);
422 rte_exit(EXIT_FAILURE, "invalid argument\n");
424 if (interactive == 1) {
425 cl = cmdline_stdin_new(main_ctx, "vdpa> ");
427 rte_panic("Cannot create cmdline instance\n");
428 cmdline_interact(cl);
429 cmdline_stdin_exit(cl);
431 for (i = 0; i < RTE_MIN(MAX_VDPA_SAMPLE_PORTS, dev_total);
434 snprintf(vports[i].ifname, MAX_PATH_LEN, "%s%d",
437 start_vdpa(&vports[i]);
440 printf("enter \'q\' to quit\n");
441 while (scanf("%c", &ch)) {
445 if (scanf("%c", &ch))
448 printf("enter \'q\' to quit\n");