[ofa-general] Re: [PATCH] infiniband-diags: command line option processing framework

Al Chu chu11 at llnl.gov
Mon Jan 26 09:22:09 PST 2009


Hey Sasha,

Just wondering, what tools are you targeting for these unified command
line options?  Since (doing a quick glance) it will break some options
for some tools.

for ibstat

/usr/sbin/ibstat -l       # list all IB devices

I don't think there will be a lot of issues.  Any changes will just have
to be announced/documented in the release notes so people can update
scripts.

Al

On Sun, 2009-01-25 at 13:51 +0200, Sasha Khapyorsky wrote:
> The main motivation of this is to unify infiniband-diags command line
> options and tools usage. Also it simplifies programming and can remove
> a lot of duplications. The usage message is also unified over all tools
> and looks like:
> 
> Usage: ibaddr [options] [<lid|dr_path|guid>]
> 
> Options:
>   --gid_show, -g          show gid address only
>   --lid_show, -l          show lid range only
>   --Lid_show, -L          show lid range (in decimal) only
>   --Ca, -C <ca>           Ca name to use
>   --Port, -P <port>       Ca port number to use
>   --Direct, -D            use Direct address argument
>   --Guid, -G              use GUID address argument
>   --timeout, -t <ms>      timeout in ms
>   --sm_port, -s <lid>     SM port lid
>   --errors, -e            show send and receive errors
>   --verbose, -v           increase verbosity level
>   --debug, -d             raise debug level
>   --usage, -u             usage message
>   --help, -h              help message
>   --version, -V           show version
> 
> Examples:
>   ibaddr 		# local port's address
>   ibaddr 32		# show lid range and gid of lid 32
>   ibaddr -G 0x8f1040023	# same but using guid address
>   ibaddr -l 32		# show lid range only
>   ibaddr -L 32		# show decimal lid range only
>   ibaddr -g 32		# show gid address only
> 
> Custom (per tool) option processing is also supported.
> 
> Signed-off-by: Sasha Khapyorsky <sashak at voltaire.com>
> ---
>  infiniband-diags/include/ibdiag_common.h |   28 +++-
>  infiniband-diags/src/ibdiag_common.c     |  248 ++++++++++++++++++++++++++++++
>  2 files changed, 274 insertions(+), 2 deletions(-)
> 
> diff --git a/infiniband-diags/include/ibdiag_common.h b/infiniband-diags/include/ibdiag_common.h
> index 0518579..4304826 100644
> --- a/infiniband-diags/include/ibdiag_common.h
> +++ b/infiniband-diags/include/ibdiag_common.h
> @@ -35,18 +35,42 @@
>  #ifndef _IBDIAG_COMMON_H_
>  #define _IBDIAG_COMMON_H_
>  
> +#include <infiniband/mad.h>
> +
>  extern int ibdebug;
> +extern int ibverbose;
> +extern char *ibd_ca;
> +extern int ibd_ca_port;
> +extern int ibd_dest_type;
> +extern ib_portid_t *ibd_sm_id;
> +extern int ibd_timeout;
>  
>  /*========================================================*/
>  /*                External interface                      */
>  /*========================================================*/
>  
>  #undef DEBUG
> -#define	DEBUG	if (ibdebug || verbose) IBWARN
> -#define	VERBOSE	if (ibdebug || verbose > 1) IBWARN
> +#define	DEBUG	if (ibdebug || ibverbose) IBWARN
> +#define	VERBOSE	if (ibdebug || ibverbose > 1) IBWARN
>  #define IBERROR(fmt, args...)	iberror(__FUNCTION__, fmt, ## args)
>  
>  extern void iberror(const char *fn, char *msg, ...);
>  extern const char *get_build_version(void);
>  
> +struct ibdiag_opt {
> +	const char *name;
> +	char letter;
> +	unsigned has_arg;
> +	const char *arg_tmpl;
> +	const char *description;
> +};
> +
> +extern int ibdiag_process_opts(int argc, char * const argv[], void *context,
> +			       const char *exclude_common_str,
> +			       const struct ibdiag_opt custom_opts[],
> +			       int (*custom_handler)(void *cxt, int val, char *optarg),
> +			       const char *usage_args,
> +			       const char *usage_examples[]);
> +extern void ibdiag_show_usage();
> +
>  #endif				/* _IBDIAG_COMMON_H_ */
> diff --git a/infiniband-diags/src/ibdiag_common.c b/infiniband-diags/src/ibdiag_common.c
> index 3a9d5c2..8dcec5e 100644
> --- a/infiniband-diags/src/ibdiag_common.c
> +++ b/infiniband-diags/src/ibdiag_common.c
> @@ -46,11 +46,259 @@
>  #include <unistd.h>
>  #include <ctype.h>
>  #include <config.h>
> +#include <getopt.h>
>  
> +#include <infiniband/umad.h>
> +#include <infiniband/mad.h>
>  #include <ibdiag_common.h>
>  #include <ibdiag_version.h>
>  
>  int ibdebug;
> +int ibverbose;
> +char *ibd_ca;
> +int ibd_ca_port;
> +int ibd_dest_type = IB_DEST_LID;
> +ib_portid_t *ibd_sm_id;
> +int ibd_timeout;
> +
> +static ib_portid_t sm_portid = {0};
> +
> +static const char *prog_name;
> +static const char *prog_args;
> +static const char **prog_examples;
> +static struct option *long_opts;
> +static const struct ibdiag_opt *opts_map[256];
> +
> +static void pretty_print(int start, int width, const char *str)
> +{
> +	int len = width - start;
> +	const char *p, *e;
> +
> +	while (1) {
> +		while(isspace(*str))
> +			str++;
> +		p = str;
> +		do {
> +			e = p + 1;
> +			p = strchr(e, ' ');
> +		} while (p && p - str < len);
> +		if (!p) {
> +			fprintf(stderr, "%s", str);
> +			break;
> +		}
> +		if (e - str == 1)
> +			e = p;
> +		fprintf(stderr, "%.*s\n%*s", e - str, str, start, "");
> +		str = e;
> +	}
> +}
> +
> +void ibdiag_show_usage()
> +{
> +	struct option *o = long_opts;
> +	int n;
> +
> +	fprintf(stderr, "\nUsage: %s [options] %s\n\n", prog_name,
> +		prog_args ? prog_args : "");
> +
> +	if (long_opts[0].name)
> +		fprintf(stderr, "Options:\n");
> +	for (o = long_opts; o->name; o++) {
> +		const struct ibdiag_opt *io = opts_map[o->val];
> +		n = fprintf(stderr, "  --%s", io->name);
> +		if (isprint(io->letter))
> +			n += fprintf(stderr, ", -%c", io->letter);
> +		if (io->has_arg)
> +			n += fprintf(stderr, " %s",
> +				     io->arg_tmpl ? io->arg_tmpl : "<val>");
> +		if (io->description && *io->description) {
> +			n += fprintf(stderr, "%*s  ", 24 - n > 0 ? 24 - n : 0, "");
> +			pretty_print(n, 74, io->description);
> +		}
> +		fprintf(stderr, "\n");
> +	}
> +
> +	if (prog_examples) {
> +		const char **p;
> +		fprintf(stderr, "\nExamples:\n");
> +		for (p = prog_examples; *p && **p; p++)
> +			fprintf(stderr, "  %s %s\n", prog_name, *p);
> +	}
> +
> +	fprintf(stderr, "\n");
> +
> +	exit(2);
> +}
> +
> +static int process_opt(int ch, char *optarg)
> +{
> +	int val;
> +
> +	switch (ch) {
> +	case 'h':
> +	case 'u':
> +		ibdiag_show_usage();
> +		break;
> +	case 'V':
> +		fprintf(stderr, "%s %s\n", prog_name, get_build_version());
> +		exit(2);
> +	case 'e':
> +		madrpc_show_errors(1);
> +		break;
> +	case 'v':
> +		ibverbose++;
> +		break;
> +	case 'd':
> +		ibdebug++;
> +		madrpc_show_errors(1);
> +		umad_debug(ibdebug - 1);
> +		break;
> +	case 'C':
> +		ibd_ca = optarg;
> +		break;
> +	case 'P':
> +		ibd_ca_port = strtoul(optarg, 0, 0);
> +		break;
> +	case 'D':
> +		ibd_dest_type = IB_DEST_DRPATH;
> +		break;
> +	case 'L':
> +		ibd_dest_type = IB_DEST_LID;
> +		break;
> +	case 'G':
> +		ibd_dest_type = IB_DEST_GUID;
> +		break;
> +	case 't':
> +		val = strtoul(optarg, 0, 0);
> +		madrpc_set_timeout(val);
> +		ibd_timeout = val;
> +		break;
> +	case 's':
> +		if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0)
> +			IBERROR("cannot resolve SM destination port %s", optarg);
> +		ibd_sm_id = &sm_portid;
> +		break;
> +	default:
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct ibdiag_opt common_opts[] = {
> +	{ "Ca", 'C', 1, "<ca>", "Ca name to use"},
> +	{ "Port", 'P', 1, "<port>", "Ca port number to use"},
> +	{ "Direct", 'D', 0, NULL, "use Direct address argument"},
> +	{ "Lid", 'L', 0, NULL, "use LID address argument"},
> +	{ "Guid", 'G', 0, NULL, "use GUID address argument"},
> +	{ "timeout", 't', 1, "<ms>", "timeout in ms"},
> +	{ "sm_port", 's', 1, "<lid>", "SM port lid" },
> +	{ "errors", 'e', 0, NULL, "show send and receive errors" },
> +	{ "verbose", 'v', 0, NULL, "increase verbosity level" },
> +	{ "debug", 'd', 0, NULL, "raise debug level" },
> +	{ "usage", 'u', 0, NULL, "usage message" },
> +	{ "help", 'h', 0, NULL, "help message" },
> +	{ "version", 'V', 0, NULL, "show version" },
> +	{}
> +};
> +
> +static void make_opt(struct option *l, const struct ibdiag_opt *o,
> +		     const struct ibdiag_opt *map[])
> +{
> +	l->name = o->name;
> +	l->has_arg = o->has_arg;
> +	l->flag = NULL;
> +	l->val = o->letter;
> +	if (!map[l->val])
> +		map[l->val] = o;
> +}
> +
> +static struct option *make_long_opts(const char *exclude_str,
> +				     const struct ibdiag_opt *custom_opts,
> +				     const struct ibdiag_opt *map[])
> +{
> +	struct option *long_opts, *l;
> +	const struct ibdiag_opt *o;
> +	unsigned n = 0;
> +
> +	if (custom_opts)
> +		for (o = custom_opts; o->name; o++)
> +			n++;
> +
> +	long_opts = malloc((sizeof(common_opts)/sizeof(common_opts[0]) + n) *
> +			   sizeof(*long_opts));
> +	if (!long_opts)
> +		return NULL;
> +
> +	l = long_opts;
> +
> +	if (custom_opts)
> +		for (o = custom_opts; o->name; o++)
> +			make_opt(l++, o, map);
> +
> +	for (o = common_opts; o->name; o++) {
> +		if (exclude_str && strchr(exclude_str, o->letter))
> +			continue;
> +		make_opt(l++, o, map);
> +	}
> +
> +	memset(l, 0, sizeof(*l));
> +
> +	return long_opts;
> +}
> +
> +static void make_str_opts(const struct option *o, char *p, unsigned size)
> +{
> +	int i, n = 0;
> +
> +	for (n = 0; o->name  && n + 2 + o->has_arg < size; o++) {
> +		p[n++] = o->val;
> +		for (i = 0; i < o->has_arg; i++)
> +			p[n++] = ':';
> +	}
> +	p[n] = '\0';
> +}
> +
> +int ibdiag_process_opts(int argc, char * const argv[], void *cxt,
> +			const char *exclude_common_str,
> +			const struct ibdiag_opt custom_opts[],
> +			int (*custom_handler)(void *cxt, int val, char *optarg),
> +			const char *usage_args, const char *usage_examples[])
> +{
> +	char str_opts[1024];
> +	const struct ibdiag_opt *o;
> +
> +	memset(opts_map, 0, sizeof(opts_map));
> +
> +	prog_name = argv[0];
> +	prog_args = usage_args;
> +	prog_examples = usage_examples;
> +
> +	long_opts = make_long_opts(exclude_common_str, custom_opts, opts_map);
> +	if (!long_opts)
> +		return -1;
> +
> +	make_str_opts(long_opts, str_opts, sizeof(str_opts));
> +
> +	while (1) {
> +		int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
> +		if ( ch == -1 )
> +			break;
> +		o = opts_map[ch];
> +		if (!o)
> +			ibdiag_show_usage();
> +		if (custom_handler) {
> +			if (custom_handler(cxt, ch, optarg) &&
> +			    process_opt(ch, optarg))
> +				ibdiag_show_usage();
> +		} else if (process_opt(ch, optarg))
> +			ibdiag_show_usage();
> +	}
> +
> +	free(long_opts);
> +
> +	return 0;
> +}
>  
>  extern char *argv0;
>  
-- 
Albert Chu
chu11 at llnl.gov
Computer Scientist
High Performance Systems Division
Lawrence Livermore National Laboratory




More information about the general mailing list