xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/ipmpstat.c (revision 8755:a95ac562c9f4)
18485SPeter.Memishian@Sun.COM /*
28485SPeter.Memishian@Sun.COM  * CDDL HEADER START
38485SPeter.Memishian@Sun.COM  *
48485SPeter.Memishian@Sun.COM  * The contents of this file are subject to the terms of the
58485SPeter.Memishian@Sun.COM  * Common Development and Distribution License (the "License").
68485SPeter.Memishian@Sun.COM  * You may not use this file except in compliance with the License.
78485SPeter.Memishian@Sun.COM  *
88485SPeter.Memishian@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98485SPeter.Memishian@Sun.COM  * or http://www.opensolaris.org/os/licensing.
108485SPeter.Memishian@Sun.COM  * See the License for the specific language governing permissions
118485SPeter.Memishian@Sun.COM  * and limitations under the License.
128485SPeter.Memishian@Sun.COM  *
138485SPeter.Memishian@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
148485SPeter.Memishian@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158485SPeter.Memishian@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
168485SPeter.Memishian@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
178485SPeter.Memishian@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
188485SPeter.Memishian@Sun.COM  *
198485SPeter.Memishian@Sun.COM  * CDDL HEADER END
208485SPeter.Memishian@Sun.COM  *
218485SPeter.Memishian@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
228485SPeter.Memishian@Sun.COM  * Use is subject to license terms.
238485SPeter.Memishian@Sun.COM  */
248485SPeter.Memishian@Sun.COM 
258485SPeter.Memishian@Sun.COM #include <alloca.h>
268485SPeter.Memishian@Sun.COM #include <arpa/inet.h>
278485SPeter.Memishian@Sun.COM #include <assert.h>
288485SPeter.Memishian@Sun.COM #include <errno.h>
298485SPeter.Memishian@Sun.COM #include <ipmp_admin.h>
308485SPeter.Memishian@Sun.COM #include <ipmp_query.h>
318485SPeter.Memishian@Sun.COM #include <libintl.h>
328485SPeter.Memishian@Sun.COM #include <libnvpair.h>
338485SPeter.Memishian@Sun.COM #include <libsysevent.h>
348485SPeter.Memishian@Sun.COM #include <locale.h>
358485SPeter.Memishian@Sun.COM #include <netdb.h>
368485SPeter.Memishian@Sun.COM #include <signal.h>
378485SPeter.Memishian@Sun.COM #include <stdarg.h>
388485SPeter.Memishian@Sun.COM #include <stdio.h>
398485SPeter.Memishian@Sun.COM #include <stdlib.h>
408485SPeter.Memishian@Sun.COM #include <string.h>
418485SPeter.Memishian@Sun.COM #include <unistd.h>
428485SPeter.Memishian@Sun.COM #include <sys/sysevent/eventdefs.h>
438485SPeter.Memishian@Sun.COM #include <sys/sysevent/ipmp.h>
448485SPeter.Memishian@Sun.COM #include <sys/sysmacros.h>
458485SPeter.Memishian@Sun.COM #include <sys/termios.h>
468485SPeter.Memishian@Sun.COM #include <sys/types.h>
478485SPeter.Memishian@Sun.COM 
488485SPeter.Memishian@Sun.COM /*
498485SPeter.Memishian@Sun.COM  * ipmpstat -- display IPMP subsystem status.
508485SPeter.Memishian@Sun.COM  *
518485SPeter.Memishian@Sun.COM  * This utility makes extensive use of libipmp and IPMP sysevents to gather
528485SPeter.Memishian@Sun.COM  * and pretty-print the status of the IPMP subsystem.  All output formats
538485SPeter.Memishian@Sun.COM  * except for -p (probe) use libipmp to create a point-in-time snapshot of the
548485SPeter.Memishian@Sun.COM  * IPMP subsystem (unless the test-special -L flag is used), and then output
558485SPeter.Memishian@Sun.COM  * the contents of that snapshot in a user-specified manner.  Because the
568485SPeter.Memishian@Sun.COM  * output format and requested fields aren't known until run-time, three sets
578485SPeter.Memishian@Sun.COM  * of function pointers and two core data structures are used. Specifically:
588485SPeter.Memishian@Sun.COM  *
598485SPeter.Memishian@Sun.COM  *      * The ipmpstat_walker_t function pointers (walk_*) iterate through
608485SPeter.Memishian@Sun.COM  *	  all instances of a given IPMP object (group, interface, or address).
618485SPeter.Memishian@Sun.COM  *	  At most one ipmpstat_walker_t is used per ipmpstat invocation.
628485SPeter.Memishian@Sun.COM  *	  Since target information is included with the interface information,
638485SPeter.Memishian@Sun.COM  *	  both -i and -t use the interface walker (walk_if()).
648485SPeter.Memishian@Sun.COM  *
658485SPeter.Memishian@Sun.COM  *      * The ipmpstat_sfunc_t function pointers (sfunc_*) obtain a given
668485SPeter.Memishian@Sun.COM  *	  value for a given IPMP object.  Each ipmpstat_sunc_t is passed a
678485SPeter.Memishian@Sun.COM  *	  buffer to write its result into, the buffer's size, and an
688485SPeter.Memishian@Sun.COM  *	  ipmpstat_sfunc_arg_t state structure.  The state structure consists
698485SPeter.Memishian@Sun.COM  *	  of a pointer to the IPMP object to obtain information from
708485SPeter.Memishian@Sun.COM  *	  (sa_data), and an open libipmp handle (sa_ih) which can be used to
718485SPeter.Memishian@Sun.COM  *	  do additional libipmp queries, if necessary (e.g., because the
728485SPeter.Memishian@Sun.COM  *	  object does not have all of the needed information).
738485SPeter.Memishian@Sun.COM  *
748485SPeter.Memishian@Sun.COM  *	* The ipmpstat_field_t structure provides the list of supported fields
758485SPeter.Memishian@Sun.COM  *	  for a given output format, along with output formatting information
768485SPeter.Memishian@Sun.COM  *	  (e.g., field width), and a pointer to an ipmpstat_sfunc_t function
778485SPeter.Memishian@Sun.COM  *	  that can obtain the value for a IPMP given object.  For a given
788485SPeter.Memishian@Sun.COM  *	  ipmpstat output format, there's a corresponding array of
798485SPeter.Memishian@Sun.COM  *	  ipmpstat_field_t structures.  Thus, one ipmpstat_field_t array is
808485SPeter.Memishian@Sun.COM  *	  used per ipmpstat invocation.
818485SPeter.Memishian@Sun.COM  *
828485SPeter.Memishian@Sun.COM  *	* The ipmpstat_ofmt_t provides an ordered list of the requested
838485SPeter.Memishian@Sun.COM  *	  ipmpstat_field_t's (e.g., via -o) for a given ipmpstat invocation.
848485SPeter.Memishian@Sun.COM  *	  It is built at runtime from the command-line arguments.  This
858485SPeter.Memishian@Sun.COM  *	  structure (and a given IPMP object) is used by ofmt_output() to
868485SPeter.Memishian@Sun.COM  *	  output a single line of information about that IPMP object.
878485SPeter.Memishian@Sun.COM  *
888485SPeter.Memishian@Sun.COM  *	* The ipmpstat_cbfunc_t function pointers (*_cbfunc) are called back
898485SPeter.Memishian@Sun.COM  *	  by the walkers.  They are used both internally to implement nested
908485SPeter.Memishian@Sun.COM  *	  walks, and by the ipmpstat output logic to provide the glue between
918485SPeter.Memishian@Sun.COM  *	  the IPMP object walkers and the ofmt_output() logic.  Usually, a
928485SPeter.Memishian@Sun.COM  *	  single line is output for each IPMP object, and thus ofmt_output()
938485SPeter.Memishian@Sun.COM  *	  can be directly invoked (see info_output_cbfunc()).  However, if
948485SPeter.Memishian@Sun.COM  *	  multiple lines need to be output, then a more complex cbfunc is
958485SPeter.Memishian@Sun.COM  *	  needed (see targinfo_output_cbfunc()).  At most one cbfunc is used
968485SPeter.Memishian@Sun.COM  *	  per ipmpstat invocation.
978485SPeter.Memishian@Sun.COM  */
988485SPeter.Memishian@Sun.COM 
998485SPeter.Memishian@Sun.COM /*
1008485SPeter.Memishian@Sun.COM  * Data type used by the sfunc callbacks to obtain the requested information
1018485SPeter.Memishian@Sun.COM  * from the agreed-upon object.
1028485SPeter.Memishian@Sun.COM  */
1038485SPeter.Memishian@Sun.COM typedef struct ipmpstat_sfunc_arg {
1048485SPeter.Memishian@Sun.COM 	ipmp_handle_t		sa_ih;
1058485SPeter.Memishian@Sun.COM 	void			*sa_data;
1068485SPeter.Memishian@Sun.COM } ipmpstat_sfunc_arg_t;
1078485SPeter.Memishian@Sun.COM 
1088485SPeter.Memishian@Sun.COM typedef void ipmpstat_sfunc_t(ipmpstat_sfunc_arg_t *, char *, uint_t);
1098485SPeter.Memishian@Sun.COM 
1108485SPeter.Memishian@Sun.COM /*
1118485SPeter.Memishian@Sun.COM  * Data type that describes how to output a field; used by ofmt_output*().
1128485SPeter.Memishian@Sun.COM  */
1138485SPeter.Memishian@Sun.COM typedef struct ipmpstat_field {
1148485SPeter.Memishian@Sun.COM 	const char		*f_name;	/* field name */
1158485SPeter.Memishian@Sun.COM 	uint_t			f_width;	/* output width */
1168485SPeter.Memishian@Sun.COM 	ipmpstat_sfunc_t	*f_sfunc;	/* value->string function */
1178485SPeter.Memishian@Sun.COM } ipmpstat_field_t;
1188485SPeter.Memishian@Sun.COM 
1198485SPeter.Memishian@Sun.COM /*
1208485SPeter.Memishian@Sun.COM  * Data type that specifies the output field order; used by ofmt_output*()
1218485SPeter.Memishian@Sun.COM  */
1228485SPeter.Memishian@Sun.COM typedef struct ipmpstat_ofmt {
1238485SPeter.Memishian@Sun.COM 	const ipmpstat_field_t	*o_field;	/* current field info */
1248485SPeter.Memishian@Sun.COM 	struct ipmpstat_ofmt	*o_next;	/* next field */
1258485SPeter.Memishian@Sun.COM } ipmpstat_ofmt_t;
1268485SPeter.Memishian@Sun.COM 
1278485SPeter.Memishian@Sun.COM /*
1288485SPeter.Memishian@Sun.COM  * Function pointers used to iterate through IPMP objects.
1298485SPeter.Memishian@Sun.COM  */
1308485SPeter.Memishian@Sun.COM typedef void ipmpstat_cbfunc_t(ipmp_handle_t, void *, void *);
1318485SPeter.Memishian@Sun.COM typedef void ipmpstat_walker_t(ipmp_handle_t, ipmpstat_cbfunc_t *, void *);
1328485SPeter.Memishian@Sun.COM 
1338485SPeter.Memishian@Sun.COM /*
1348485SPeter.Memishian@Sun.COM  * Data type used to implement nested walks.
1358485SPeter.Memishian@Sun.COM  */
1368485SPeter.Memishian@Sun.COM typedef struct ipmpstat_walkdata {
1378485SPeter.Memishian@Sun.COM 	ipmpstat_cbfunc_t	*iw_func; 	/* caller-specified callback */
1388485SPeter.Memishian@Sun.COM 	void			*iw_funcarg; 	/* caller-specified arg */
1398485SPeter.Memishian@Sun.COM } ipmpstat_walkdata_t;
1408485SPeter.Memishian@Sun.COM 
1418485SPeter.Memishian@Sun.COM /*
1428485SPeter.Memishian@Sun.COM  * Data type used by enum2str() to map an enumerated value to a string.
1438485SPeter.Memishian@Sun.COM  */
1448485SPeter.Memishian@Sun.COM typedef struct ipmpstat_enum {
1458485SPeter.Memishian@Sun.COM 	const char		*e_name;	/* string */
1468485SPeter.Memishian@Sun.COM 	int			e_val;		/* value */
1478485SPeter.Memishian@Sun.COM } ipmpstat_enum_t;
1488485SPeter.Memishian@Sun.COM 
1498485SPeter.Memishian@Sun.COM /*
1508485SPeter.Memishian@Sun.COM  * Data type used to pass state between probe_output() and probe_event().
1518485SPeter.Memishian@Sun.COM  */
1528485SPeter.Memishian@Sun.COM typedef struct ipmpstat_probe_state {
1538485SPeter.Memishian@Sun.COM 	ipmp_handle_t	ps_ih;			/* open IPMP handle */
1548485SPeter.Memishian@Sun.COM 	ipmpstat_ofmt_t	*ps_ofmt; 		/* requested ofmt string */
1558485SPeter.Memishian@Sun.COM } ipmpstat_probe_state_t;
1568485SPeter.Memishian@Sun.COM 
1578485SPeter.Memishian@Sun.COM /*
1588485SPeter.Memishian@Sun.COM  * Options that modify the output mode; more than one may be lit.
1598485SPeter.Memishian@Sun.COM  */
1608485SPeter.Memishian@Sun.COM typedef enum {
1618485SPeter.Memishian@Sun.COM 	IPMPSTAT_OPT_NUMERIC	= 0x1,
1628485SPeter.Memishian@Sun.COM 	IPMPSTAT_OPT_PARSABLE 	= 0x2
1638485SPeter.Memishian@Sun.COM } ipmpstat_opt_t;
1648485SPeter.Memishian@Sun.COM 
1658485SPeter.Memishian@Sun.COM /*
1668485SPeter.Memishian@Sun.COM  * Indices for the FLAGS field of the `-i' output format.
1678485SPeter.Memishian@Sun.COM  */
1688485SPeter.Memishian@Sun.COM enum {
1698485SPeter.Memishian@Sun.COM 	IPMPSTAT_IFLAG_INDEX,	IPMPSTAT_SFLAG_INDEX,	IPMPSTAT_M4FLAG_INDEX,
1708485SPeter.Memishian@Sun.COM 	IPMPSTAT_BFLAG_INDEX,	IPMPSTAT_M6FLAG_INDEX,	IPMPSTAT_DFLAG_INDEX,
1718485SPeter.Memishian@Sun.COM 	IPMPSTAT_HFLAG_INDEX,	IPMPSTAT_NUM_FLAGS
1728485SPeter.Memishian@Sun.COM };
1738485SPeter.Memishian@Sun.COM 
1748485SPeter.Memishian@Sun.COM #define	IPMPSTAT_NCOL	80
1758485SPeter.Memishian@Sun.COM #define	NS2FLOATMS(ns)	((float)(ns) / (NANOSEC / MILLISEC))
1768485SPeter.Memishian@Sun.COM #define	MS2FLOATSEC(ms)	((float)(ms) / 1000)
1778485SPeter.Memishian@Sun.COM 
1788485SPeter.Memishian@Sun.COM static const char	*progname;
1798485SPeter.Memishian@Sun.COM static hrtime_t		probe_output_start;
1808485SPeter.Memishian@Sun.COM static struct winsize	winsize;
1818485SPeter.Memishian@Sun.COM static ipmpstat_opt_t	opt;
1828485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	addr_state[], group_state[], if_state[], if_link[];
1838485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	if_probe[], targ_mode[];
1848485SPeter.Memishian@Sun.COM static ipmpstat_field_t addr_fields[], group_fields[], if_fields[];
1858485SPeter.Memishian@Sun.COM static ipmpstat_field_t probe_fields[], targ_fields[];
1868485SPeter.Memishian@Sun.COM static ipmpstat_cbfunc_t walk_addr_cbfunc, walk_if_cbfunc;
1878485SPeter.Memishian@Sun.COM static ipmpstat_cbfunc_t info_output_cbfunc, targinfo_output_cbfunc;
1888485SPeter.Memishian@Sun.COM static ipmpstat_walker_t walk_addr, walk_if, walk_group;
1898485SPeter.Memishian@Sun.COM 
1908485SPeter.Memishian@Sun.COM static int probe_event(sysevent_t *, void *);
1918485SPeter.Memishian@Sun.COM static void probe_output(ipmp_handle_t, ipmpstat_ofmt_t *);
1928485SPeter.Memishian@Sun.COM static ipmpstat_field_t *field_find(ipmpstat_field_t *, const char *);
1938485SPeter.Memishian@Sun.COM static ipmpstat_ofmt_t *ofmt_create(const char *, ipmpstat_field_t []);
1948485SPeter.Memishian@Sun.COM static void ofmt_output(const ipmpstat_ofmt_t *, ipmp_handle_t, void *);
1958485SPeter.Memishian@Sun.COM static void ofmt_destroy(ipmpstat_ofmt_t *);
1968485SPeter.Memishian@Sun.COM static void enum2str(const ipmpstat_enum_t *, int, char *, uint_t);
1978485SPeter.Memishian@Sun.COM static void sockaddr2str(const struct sockaddr_storage *, char *, uint_t);
1988485SPeter.Memishian@Sun.COM static void sighandler(int);
1998485SPeter.Memishian@Sun.COM static void usage(void);
2008485SPeter.Memishian@Sun.COM static void die(const char *, ...);
2018485SPeter.Memishian@Sun.COM static void die_ipmperr(int, const char *, ...);
2028485SPeter.Memishian@Sun.COM static void warn(const char *, ...);
2038485SPeter.Memishian@Sun.COM static void warn_ipmperr(int, const char *, ...);
2048485SPeter.Memishian@Sun.COM 
2058485SPeter.Memishian@Sun.COM int
2068485SPeter.Memishian@Sun.COM main(int argc, char **argv)
2078485SPeter.Memishian@Sun.COM {
2088485SPeter.Memishian@Sun.COM 	int c;
2098485SPeter.Memishian@Sun.COM 	int err;
2108485SPeter.Memishian@Sun.COM 	const char *ofields = NULL;
2118485SPeter.Memishian@Sun.COM 	ipmp_handle_t ih;
2128485SPeter.Memishian@Sun.COM 	ipmp_qcontext_t qcontext = IPMP_QCONTEXT_SNAP;
2138485SPeter.Memishian@Sun.COM 	ipmpstat_ofmt_t *ofmt;
2148485SPeter.Memishian@Sun.COM 	ipmpstat_field_t *fields = NULL;
2158485SPeter.Memishian@Sun.COM 	ipmpstat_cbfunc_t *cbfunc;
2168485SPeter.Memishian@Sun.COM 	ipmpstat_walker_t *walker;
2178485SPeter.Memishian@Sun.COM 
2188485SPeter.Memishian@Sun.COM 	if ((progname = strrchr(argv[0], '/')) == NULL)
2198485SPeter.Memishian@Sun.COM 		progname = argv[0];
2208485SPeter.Memishian@Sun.COM 	else
2218485SPeter.Memishian@Sun.COM 		progname++;
2228485SPeter.Memishian@Sun.COM 
2238485SPeter.Memishian@Sun.COM 	(void) setlocale(LC_ALL, "");
2248485SPeter.Memishian@Sun.COM 	(void) textdomain(TEXT_DOMAIN);
2258485SPeter.Memishian@Sun.COM 
2268485SPeter.Memishian@Sun.COM 	while ((c = getopt(argc, argv, "nLPo:agipt")) != EOF) {
2278485SPeter.Memishian@Sun.COM 		if (fields != NULL && strchr("agipt", c) != NULL)
2288485SPeter.Memishian@Sun.COM 			die("only one output format may be specified\n");
2298485SPeter.Memishian@Sun.COM 
2308485SPeter.Memishian@Sun.COM 		switch (c) {
2318485SPeter.Memishian@Sun.COM 		case 'n':
2328485SPeter.Memishian@Sun.COM 			opt |= IPMPSTAT_OPT_NUMERIC;
2338485SPeter.Memishian@Sun.COM 			break;
2348485SPeter.Memishian@Sun.COM 		case 'L':
2358485SPeter.Memishian@Sun.COM 			/* Undocumented option: for testing use ONLY */
2368485SPeter.Memishian@Sun.COM 			qcontext = IPMP_QCONTEXT_LIVE;
2378485SPeter.Memishian@Sun.COM 			break;
2388485SPeter.Memishian@Sun.COM 		case 'P':
2398485SPeter.Memishian@Sun.COM 			opt |= IPMPSTAT_OPT_PARSABLE;
2408485SPeter.Memishian@Sun.COM 			break;
2418485SPeter.Memishian@Sun.COM 		case 'o':
2428485SPeter.Memishian@Sun.COM 			ofields = optarg;
2438485SPeter.Memishian@Sun.COM 			break;
2448485SPeter.Memishian@Sun.COM 		case 'a':
2458485SPeter.Memishian@Sun.COM 			walker = walk_addr;
2468485SPeter.Memishian@Sun.COM 			cbfunc = info_output_cbfunc;
2478485SPeter.Memishian@Sun.COM 			fields = addr_fields;
2488485SPeter.Memishian@Sun.COM 			break;
2498485SPeter.Memishian@Sun.COM 		case 'g':
2508485SPeter.Memishian@Sun.COM 			walker = walk_group;
2518485SPeter.Memishian@Sun.COM 			cbfunc = info_output_cbfunc;
2528485SPeter.Memishian@Sun.COM 			fields = group_fields;
2538485SPeter.Memishian@Sun.COM 			break;
2548485SPeter.Memishian@Sun.COM 		case 'i':
2558485SPeter.Memishian@Sun.COM 			walker = walk_if;
2568485SPeter.Memishian@Sun.COM 			cbfunc = info_output_cbfunc;
2578485SPeter.Memishian@Sun.COM 			fields = if_fields;
2588485SPeter.Memishian@Sun.COM 			break;
2598485SPeter.Memishian@Sun.COM 		case 'p':
2608485SPeter.Memishian@Sun.COM 			fields = probe_fields;
2618485SPeter.Memishian@Sun.COM 			break;
2628485SPeter.Memishian@Sun.COM 		case 't':
2638485SPeter.Memishian@Sun.COM 			walker = walk_if;
2648485SPeter.Memishian@Sun.COM 			cbfunc = targinfo_output_cbfunc;
2658485SPeter.Memishian@Sun.COM 			fields = targ_fields;
2668485SPeter.Memishian@Sun.COM 			break;
2678485SPeter.Memishian@Sun.COM 		default:
2688485SPeter.Memishian@Sun.COM 			usage();
2698485SPeter.Memishian@Sun.COM 			break;
2708485SPeter.Memishian@Sun.COM 		}
2718485SPeter.Memishian@Sun.COM 	}
2728485SPeter.Memishian@Sun.COM 
2738485SPeter.Memishian@Sun.COM 	if (argc > optind || fields == NULL)
2748485SPeter.Memishian@Sun.COM 		usage();
2758485SPeter.Memishian@Sun.COM 
2768485SPeter.Memishian@Sun.COM 	if (opt & IPMPSTAT_OPT_PARSABLE) {
2778485SPeter.Memishian@Sun.COM 		if (ofields == NULL) {
2788485SPeter.Memishian@Sun.COM 			die("output field list (-o) required in parsable "
2798485SPeter.Memishian@Sun.COM 			    "output mode\n");
2808485SPeter.Memishian@Sun.COM 		} else if (strcasecmp(ofields, "all") == 0) {
2818485SPeter.Memishian@Sun.COM 			die("\"all\" not allowed in parsable output mode\n");
2828485SPeter.Memishian@Sun.COM 		}
2838485SPeter.Memishian@Sun.COM 	}
2848485SPeter.Memishian@Sun.COM 
2858485SPeter.Memishian@Sun.COM 	/*
2868485SPeter.Memishian@Sun.COM 	 * Obtain the window size and monitor changes to the size.  This data
2878485SPeter.Memishian@Sun.COM 	 * is used to redisplay the output headers when necessary.
2888485SPeter.Memishian@Sun.COM 	 */
2898485SPeter.Memishian@Sun.COM 	(void) sigset(SIGWINCH, sighandler);
2908485SPeter.Memishian@Sun.COM 	sighandler(SIGWINCH);
2918485SPeter.Memishian@Sun.COM 
2928485SPeter.Memishian@Sun.COM 	if ((err = ipmp_open(&ih)) != IPMP_SUCCESS)
2938485SPeter.Memishian@Sun.COM 		die_ipmperr(err, "cannot create IPMP handle");
2948485SPeter.Memishian@Sun.COM 
2958485SPeter.Memishian@Sun.COM 	if (ipmp_ping_daemon(ih) != IPMP_SUCCESS)
2968485SPeter.Memishian@Sun.COM 		die("cannot contact in.mpathd(1M) -- is IPMP in use?\n");
2978485SPeter.Memishian@Sun.COM 
2988485SPeter.Memishian@Sun.COM 	/*
2998485SPeter.Memishian@Sun.COM 	 * Create the ofmt linked list that will eventually be passed to
3008485SPeter.Memishian@Sun.COM 	 * to ofmt_output() to output the fields.
3018485SPeter.Memishian@Sun.COM 	 */
3028485SPeter.Memishian@Sun.COM 	ofmt = ofmt_create(ofields, fields);
3038485SPeter.Memishian@Sun.COM 
3048485SPeter.Memishian@Sun.COM 	/*
3058485SPeter.Memishian@Sun.COM 	 * If we've been asked to display probes, then call the probe output
3068485SPeter.Memishian@Sun.COM 	 * function.  Otherwise, snapshot IPMP state (or use live state) and
3078485SPeter.Memishian@Sun.COM 	 * invoke the specified walker with the specified callback function.
3088485SPeter.Memishian@Sun.COM 	 */
3098485SPeter.Memishian@Sun.COM 	if (fields == probe_fields) {
3108485SPeter.Memishian@Sun.COM 		probe_output(ih, ofmt);
3118485SPeter.Memishian@Sun.COM 	} else {
3128485SPeter.Memishian@Sun.COM 		if ((err = ipmp_setqcontext(ih, qcontext)) != IPMP_SUCCESS) {
3138485SPeter.Memishian@Sun.COM 			if (qcontext == IPMP_QCONTEXT_SNAP)
3148485SPeter.Memishian@Sun.COM 				die_ipmperr(err, "cannot snapshot IPMP state");
3158485SPeter.Memishian@Sun.COM 			else
3168485SPeter.Memishian@Sun.COM 				die_ipmperr(err, "cannot use live IPMP state");
3178485SPeter.Memishian@Sun.COM 		}
3188485SPeter.Memishian@Sun.COM 		(*walker)(ih, cbfunc, ofmt);
3198485SPeter.Memishian@Sun.COM 	}
3208485SPeter.Memishian@Sun.COM 
3218485SPeter.Memishian@Sun.COM 	ofmt_destroy(ofmt);
3228485SPeter.Memishian@Sun.COM 	ipmp_close(ih);
3238485SPeter.Memishian@Sun.COM 
3248485SPeter.Memishian@Sun.COM 	return (EXIT_SUCCESS);
3258485SPeter.Memishian@Sun.COM }
3268485SPeter.Memishian@Sun.COM 
3278485SPeter.Memishian@Sun.COM /*
3288485SPeter.Memishian@Sun.COM  * Walks all IPMP groups on the system and invokes `cbfunc' on each, passing
3298485SPeter.Memishian@Sun.COM  * it `ih', the ipmp_groupinfo_t pointer, and `arg'.
3308485SPeter.Memishian@Sun.COM  */
3318485SPeter.Memishian@Sun.COM static void
3328485SPeter.Memishian@Sun.COM walk_group(ipmp_handle_t ih, ipmpstat_cbfunc_t *cbfunc, void *arg)
3338485SPeter.Memishian@Sun.COM {
3348485SPeter.Memishian@Sun.COM 	int err;
3358485SPeter.Memishian@Sun.COM 	uint_t i;
3368485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop;
3378485SPeter.Memishian@Sun.COM 	ipmp_grouplist_t *grlistp;
3388485SPeter.Memishian@Sun.COM 
3398485SPeter.Memishian@Sun.COM 	if ((err = ipmp_getgrouplist(ih, &grlistp)) != IPMP_SUCCESS)
3408485SPeter.Memishian@Sun.COM 		die_ipmperr(err, "cannot get IPMP group list");
3418485SPeter.Memishian@Sun.COM 
3428485SPeter.Memishian@Sun.COM 	for (i = 0; i < grlistp->gl_ngroup; i++) {
3438485SPeter.Memishian@Sun.COM 		err = ipmp_getgroupinfo(ih, grlistp->gl_groups[i], &grinfop);
3448485SPeter.Memishian@Sun.COM 		if (err != IPMP_SUCCESS) {
3458485SPeter.Memishian@Sun.COM 			warn_ipmperr(err, "cannot get info for group `%s'",
3468485SPeter.Memishian@Sun.COM 			    grlistp->gl_groups[i]);
3478485SPeter.Memishian@Sun.COM 			continue;
3488485SPeter.Memishian@Sun.COM 		}
3498485SPeter.Memishian@Sun.COM 		(*cbfunc)(ih, grinfop, arg);
3508485SPeter.Memishian@Sun.COM 		ipmp_freegroupinfo(grinfop);
3518485SPeter.Memishian@Sun.COM 	}
3528485SPeter.Memishian@Sun.COM 
3538485SPeter.Memishian@Sun.COM 	ipmp_freegrouplist(grlistp);
3548485SPeter.Memishian@Sun.COM }
3558485SPeter.Memishian@Sun.COM 
3568485SPeter.Memishian@Sun.COM /*
3578485SPeter.Memishian@Sun.COM  * Walks all IPMP interfaces on the system and invokes `cbfunc' on each,
3588485SPeter.Memishian@Sun.COM  * passing it `ih', the ipmp_ifinfo_t pointer, and `arg'.
3598485SPeter.Memishian@Sun.COM  */
3608485SPeter.Memishian@Sun.COM static void
3618485SPeter.Memishian@Sun.COM walk_if(ipmp_handle_t ih, ipmpstat_cbfunc_t *cbfunc, void *arg)
3628485SPeter.Memishian@Sun.COM {
3638485SPeter.Memishian@Sun.COM 	ipmpstat_walkdata_t iw = { cbfunc, arg };
3648485SPeter.Memishian@Sun.COM 
3658485SPeter.Memishian@Sun.COM 	walk_group(ih, walk_if_cbfunc, &iw);
3668485SPeter.Memishian@Sun.COM }
3678485SPeter.Memishian@Sun.COM 
3688485SPeter.Memishian@Sun.COM /*
3698485SPeter.Memishian@Sun.COM  * Walks all IPMP data addresses on the system and invokes `cbfunc' on each.
3708485SPeter.Memishian@Sun.COM  * passing it `ih', the ipmp_addrinfo_t pointer, and `arg'.
3718485SPeter.Memishian@Sun.COM  */
3728485SPeter.Memishian@Sun.COM static void
3738485SPeter.Memishian@Sun.COM walk_addr(ipmp_handle_t ih, ipmpstat_cbfunc_t *cbfunc, void *arg)
3748485SPeter.Memishian@Sun.COM {
3758485SPeter.Memishian@Sun.COM 	ipmpstat_walkdata_t iw = { cbfunc, arg };
3768485SPeter.Memishian@Sun.COM 
3778485SPeter.Memishian@Sun.COM 	walk_group(ih, walk_addr_cbfunc, &iw);
3788485SPeter.Memishian@Sun.COM }
3798485SPeter.Memishian@Sun.COM 
3808485SPeter.Memishian@Sun.COM /*
3818485SPeter.Memishian@Sun.COM  * Nested walker callback function for walk_if().
3828485SPeter.Memishian@Sun.COM  */
3838485SPeter.Memishian@Sun.COM static void
3848485SPeter.Memishian@Sun.COM walk_if_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
3858485SPeter.Memishian@Sun.COM {
3868485SPeter.Memishian@Sun.COM 	int err;
3878485SPeter.Memishian@Sun.COM 	uint_t i;
3888485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop = infop;
3898485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop;
3908485SPeter.Memishian@Sun.COM 	ipmp_iflist_t *iflistp = grinfop->gr_iflistp;
3918485SPeter.Memishian@Sun.COM 	ipmpstat_walkdata_t *iwp = arg;
3928485SPeter.Memishian@Sun.COM 
3938485SPeter.Memishian@Sun.COM 	for (i = 0; i < iflistp->il_nif; i++) {
3948485SPeter.Memishian@Sun.COM 		err = ipmp_getifinfo(ih, iflistp->il_ifs[i], &ifinfop);
3958485SPeter.Memishian@Sun.COM 		if (err != IPMP_SUCCESS) {
3968485SPeter.Memishian@Sun.COM 			warn_ipmperr(err, "cannot get info for interface `%s'",
3978485SPeter.Memishian@Sun.COM 			    iflistp->il_ifs[i]);
3988485SPeter.Memishian@Sun.COM 			continue;
3998485SPeter.Memishian@Sun.COM 		}
4008485SPeter.Memishian@Sun.COM 		(*iwp->iw_func)(ih, ifinfop, iwp->iw_funcarg);
4018485SPeter.Memishian@Sun.COM 		ipmp_freeifinfo(ifinfop);
4028485SPeter.Memishian@Sun.COM 	}
4038485SPeter.Memishian@Sun.COM }
4048485SPeter.Memishian@Sun.COM 
4058485SPeter.Memishian@Sun.COM /*
4068485SPeter.Memishian@Sun.COM  * Nested walker callback function for walk_addr().
4078485SPeter.Memishian@Sun.COM  */
4088485SPeter.Memishian@Sun.COM static void
4098485SPeter.Memishian@Sun.COM walk_addr_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
4108485SPeter.Memishian@Sun.COM {
4118485SPeter.Memishian@Sun.COM 	int err;
4128485SPeter.Memishian@Sun.COM 	uint_t i;
4138485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop = infop;
4148485SPeter.Memishian@Sun.COM 	ipmp_addrinfo_t *adinfop;
4158485SPeter.Memishian@Sun.COM 	ipmp_addrlist_t *adlistp = grinfop->gr_adlistp;
4168485SPeter.Memishian@Sun.COM 	ipmpstat_walkdata_t *iwp = arg;
4178485SPeter.Memishian@Sun.COM 	char addr[INET6_ADDRSTRLEN];
4188485SPeter.Memishian@Sun.COM 	struct sockaddr_storage *addrp;
4198485SPeter.Memishian@Sun.COM 
4208485SPeter.Memishian@Sun.COM 	for (i = 0; i < adlistp->al_naddr; i++) {
4218485SPeter.Memishian@Sun.COM 		addrp = &adlistp->al_addrs[i];
4228485SPeter.Memishian@Sun.COM 		err = ipmp_getaddrinfo(ih, grinfop->gr_name, addrp, &adinfop);
4238485SPeter.Memishian@Sun.COM 		if (err != IPMP_SUCCESS) {
4248485SPeter.Memishian@Sun.COM 			sockaddr2str(addrp, addr, sizeof (addr));
4258485SPeter.Memishian@Sun.COM 			warn_ipmperr(err, "cannot get info for `%s'", addr);
4268485SPeter.Memishian@Sun.COM 			continue;
4278485SPeter.Memishian@Sun.COM 		}
4288485SPeter.Memishian@Sun.COM 		(*iwp->iw_func)(ih, adinfop, iwp->iw_funcarg);
4298485SPeter.Memishian@Sun.COM 		ipmp_freeaddrinfo(adinfop);
4308485SPeter.Memishian@Sun.COM 	}
4318485SPeter.Memishian@Sun.COM }
4328485SPeter.Memishian@Sun.COM 
4338485SPeter.Memishian@Sun.COM static void
4348485SPeter.Memishian@Sun.COM sfunc_nvwarn(const char *nvname, char *buf, uint_t bufsize)
4358485SPeter.Memishian@Sun.COM {
4368485SPeter.Memishian@Sun.COM 	warn("cannot retrieve %s\n", nvname);
4378485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, "?", bufsize);
4388485SPeter.Memishian@Sun.COM }
4398485SPeter.Memishian@Sun.COM 
4408485SPeter.Memishian@Sun.COM static void
4418485SPeter.Memishian@Sun.COM sfunc_addr_address(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
4428485SPeter.Memishian@Sun.COM {
4438485SPeter.Memishian@Sun.COM 	ipmp_addrinfo_t *adinfop = arg->sa_data;
4448485SPeter.Memishian@Sun.COM 
4458485SPeter.Memishian@Sun.COM 	sockaddr2str(&adinfop->ad_addr, buf, bufsize);
4468485SPeter.Memishian@Sun.COM }
4478485SPeter.Memishian@Sun.COM 
4488485SPeter.Memishian@Sun.COM static void
4498485SPeter.Memishian@Sun.COM sfunc_addr_group(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
4508485SPeter.Memishian@Sun.COM {
4518485SPeter.Memishian@Sun.COM 	int err;
4528485SPeter.Memishian@Sun.COM 	ipmp_addrinfo_t *adinfop = arg->sa_data;
4538485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop;
4548485SPeter.Memishian@Sun.COM 
4558485SPeter.Memishian@Sun.COM 	err = ipmp_getgroupinfo(arg->sa_ih, adinfop->ad_group, &grinfop);
4568485SPeter.Memishian@Sun.COM 	if (err != IPMP_SUCCESS) {
4578485SPeter.Memishian@Sun.COM 		warn_ipmperr(err, "cannot get info for group `%s'",
4588485SPeter.Memishian@Sun.COM 		    adinfop->ad_group);
4598485SPeter.Memishian@Sun.COM 		(void) strlcpy(buf, "?", bufsize);
4608485SPeter.Memishian@Sun.COM 		return;
4618485SPeter.Memishian@Sun.COM 	}
4628485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, grinfop->gr_ifname, bufsize);
4638485SPeter.Memishian@Sun.COM 	ipmp_freegroupinfo(grinfop);
4648485SPeter.Memishian@Sun.COM }
4658485SPeter.Memishian@Sun.COM 
4668485SPeter.Memishian@Sun.COM static void
4678485SPeter.Memishian@Sun.COM sfunc_addr_state(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
4688485SPeter.Memishian@Sun.COM {
4698485SPeter.Memishian@Sun.COM 	ipmp_addrinfo_t *adinfop = arg->sa_data;
4708485SPeter.Memishian@Sun.COM 
4718485SPeter.Memishian@Sun.COM 	enum2str(addr_state, adinfop->ad_state, buf, bufsize);
4728485SPeter.Memishian@Sun.COM }
4738485SPeter.Memishian@Sun.COM 
4748485SPeter.Memishian@Sun.COM static void
4758485SPeter.Memishian@Sun.COM sfunc_addr_inbound(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
4768485SPeter.Memishian@Sun.COM {
4778485SPeter.Memishian@Sun.COM 	ipmp_addrinfo_t *adinfop = arg->sa_data;
4788485SPeter.Memishian@Sun.COM 
4798485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, adinfop->ad_binding, bufsize);
4808485SPeter.Memishian@Sun.COM }
4818485SPeter.Memishian@Sun.COM 
4828485SPeter.Memishian@Sun.COM static void
4838485SPeter.Memishian@Sun.COM sfunc_addr_outbound(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
4848485SPeter.Memishian@Sun.COM {
4858485SPeter.Memishian@Sun.COM 	int err;
4868485SPeter.Memishian@Sun.COM 	uint_t i, nactive = 0;
4878485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop;
4888485SPeter.Memishian@Sun.COM 	ipmp_iflist_t *iflistp;
4898485SPeter.Memishian@Sun.COM 	ipmp_addrinfo_t *adinfop = arg->sa_data;
4908485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop;
4918485SPeter.Memishian@Sun.COM 
4928485SPeter.Memishian@Sun.COM 	if (adinfop->ad_state == IPMP_ADDR_DOWN)
4938485SPeter.Memishian@Sun.COM 		return;
4948485SPeter.Memishian@Sun.COM 
4958485SPeter.Memishian@Sun.COM 	/*
4968485SPeter.Memishian@Sun.COM 	 * If there's no inbound interface for this address, there can't
4978485SPeter.Memishian@Sun.COM 	 * be any outbound traffic.
4988485SPeter.Memishian@Sun.COM 	 */
4998485SPeter.Memishian@Sun.COM 	if (adinfop->ad_binding[0] == '\0')
5008485SPeter.Memishian@Sun.COM 		return;
5018485SPeter.Memishian@Sun.COM 
5028485SPeter.Memishian@Sun.COM 	/*
5038485SPeter.Memishian@Sun.COM 	 * The address can use any active interface in the group, so
5048485SPeter.Memishian@Sun.COM 	 * obtain all of those.
5058485SPeter.Memishian@Sun.COM 	 */
5068485SPeter.Memishian@Sun.COM 	err = ipmp_getgroupinfo(arg->sa_ih, adinfop->ad_group, &grinfop);
5078485SPeter.Memishian@Sun.COM 	if (err != IPMP_SUCCESS) {
5088485SPeter.Memishian@Sun.COM 		warn_ipmperr(err, "cannot get info for group `%s'",
5098485SPeter.Memishian@Sun.COM 		    adinfop->ad_group);
5108485SPeter.Memishian@Sun.COM 		(void) strlcpy(buf, "?", bufsize);
5118485SPeter.Memishian@Sun.COM 		return;
5128485SPeter.Memishian@Sun.COM 	}
5138485SPeter.Memishian@Sun.COM 
5148485SPeter.Memishian@Sun.COM 	iflistp = grinfop->gr_iflistp;
5158485SPeter.Memishian@Sun.COM 	for (i = 0; i < iflistp->il_nif; i++) {
5168485SPeter.Memishian@Sun.COM 		err = ipmp_getifinfo(arg->sa_ih, iflistp->il_ifs[i], &ifinfop);
5178485SPeter.Memishian@Sun.COM 		if (err != IPMP_SUCCESS) {
5188485SPeter.Memishian@Sun.COM 			warn_ipmperr(err, "cannot get info for interface `%s'",
5198485SPeter.Memishian@Sun.COM 			    iflistp->il_ifs[i]);
5208485SPeter.Memishian@Sun.COM 			continue;
5218485SPeter.Memishian@Sun.COM 		}
5228485SPeter.Memishian@Sun.COM 
5238485SPeter.Memishian@Sun.COM 		if (ifinfop->if_flags & IPMP_IFFLAG_ACTIVE) {
5248485SPeter.Memishian@Sun.COM 			if (nactive++ != 0)
5258485SPeter.Memishian@Sun.COM 				(void) strlcat(buf, " ", bufsize);
5268485SPeter.Memishian@Sun.COM 			(void) strlcat(buf, ifinfop->if_name, bufsize);
5278485SPeter.Memishian@Sun.COM 		}
5288485SPeter.Memishian@Sun.COM 		ipmp_freeifinfo(ifinfop);
5298485SPeter.Memishian@Sun.COM 	}
5308485SPeter.Memishian@Sun.COM 	ipmp_freegroupinfo(grinfop);
5318485SPeter.Memishian@Sun.COM }
5328485SPeter.Memishian@Sun.COM 
5338485SPeter.Memishian@Sun.COM static void
5348485SPeter.Memishian@Sun.COM sfunc_group_name(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
5358485SPeter.Memishian@Sun.COM {
5368485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop = arg->sa_data;
5378485SPeter.Memishian@Sun.COM 
5388485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, grinfop->gr_name, bufsize);
5398485SPeter.Memishian@Sun.COM }
5408485SPeter.Memishian@Sun.COM 
5418485SPeter.Memishian@Sun.COM static void
5428485SPeter.Memishian@Sun.COM sfunc_group_ifname(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
5438485SPeter.Memishian@Sun.COM {
5448485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop = arg->sa_data;
5458485SPeter.Memishian@Sun.COM 
5468485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, grinfop->gr_ifname, bufsize);
5478485SPeter.Memishian@Sun.COM }
5488485SPeter.Memishian@Sun.COM 
5498485SPeter.Memishian@Sun.COM static void
5508485SPeter.Memishian@Sun.COM sfunc_group_state(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
5518485SPeter.Memishian@Sun.COM {
5528485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop = arg->sa_data;
5538485SPeter.Memishian@Sun.COM 
5548485SPeter.Memishian@Sun.COM 	enum2str(group_state, grinfop->gr_state, buf, bufsize);
5558485SPeter.Memishian@Sun.COM }
5568485SPeter.Memishian@Sun.COM 
5578485SPeter.Memishian@Sun.COM static void
5588485SPeter.Memishian@Sun.COM sfunc_group_fdt(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
5598485SPeter.Memishian@Sun.COM {
5608485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop = arg->sa_data;
5618485SPeter.Memishian@Sun.COM 
5628485SPeter.Memishian@Sun.COM 	if (grinfop->gr_fdt == 0)
5638485SPeter.Memishian@Sun.COM 		return;
5648485SPeter.Memishian@Sun.COM 
5658485SPeter.Memishian@Sun.COM 	(void) snprintf(buf, bufsize, "%.2fs", MS2FLOATSEC(grinfop->gr_fdt));
5668485SPeter.Memishian@Sun.COM }
5678485SPeter.Memishian@Sun.COM 
5688485SPeter.Memishian@Sun.COM static void
5698485SPeter.Memishian@Sun.COM sfunc_group_interfaces(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
5708485SPeter.Memishian@Sun.COM {
5718485SPeter.Memishian@Sun.COM 	int err;
5728485SPeter.Memishian@Sun.COM 	uint_t i;
5738485SPeter.Memishian@Sun.COM 	char *active, *inactive, *unusable;
5748485SPeter.Memishian@Sun.COM 	uint_t nactive = 0, ninactive = 0, nunusable = 0;
5758485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop = arg->sa_data;
5768485SPeter.Memishian@Sun.COM 	ipmp_iflist_t *iflistp = grinfop->gr_iflistp;
5778485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop;
5788485SPeter.Memishian@Sun.COM 
5798485SPeter.Memishian@Sun.COM 	active = alloca(bufsize);
5808485SPeter.Memishian@Sun.COM 	active[0] = '\0';
5818485SPeter.Memishian@Sun.COM 	inactive = alloca(bufsize);
5828485SPeter.Memishian@Sun.COM 	inactive[0] = '\0';
5838485SPeter.Memishian@Sun.COM 	unusable = alloca(bufsize);
5848485SPeter.Memishian@Sun.COM 	unusable[0] = '\0';
5858485SPeter.Memishian@Sun.COM 
5868485SPeter.Memishian@Sun.COM 	for (i = 0; i < iflistp->il_nif; i++) {
5878485SPeter.Memishian@Sun.COM 		err = ipmp_getifinfo(arg->sa_ih, iflistp->il_ifs[i], &ifinfop);
5888485SPeter.Memishian@Sun.COM 		if (err != IPMP_SUCCESS) {
5898485SPeter.Memishian@Sun.COM 			warn_ipmperr(err, "cannot get info for interface `%s'",
5908485SPeter.Memishian@Sun.COM 			    iflistp->il_ifs[i]);
5918485SPeter.Memishian@Sun.COM 			continue;
5928485SPeter.Memishian@Sun.COM 		}
5938485SPeter.Memishian@Sun.COM 
5948485SPeter.Memishian@Sun.COM 		if (ifinfop->if_flags & IPMP_IFFLAG_ACTIVE) {
5958485SPeter.Memishian@Sun.COM 			if (nactive++ != 0)
5968485SPeter.Memishian@Sun.COM 				(void) strlcat(active, " ", bufsize);
5978485SPeter.Memishian@Sun.COM 			(void) strlcat(active, ifinfop->if_name, bufsize);
5988485SPeter.Memishian@Sun.COM 		} else if (ifinfop->if_flags & IPMP_IFFLAG_INACTIVE) {
5998485SPeter.Memishian@Sun.COM 			if (ninactive++ != 0)
6008485SPeter.Memishian@Sun.COM 				(void) strlcat(inactive, " ", bufsize);
6018485SPeter.Memishian@Sun.COM 			(void) strlcat(inactive, ifinfop->if_name, bufsize);
6028485SPeter.Memishian@Sun.COM 		} else {
6038485SPeter.Memishian@Sun.COM 			if (nunusable++ != 0)
6048485SPeter.Memishian@Sun.COM 				(void) strlcat(unusable, " ", bufsize);
6058485SPeter.Memishian@Sun.COM 			(void) strlcat(unusable, ifinfop->if_name, bufsize);
6068485SPeter.Memishian@Sun.COM 		}
6078485SPeter.Memishian@Sun.COM 
6088485SPeter.Memishian@Sun.COM 		ipmp_freeifinfo(ifinfop);
6098485SPeter.Memishian@Sun.COM 	}
6108485SPeter.Memishian@Sun.COM 
6118485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, active, bufsize);
6128485SPeter.Memishian@Sun.COM 
6138485SPeter.Memishian@Sun.COM 	if (ninactive > 0) {
6148485SPeter.Memishian@Sun.COM 		if (nactive != 0)
6158485SPeter.Memishian@Sun.COM 			(void) strlcat(buf, " ", bufsize);
6168485SPeter.Memishian@Sun.COM 
6178485SPeter.Memishian@Sun.COM 		(void) strlcat(buf, "(", bufsize);
6188485SPeter.Memishian@Sun.COM 		(void) strlcat(buf, inactive, bufsize);
6198485SPeter.Memishian@Sun.COM 		(void) strlcat(buf, ")", bufsize);
6208485SPeter.Memishian@Sun.COM 	}
6218485SPeter.Memishian@Sun.COM 
6228485SPeter.Memishian@Sun.COM 	if (nunusable > 0) {
6238485SPeter.Memishian@Sun.COM 		if (nactive + ninactive != 0)
6248485SPeter.Memishian@Sun.COM 			(void) strlcat(buf, " ", bufsize);
6258485SPeter.Memishian@Sun.COM 
6268485SPeter.Memishian@Sun.COM 		(void) strlcat(buf, "[", bufsize);
6278485SPeter.Memishian@Sun.COM 		(void) strlcat(buf, unusable, bufsize);
6288485SPeter.Memishian@Sun.COM 		(void) strlcat(buf, "]", bufsize);
6298485SPeter.Memishian@Sun.COM 	}
6308485SPeter.Memishian@Sun.COM }
6318485SPeter.Memishian@Sun.COM 
6328485SPeter.Memishian@Sun.COM static void
6338485SPeter.Memishian@Sun.COM sfunc_if_name(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
6348485SPeter.Memishian@Sun.COM {
6358485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
6368485SPeter.Memishian@Sun.COM 
6378485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, ifinfop->if_name, bufsize);
6388485SPeter.Memishian@Sun.COM }
6398485SPeter.Memishian@Sun.COM 
6408485SPeter.Memishian@Sun.COM static void
6418485SPeter.Memishian@Sun.COM sfunc_if_active(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
6428485SPeter.Memishian@Sun.COM {
6438485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
6448485SPeter.Memishian@Sun.COM 
6458485SPeter.Memishian@Sun.COM 	if (ifinfop->if_flags & IPMP_IFFLAG_ACTIVE)
6468485SPeter.Memishian@Sun.COM 		(void) strlcpy(buf, "yes", bufsize);
6478485SPeter.Memishian@Sun.COM 	else
6488485SPeter.Memishian@Sun.COM 		(void) strlcpy(buf, "no", bufsize);
6498485SPeter.Memishian@Sun.COM }
6508485SPeter.Memishian@Sun.COM 
6518485SPeter.Memishian@Sun.COM static void
6528485SPeter.Memishian@Sun.COM sfunc_if_group(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
6538485SPeter.Memishian@Sun.COM {
6548485SPeter.Memishian@Sun.COM 	int err;
6558485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
6568485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop;
6578485SPeter.Memishian@Sun.COM 
6588485SPeter.Memishian@Sun.COM 	err = ipmp_getgroupinfo(arg->sa_ih, ifinfop->if_group, &grinfop);
6598485SPeter.Memishian@Sun.COM 	if (err != IPMP_SUCCESS) {
6608485SPeter.Memishian@Sun.COM 		warn_ipmperr(err, "cannot get info for group `%s'",
6618485SPeter.Memishian@Sun.COM 		    ifinfop->if_group);
6628485SPeter.Memishian@Sun.COM 		(void) strlcpy(buf, "?", bufsize);
6638485SPeter.Memishian@Sun.COM 		return;
6648485SPeter.Memishian@Sun.COM 	}
6658485SPeter.Memishian@Sun.COM 
6668485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, grinfop->gr_ifname, bufsize);
6678485SPeter.Memishian@Sun.COM 	ipmp_freegroupinfo(grinfop);
6688485SPeter.Memishian@Sun.COM }
6698485SPeter.Memishian@Sun.COM 
6708485SPeter.Memishian@Sun.COM static void
6718485SPeter.Memishian@Sun.COM sfunc_if_flags(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
6728485SPeter.Memishian@Sun.COM {
6738485SPeter.Memishian@Sun.COM 	int err;
6748485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
6758485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop;
6768485SPeter.Memishian@Sun.COM 
6778485SPeter.Memishian@Sun.COM 	assert(bufsize > IPMPSTAT_NUM_FLAGS);
6788485SPeter.Memishian@Sun.COM 
6798485SPeter.Memishian@Sun.COM 	(void) memset(buf, '-', IPMPSTAT_NUM_FLAGS);
6808485SPeter.Memishian@Sun.COM 	buf[IPMPSTAT_NUM_FLAGS] = '\0';
6818485SPeter.Memishian@Sun.COM 
6828485SPeter.Memishian@Sun.COM 	if (ifinfop->if_type == IPMP_IF_STANDBY)
6838485SPeter.Memishian@Sun.COM 		buf[IPMPSTAT_SFLAG_INDEX] = 's';
6848485SPeter.Memishian@Sun.COM 
6858485SPeter.Memishian@Sun.COM 	if (ifinfop->if_flags & IPMP_IFFLAG_INACTIVE)
6868485SPeter.Memishian@Sun.COM 		buf[IPMPSTAT_IFLAG_INDEX] = 'i';
6878485SPeter.Memishian@Sun.COM 
6888485SPeter.Memishian@Sun.COM 	if (ifinfop->if_flags & IPMP_IFFLAG_DOWN)
6898485SPeter.Memishian@Sun.COM 		buf[IPMPSTAT_DFLAG_INDEX] = 'd';
6908485SPeter.Memishian@Sun.COM 
6918485SPeter.Memishian@Sun.COM 	if (ifinfop->if_flags & IPMP_IFFLAG_HWADDRDUP)
6928485SPeter.Memishian@Sun.COM 		buf[IPMPSTAT_HFLAG_INDEX] = 'h';
6938485SPeter.Memishian@Sun.COM 
6948485SPeter.Memishian@Sun.COM 	err = ipmp_getgroupinfo(arg->sa_ih, ifinfop->if_group, &grinfop);
6958485SPeter.Memishian@Sun.COM 	if (err != IPMP_SUCCESS) {
6968485SPeter.Memishian@Sun.COM 		warn_ipmperr(err, "cannot get broadcast/multicast info for "
6978485SPeter.Memishian@Sun.COM 		    "group `%s'", ifinfop->if_group);
6988485SPeter.Memishian@Sun.COM 		return;
6998485SPeter.Memishian@Sun.COM 	}
7008485SPeter.Memishian@Sun.COM 
7018485SPeter.Memishian@Sun.COM 	if (strcmp(grinfop->gr_m4ifname, ifinfop->if_name) == 0)
7028485SPeter.Memishian@Sun.COM 		buf[IPMPSTAT_M4FLAG_INDEX] = 'm';
7038485SPeter.Memishian@Sun.COM 
7048485SPeter.Memishian@Sun.COM 	if (strcmp(grinfop->gr_m6ifname, ifinfop->if_name) == 0)
7058485SPeter.Memishian@Sun.COM 		buf[IPMPSTAT_M6FLAG_INDEX] = 'M';
7068485SPeter.Memishian@Sun.COM 
7078485SPeter.Memishian@Sun.COM 	if (strcmp(grinfop->gr_bcifname, ifinfop->if_name) == 0)
7088485SPeter.Memishian@Sun.COM 		buf[IPMPSTAT_BFLAG_INDEX] = 'b';
7098485SPeter.Memishian@Sun.COM 
7108485SPeter.Memishian@Sun.COM 	ipmp_freegroupinfo(grinfop);
7118485SPeter.Memishian@Sun.COM }
7128485SPeter.Memishian@Sun.COM 
7138485SPeter.Memishian@Sun.COM static void
7148485SPeter.Memishian@Sun.COM sfunc_if_link(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
7158485SPeter.Memishian@Sun.COM {
7168485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
7178485SPeter.Memishian@Sun.COM 
7188485SPeter.Memishian@Sun.COM 	enum2str(if_link, ifinfop->if_linkstate, buf, bufsize);
7198485SPeter.Memishian@Sun.COM }
7208485SPeter.Memishian@Sun.COM 
7218485SPeter.Memishian@Sun.COM static void
7228485SPeter.Memishian@Sun.COM sfunc_if_probe(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
7238485SPeter.Memishian@Sun.COM {
7248485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
7258485SPeter.Memishian@Sun.COM 
7268485SPeter.Memishian@Sun.COM 	enum2str(if_probe, ifinfop->if_probestate, buf, bufsize);
7278485SPeter.Memishian@Sun.COM }
7288485SPeter.Memishian@Sun.COM 
7298485SPeter.Memishian@Sun.COM static void
7308485SPeter.Memishian@Sun.COM sfunc_if_state(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
7318485SPeter.Memishian@Sun.COM {
7328485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
7338485SPeter.Memishian@Sun.COM 
7348485SPeter.Memishian@Sun.COM 	enum2str(if_state, ifinfop->if_state, buf, bufsize);
7358485SPeter.Memishian@Sun.COM }
7368485SPeter.Memishian@Sun.COM 
7378485SPeter.Memishian@Sun.COM static void
7388485SPeter.Memishian@Sun.COM sfunc_probe_id(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
7398485SPeter.Memishian@Sun.COM {
7408485SPeter.Memishian@Sun.COM 	uint32_t probe_id;
7418485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
7428485SPeter.Memishian@Sun.COM 
7438485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_uint32(nvl, IPMP_PROBE_ID, &probe_id) != 0) {
7448485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_ID", buf, bufsize);
7458485SPeter.Memishian@Sun.COM 		return;
7468485SPeter.Memishian@Sun.COM 	}
7478485SPeter.Memishian@Sun.COM 
7488485SPeter.Memishian@Sun.COM 	(void) snprintf(buf, bufsize, "%u", probe_id);
7498485SPeter.Memishian@Sun.COM }
7508485SPeter.Memishian@Sun.COM 
7518485SPeter.Memishian@Sun.COM static void
7528485SPeter.Memishian@Sun.COM sfunc_probe_ifname(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
7538485SPeter.Memishian@Sun.COM {
7548485SPeter.Memishian@Sun.COM 	char *ifname;
7558485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
7568485SPeter.Memishian@Sun.COM 
7578485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_string(nvl, IPMP_IF_NAME, &ifname) != 0) {
7588485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_IF_NAME", buf, bufsize);
7598485SPeter.Memishian@Sun.COM 		return;
7608485SPeter.Memishian@Sun.COM 	}
7618485SPeter.Memishian@Sun.COM 
7628485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, ifname, bufsize);
7638485SPeter.Memishian@Sun.COM }
7648485SPeter.Memishian@Sun.COM 
7658485SPeter.Memishian@Sun.COM static void
7668485SPeter.Memishian@Sun.COM sfunc_probe_time(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
7678485SPeter.Memishian@Sun.COM {
7688485SPeter.Memishian@Sun.COM 	hrtime_t start;
7698485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
7708485SPeter.Memishian@Sun.COM 
7718485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_START_TIME, &start) != 0) {
7728485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_START_TIME", buf, bufsize);
7738485SPeter.Memishian@Sun.COM 		return;
7748485SPeter.Memishian@Sun.COM 	}
7758485SPeter.Memishian@Sun.COM 
7768485SPeter.Memishian@Sun.COM 	(void) snprintf(buf, bufsize, "%.2fs",
7778485SPeter.Memishian@Sun.COM 	    (float)(start - probe_output_start) / NANOSEC);
7788485SPeter.Memishian@Sun.COM }
7798485SPeter.Memishian@Sun.COM 
7808485SPeter.Memishian@Sun.COM static void
7818485SPeter.Memishian@Sun.COM sfunc_probe_target(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
7828485SPeter.Memishian@Sun.COM {
7838485SPeter.Memishian@Sun.COM 	uint_t nelem;
7848485SPeter.Memishian@Sun.COM 	struct sockaddr_storage *target;
7858485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
7868485SPeter.Memishian@Sun.COM 
7878485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_byte_array(nvl, IPMP_PROBE_TARGET,
7888485SPeter.Memishian@Sun.COM 	    (uchar_t **)&target, &nelem) != 0) {
7898485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_TARGET", buf, bufsize);
7908485SPeter.Memishian@Sun.COM 		return;
7918485SPeter.Memishian@Sun.COM 	}
7928485SPeter.Memishian@Sun.COM 
7938485SPeter.Memishian@Sun.COM 	sockaddr2str(target, buf, bufsize);
7948485SPeter.Memishian@Sun.COM }
7958485SPeter.Memishian@Sun.COM 
7968485SPeter.Memishian@Sun.COM static void
7978485SPeter.Memishian@Sun.COM sfunc_probe_rtt(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
7988485SPeter.Memishian@Sun.COM {
7998485SPeter.Memishian@Sun.COM 	hrtime_t start, ackproc;
8008485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
8018485SPeter.Memishian@Sun.COM 	uint32_t state;
8028485SPeter.Memishian@Sun.COM 
8038485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_uint32(nvl, IPMP_PROBE_STATE, &state) != 0) {
8048485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_STATE", buf, bufsize);
8058485SPeter.Memishian@Sun.COM 		return;
8068485SPeter.Memishian@Sun.COM 	}
8078485SPeter.Memishian@Sun.COM 
8088485SPeter.Memishian@Sun.COM 	if (state != IPMP_PROBE_ACKED)
8098485SPeter.Memishian@Sun.COM 		return;
8108485SPeter.Memishian@Sun.COM 
8118485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_START_TIME, &start) != 0) {
8128485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_START_TIME", buf, bufsize);
8138485SPeter.Memishian@Sun.COM 		return;
8148485SPeter.Memishian@Sun.COM 	}
8158485SPeter.Memishian@Sun.COM 
8168485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_ACKPROC_TIME, &ackproc) != 0) {
8178485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_ACKPROC_TIME", buf, bufsize);
8188485SPeter.Memishian@Sun.COM 		return;
8198485SPeter.Memishian@Sun.COM 	}
8208485SPeter.Memishian@Sun.COM 
8218485SPeter.Memishian@Sun.COM 	(void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(ackproc - start));
8228485SPeter.Memishian@Sun.COM }
8238485SPeter.Memishian@Sun.COM 
8248485SPeter.Memishian@Sun.COM static void
8258485SPeter.Memishian@Sun.COM sfunc_probe_netrtt(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
8268485SPeter.Memishian@Sun.COM {
8278485SPeter.Memishian@Sun.COM 	hrtime_t sent, ackrecv;
8288485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
8298485SPeter.Memishian@Sun.COM 	uint32_t state;
8308485SPeter.Memishian@Sun.COM 
8318485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_uint32(nvl, IPMP_PROBE_STATE, &state) != 0) {
8328485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_STATE", buf, bufsize);
8338485SPeter.Memishian@Sun.COM 		return;
8348485SPeter.Memishian@Sun.COM 	}
8358485SPeter.Memishian@Sun.COM 
8368485SPeter.Memishian@Sun.COM 	if (state != IPMP_PROBE_ACKED)
8378485SPeter.Memishian@Sun.COM 		return;
8388485SPeter.Memishian@Sun.COM 
8398485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_SENT_TIME, &sent) != 0) {
8408485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_SENT_TIME", buf, bufsize);
8418485SPeter.Memishian@Sun.COM 		return;
8428485SPeter.Memishian@Sun.COM 	}
8438485SPeter.Memishian@Sun.COM 
8448485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_ACKRECV_TIME, &ackrecv) != 0) {
8458485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_ACKRECV_TIME", buf, bufsize);
8468485SPeter.Memishian@Sun.COM 		return;
8478485SPeter.Memishian@Sun.COM 	}
8488485SPeter.Memishian@Sun.COM 
8498485SPeter.Memishian@Sun.COM 	(void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(ackrecv - sent));
8508485SPeter.Memishian@Sun.COM }
8518485SPeter.Memishian@Sun.COM 
8528485SPeter.Memishian@Sun.COM static void
8538485SPeter.Memishian@Sun.COM sfunc_probe_rttavg(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
8548485SPeter.Memishian@Sun.COM {
8558485SPeter.Memishian@Sun.COM 	int64_t rttavg;
8568485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
8578485SPeter.Memishian@Sun.COM 
8588485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_int64(nvl, IPMP_PROBE_TARGET_RTTAVG, &rttavg) != 0) {
8598485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_TARGET_RTTAVG", buf, bufsize);
8608485SPeter.Memishian@Sun.COM 		return;
8618485SPeter.Memishian@Sun.COM 	}
8628485SPeter.Memishian@Sun.COM 
8638485SPeter.Memishian@Sun.COM 	if (rttavg != 0)
8648485SPeter.Memishian@Sun.COM 		(void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(rttavg));
8658485SPeter.Memishian@Sun.COM }
8668485SPeter.Memishian@Sun.COM 
8678485SPeter.Memishian@Sun.COM static void
8688485SPeter.Memishian@Sun.COM sfunc_probe_rttdev(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
8698485SPeter.Memishian@Sun.COM {
8708485SPeter.Memishian@Sun.COM 	int64_t rttdev;
8718485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
8728485SPeter.Memishian@Sun.COM 
8738485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_int64(nvl, IPMP_PROBE_TARGET_RTTDEV, &rttdev) != 0) {
8748485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_TARGET_RTTDEV", buf, bufsize);
8758485SPeter.Memishian@Sun.COM 		return;
8768485SPeter.Memishian@Sun.COM 	}
8778485SPeter.Memishian@Sun.COM 
8788485SPeter.Memishian@Sun.COM 	if (rttdev != 0)
8798485SPeter.Memishian@Sun.COM 		(void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(rttdev));
8808485SPeter.Memishian@Sun.COM }
8818485SPeter.Memishian@Sun.COM 
8828485SPeter.Memishian@Sun.COM /* ARGSUSED */
8838485SPeter.Memishian@Sun.COM static void
8848485SPeter.Memishian@Sun.COM probe_enabled_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
8858485SPeter.Memishian@Sun.COM {
8868485SPeter.Memishian@Sun.COM 	uint_t *nenabledp = arg;
8878485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = infop;
8888485SPeter.Memishian@Sun.COM 
8898485SPeter.Memishian@Sun.COM 	if (ifinfop->if_probestate != IPMP_PROBE_DISABLED)
8908485SPeter.Memishian@Sun.COM 		(*nenabledp)++;
8918485SPeter.Memishian@Sun.COM }
8928485SPeter.Memishian@Sun.COM 
8938485SPeter.Memishian@Sun.COM static void
8948485SPeter.Memishian@Sun.COM probe_output(ipmp_handle_t ih, ipmpstat_ofmt_t *ofmt)
8958485SPeter.Memishian@Sun.COM {
8968485SPeter.Memishian@Sun.COM 	char sub[MAX_SUBID_LEN];
8978485SPeter.Memishian@Sun.COM 	evchan_t *evch;
8988485SPeter.Memishian@Sun.COM 	ipmpstat_probe_state_t ps = { ih, ofmt };
8998485SPeter.Memishian@Sun.COM 	uint_t nenabled = 0;
9008485SPeter.Memishian@Sun.COM 
9018485SPeter.Memishian@Sun.COM 	/*
9028485SPeter.Memishian@Sun.COM 	 * Check if any interfaces are enabled for probe-based failure
9038485SPeter.Memishian@Sun.COM 	 * detection.  If not, immediately fail.
9048485SPeter.Memishian@Sun.COM 	 */
9058485SPeter.Memishian@Sun.COM 	walk_if(ih, probe_enabled_cbfunc, &nenabled);
9068485SPeter.Memishian@Sun.COM 	if (nenabled == 0)
9078485SPeter.Memishian@Sun.COM 		die("probe-based failure detection is disabled\n");
9088485SPeter.Memishian@Sun.COM 
9098485SPeter.Memishian@Sun.COM 	probe_output_start = gethrtime();
9108485SPeter.Memishian@Sun.COM 
9118485SPeter.Memishian@Sun.COM 	/*
9128485SPeter.Memishian@Sun.COM 	 * Unfortunately, until 4791900 is fixed, only privileged processes
9138485SPeter.Memishian@Sun.COM 	 * can bind and thus receive sysevents.
9148485SPeter.Memishian@Sun.COM 	 */
9158485SPeter.Memishian@Sun.COM 	errno = sysevent_evc_bind(IPMP_EVENT_CHAN, &evch, EVCH_CREAT);
9168485SPeter.Memishian@Sun.COM 	if (errno != 0) {
9178485SPeter.Memishian@Sun.COM 		if (errno == EPERM)
9188485SPeter.Memishian@Sun.COM 			die("insufficient privileges for -p\n");
9198485SPeter.Memishian@Sun.COM 		die("sysevent_evc_bind to channel %s failed", IPMP_EVENT_CHAN);
9208485SPeter.Memishian@Sun.COM 	}
9218485SPeter.Memishian@Sun.COM 
9228485SPeter.Memishian@Sun.COM 	/*
9238485SPeter.Memishian@Sun.COM 	 * The subscriber must be unique in order for sysevent_evc_subscribe()
9248485SPeter.Memishian@Sun.COM 	 * to succeed, so combine our name and pid.
9258485SPeter.Memishian@Sun.COM 	 */
9268485SPeter.Memishian@Sun.COM 	(void) snprintf(sub, sizeof (sub), "%d-%s", getpid(), progname);
9278485SPeter.Memishian@Sun.COM 
9288485SPeter.Memishian@Sun.COM 	errno = sysevent_evc_subscribe(evch, sub, EC_IPMP, probe_event, &ps, 0);
9298485SPeter.Memishian@Sun.COM 	if (errno != 0)
9308485SPeter.Memishian@Sun.COM 		die("sysevent_evc_subscribe for class %s failed", EC_IPMP);
9318485SPeter.Memishian@Sun.COM 
9328485SPeter.Memishian@Sun.COM 	for (;;)
9338485SPeter.Memishian@Sun.COM 		(void) pause();
9348485SPeter.Memishian@Sun.COM }
9358485SPeter.Memishian@Sun.COM 
9368485SPeter.Memishian@Sun.COM static int
9378485SPeter.Memishian@Sun.COM probe_event(sysevent_t *ev, void *arg)
9388485SPeter.Memishian@Sun.COM {
9398485SPeter.Memishian@Sun.COM 	nvlist_t *nvl;
9408485SPeter.Memishian@Sun.COM 	uint32_t state;
9418485SPeter.Memishian@Sun.COM 	uint32_t version;
9428485SPeter.Memishian@Sun.COM 	ipmpstat_probe_state_t *psp = arg;
9438485SPeter.Memishian@Sun.COM 
9448485SPeter.Memishian@Sun.COM 	if (strcmp(sysevent_get_subclass_name(ev), ESC_IPMP_PROBE_STATE) != 0)
9458485SPeter.Memishian@Sun.COM 		return (0);
9468485SPeter.Memishian@Sun.COM 
9478485SPeter.Memishian@Sun.COM 	if (sysevent_get_attr_list(ev, &nvl) != 0) {
9488485SPeter.Memishian@Sun.COM 		warn("sysevent_get_attr_list failed; dropping event");
9498485SPeter.Memishian@Sun.COM 		return (0);
9508485SPeter.Memishian@Sun.COM 	}
9518485SPeter.Memishian@Sun.COM 
9528485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_uint32(nvl, IPMP_EVENT_VERSION, &version) != 0) {
9538485SPeter.Memishian@Sun.COM 		warn("dropped event with no IPMP_EVENT_VERSION\n");
9548485SPeter.Memishian@Sun.COM 		goto out;
9558485SPeter.Memishian@Sun.COM 	}
9568485SPeter.Memishian@Sun.COM 
9578485SPeter.Memishian@Sun.COM 	if (version != IPMP_EVENT_CUR_VERSION) {
9588485SPeter.Memishian@Sun.COM 		warn("dropped event with unsupported IPMP_EVENT_VERSION %d\n",
9598485SPeter.Memishian@Sun.COM 		    version);
9608485SPeter.Memishian@Sun.COM 		goto out;
9618485SPeter.Memishian@Sun.COM 	}
9628485SPeter.Memishian@Sun.COM 
9638485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_uint32(nvl, IPMP_PROBE_STATE, &state) != 0) {
9648485SPeter.Memishian@Sun.COM 		warn("dropped event with no IPMP_PROBE_STATE\n");
9658485SPeter.Memishian@Sun.COM 		goto out;
9668485SPeter.Memishian@Sun.COM 	}
9678485SPeter.Memishian@Sun.COM 
9688485SPeter.Memishian@Sun.COM 	if (state == IPMP_PROBE_ACKED || state == IPMP_PROBE_LOST)
9698485SPeter.Memishian@Sun.COM 		ofmt_output(psp->ps_ofmt, psp->ps_ih, nvl);
9708485SPeter.Memishian@Sun.COM out:
9718485SPeter.Memishian@Sun.COM 	nvlist_free(nvl);
9728485SPeter.Memishian@Sun.COM 	return (0);
9738485SPeter.Memishian@Sun.COM }
9748485SPeter.Memishian@Sun.COM 
9758485SPeter.Memishian@Sun.COM static void
9768485SPeter.Memishian@Sun.COM sfunc_targ_ifname(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
9778485SPeter.Memishian@Sun.COM {
9788485SPeter.Memishian@Sun.COM 	ipmp_targinfo_t *targinfop = arg->sa_data;
9798485SPeter.Memishian@Sun.COM 
9808485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, targinfop->it_name, bufsize);
9818485SPeter.Memishian@Sun.COM }
9828485SPeter.Memishian@Sun.COM 
9838485SPeter.Memishian@Sun.COM static void
9848485SPeter.Memishian@Sun.COM sfunc_targ_mode(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
9858485SPeter.Memishian@Sun.COM {
9868485SPeter.Memishian@Sun.COM 	ipmp_targinfo_t *targinfop = arg->sa_data;
9878485SPeter.Memishian@Sun.COM 
9888485SPeter.Memishian@Sun.COM 	enum2str(targ_mode, targinfop->it_targmode, buf, bufsize);
9898485SPeter.Memishian@Sun.COM }
9908485SPeter.Memishian@Sun.COM 
9918485SPeter.Memishian@Sun.COM static void
9928485SPeter.Memishian@Sun.COM sfunc_targ_testaddr(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
9938485SPeter.Memishian@Sun.COM {
9948485SPeter.Memishian@Sun.COM 	ipmp_targinfo_t *targinfop = arg->sa_data;
9958485SPeter.Memishian@Sun.COM 
9968485SPeter.Memishian@Sun.COM 	if (targinfop->it_targmode != IPMP_TARG_DISABLED)
9978485SPeter.Memishian@Sun.COM 		sockaddr2str(&targinfop->it_testaddr, buf, bufsize);
9988485SPeter.Memishian@Sun.COM }
9998485SPeter.Memishian@Sun.COM 
10008485SPeter.Memishian@Sun.COM static void
10018485SPeter.Memishian@Sun.COM sfunc_targ_targets(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
10028485SPeter.Memishian@Sun.COM {
10038485SPeter.Memishian@Sun.COM 	uint_t i;
10048485SPeter.Memishian@Sun.COM 	char *targname = alloca(bufsize);
10058485SPeter.Memishian@Sun.COM 	ipmp_targinfo_t *targinfop = arg->sa_data;
10068485SPeter.Memishian@Sun.COM 	ipmp_addrlist_t *targlistp = targinfop->it_targlistp;
10078485SPeter.Memishian@Sun.COM 
10088485SPeter.Memishian@Sun.COM 	for (i = 0; i < targlistp->al_naddr; i++) {
10098485SPeter.Memishian@Sun.COM 		sockaddr2str(&targlistp->al_addrs[i], targname, bufsize);
10108485SPeter.Memishian@Sun.COM 		(void) strlcat(buf, targname, bufsize);
10118485SPeter.Memishian@Sun.COM 		if ((i + 1) < targlistp->al_naddr)
10128485SPeter.Memishian@Sun.COM 			(void) strlcat(buf, " ", bufsize);
10138485SPeter.Memishian@Sun.COM 	}
10148485SPeter.Memishian@Sun.COM }
10158485SPeter.Memishian@Sun.COM 
10168485SPeter.Memishian@Sun.COM static void
10178485SPeter.Memishian@Sun.COM info_output_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
10188485SPeter.Memishian@Sun.COM {
10198485SPeter.Memishian@Sun.COM 	ofmt_output(arg, ih, infop);
10208485SPeter.Memishian@Sun.COM }
10218485SPeter.Memishian@Sun.COM 
10228485SPeter.Memishian@Sun.COM static void
10238485SPeter.Memishian@Sun.COM targinfo_output_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
10248485SPeter.Memishian@Sun.COM {
10258485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = infop;
10268485SPeter.Memishian@Sun.COM 	ipmp_if_targmode_t targmode4 = ifinfop->if_targinfo4.it_targmode;
10278485SPeter.Memishian@Sun.COM 	ipmp_if_targmode_t targmode6 = ifinfop->if_targinfo6.it_targmode;
10288485SPeter.Memishian@Sun.COM 
10298485SPeter.Memishian@Sun.COM 	/*
10308485SPeter.Memishian@Sun.COM 	 * Usually, either IPv4 or IPv6 probing will be enabled, but the admin
10318485SPeter.Memishian@Sun.COM 	 * may enable both.  If only one is enabled, omit the other one so as
10328485SPeter.Memishian@Sun.COM 	 * to not encourage the admin to enable both.  If neither is enabled,
10338485SPeter.Memishian@Sun.COM 	 * we still print one just so the admin can see a MODE of "disabled".
10348485SPeter.Memishian@Sun.COM 	 */
10358485SPeter.Memishian@Sun.COM 	if (targmode4 != IPMP_TARG_DISABLED || targmode6 == IPMP_TARG_DISABLED)
10368485SPeter.Memishian@Sun.COM 		ofmt_output(arg, ih, &ifinfop->if_targinfo4);
10378485SPeter.Memishian@Sun.COM 	if (targmode6 != IPMP_TARG_DISABLED)
10388485SPeter.Memishian@Sun.COM 		ofmt_output(arg, ih, &ifinfop->if_targinfo6);
10398485SPeter.Memishian@Sun.COM }
10408485SPeter.Memishian@Sun.COM 
10418485SPeter.Memishian@Sun.COM /*
10428485SPeter.Memishian@Sun.COM  * Creates an ipmpstat_ofmt_t field list from the comma-separated list of
10438485SPeter.Memishian@Sun.COM  * user-specified fields passed via `ofields'.  The table of known fields
10448485SPeter.Memishian@Sun.COM  * (and their attributes) is passed via `fields'.
10458485SPeter.Memishian@Sun.COM  */
10468485SPeter.Memishian@Sun.COM static ipmpstat_ofmt_t *
10478485SPeter.Memishian@Sun.COM ofmt_create(const char *ofields, ipmpstat_field_t fields[])
10488485SPeter.Memishian@Sun.COM {
10498485SPeter.Memishian@Sun.COM 	char *token, *lasts, *ofields_dup;
10508485SPeter.Memishian@Sun.COM 	const char *fieldname;
10518485SPeter.Memishian@Sun.COM 	ipmpstat_ofmt_t *ofmt, *ofmt_head = NULL, *ofmt_tail;
10528485SPeter.Memishian@Sun.COM 	ipmpstat_field_t *fieldp;
10538485SPeter.Memishian@Sun.COM 	uint_t cols = 0;
10548485SPeter.Memishian@Sun.COM 
10558485SPeter.Memishian@Sun.COM 	/*
10568485SPeter.Memishian@Sun.COM 	 * If "-o" was omitted or "-o all" was specified, build a list of
10578485SPeter.Memishian@Sun.COM 	 * field names.  If "-o" was omitted, stop building the list when
10588485SPeter.Memishian@Sun.COM 	 * we run out of columns.
10598485SPeter.Memishian@Sun.COM 	 */
10608485SPeter.Memishian@Sun.COM 	if (ofields == NULL || strcasecmp(ofields, "all") == 0) {
10618485SPeter.Memishian@Sun.COM 		for (fieldp = fields; fieldp->f_name != NULL; fieldp++) {
10628485SPeter.Memishian@Sun.COM 			cols += fieldp->f_width;
10638485SPeter.Memishian@Sun.COM 			if (ofields == NULL && cols > IPMPSTAT_NCOL)
10648485SPeter.Memishian@Sun.COM 				break;
10658485SPeter.Memishian@Sun.COM 
10668485SPeter.Memishian@Sun.COM 			if ((ofmt = calloc(sizeof (*ofmt), 1)) == NULL)
10678485SPeter.Memishian@Sun.COM 				die("cannot allocate output format list");
10688485SPeter.Memishian@Sun.COM 
10698485SPeter.Memishian@Sun.COM 			ofmt->o_field = fieldp;
10708485SPeter.Memishian@Sun.COM 			if (ofmt_head == NULL) {
10718485SPeter.Memishian@Sun.COM 				ofmt_head = ofmt;
10728485SPeter.Memishian@Sun.COM 				ofmt_tail = ofmt;
10738485SPeter.Memishian@Sun.COM 			} else {
10748485SPeter.Memishian@Sun.COM 				ofmt_tail->o_next = ofmt;
10758485SPeter.Memishian@Sun.COM 				ofmt_tail = ofmt;
10768485SPeter.Memishian@Sun.COM 			}
10778485SPeter.Memishian@Sun.COM 		}
10788485SPeter.Memishian@Sun.COM 		return (ofmt_head);
10798485SPeter.Memishian@Sun.COM 	}
10808485SPeter.Memishian@Sun.COM 
10818485SPeter.Memishian@Sun.COM 	if ((ofields_dup = strdup(ofields)) == NULL)
10828485SPeter.Memishian@Sun.COM 		die("cannot allocate output format list");
10838485SPeter.Memishian@Sun.COM 
10848485SPeter.Memishian@Sun.COM 	token = ofields_dup;
10858485SPeter.Memishian@Sun.COM 	while ((fieldname = strtok_r(token, ",", &lasts)) != NULL) {
10868485SPeter.Memishian@Sun.COM 		token = NULL;
10878485SPeter.Memishian@Sun.COM 
10888485SPeter.Memishian@Sun.COM 		if ((fieldp = field_find(fields, fieldname)) == NULL) {
10898485SPeter.Memishian@Sun.COM 			/*
10908485SPeter.Memishian@Sun.COM 			 * Since machine parsers are unlikely to be able to
10918485SPeter.Memishian@Sun.COM 			 * gracefully handle missing fields, die if we're in
10928485SPeter.Memishian@Sun.COM 			 * parsable mode.  Otherwise, just print a warning.
10938485SPeter.Memishian@Sun.COM 			 */
10948485SPeter.Memishian@Sun.COM 			if (opt & IPMPSTAT_OPT_PARSABLE)
10958485SPeter.Memishian@Sun.COM 				die("unknown output field `%s'\n", fieldname);
10968485SPeter.Memishian@Sun.COM 
10978485SPeter.Memishian@Sun.COM 			warn("ignoring unknown output field `%s'\n", fieldname);
10988485SPeter.Memishian@Sun.COM 			continue;
10998485SPeter.Memishian@Sun.COM 		}
11008485SPeter.Memishian@Sun.COM 
11018485SPeter.Memishian@Sun.COM 		if ((ofmt = calloc(sizeof (*ofmt), 1)) == NULL)
11028485SPeter.Memishian@Sun.COM 			die("cannot allocate output format list");
11038485SPeter.Memishian@Sun.COM 
11048485SPeter.Memishian@Sun.COM 		ofmt->o_field = fieldp;
11058485SPeter.Memishian@Sun.COM 		if (ofmt_head == NULL) {
11068485SPeter.Memishian@Sun.COM 			ofmt_head = ofmt;
11078485SPeter.Memishian@Sun.COM 			ofmt_tail = ofmt;
11088485SPeter.Memishian@Sun.COM 		} else {
11098485SPeter.Memishian@Sun.COM 			ofmt_tail->o_next = ofmt;
11108485SPeter.Memishian@Sun.COM 			ofmt_tail = ofmt;
11118485SPeter.Memishian@Sun.COM 		}
11128485SPeter.Memishian@Sun.COM 	}
11138485SPeter.Memishian@Sun.COM 
11148485SPeter.Memishian@Sun.COM 	free(ofields_dup);
11158485SPeter.Memishian@Sun.COM 	if (ofmt_head == NULL)
11168485SPeter.Memishian@Sun.COM 		die("no valid output fields specified\n");
11178485SPeter.Memishian@Sun.COM 
11188485SPeter.Memishian@Sun.COM 	return (ofmt_head);
11198485SPeter.Memishian@Sun.COM }
11208485SPeter.Memishian@Sun.COM 
11218485SPeter.Memishian@Sun.COM /*
11228485SPeter.Memishian@Sun.COM  * Destroys the provided `ofmt' field list.
11238485SPeter.Memishian@Sun.COM  */
11248485SPeter.Memishian@Sun.COM static void
11258485SPeter.Memishian@Sun.COM ofmt_destroy(ipmpstat_ofmt_t *ofmt)
11268485SPeter.Memishian@Sun.COM {
11278485SPeter.Memishian@Sun.COM 	ipmpstat_ofmt_t *ofmt_next;
11288485SPeter.Memishian@Sun.COM 
11298485SPeter.Memishian@Sun.COM 	for (; ofmt != NULL; ofmt = ofmt_next) {
11308485SPeter.Memishian@Sun.COM 		ofmt_next = ofmt->o_next;
11318485SPeter.Memishian@Sun.COM 		free(ofmt);
11328485SPeter.Memishian@Sun.COM 	}
11338485SPeter.Memishian@Sun.COM }
11348485SPeter.Memishian@Sun.COM 
11358485SPeter.Memishian@Sun.COM /*
11368485SPeter.Memishian@Sun.COM  * Outputs a header for the fields named by `ofmt'.
11378485SPeter.Memishian@Sun.COM  */
11388485SPeter.Memishian@Sun.COM static void
11398485SPeter.Memishian@Sun.COM ofmt_output_header(const ipmpstat_ofmt_t *ofmt)
11408485SPeter.Memishian@Sun.COM {
11418485SPeter.Memishian@Sun.COM 	const ipmpstat_field_t *fieldp;
11428485SPeter.Memishian@Sun.COM 
11438485SPeter.Memishian@Sun.COM 	for (; ofmt != NULL; ofmt = ofmt->o_next) {
11448485SPeter.Memishian@Sun.COM 		fieldp = ofmt->o_field;
11458485SPeter.Memishian@Sun.COM 
11468485SPeter.Memishian@Sun.COM 		if (ofmt->o_next == NULL)
11478485SPeter.Memishian@Sun.COM 			(void) printf("%s", fieldp->f_name);
11488485SPeter.Memishian@Sun.COM 		else
11498485SPeter.Memishian@Sun.COM 			(void) printf("%-*s", fieldp->f_width, fieldp->f_name);
11508485SPeter.Memishian@Sun.COM 	}
11518485SPeter.Memishian@Sun.COM 	(void) printf("\n");
11528485SPeter.Memishian@Sun.COM }
11538485SPeter.Memishian@Sun.COM 
11548485SPeter.Memishian@Sun.COM /*
11558485SPeter.Memishian@Sun.COM  * Outputs one row of values for the fields named by `ofmt'.  The values to
11568485SPeter.Memishian@Sun.COM  * output are obtained through the `ofmt' function pointers, which are
11578485SPeter.Memishian@Sun.COM  * indirectly passed the `ih' and `arg' structures for state; see the block
11588485SPeter.Memishian@Sun.COM  * comment at the start of this file for details.
11598485SPeter.Memishian@Sun.COM  */
11608485SPeter.Memishian@Sun.COM static void
11618485SPeter.Memishian@Sun.COM ofmt_output(const ipmpstat_ofmt_t *ofmt, ipmp_handle_t ih, void *arg)
11628485SPeter.Memishian@Sun.COM {
11638485SPeter.Memishian@Sun.COM 	int i;
11648485SPeter.Memishian@Sun.COM 	char buf[1024];
11658485SPeter.Memishian@Sun.COM 	boolean_t escsep;
11668485SPeter.Memishian@Sun.COM 	static int nrow;
11678485SPeter.Memishian@Sun.COM 	const char *value;
11688485SPeter.Memishian@Sun.COM 	uint_t width, valwidth;
11698485SPeter.Memishian@Sun.COM 	uint_t compress, overflow = 0;
11708485SPeter.Memishian@Sun.COM 	const ipmpstat_field_t *fieldp;
11718485SPeter.Memishian@Sun.COM 	ipmpstat_sfunc_arg_t sfunc_arg;
11728485SPeter.Memishian@Sun.COM 
11738485SPeter.Memishian@Sun.COM 	/*
11748485SPeter.Memishian@Sun.COM 	 * For each screenful of data, display the header.
11758485SPeter.Memishian@Sun.COM 	 */
11768485SPeter.Memishian@Sun.COM 	if ((nrow++ % winsize.ws_row) == 0 && !(opt & IPMPSTAT_OPT_PARSABLE)) {
11778485SPeter.Memishian@Sun.COM 		ofmt_output_header(ofmt);
11788485SPeter.Memishian@Sun.COM 		nrow++;
11798485SPeter.Memishian@Sun.COM 	}
11808485SPeter.Memishian@Sun.COM 
11818485SPeter.Memishian@Sun.COM 	/*
11828485SPeter.Memishian@Sun.COM 	 * Check if we'll be displaying multiple fields per line, and thus
11838485SPeter.Memishian@Sun.COM 	 * need to escape the field separator.
11848485SPeter.Memishian@Sun.COM 	 */
11858485SPeter.Memishian@Sun.COM 	escsep = (ofmt != NULL && ofmt->o_next != NULL);
11868485SPeter.Memishian@Sun.COM 
11878485SPeter.Memishian@Sun.COM 	for (; ofmt != NULL; ofmt = ofmt->o_next) {
11888485SPeter.Memishian@Sun.COM 		fieldp = ofmt->o_field;
11898485SPeter.Memishian@Sun.COM 
11908485SPeter.Memishian@Sun.COM 		sfunc_arg.sa_ih = ih;
11918485SPeter.Memishian@Sun.COM 		sfunc_arg.sa_data = arg;
11928485SPeter.Memishian@Sun.COM 
11938485SPeter.Memishian@Sun.COM 		buf[0] = '\0';
11948485SPeter.Memishian@Sun.COM 		(*fieldp->f_sfunc)(&sfunc_arg, buf, sizeof (buf));
11958485SPeter.Memishian@Sun.COM 
11968485SPeter.Memishian@Sun.COM 		if (opt & IPMPSTAT_OPT_PARSABLE) {
11978485SPeter.Memishian@Sun.COM 			for (i = 0; buf[i] != '\0'; i++) {
11988485SPeter.Memishian@Sun.COM 				if (escsep && (buf[i] == ':' || buf[i] == '\\'))
11998485SPeter.Memishian@Sun.COM 					(void) putchar('\\');
12008485SPeter.Memishian@Sun.COM 				(void) putchar(buf[i]);
12018485SPeter.Memishian@Sun.COM 			}
12028485SPeter.Memishian@Sun.COM 			if (ofmt->o_next != NULL)
12038485SPeter.Memishian@Sun.COM 				(void) putchar(':');
12048485SPeter.Memishian@Sun.COM 		} else {
12058485SPeter.Memishian@Sun.COM 			value = (buf[0] == '\0') ? "--" : buf;
12068485SPeter.Memishian@Sun.COM 
12078485SPeter.Memishian@Sun.COM 			/*
12088485SPeter.Memishian@Sun.COM 			 * To avoid needless line-wraps, for the last field,
12098485SPeter.Memishian@Sun.COM 			 * don't include any trailing whitespace.
12108485SPeter.Memishian@Sun.COM 			 */
12118485SPeter.Memishian@Sun.COM 			if (ofmt->o_next == NULL) {
12128485SPeter.Memishian@Sun.COM 				(void) printf("%s", value);
12138485SPeter.Memishian@Sun.COM 				continue;
12148485SPeter.Memishian@Sun.COM 			}
12158485SPeter.Memishian@Sun.COM 
12168485SPeter.Memishian@Sun.COM 			/*
12178485SPeter.Memishian@Sun.COM 			 * For other fields, grow the width as necessary to
12188485SPeter.Memishian@Sun.COM 			 * ensure the value completely fits.  However, if
12198485SPeter.Memishian@Sun.COM 			 * there's unused whitespace in subsequent fields,
12208485SPeter.Memishian@Sun.COM 			 * then "compress" that whitespace to attempt to get
12218485SPeter.Memishian@Sun.COM 			 * the columns to line up again.
12228485SPeter.Memishian@Sun.COM 			 */
12238485SPeter.Memishian@Sun.COM 			width = fieldp->f_width;
12248485SPeter.Memishian@Sun.COM 			valwidth = strlen(value);
12258485SPeter.Memishian@Sun.COM 
12268485SPeter.Memishian@Sun.COM 			if (valwidth + overflow >= width) {
12278485SPeter.Memishian@Sun.COM 				overflow += valwidth - width + 1;
12288485SPeter.Memishian@Sun.COM 				(void) printf("%s ", value);
12298485SPeter.Memishian@Sun.COM 				continue;
12308485SPeter.Memishian@Sun.COM 			}
12318485SPeter.Memishian@Sun.COM 
12328485SPeter.Memishian@Sun.COM 			if (overflow > 0) {
12338485SPeter.Memishian@Sun.COM 				compress = MIN(overflow, width - valwidth);
12348485SPeter.Memishian@Sun.COM 				overflow -= compress;
12358485SPeter.Memishian@Sun.COM 				width -= compress;
12368485SPeter.Memishian@Sun.COM 			}
12378485SPeter.Memishian@Sun.COM 			(void) printf("%-*s", width, value);
12388485SPeter.Memishian@Sun.COM 		}
12398485SPeter.Memishian@Sun.COM 	}
12408485SPeter.Memishian@Sun.COM 	(void) printf("\n");
12418485SPeter.Memishian@Sun.COM 
12428485SPeter.Memishian@Sun.COM 	/*
12438485SPeter.Memishian@Sun.COM 	 * In case stdout has been redirected to e.g. a pipe, flush stdout so
12448485SPeter.Memishian@Sun.COM 	 * that commands can act on our output immediately.
12458485SPeter.Memishian@Sun.COM 	 */
12468485SPeter.Memishian@Sun.COM 	(void) fflush(stdout);
12478485SPeter.Memishian@Sun.COM }
12488485SPeter.Memishian@Sun.COM 
12498485SPeter.Memishian@Sun.COM /*
12508485SPeter.Memishian@Sun.COM  * Searches the `fields' array for a field matching `fieldname'.  Returns
12518485SPeter.Memishian@Sun.COM  * a pointer to that field on success, or NULL on failure.
12528485SPeter.Memishian@Sun.COM  */
12538485SPeter.Memishian@Sun.COM static ipmpstat_field_t *
12548485SPeter.Memishian@Sun.COM field_find(ipmpstat_field_t *fields, const char *fieldname)
12558485SPeter.Memishian@Sun.COM {
12568485SPeter.Memishian@Sun.COM 	ipmpstat_field_t *fieldp;
12578485SPeter.Memishian@Sun.COM 
12588485SPeter.Memishian@Sun.COM 	for (fieldp = fields; fieldp->f_name != NULL; fieldp++) {
12598485SPeter.Memishian@Sun.COM 		if (strcasecmp(fieldp->f_name, fieldname) == 0)
12608485SPeter.Memishian@Sun.COM 			return (fieldp);
12618485SPeter.Memishian@Sun.COM 	}
12628485SPeter.Memishian@Sun.COM 	return (NULL);
12638485SPeter.Memishian@Sun.COM }
12648485SPeter.Memishian@Sun.COM 
12658485SPeter.Memishian@Sun.COM /*
12668485SPeter.Memishian@Sun.COM  * Uses `enums' to map `enumval' to a string, and stores at most `bufsize'
12678485SPeter.Memishian@Sun.COM  * bytes of that string into `buf'.
12688485SPeter.Memishian@Sun.COM  */
12698485SPeter.Memishian@Sun.COM static void
12708485SPeter.Memishian@Sun.COM enum2str(const ipmpstat_enum_t *enums, int enumval, char *buf, uint_t bufsize)
12718485SPeter.Memishian@Sun.COM {
12728485SPeter.Memishian@Sun.COM 	const ipmpstat_enum_t *enump;
12738485SPeter.Memishian@Sun.COM 
12748485SPeter.Memishian@Sun.COM 	for (enump = enums; enump->e_name != NULL; enump++) {
12758485SPeter.Memishian@Sun.COM 		if (enump->e_val == enumval) {
12768485SPeter.Memishian@Sun.COM 			(void) strlcpy(buf, enump->e_name, bufsize);
12778485SPeter.Memishian@Sun.COM 			return;
12788485SPeter.Memishian@Sun.COM 		}
12798485SPeter.Memishian@Sun.COM 	}
12808485SPeter.Memishian@Sun.COM 	(void) snprintf(buf, bufsize, "<%d>", enumval);
12818485SPeter.Memishian@Sun.COM }
12828485SPeter.Memishian@Sun.COM 
12838485SPeter.Memishian@Sun.COM /*
12848485SPeter.Memishian@Sun.COM  * Stores the stringified value of the sockaddr_storage pointed to by `ssp'
12858485SPeter.Memishian@Sun.COM  * into at most `bufsize' bytes of `buf'.
12868485SPeter.Memishian@Sun.COM  */
12878485SPeter.Memishian@Sun.COM static void
12888485SPeter.Memishian@Sun.COM sockaddr2str(const struct sockaddr_storage *ssp, char *buf, uint_t bufsize)
12898485SPeter.Memishian@Sun.COM {
12908485SPeter.Memishian@Sun.COM 	int flags = NI_NOFQDN;
12918485SPeter.Memishian@Sun.COM 	socklen_t socklen;
12928485SPeter.Memishian@Sun.COM 	struct sockaddr *sp = (struct sockaddr *)ssp;
12938485SPeter.Memishian@Sun.COM 
12948485SPeter.Memishian@Sun.COM 	/*
12958485SPeter.Memishian@Sun.COM 	 * Sadly, getnameinfo() does not allow the socklen to be oversized for
12968485SPeter.Memishian@Sun.COM 	 * a given family -- so we must determine the exact size to pass to it.
12978485SPeter.Memishian@Sun.COM 	 */
12988485SPeter.Memishian@Sun.COM 	switch (ssp->ss_family) {
12998485SPeter.Memishian@Sun.COM 	case AF_INET:
13008485SPeter.Memishian@Sun.COM 		socklen = sizeof (struct sockaddr_in);
13018485SPeter.Memishian@Sun.COM 		break;
13028485SPeter.Memishian@Sun.COM 	case AF_INET6:
13038485SPeter.Memishian@Sun.COM 		socklen = sizeof (struct sockaddr_in6);
13048485SPeter.Memishian@Sun.COM 		break;
13058485SPeter.Memishian@Sun.COM 	default:
13068485SPeter.Memishian@Sun.COM 		(void) strlcpy(buf, "?", bufsize);
13078485SPeter.Memishian@Sun.COM 		return;
13088485SPeter.Memishian@Sun.COM 	}
13098485SPeter.Memishian@Sun.COM 
13108485SPeter.Memishian@Sun.COM 	if (opt & IPMPSTAT_OPT_NUMERIC)
13118485SPeter.Memishian@Sun.COM 		flags |= NI_NUMERICHOST;
13128485SPeter.Memishian@Sun.COM 
13138485SPeter.Memishian@Sun.COM 	(void) getnameinfo(sp, socklen, buf, bufsize, NULL, 0, flags);
13148485SPeter.Memishian@Sun.COM }
13158485SPeter.Memishian@Sun.COM 
13168485SPeter.Memishian@Sun.COM static void
13178485SPeter.Memishian@Sun.COM sighandler(int sig)
13188485SPeter.Memishian@Sun.COM {
13198485SPeter.Memishian@Sun.COM 	assert(sig == SIGWINCH);
13208485SPeter.Memishian@Sun.COM 
13218485SPeter.Memishian@Sun.COM 	if (ioctl(1, TIOCGWINSZ, &winsize) == -1 ||
13228485SPeter.Memishian@Sun.COM 	    winsize.ws_col == 0 || winsize.ws_row == 0) {
13238485SPeter.Memishian@Sun.COM 		winsize.ws_col = 80;
13248485SPeter.Memishian@Sun.COM 		winsize.ws_row = 24;
13258485SPeter.Memishian@Sun.COM 	}
13268485SPeter.Memishian@Sun.COM }
13278485SPeter.Memishian@Sun.COM 
13288485SPeter.Memishian@Sun.COM static void
13298485SPeter.Memishian@Sun.COM usage(void)
13308485SPeter.Memishian@Sun.COM {
13318485SPeter.Memishian@Sun.COM 	const char *argstr = gettext("[-n] [-o <field> [-P]] -a|-g|-i|-p|-t");
13328485SPeter.Memishian@Sun.COM 
13338485SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, gettext("usage: %s %s\n"), progname, argstr);
1334*8755SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, gettext("\n"
1335*8755SPeter.Memishian@Sun.COM 	    "  output modes:\t -a  display IPMP data address information\n"
1336*8755SPeter.Memishian@Sun.COM 	    "\t\t -g  display IPMP group information\n"
1337*8755SPeter.Memishian@Sun.COM 	    "\t\t -i  display IPMP-related IP interface information\n"
1338*8755SPeter.Memishian@Sun.COM 	    "\t\t -p  display IPMP probe information\n"
1339*8755SPeter.Memishian@Sun.COM 	    "\t\t -t  display IPMP target information\n\n"
1340*8755SPeter.Memishian@Sun.COM 	    "       options:\t -n  display IP addresses numerically\n"
1341*8755SPeter.Memishian@Sun.COM 	    "\t\t -o  display only the specified fields, in order\n"
1342*8755SPeter.Memishian@Sun.COM 	    "\t\t -P  display using parsable output mode\n"));
1343*8755SPeter.Memishian@Sun.COM 
13448485SPeter.Memishian@Sun.COM 	exit(EXIT_FAILURE);
13458485SPeter.Memishian@Sun.COM }
13468485SPeter.Memishian@Sun.COM 
13478485SPeter.Memishian@Sun.COM /* PRINTFLIKE1 */
13488485SPeter.Memishian@Sun.COM static void
13498485SPeter.Memishian@Sun.COM warn(const char *format, ...)
13508485SPeter.Memishian@Sun.COM {
13518485SPeter.Memishian@Sun.COM 	va_list alist;
13528485SPeter.Memishian@Sun.COM 	int error = errno;
13538485SPeter.Memishian@Sun.COM 
13548485SPeter.Memishian@Sun.COM 	format = gettext(format);
13558485SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
13568485SPeter.Memishian@Sun.COM 
13578485SPeter.Memishian@Sun.COM 	va_start(alist, format);
13588485SPeter.Memishian@Sun.COM 	(void) vfprintf(stderr, format, alist);
13598485SPeter.Memishian@Sun.COM 	va_end(alist);
13608485SPeter.Memishian@Sun.COM 
13618485SPeter.Memishian@Sun.COM 	if (strchr(format, '\n') == NULL)
13628485SPeter.Memishian@Sun.COM 		(void) fprintf(stderr, ": %s\n", strerror(error));
13638485SPeter.Memishian@Sun.COM }
13648485SPeter.Memishian@Sun.COM 
13658485SPeter.Memishian@Sun.COM /* PRINTFLIKE2 */
13668485SPeter.Memishian@Sun.COM static void
13678485SPeter.Memishian@Sun.COM warn_ipmperr(int ipmperr, const char *format, ...)
13688485SPeter.Memishian@Sun.COM {
13698485SPeter.Memishian@Sun.COM 	va_list alist;
13708485SPeter.Memishian@Sun.COM 
13718485SPeter.Memishian@Sun.COM 	format = gettext(format);
13728485SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
13738485SPeter.Memishian@Sun.COM 
13748485SPeter.Memishian@Sun.COM 	va_start(alist, format);
13758485SPeter.Memishian@Sun.COM 	(void) vfprintf(stderr, format, alist);
13768485SPeter.Memishian@Sun.COM 	va_end(alist);
13778485SPeter.Memishian@Sun.COM 
13788485SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, ": %s\n", ipmp_errmsg(ipmperr));
13798485SPeter.Memishian@Sun.COM }
13808485SPeter.Memishian@Sun.COM 
13818485SPeter.Memishian@Sun.COM /* PRINTFLIKE1 */
13828485SPeter.Memishian@Sun.COM static void
13838485SPeter.Memishian@Sun.COM die(const char *format, ...)
13848485SPeter.Memishian@Sun.COM {
13858485SPeter.Memishian@Sun.COM 	va_list alist;
13868485SPeter.Memishian@Sun.COM 	int error = errno;
13878485SPeter.Memishian@Sun.COM 
13888485SPeter.Memishian@Sun.COM 	format = gettext(format);
13898485SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, "%s: ", progname);
13908485SPeter.Memishian@Sun.COM 
13918485SPeter.Memishian@Sun.COM 	va_start(alist, format);
13928485SPeter.Memishian@Sun.COM 	(void) vfprintf(stderr, format, alist);
13938485SPeter.Memishian@Sun.COM 	va_end(alist);
13948485SPeter.Memishian@Sun.COM 
13958485SPeter.Memishian@Sun.COM 	if (strchr(format, '\n') == NULL)
13968485SPeter.Memishian@Sun.COM 		(void) fprintf(stderr, ": %s\n", strerror(error));
13978485SPeter.Memishian@Sun.COM 
13988485SPeter.Memishian@Sun.COM 	exit(EXIT_FAILURE);
13998485SPeter.Memishian@Sun.COM }
14008485SPeter.Memishian@Sun.COM 
14018485SPeter.Memishian@Sun.COM /* PRINTFLIKE2 */
14028485SPeter.Memishian@Sun.COM static void
14038485SPeter.Memishian@Sun.COM die_ipmperr(int ipmperr, const char *format, ...)
14048485SPeter.Memishian@Sun.COM {
14058485SPeter.Memishian@Sun.COM 	va_list alist;
14068485SPeter.Memishian@Sun.COM 
14078485SPeter.Memishian@Sun.COM 	format = gettext(format);
14088485SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, "%s: ", progname);
14098485SPeter.Memishian@Sun.COM 
14108485SPeter.Memishian@Sun.COM 	va_start(alist, format);
14118485SPeter.Memishian@Sun.COM 	(void) vfprintf(stderr, format, alist);
14128485SPeter.Memishian@Sun.COM 	va_end(alist);
14138485SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, ": %s\n", ipmp_errmsg(ipmperr));
14148485SPeter.Memishian@Sun.COM 
14158485SPeter.Memishian@Sun.COM 	exit(EXIT_FAILURE);
14168485SPeter.Memishian@Sun.COM }
14178485SPeter.Memishian@Sun.COM 
14188485SPeter.Memishian@Sun.COM static ipmpstat_field_t addr_fields[] = {
14198485SPeter.Memishian@Sun.COM 	{ "ADDRESS",    26,	sfunc_addr_address	},
14208485SPeter.Memishian@Sun.COM 	{ "STATE",	7,	sfunc_addr_state	},
14218485SPeter.Memishian@Sun.COM 	{ "GROUP",	12,	sfunc_addr_group	},
14228485SPeter.Memishian@Sun.COM 	{ "INBOUND",	12,	sfunc_addr_inbound	},
14238485SPeter.Memishian@Sun.COM 	{ "OUTBOUND",	23,	sfunc_addr_outbound	},
14248485SPeter.Memishian@Sun.COM 	{ NULL,		0, 	NULL			}
14258485SPeter.Memishian@Sun.COM };
14268485SPeter.Memishian@Sun.COM 
14278485SPeter.Memishian@Sun.COM static ipmpstat_field_t group_fields[] = {
14288485SPeter.Memishian@Sun.COM 	{ "GROUP",	12, 	sfunc_group_ifname	},
14298485SPeter.Memishian@Sun.COM 	{ "GROUPNAME",	12,	sfunc_group_name 	},
14308485SPeter.Memishian@Sun.COM 	{ "STATE",	10,	sfunc_group_state	},
14318485SPeter.Memishian@Sun.COM 	{ "FDT",	10,	sfunc_group_fdt		},
14328485SPeter.Memishian@Sun.COM 	{ "INTERFACES",	30,	sfunc_group_interfaces	},
14338485SPeter.Memishian@Sun.COM 	{ NULL,		0, 	NULL			}
14348485SPeter.Memishian@Sun.COM };
14358485SPeter.Memishian@Sun.COM 
14368485SPeter.Memishian@Sun.COM static ipmpstat_field_t if_fields[] = {
14378485SPeter.Memishian@Sun.COM 	{ "INTERFACE",	12,	sfunc_if_name		},
14388485SPeter.Memishian@Sun.COM 	{ "ACTIVE",	8, 	sfunc_if_active		},
14398485SPeter.Memishian@Sun.COM 	{ "GROUP",	12,	sfunc_if_group		},
14408485SPeter.Memishian@Sun.COM 	{ "FLAGS",	10,	sfunc_if_flags		},
14418485SPeter.Memishian@Sun.COM 	{ "LINK",	10,	sfunc_if_link		},
14428485SPeter.Memishian@Sun.COM 	{ "PROBE",	10,	sfunc_if_probe		},
14438485SPeter.Memishian@Sun.COM 	{ "STATE",	10, 	sfunc_if_state		},
14448485SPeter.Memishian@Sun.COM 	{ NULL,		0, 	NULL			}
14458485SPeter.Memishian@Sun.COM };
14468485SPeter.Memishian@Sun.COM 
14478485SPeter.Memishian@Sun.COM static ipmpstat_field_t probe_fields[] = {
14488485SPeter.Memishian@Sun.COM 	{ "TIME",	10,	sfunc_probe_time	},
14498485SPeter.Memishian@Sun.COM 	{ "INTERFACE",	12,	sfunc_probe_ifname	},
14508485SPeter.Memishian@Sun.COM 	{ "PROBE",	7,	sfunc_probe_id		},
14518485SPeter.Memishian@Sun.COM 	{ "NETRTT",	10,	sfunc_probe_netrtt	},
14528485SPeter.Memishian@Sun.COM 	{ "RTT",	10,	sfunc_probe_rtt		},
14538485SPeter.Memishian@Sun.COM 	{ "RTTAVG",	10,	sfunc_probe_rttavg	},
14548485SPeter.Memishian@Sun.COM 	{ "TARGET",	20,	sfunc_probe_target	},
14558485SPeter.Memishian@Sun.COM 	{ "RTTDEV",	10,	sfunc_probe_rttdev	},
14568485SPeter.Memishian@Sun.COM 	{ NULL,		0, 	NULL			}
14578485SPeter.Memishian@Sun.COM };
14588485SPeter.Memishian@Sun.COM 
14598485SPeter.Memishian@Sun.COM static ipmpstat_field_t targ_fields[] = {
14608485SPeter.Memishian@Sun.COM 	{ "INTERFACE",	12,	sfunc_targ_ifname	},
14618485SPeter.Memishian@Sun.COM 	{ "MODE",	10,	sfunc_targ_mode		},
14628485SPeter.Memishian@Sun.COM 	{ "TESTADDR",	20,	sfunc_targ_testaddr	},
14638485SPeter.Memishian@Sun.COM 	{ "TARGETS",	38,	sfunc_targ_targets	},
14648485SPeter.Memishian@Sun.COM 	{ NULL,		0, 	NULL			}
14658485SPeter.Memishian@Sun.COM };
14668485SPeter.Memishian@Sun.COM 
14678485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	addr_state[] = {
14688485SPeter.Memishian@Sun.COM 	{ "up",		IPMP_ADDR_UP			},
14698485SPeter.Memishian@Sun.COM 	{ "down",	IPMP_ADDR_DOWN			},
14708485SPeter.Memishian@Sun.COM 	{ NULL,		0 				}
14718485SPeter.Memishian@Sun.COM };
14728485SPeter.Memishian@Sun.COM 
14738485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	group_state[] = {
14748485SPeter.Memishian@Sun.COM 	{ "ok",		IPMP_GROUP_OK 			},
14758485SPeter.Memishian@Sun.COM 	{ "failed",	IPMP_GROUP_FAILED		},
14768485SPeter.Memishian@Sun.COM 	{ "degraded",	IPMP_GROUP_DEGRADED		},
14778485SPeter.Memishian@Sun.COM 	{ NULL,		0 				}
14788485SPeter.Memishian@Sun.COM };
14798485SPeter.Memishian@Sun.COM 
14808485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	if_link[] = {
14818485SPeter.Memishian@Sun.COM 	{ "up",		IPMP_LINK_UP 			},
14828485SPeter.Memishian@Sun.COM 	{ "down",	IPMP_LINK_DOWN			},
14838485SPeter.Memishian@Sun.COM 	{ "unknown",	IPMP_LINK_UNKNOWN		},
14848485SPeter.Memishian@Sun.COM 	{ NULL,		0 				}
14858485SPeter.Memishian@Sun.COM };
14868485SPeter.Memishian@Sun.COM 
14878485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	if_probe[] = {
14888485SPeter.Memishian@Sun.COM 	{ "ok",		IPMP_PROBE_OK 			},
14898485SPeter.Memishian@Sun.COM 	{ "failed",	IPMP_PROBE_FAILED		},
14908485SPeter.Memishian@Sun.COM 	{ "unknown",	IPMP_PROBE_UNKNOWN		},
14918485SPeter.Memishian@Sun.COM 	{ "disabled",	IPMP_PROBE_DISABLED		},
14928485SPeter.Memishian@Sun.COM 	{ NULL,		0 				}
14938485SPeter.Memishian@Sun.COM };
14948485SPeter.Memishian@Sun.COM 
14958485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	if_state[] = {
14968485SPeter.Memishian@Sun.COM 	{ "ok",		IPMP_IF_OK 			},
14978485SPeter.Memishian@Sun.COM 	{ "failed",	IPMP_IF_FAILED			},
14988485SPeter.Memishian@Sun.COM 	{ "unknown",	IPMP_IF_UNKNOWN			},
14998485SPeter.Memishian@Sun.COM 	{ "offline",	IPMP_IF_OFFLINE			},
15008485SPeter.Memishian@Sun.COM 	{ NULL,		0 				}
15018485SPeter.Memishian@Sun.COM };
15028485SPeter.Memishian@Sun.COM 
15038485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	targ_mode[] = {
15048485SPeter.Memishian@Sun.COM 	{ "disabled",	IPMP_TARG_DISABLED		},
15058485SPeter.Memishian@Sun.COM 	{ "routes",	IPMP_TARG_ROUTES		},
15068485SPeter.Memishian@Sun.COM 	{ "multicast",	IPMP_TARG_MULTICAST		},
15078485SPeter.Memishian@Sun.COM 	{ NULL,		0 				}
15088485SPeter.Memishian@Sun.COM };
1509