From fbb9430ec40cf40e2e5aebce32726ebbba89fb6f Mon Sep 17 00:00:00 2001 From: Jim Harris Date: Thu, 9 Nov 2017 13:20:56 -0700 Subject: [PATCH] app: add spdk_app_parse_args() This is a helper function that eliminates a lot of duplicated code in our target applications, specifically around common command line argument parsing and usage messages. This patch only moves the iscsi, nvmf and vhost targets to use this function, but there are other test/example applications that could also take advantage of it to reduce duplicated code and improve consistency. Signed-off-by: Jim Harris Change-Id: I1903de3daed90ac6282b006a8283b9df07ce37e9 Reviewed-on: https://review.gerrithub.io/386542 Reviewed-by: Ben Walker Reviewed-by: Daniel Verkamp Tested-by: SPDK Automated Test System --- app/iscsi_tgt/iscsi_tgt.c | 97 ++++------------------------------ app/nvmf_tgt/nvmf_main.c | 89 ++------------------------------ app/vhost/vhost.c | 101 ++++-------------------------------- include/spdk/event.h | 19 +++++++ lib/event/app.c | 106 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 151 insertions(+), 261 deletions(-) diff --git a/app/iscsi_tgt/iscsi_tgt.c b/app/iscsi_tgt/iscsi_tgt.c index b267e9140..f99aa99d5 100644 --- a/app/iscsi_tgt/iscsi_tgt.c +++ b/app/iscsi_tgt/iscsi_tgt.c @@ -57,31 +57,8 @@ spdk_sigusr1(int signo __attribute__((__unused__))) } static void -common_usage(const char *executable_name, struct spdk_app_opts *default_opts) +iscsi_usage(void) { - printf("%s [options]\n", executable_name); - printf("options:\n"); - printf(" -c config config file (default %s)\n", default_opts->config_file); - printf(" -e mask tracepoint group mask for spdk trace buffers (default 0x0)\n"); - printf(" -m mask core mask for DPDK\n"); - printf(" -i shared memory ID (optional)\n"); - printf(" -n channel number of memory channels used for DPDK\n"); - printf(" -p core master (primary) core for DPDK\n"); - printf(" -s size memory size in MB for DPDK\n"); - spdk_tracelog_usage(stdout, "-t"); - printf(" -H show this usage\n"); - printf(" -d disable coredump file enabling\n"); - printf(" -q disable notice level logging to stderr\n"); -} - -static void -usage(char *executable_name) -{ - struct spdk_app_opts default_opts; - - spdk_app_opts_init(&default_opts); - default_opts.config_file = SPDK_ISCSI_DEFAULT_CONFIG; - common_usage(executable_name, &default_opts); printf(" -b run iscsi target background, the default is foreground\n"); } @@ -95,62 +72,15 @@ spdk_startup(void *arg1, void *arg2) } static void -iscsi_parse_args(int argc, char **argv, struct spdk_app_opts *opts) +iscsi_parse_arg(int ch, char *arg) { - int ch, rc; - - while ((ch = getopt(argc, argv, "bc:de:i:m:n:p:qs:t:H")) != -1) { - switch (ch) { - case 'd': - opts->enable_coredump = false; - break; - case 'c': - opts->config_file = optarg; - break; - case 'i': - opts->shm_id = atoi(optarg); - break; - case 't': - rc = spdk_log_set_trace_flag(optarg); - if (rc < 0) { - fprintf(stderr, "unknown flag\n"); - usage(argv[0]); - exit(EXIT_FAILURE); - } - opts->print_level = SPDK_LOG_DEBUG; -#ifndef DEBUG - fprintf(stderr, "%s must be built with CONFIG_DEBUG=y for -t flag\n", - argv[0]); - usage(argv[0]); - exit(EXIT_FAILURE); -#endif - break; - case 'e': - opts->tpoint_group_mask = optarg; - break; - case 'q': - opts->print_level = SPDK_LOG_WARN; - break; - case 'm': - opts->reactor_mask = optarg; - break; - case 'n': - opts->mem_channel = atoi(optarg); - break; - case 'p': - opts->master_core = atoi(optarg); - break; - case 's': - opts->mem_size = atoi(optarg); - break; - case 'b': - g_daemon_mode = 1; - break; - case 'H': - default: - usage(argv[0]); - exit(EXIT_SUCCESS); - } + switch (ch) { + case 'b': + g_daemon_mode = 1; + break; + default: + assert(false); + break; } } @@ -160,15 +90,10 @@ main(int argc, char **argv) int rc; struct spdk_app_opts opts = {}; - /* default value in opts structure */ spdk_app_opts_init(&opts); - - if (access(SPDK_ISCSI_DEFAULT_CONFIG, F_OK) == 0) { - opts.config_file = SPDK_ISCSI_DEFAULT_CONFIG; - } + opts.config_file = SPDK_ISCSI_DEFAULT_CONFIG; opts.name = "iscsi"; - - iscsi_parse_args(argc, argv, &opts); + spdk_app_parse_args(argc, argv, &opts, "b", iscsi_parse_arg, iscsi_usage); if (g_daemon_mode) { if (daemon(1, 0) < 0) { diff --git a/app/nvmf_tgt/nvmf_main.c b/app/nvmf_tgt/nvmf_main.c index 3c5003e9b..d457fdf55 100644 --- a/app/nvmf_tgt/nvmf_main.c +++ b/app/nvmf_tgt/nvmf_main.c @@ -42,91 +42,13 @@ #define SPDK_NVMF_DEFAULT_CONFIG SPDK_NVMF_BUILD_ETC "/nvmf.conf" static void -common_usage(const char *executable_name, struct spdk_app_opts *default_opts) +nvmf_usage(void) { - printf("%s [options]\n", executable_name); - printf("options:\n"); - printf(" -c config - config file (default %s)\n", default_opts->config_file); - printf(" -e mask - tracepoint group mask for spdk trace buffers (default 0x0)\n"); - printf(" -m mask - core mask for DPDK\n"); - printf(" -i shared memory ID (optional)\n"); - printf(" -n channel number of memory channels used for DPDK\n"); - printf(" -p core master (primary) core for DPDK\n"); - printf(" -s size memory size in MB for DPDK\n"); - - spdk_tracelog_usage(stdout, "-t"); - - printf(" -v - verbose (enable warnings)\n"); - printf(" -H - show this usage\n"); - printf(" -d - disable coredump file enabling\n"); } static void -usage(const char *executable_name) +nvmf_parse_arg(int ch, char *arg) { - struct spdk_app_opts default_opts; - - spdk_app_opts_init(&default_opts); - default_opts.config_file = SPDK_NVMF_DEFAULT_CONFIG; - common_usage(executable_name, &default_opts); -} - -static void -nvmf_parse_args(int argc, char **argv, struct spdk_app_opts *opts) -{ - int ch, rc; - - while ((ch = getopt(argc, argv, "c:de:i:m:n:p:qs:t:DH")) != -1) { - switch (ch) { - case 'd': - opts->enable_coredump = false; - break; - case 'c': - opts->config_file = optarg; - break; - case 'i': - opts->shm_id = atoi(optarg); - break; - case 't': - rc = spdk_log_set_trace_flag(optarg); - if (rc < 0) { - fprintf(stderr, "unknown flag\n"); - usage(argv[0]); - exit(EXIT_FAILURE); - } - opts->print_level = SPDK_LOG_DEBUG; -#ifndef DEBUG - fprintf(stderr, "%s must be rebuilt with CONFIG_DEBUG=y for -t flag.\n", - argv[0]); - usage(argv[0]); - exit(EXIT_FAILURE); -#endif - break; - case 'm': - opts->reactor_mask = optarg; - break; - case 'n': - opts->mem_channel = atoi(optarg); - break; - case 'p': - opts->master_core = atoi(optarg); - break; - case 's': - opts->mem_size = atoi(optarg); - break; - case 'e': - opts->tpoint_group_mask = optarg; - break; - case 'q': - opts->print_level = SPDK_LOG_WARN; - break; - case 'D': - case 'H': - default: - usage(argv[0]); - exit(EXIT_SUCCESS); - } - } } int @@ -138,12 +60,9 @@ main(int argc, char **argv) /* default value in opts */ spdk_app_opts_init(&opts); opts.name = "nvmf"; - if (access(SPDK_NVMF_DEFAULT_CONFIG, F_OK) == 0) { - opts.config_file = SPDK_NVMF_DEFAULT_CONFIG; - } + opts.config_file = SPDK_NVMF_DEFAULT_CONFIG; opts.max_delay_us = 1000; /* 1 ms */ - - nvmf_parse_args(argc, argv, &opts); + spdk_app_parse_args(argc, argv, &opts, "", nvmf_parse_arg, nvmf_usage); rc = spdk_nvmf_tgt_start(&opts); diff --git a/app/vhost/vhost.c b/app/vhost/vhost.c index 484b8f058..f0f5055a3 100644 --- a/app/vhost/vhost.c +++ b/app/vhost/vhost.c @@ -52,37 +52,13 @@ vhost_app_opts_init(struct spdk_app_opts *opts) { spdk_app_opts_init(opts); opts->name = "vhost"; - if (access(SPDK_VHOST_DEFAULT_CONFIG, F_OK) == 0) { - opts->config_file = SPDK_VHOST_DEFAULT_CONFIG; - } + opts->config_file = SPDK_VHOST_DEFAULT_CONFIG; opts->mem_size = SPDK_VHOST_DEFAULT_MEM_SIZE; } static void -common_usage(char *executable_name, struct spdk_app_opts *default_opts) +vhost_usage(void) { - printf("%s [options]\n", executable_name); - printf("options:\n"); - printf(" -c config config file (default: %s)\n", default_opts->config_file); - printf(" -e mask tracepoint group mask for spdk trace buffers (default: 0x0)\n"); - printf(" -i shm_id shared memory ID (optional)\n"); - printf(" -m mask reactor core mask (default: 0x1)\n"); - printf(" -N pass --no-pci to DPDK\n"); - printf(" -p core master (primary) core for DPDK\n"); - printf(" -s size memory size in MB for DPDK (default: %dMB)\n", default_opts->mem_size); - spdk_tracelog_usage(stdout, "-t"); - printf(" -h show this usage\n"); - printf(" -d disable coredump file enabling\n"); - printf(" -q disable notice level logging to stderr\n"); -} - -static void -usage(char *executable_name) -{ - struct spdk_app_opts defaults; - - vhost_app_opts_init(&defaults); - common_usage(executable_name, &defaults); printf(" -f pidfile save pid to file under given path\n"); printf(" -S dir directory where to create vhost sockets (default: pwd)\n"); } @@ -103,70 +79,15 @@ save_pid(const char *pid_path) } static void -vhost_parse_args(int argc, char **argv, struct spdk_app_opts *opts) +vhost_parse_arg(int ch, char *arg) { - int ch, rc; - - vhost_app_opts_init(opts); - - while ((ch = getopt(argc, argv, "c:de:f:i:m:Np:qs:S:t:h")) != -1) { - switch (ch) { - case 'c': - opts->config_file = optarg; - break; - case 'd': - opts->enable_coredump = false; - break; - case 'e': - opts->tpoint_group_mask = optarg; - break; - case 'f': - g_pid_path = optarg; - break; - case 'h': - usage(argv[0]); - exit(EXIT_SUCCESS); - case 'i': - opts->shm_id = strtoul(optarg, NULL, 10); - break; - case 'm': - opts->reactor_mask = optarg; - break; - case 'N': - opts->no_pci = true; - break; - case 'p': - opts->master_core = strtoul(optarg, NULL, 10); - break; - case 'q': - opts->print_level = SPDK_LOG_WARN; - break; - case 's': - opts->mem_size = strtoul(optarg, NULL, 10); - break; - case 'S': - g_socket_path = optarg; - break; - case 't': - rc = spdk_log_set_trace_flag(optarg); - if (rc < 0) { - fprintf(stderr, "unknown flag\n"); - usage(argv[0]); - exit(EXIT_FAILURE); - } - opts->print_level = SPDK_LOG_DEBUG; -#ifndef DEBUG - fprintf(stderr, "%s must be rebuilt with CONFIG_DEBUG=y for -t flag.\n", - argv[0]); - usage(argv[0]); - exit(EXIT_FAILURE); -#endif - break; - default: - fprintf(stderr, "%s Unknown option '-%c'.\n", argv[0], ch); - usage(argv[0]); - exit(EXIT_FAILURE); - } + switch (ch) { + case 'f': + g_pid_path = arg; + break; + case 'S': + g_socket_path = arg; + break; } } @@ -178,7 +99,7 @@ main(int argc, char *argv[]) vhost_app_opts_init(&opts); - vhost_parse_args(argc, argv, &opts); + spdk_app_parse_args(argc, argv, &opts, "f:S:", vhost_parse_arg, vhost_usage); if (g_pid_path) { save_pid(g_pid_path); diff --git a/include/spdk/event.h b/include/spdk/event.h index 790d71a6f..7bf318494 100644 --- a/include/spdk/event.h +++ b/include/spdk/event.h @@ -152,6 +152,25 @@ int spdk_app_get_core_count(void) __attribute__((deprecated)); */ uint32_t spdk_app_get_current_core(void) __attribute__((deprecated)); +#define SPDK_APP_GETOPT_STRING "c:de:hi:m:n:p:qs:t:" + +/** + * \brief Helper function for parsing arguments and printing usage messages. + * + * \param argc Count of arguments in argv parameter array. + * \param argv Array of command line arguments. + * \param opts Default options for the application. + * \param getopt_str String representing the app-specific command line parameters. + * Characters in this string must not conflict with characters in + * SPDK_APP_GETOPT_STRING. + * \param parse Function pointer to call if an argument in getopt_str is found. + * \param usage Function pointer to print usage messages for app-specific command + * line parameters. + */ +int spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts, + const char *getopt_str, void (*parse)(int ch, char *arg), + void (*usage)(void)); + /** * \brief Allocate an event to be passed to \ref spdk_event_call */ diff --git a/lib/event/app.c b/lib/event/app.c index a0237ada8..aa16e3e78 100644 --- a/lib/event/app.c +++ b/lib/event/app.c @@ -39,6 +39,7 @@ #include "spdk/log.h" #include "spdk/conf.h" #include "spdk/trace.h" +#include "spdk/string.h" #define SPDK_APP_DEFAULT_LOG_PRIORITY SPDK_LOG_INFO @@ -446,3 +447,108 @@ spdk_app_stop(int rc) */ spdk_event_call(spdk_event_allocate(g_init_lcore, _spdk_app_stop, NULL, NULL)); } + +static void +usage(char *executable_name, struct spdk_app_opts *default_opts, void (*app_usage)(void)) +{ + printf("%s [options]\n", executable_name); + printf("options:\n"); + printf(" -c config config file (default %s)\n", default_opts->config_file); + printf(" -d disable coredump file enabling\n"); + printf(" -e mask tracepoint group mask for spdk trace buffers (default 0x0)\n"); + printf(" -h show this usage\n"); + printf(" -i shared memory ID (optional)\n"); + printf(" -m mask core mask for DPDK\n"); + printf(" -n channel number of memory channels used for DPDK\n"); + printf(" -p core master (primary) core for DPDK\n"); + printf(" -q disable notice level logging to stderr\n"); + printf(" -s size memory size in MB for DPDK (default: "); + if (default_opts->mem_size > 0) { + printf("%dMB)\n", default_opts->mem_size); + } else { + printf("all hugepage memory)\n"); + } + spdk_tracelog_usage(stdout, "-t"); + app_usage(); +} + +int +spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts, + const char *app_getopt_str, void (*app_parse)(int ch, char *arg), + void (*app_usage)(void)) +{ + int ch, rc; + struct spdk_app_opts default_opts; + char *getopt_str; + + memcpy(&default_opts, opts, sizeof(default_opts)); + + if (opts->config_file && access(opts->config_file, F_OK) != 0) { + opts->config_file = NULL; + } + + getopt_str = spdk_sprintf_alloc("%s%s", app_getopt_str, SPDK_APP_GETOPT_STRING); + if (getopt_str == NULL) { + fprintf(stderr, "Could not allocate getopt_str in %s()\n", __func__); + exit(EXIT_FAILURE); + } + + while ((ch = getopt(argc, argv, getopt_str)) != -1) { + switch (ch) { + case 'c': + opts->config_file = optarg; + break; + case 'd': + opts->enable_coredump = false; + break; + case 'e': + opts->tpoint_group_mask = optarg; + break; + case 'h': + usage(argv[0], &default_opts, app_usage); + exit(EXIT_SUCCESS); + case 'i': + opts->shm_id = atoi(optarg); + break; + case 'm': + opts->reactor_mask = optarg; + break; + case 'n': + opts->mem_channel = atoi(optarg); + break; + case 'p': + opts->master_core = atoi(optarg); + break; + case 'q': + opts->print_level = SPDK_LOG_WARN; + break; + case 's': + opts->mem_size = atoi(optarg); + break; + case 't': + rc = spdk_log_set_trace_flag(optarg); + if (rc < 0) { + fprintf(stderr, "unknown flag\n"); + usage(argv[0], &default_opts, app_usage); + exit(EXIT_FAILURE); + } + opts->print_level = SPDK_LOG_DEBUG; +#ifndef DEBUG + fprintf(stderr, "%s must be built with CONFIG_DEBUG=y for -t flag\n", + argv[0]); + usage(argv[0], &default_opts, app_usage); + exit(EXIT_FAILURE); +#endif + break; + case '?': + usage(argv[0], &default_opts, app_usage); + exit(EXIT_FAILURE); + default: + app_parse(ch, optarg); + } + } + + free(getopt_str); + + return 0; +}