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 <james.r.harris@intel.com>
Change-Id: I1903de3daed90ac6282b006a8283b9df07ce37e9

Reviewed-on: https://review.gerrithub.io/386542
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
This commit is contained in:
Jim Harris 2017-11-09 13:20:56 -07:00 committed by Daniel Verkamp
parent 246cdd08e1
commit fbb9430ec4
5 changed files with 151 additions and 261 deletions

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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
*/

View File

@ -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;
}