1e11c3f44Smeem /*
2e11c3f44Smeem  * CDDL HEADER START
3e11c3f44Smeem  *
4e11c3f44Smeem  * The contents of this file are subject to the terms of the
5e11c3f44Smeem  * Common Development and Distribution License (the "License").
6e11c3f44Smeem  * You may not use this file except in compliance with the License.
7e11c3f44Smeem  *
8e11c3f44Smeem  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9e11c3f44Smeem  * or http://www.opensolaris.org/os/licensing.
10e11c3f44Smeem  * See the License for the specific language governing permissions
11e11c3f44Smeem  * and limitations under the License.
12e11c3f44Smeem  *
13e11c3f44Smeem  * When distributing Covered Code, include this CDDL HEADER in each
14e11c3f44Smeem  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15e11c3f44Smeem  * If applicable, add the following below this CDDL HEADER, with the
16e11c3f44Smeem  * fields enclosed by brackets "[]" replaced with your own identifying
17e11c3f44Smeem  * information: Portions Copyright [yyyy] [name of copyright owner]
18e11c3f44Smeem  *
19e11c3f44Smeem  * CDDL HEADER END
20e11c3f44Smeem  *
21e11c3f44Smeem  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
22e11c3f44Smeem  * Use is subject to license terms.
23e11c3f44Smeem  */
24e11c3f44Smeem 
25e11c3f44Smeem #include <alloca.h>
26e11c3f44Smeem #include <arpa/inet.h>
27e11c3f44Smeem #include <assert.h>
28e11c3f44Smeem #include <errno.h>
29e11c3f44Smeem #include <ipmp_admin.h>
30e11c3f44Smeem #include <ipmp_query.h>
31e11c3f44Smeem #include <libintl.h>
32e11c3f44Smeem #include <libnvpair.h>
33e11c3f44Smeem #include <libsysevent.h>
34e11c3f44Smeem #include <locale.h>
35e11c3f44Smeem #include <netdb.h>
368002d411SSowmini Varadhan #include <ofmt.h>
37e11c3f44Smeem #include <signal.h>
38e11c3f44Smeem #include <stdarg.h>
39e11c3f44Smeem #include <stdio.h>
40e11c3f44Smeem #include <stdlib.h>
41e11c3f44Smeem #include <string.h>
42e11c3f44Smeem #include <unistd.h>
43e11c3f44Smeem #include <sys/sysevent/eventdefs.h>
44e11c3f44Smeem #include <sys/sysevent/ipmp.h>
45e11c3f44Smeem #include <sys/sysmacros.h>
46e11c3f44Smeem #include <sys/termios.h>
47e11c3f44Smeem #include <sys/types.h>
48e11c3f44Smeem 
49e11c3f44Smeem /*
50e11c3f44Smeem  * ipmpstat -- display IPMP subsystem status.
51e11c3f44Smeem  *
52e11c3f44Smeem  * This utility makes extensive use of libipmp and IPMP sysevents to gather
53e11c3f44Smeem  * and pretty-print the status of the IPMP subsystem.  All output formats
54e11c3f44Smeem  * except for -p (probe) use libipmp to create a point-in-time snapshot of the
55e11c3f44Smeem  * IPMP subsystem (unless the test-special -L flag is used), and then output
56e11c3f44Smeem  * the contents of that snapshot in a user-specified manner.  Because the
57e11c3f44Smeem  * output format and requested fields aren't known until run-time, three sets
58e11c3f44Smeem  * of function pointers and two core data structures are used. Specifically:
59e11c3f44Smeem  *
60e11c3f44Smeem  *      * The ipmpstat_walker_t function pointers (walk_*) iterate through
61e11c3f44Smeem  *	  all instances of a given IPMP object (group, interface, or address).
62e11c3f44Smeem  *	  At most one ipmpstat_walker_t is used per ipmpstat invocation.
63e11c3f44Smeem  *	  Since target information is included with the interface information,
64e11c3f44Smeem  *	  both -i and -t use the interface walker (walk_if()).
65e11c3f44Smeem  *
668002d411SSowmini Varadhan  *      * The ofmt_sfunc_t function pointers (sfunc_*) obtain a given value
678002d411SSowmini Varadhan  *	  for a given IPMP object.  Each ofmt_sfunc_t is passed a buffer to
688002d411SSowmini Varadhan  *	  write its result into, the buffer's size, and an ipmpstat_sfunc_arg_t
698002d411SSowmini Varadhan  *	  state structure.  The state structure consists of a pointer to the
708002d411SSowmini Varadhan  *	  IPMP object to obtain information from (sa_data), and an open libipmp
718002d411SSowmini Varadhan  *	  handle (sa_ih) which can be used to do additional libipmp queries, if
728002d411SSowmini Varadhan  *	  necessary (e.g., because the object does not have all of the needed
738002d411SSowmini Varadhan  *	  information).
74e11c3f44Smeem  *
758002d411SSowmini Varadhan  *	* The ofmt_field_t arrays (*_fields[]) provide the supported fields for
768002d411SSowmini Varadhan  *	  a given output format, along with output formatting information
778002d411SSowmini Varadhan  *	  (e.g., field width) and a pointer to an ofmt_sfunc_t function that
788002d411SSowmini Varadhan  *	  can obtain the value for a given IPMP object.  One ofmt_field_t array
798002d411SSowmini Varadhan  *	  is used per ipmpstat invocation, and is passed to ofmt_open() (along
808002d411SSowmini Varadhan  *	  with the output fields and modes requested by the user) to create an
818002d411SSowmini Varadhan  *	  ofmt_t.
82e11c3f44Smeem  *
838002d411SSowmini Varadhan  *      * The ofmt_t structure is a handle that tracks all information
848002d411SSowmini Varadhan  *        related to output formatting and is used by libinetutil`ofmt_print()
858002d411SSowmini Varadhan  *	  (indirectly through our local ofmt_output() utility routine) to
868002d411SSowmini Varadhan  *	  output a single line of information about the provided IPMP object.
87e11c3f44Smeem  *
88e11c3f44Smeem  *	* The ipmpstat_cbfunc_t function pointers (*_cbfunc) are called back
89e11c3f44Smeem  *	  by the walkers.  They are used both internally to implement nested
90e11c3f44Smeem  *	  walks, and by the ipmpstat output logic to provide the glue between
91e11c3f44Smeem  *	  the IPMP object walkers and the ofmt_output() logic.  Usually, a
92e11c3f44Smeem  *	  single line is output for each IPMP object, and thus ofmt_output()
93e11c3f44Smeem  *	  can be directly invoked (see info_output_cbfunc()).  However, if
94e11c3f44Smeem  *	  multiple lines need to be output, then a more complex cbfunc is
95e11c3f44Smeem  *	  needed (see targinfo_output_cbfunc()).  At most one cbfunc is used
96e11c3f44Smeem  *	  per ipmpstat invocation.
97e11c3f44Smeem  */
98e11c3f44Smeem 
99e11c3f44Smeem /*
100e11c3f44Smeem  * Data type used by the sfunc callbacks to obtain the requested information
101e11c3f44Smeem  * from the agreed-upon object.
102e11c3f44Smeem  */
103e11c3f44Smeem typedef struct ipmpstat_sfunc_arg {
104e11c3f44Smeem 	ipmp_handle_t		sa_ih;
105e11c3f44Smeem 	void			*sa_data;
106e11c3f44Smeem } ipmpstat_sfunc_arg_t;
107e11c3f44Smeem 
108e11c3f44Smeem /*
109e11c3f44Smeem  * Function pointers used to iterate through IPMP objects.
110e11c3f44Smeem  */
111e11c3f44Smeem typedef void ipmpstat_cbfunc_t(ipmp_handle_t, void *, void *);
112e11c3f44Smeem typedef void ipmpstat_walker_t(ipmp_handle_t, ipmpstat_cbfunc_t *, void *);
113e11c3f44Smeem 
114e11c3f44Smeem /*
115e11c3f44Smeem  * Data type used to implement nested walks.
116e11c3f44Smeem  */
117e11c3f44Smeem typedef struct ipmpstat_walkdata {
118e11c3f44Smeem 	ipmpstat_cbfunc_t	*iw_func; 	/* caller-specified callback */
119e11c3f44Smeem 	void			*iw_funcarg; 	/* caller-specified arg */
120e11c3f44Smeem } ipmpstat_walkdata_t;
121e11c3f44Smeem 
122e11c3f44Smeem /*
123e11c3f44Smeem  * Data type used by enum2str() to map an enumerated value to a string.
124e11c3f44Smeem  */
125e11c3f44Smeem typedef struct ipmpstat_enum {
126e11c3f44Smeem 	const char		*e_name;	/* string */
127e11c3f44Smeem 	int			e_val;		/* value */
128e11c3f44Smeem } ipmpstat_enum_t;
129e11c3f44Smeem 
130e11c3f44Smeem /*
131e11c3f44Smeem  * Data type used to pass state between probe_output() and probe_event().
132e11c3f44Smeem  */
133e11c3f44Smeem typedef struct ipmpstat_probe_state {
1348002d411SSowmini Varadhan 	ipmp_handle_t	ps_ih;		/* open IPMP handle */
1358002d411SSowmini Varadhan 	ofmt_handle_t	ps_ofmt;	/* open formatted-output handle */
136e11c3f44Smeem } ipmpstat_probe_state_t;
137e11c3f44Smeem 
138e11c3f44Smeem /*
139e11c3f44Smeem  * Options that modify the output mode; more than one may be lit.
140e11c3f44Smeem  */
141e11c3f44Smeem typedef enum {
142e11c3f44Smeem 	IPMPSTAT_OPT_NUMERIC	= 0x1,
143e11c3f44Smeem 	IPMPSTAT_OPT_PARSABLE 	= 0x2
144e11c3f44Smeem } ipmpstat_opt_t;
145e11c3f44Smeem 
146e11c3f44Smeem /*
147e11c3f44Smeem  * Indices for the FLAGS field of the `-i' output format.
148e11c3f44Smeem  */
149e11c3f44Smeem enum {
150e11c3f44Smeem 	IPMPSTAT_IFLAG_INDEX,	IPMPSTAT_SFLAG_INDEX,	IPMPSTAT_M4FLAG_INDEX,
151e11c3f44Smeem 	IPMPSTAT_BFLAG_INDEX,	IPMPSTAT_M6FLAG_INDEX,	IPMPSTAT_DFLAG_INDEX,
152e11c3f44Smeem 	IPMPSTAT_HFLAG_INDEX,	IPMPSTAT_NUM_FLAGS
153e11c3f44Smeem };
154e11c3f44Smeem 
155e11c3f44Smeem #define	IPMPSTAT_NCOL	80
15619449258SJosef 'Jeff' Sipek #define	NS2FLOATMS(ns)	(NSEC2MSEC((float)(ns)))
157e11c3f44Smeem #define	MS2FLOATSEC(ms)	((float)(ms) / 1000)
158e11c3f44Smeem 
159e11c3f44Smeem static const char	*progname;
160e11c3f44Smeem static hrtime_t		probe_output_start;
161e11c3f44Smeem static ipmpstat_opt_t	opt;
1628002d411SSowmini Varadhan static ofmt_handle_t	ofmt;
163e11c3f44Smeem static ipmpstat_enum_t	addr_state[], group_state[], if_state[], if_link[];
164e11c3f44Smeem static ipmpstat_enum_t	if_probe[], targ_mode[];
1658002d411SSowmini Varadhan static ofmt_field_t	addr_fields[], group_fields[], if_fields[];
1668002d411SSowmini Varadhan static ofmt_field_t	probe_fields[], targ_fields[];
167e11c3f44Smeem static ipmpstat_cbfunc_t walk_addr_cbfunc, walk_if_cbfunc;
168e11c3f44Smeem static ipmpstat_cbfunc_t info_output_cbfunc, targinfo_output_cbfunc;
169e11c3f44Smeem static ipmpstat_walker_t walk_addr, walk_if, walk_group;
170e11c3f44Smeem 
171e11c3f44Smeem static int probe_event(sysevent_t *, void *);
1728002d411SSowmini Varadhan static void probe_output(ipmp_handle_t, ofmt_handle_t);
1738002d411SSowmini Varadhan static void ofmt_output(ofmt_handle_t, ipmp_handle_t, void *);
174e11c3f44Smeem static void enum2str(const ipmpstat_enum_t *, int, char *, uint_t);
175e11c3f44Smeem static void sockaddr2str(const struct sockaddr_storage *, char *, uint_t);
176e11c3f44Smeem static void sighandler(int);
177e11c3f44Smeem static void usage(void);
178e11c3f44Smeem static void die(const char *, ...);
179e11c3f44Smeem static void die_ipmperr(int, const char *, ...);
180e11c3f44Smeem static void warn(const char *, ...);
181e11c3f44Smeem static void warn_ipmperr(int, const char *, ...);
182e11c3f44Smeem 
183e11c3f44Smeem int
main(int argc,char ** argv)184e11c3f44Smeem main(int argc, char **argv)
185e11c3f44Smeem {
186e11c3f44Smeem 	int c;
187e11c3f44Smeem 	int err;
188e11c3f44Smeem 	const char *ofields = NULL;
1898002d411SSowmini Varadhan 	ofmt_status_t ofmterr;
1908002d411SSowmini Varadhan 	ofmt_field_t *fields = NULL;
1918002d411SSowmini Varadhan 	uint_t ofmtflags = 0;
192e11c3f44Smeem 	ipmp_handle_t ih;
193e11c3f44Smeem 	ipmp_qcontext_t qcontext = IPMP_QCONTEXT_SNAP;
194e11c3f44Smeem 	ipmpstat_cbfunc_t *cbfunc;
195e11c3f44Smeem 	ipmpstat_walker_t *walker;
1968002d411SSowmini Varadhan 	char errbuf[OFMT_BUFSIZE];
197e11c3f44Smeem 
198e11c3f44Smeem 	if ((progname = strrchr(argv[0], '/')) == NULL)
199e11c3f44Smeem 		progname = argv[0];
200e11c3f44Smeem 	else
201e11c3f44Smeem 		progname++;
202e11c3f44Smeem 
203e11c3f44Smeem 	(void) setlocale(LC_ALL, "");
204e11c3f44Smeem 	(void) textdomain(TEXT_DOMAIN);
205e11c3f44Smeem 
206e11c3f44Smeem 	while ((c = getopt(argc, argv, "nLPo:agipt")) != EOF) {
207e11c3f44Smeem 		if (fields != NULL && strchr("agipt", c) != NULL)
208e11c3f44Smeem 			die("only one output format may be specified\n");
209e11c3f44Smeem 
210e11c3f44Smeem 		switch (c) {
211e11c3f44Smeem 		case 'n':
212e11c3f44Smeem 			opt |= IPMPSTAT_OPT_NUMERIC;
213e11c3f44Smeem 			break;
214e11c3f44Smeem 		case 'L':
215e11c3f44Smeem 			/* Undocumented option: for testing use ONLY */
216e11c3f44Smeem 			qcontext = IPMP_QCONTEXT_LIVE;
217e11c3f44Smeem 			break;
218e11c3f44Smeem 		case 'P':
219e11c3f44Smeem 			opt |= IPMPSTAT_OPT_PARSABLE;
2208002d411SSowmini Varadhan 			ofmtflags |= OFMT_PARSABLE;
221e11c3f44Smeem 			break;
222e11c3f44Smeem 		case 'o':
223e11c3f44Smeem 			ofields = optarg;
224e11c3f44Smeem 			break;
225e11c3f44Smeem 		case 'a':
226e11c3f44Smeem 			walker = walk_addr;
227e11c3f44Smeem 			cbfunc = info_output_cbfunc;
228e11c3f44Smeem 			fields = addr_fields;
229e11c3f44Smeem 			break;
230e11c3f44Smeem 		case 'g':
231e11c3f44Smeem 			walker = walk_group;
232e11c3f44Smeem 			cbfunc = info_output_cbfunc;
233e11c3f44Smeem 			fields = group_fields;
234e11c3f44Smeem 			break;
235e11c3f44Smeem 		case 'i':
236e11c3f44Smeem 			walker = walk_if;
237e11c3f44Smeem 			cbfunc = info_output_cbfunc;
238e11c3f44Smeem 			fields = if_fields;
239e11c3f44Smeem 			break;
240e11c3f44Smeem 		case 'p':
241e11c3f44Smeem 			fields = probe_fields;
242e11c3f44Smeem 			break;
243e11c3f44Smeem 		case 't':
244e11c3f44Smeem 			walker = walk_if;
245e11c3f44Smeem 			cbfunc = targinfo_output_cbfunc;
246e11c3f44Smeem 			fields = targ_fields;
247e11c3f44Smeem 			break;
248e11c3f44Smeem 		default:
249e11c3f44Smeem 			usage();
250e11c3f44Smeem 			break;
251e11c3f44Smeem 		}
252e11c3f44Smeem 	}
253e11c3f44Smeem 
254e11c3f44Smeem 	if (argc > optind || fields == NULL)
255e11c3f44Smeem 		usage();
256e11c3f44Smeem 
2578002d411SSowmini Varadhan 	/*
2588002d411SSowmini Varadhan 	 * Open a handle to the formatted output engine.
2598002d411SSowmini Varadhan 	 */
2608002d411SSowmini Varadhan 	ofmterr = ofmt_open(ofields, fields, ofmtflags, IPMPSTAT_NCOL, &ofmt);
2618002d411SSowmini Varadhan 	if (ofmterr != OFMT_SUCCESS) {
2628002d411SSowmini Varadhan 		/*
2638002d411SSowmini Varadhan 		 * If some fields were badly formed in human-friendly mode, we
2648002d411SSowmini Varadhan 		 * emit a warning and continue.  Otherwise exit immediately.
2658002d411SSowmini Varadhan 		 */
2668002d411SSowmini Varadhan 		(void) ofmt_strerror(ofmt, ofmterr, errbuf, sizeof (errbuf));
2678002d411SSowmini Varadhan 		if (ofmterr != OFMT_EBADFIELDS || (opt & IPMPSTAT_OPT_PARSABLE))
2688002d411SSowmini Varadhan 			die("%s\n", errbuf);
2698002d411SSowmini Varadhan 		else
2708002d411SSowmini Varadhan 			warn("%s\n", errbuf);
271e11c3f44Smeem 	}
272e11c3f44Smeem 
273e11c3f44Smeem 	/*
274e11c3f44Smeem 	 * Obtain the window size and monitor changes to the size.  This data
275e11c3f44Smeem 	 * is used to redisplay the output headers when necessary.
276e11c3f44Smeem 	 */
277e11c3f44Smeem 	(void) sigset(SIGWINCH, sighandler);
278e11c3f44Smeem 
279e11c3f44Smeem 	if ((err = ipmp_open(&ih)) != IPMP_SUCCESS)
280e11c3f44Smeem 		die_ipmperr(err, "cannot create IPMP handle");
281e11c3f44Smeem 
282e11c3f44Smeem 	if (ipmp_ping_daemon(ih) != IPMP_SUCCESS)
283*bbf21555SRichard Lowe 		die("cannot contact in.mpathd(8) -- is IPMP in use?\n");
284e11c3f44Smeem 
285e11c3f44Smeem 	/*
286e11c3f44Smeem 	 * If we've been asked to display probes, then call the probe output
287e11c3f44Smeem 	 * function.  Otherwise, snapshot IPMP state (or use live state) and
288e11c3f44Smeem 	 * invoke the specified walker with the specified callback function.
289e11c3f44Smeem 	 */
290e11c3f44Smeem 	if (fields == probe_fields) {
291e11c3f44Smeem 		probe_output(ih, ofmt);
292e11c3f44Smeem 	} else {
293e11c3f44Smeem 		if ((err = ipmp_setqcontext(ih, qcontext)) != IPMP_SUCCESS) {
294e11c3f44Smeem 			if (qcontext == IPMP_QCONTEXT_SNAP)
295e11c3f44Smeem 				die_ipmperr(err, "cannot snapshot IPMP state");
296e11c3f44Smeem 			else
297e11c3f44Smeem 				die_ipmperr(err, "cannot use live IPMP state");
298e11c3f44Smeem 		}
299e11c3f44Smeem 		(*walker)(ih, cbfunc, ofmt);
300e11c3f44Smeem 	}
301e11c3f44Smeem 
3028002d411SSowmini Varadhan 	ofmt_close(ofmt);
303e11c3f44Smeem 	ipmp_close(ih);
304e11c3f44Smeem 
305e11c3f44Smeem 	return (EXIT_SUCCESS);
306e11c3f44Smeem }
307e11c3f44Smeem 
308e11c3f44Smeem /*
309e11c3f44Smeem  * Walks all IPMP groups on the system and invokes `cbfunc' on each, passing
310e11c3f44Smeem  * it `ih', the ipmp_groupinfo_t pointer, and `arg'.
311e11c3f44Smeem  */
312e11c3f44Smeem static void
walk_group(ipmp_handle_t ih,ipmpstat_cbfunc_t * cbfunc,void * arg)313e11c3f44Smeem walk_group(ipmp_handle_t ih, ipmpstat_cbfunc_t *cbfunc, void *arg)
314e11c3f44Smeem {
315e11c3f44Smeem 	int err;
316e11c3f44Smeem 	uint_t i;
317e11c3f44Smeem 	ipmp_groupinfo_t *grinfop;
318e11c3f44Smeem 	ipmp_grouplist_t *grlistp;
319e11c3f44Smeem 
320e11c3f44Smeem 	if ((err = ipmp_getgrouplist(ih, &grlistp)) != IPMP_SUCCESS)
321e11c3f44Smeem 		die_ipmperr(err, "cannot get IPMP group list");
322e11c3f44Smeem 
323e11c3f44Smeem 	for (i = 0; i < grlistp->gl_ngroup; i++) {
324e11c3f44Smeem 		err = ipmp_getgroupinfo(ih, grlistp->gl_groups[i], &grinfop);
325e11c3f44Smeem 		if (err != IPMP_SUCCESS) {
326e11c3f44Smeem 			warn_ipmperr(err, "cannot get info for group `%s'",
327e11c3f44Smeem 			    grlistp->gl_groups[i]);
328e11c3f44Smeem 			continue;
329e11c3f44Smeem 		}
330e11c3f44Smeem 		(*cbfunc)(ih, grinfop, arg);
331e11c3f44Smeem 		ipmp_freegroupinfo(grinfop);
332e11c3f44Smeem 	}
333e11c3f44Smeem 
334e11c3f44Smeem 	ipmp_freegrouplist(grlistp);
335e11c3f44Smeem }
336e11c3f44Smeem 
337e11c3f44Smeem /*
338e11c3f44Smeem  * Walks all IPMP interfaces on the system and invokes `cbfunc' on each,
339e11c3f44Smeem  * passing it `ih', the ipmp_ifinfo_t pointer, and `arg'.
340e11c3f44Smeem  */
341e11c3f44Smeem static void
walk_if(ipmp_handle_t ih,ipmpstat_cbfunc_t * cbfunc,void * arg)342e11c3f44Smeem walk_if(ipmp_handle_t ih, ipmpstat_cbfunc_t *cbfunc, void *arg)
343e11c3f44Smeem {
344e11c3f44Smeem 	ipmpstat_walkdata_t iw = { cbfunc, arg };
345e11c3f44Smeem 
346e11c3f44Smeem 	walk_group(ih, walk_if_cbfunc, &iw);
347e11c3f44Smeem }
348e11c3f44Smeem 
349e11c3f44Smeem /*
350e11c3f44Smeem  * Walks all IPMP data addresses on the system and invokes `cbfunc' on each.
351e11c3f44Smeem  * passing it `ih', the ipmp_addrinfo_t pointer, and `arg'.
352e11c3f44Smeem  */
353e11c3f44Smeem static void
walk_addr(ipmp_handle_t ih,ipmpstat_cbfunc_t * cbfunc,void * arg)354e11c3f44Smeem walk_addr(ipmp_handle_t ih, ipmpstat_cbfunc_t *cbfunc, void *arg)
355e11c3f44Smeem {
356e11c3f44Smeem 	ipmpstat_walkdata_t iw = { cbfunc, arg };
357e11c3f44Smeem 
358e11c3f44Smeem 	walk_group(ih, walk_addr_cbfunc, &iw);
359e11c3f44Smeem }
360e11c3f44Smeem 
361e11c3f44Smeem /*
362e11c3f44Smeem  * Nested walker callback function for walk_if().
363e11c3f44Smeem  */
364e11c3f44Smeem static void
walk_if_cbfunc(ipmp_handle_t ih,void * infop,void * arg)365e11c3f44Smeem walk_if_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
366e11c3f44Smeem {
367e11c3f44Smeem 	int err;
368e11c3f44Smeem 	uint_t i;
369e11c3f44Smeem 	ipmp_groupinfo_t *grinfop = infop;
370e11c3f44Smeem 	ipmp_ifinfo_t *ifinfop;
371e11c3f44Smeem 	ipmp_iflist_t *iflistp = grinfop->gr_iflistp;
372e11c3f44Smeem 	ipmpstat_walkdata_t *iwp = arg;
373e11c3f44Smeem 
374e11c3f44Smeem 	for (i = 0; i < iflistp->il_nif; i++) {
375e11c3f44Smeem 		err = ipmp_getifinfo(ih, iflistp->il_ifs[i], &ifinfop);
376e11c3f44Smeem 		if (err != IPMP_SUCCESS) {
377e11c3f44Smeem 			warn_ipmperr(err, "cannot get info for interface `%s'",
378e11c3f44Smeem 			    iflistp->il_ifs[i]);
379e11c3f44Smeem 			continue;
380e11c3f44Smeem 		}
381e11c3f44Smeem 		(*iwp->iw_func)(ih, ifinfop, iwp->iw_funcarg);
382e11c3f44Smeem 		ipmp_freeifinfo(ifinfop);
383e11c3f44Smeem 	}
384e11c3f44Smeem }
385e11c3f44Smeem 
386e11c3f44Smeem /*
387e11c3f44Smeem  * Nested walker callback function for walk_addr().
388e11c3f44Smeem  */
389e11c3f44Smeem static void
walk_addr_cbfunc(ipmp_handle_t ih,void * infop,void * arg)390e11c3f44Smeem walk_addr_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
391e11c3f44Smeem {
392e11c3f44Smeem 	int err;
393e11c3f44Smeem 	uint_t i;
394e11c3f44Smeem 	ipmp_groupinfo_t *grinfop = infop;
395e11c3f44Smeem 	ipmp_addrinfo_t *adinfop;
396e11c3f44Smeem 	ipmp_addrlist_t *adlistp = grinfop->gr_adlistp;
397e11c3f44Smeem 	ipmpstat_walkdata_t *iwp = arg;
398e11c3f44Smeem 	char addr[INET6_ADDRSTRLEN];
399e11c3f44Smeem 	struct sockaddr_storage *addrp;
400e11c3f44Smeem 
401e11c3f44Smeem 	for (i = 0; i < adlistp->al_naddr; i++) {
402e11c3f44Smeem 		addrp = &adlistp->al_addrs[i];
403e11c3f44Smeem 		err = ipmp_getaddrinfo(ih, grinfop->gr_name, addrp, &adinfop);
404e11c3f44Smeem 		if (err != IPMP_SUCCESS) {
405e11c3f44Smeem 			sockaddr2str(addrp, addr, sizeof (addr));
406e11c3f44Smeem 			warn_ipmperr(err, "cannot get info for `%s'", addr);
407e11c3f44Smeem 			continue;
408e11c3f44Smeem 		}
409e11c3f44Smeem 		(*iwp->iw_func)(ih, adinfop, iwp->iw_funcarg);
410e11c3f44Smeem 		ipmp_freeaddrinfo(adinfop);
411e11c3f44Smeem 	}
412e11c3f44Smeem }
413e11c3f44Smeem 
4148002d411SSowmini Varadhan static boolean_t
sfunc_nvwarn(const char * nvname)4158002d411SSowmini Varadhan sfunc_nvwarn(const char *nvname)
416e11c3f44Smeem {
417e11c3f44Smeem 	warn("cannot retrieve %s\n", nvname);
4188002d411SSowmini Varadhan 	return (B_FALSE);
419e11c3f44Smeem }
420e11c3f44Smeem 
4218002d411SSowmini Varadhan static boolean_t
sfunc_addr_address(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)4228002d411SSowmini Varadhan sfunc_addr_address(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
423e11c3f44Smeem {
4248002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
425e11c3f44Smeem 	ipmp_addrinfo_t *adinfop = arg->sa_data;
426e11c3f44Smeem 
427e11c3f44Smeem 	sockaddr2str(&adinfop->ad_addr, buf, bufsize);
4288002d411SSowmini Varadhan 	return (B_TRUE);
429e11c3f44Smeem }
430e11c3f44Smeem 
4318002d411SSowmini Varadhan static boolean_t
sfunc_addr_group(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)4328002d411SSowmini Varadhan sfunc_addr_group(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
433e11c3f44Smeem {
4348002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
435e11c3f44Smeem 	int err;
436e11c3f44Smeem 	ipmp_addrinfo_t *adinfop = arg->sa_data;
437e11c3f44Smeem 	ipmp_groupinfo_t *grinfop;
438e11c3f44Smeem 
439e11c3f44Smeem 	err = ipmp_getgroupinfo(arg->sa_ih, adinfop->ad_group, &grinfop);
440e11c3f44Smeem 	if (err != IPMP_SUCCESS) {
441e11c3f44Smeem 		warn_ipmperr(err, "cannot get info for group `%s'",
442e11c3f44Smeem 		    adinfop->ad_group);
4438002d411SSowmini Varadhan 		return (B_FALSE);
444e11c3f44Smeem 	}
445e11c3f44Smeem 	(void) strlcpy(buf, grinfop->gr_ifname, bufsize);
446e11c3f44Smeem 	ipmp_freegroupinfo(grinfop);
4478002d411SSowmini Varadhan 	return (B_TRUE);
448e11c3f44Smeem }
449e11c3f44Smeem 
4508002d411SSowmini Varadhan static boolean_t
sfunc_addr_state(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)4518002d411SSowmini Varadhan sfunc_addr_state(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
452e11c3f44Smeem {
4538002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
454e11c3f44Smeem 	ipmp_addrinfo_t *adinfop = arg->sa_data;
455e11c3f44Smeem 
456e11c3f44Smeem 	enum2str(addr_state, adinfop->ad_state, buf, bufsize);
4578002d411SSowmini Varadhan 	return (B_TRUE);
458e11c3f44Smeem }
459e11c3f44Smeem 
4608002d411SSowmini Varadhan static boolean_t
sfunc_addr_inbound(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)4618002d411SSowmini Varadhan sfunc_addr_inbound(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
462e11c3f44Smeem {
4638002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
464e11c3f44Smeem 	ipmp_addrinfo_t *adinfop = arg->sa_data;
465e11c3f44Smeem 
466e11c3f44Smeem 	(void) strlcpy(buf, adinfop->ad_binding, bufsize);
4678002d411SSowmini Varadhan 	return (B_TRUE);
468e11c3f44Smeem }
469e11c3f44Smeem 
4708002d411SSowmini Varadhan static boolean_t
sfunc_addr_outbound(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)4718002d411SSowmini Varadhan sfunc_addr_outbound(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
472e11c3f44Smeem {
4738002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
474e11c3f44Smeem 	int err;
475e11c3f44Smeem 	uint_t i, nactive = 0;
476e11c3f44Smeem 	ipmp_ifinfo_t *ifinfop;
477e11c3f44Smeem 	ipmp_iflist_t *iflistp;
478e11c3f44Smeem 	ipmp_addrinfo_t *adinfop = arg->sa_data;
479e11c3f44Smeem 	ipmp_groupinfo_t *grinfop;
480e11c3f44Smeem 
481e11c3f44Smeem 	if (adinfop->ad_state == IPMP_ADDR_DOWN)
4828002d411SSowmini Varadhan 		return (B_TRUE);
483e11c3f44Smeem 
484e11c3f44Smeem 	/*
485e11c3f44Smeem 	 * If there's no inbound interface for this address, there can't
486e11c3f44Smeem 	 * be any outbound traffic.
487e11c3f44Smeem 	 */
488e11c3f44Smeem 	if (adinfop->ad_binding[0] == '\0')
4898002d411SSowmini Varadhan 		return (B_TRUE);
490e11c3f44Smeem 
491e11c3f44Smeem 	/*
492e11c3f44Smeem 	 * The address can use any active interface in the group, so
493e11c3f44Smeem 	 * obtain all of those.
494e11c3f44Smeem 	 */
495e11c3f44Smeem 	err = ipmp_getgroupinfo(arg->sa_ih, adinfop->ad_group, &grinfop);
496e11c3f44Smeem 	if (err != IPMP_SUCCESS) {
497e11c3f44Smeem 		warn_ipmperr(err, "cannot get info for group `%s'",
498e11c3f44Smeem 		    adinfop->ad_group);
4998002d411SSowmini Varadhan 		return (B_FALSE);
500e11c3f44Smeem 	}
501e11c3f44Smeem 
502e11c3f44Smeem 	iflistp = grinfop->gr_iflistp;
503e11c3f44Smeem 	for (i = 0; i < iflistp->il_nif; i++) {
504e11c3f44Smeem 		err = ipmp_getifinfo(arg->sa_ih, iflistp->il_ifs[i], &ifinfop);
505e11c3f44Smeem 		if (err != IPMP_SUCCESS) {
506e11c3f44Smeem 			warn_ipmperr(err, "cannot get info for interface `%s'",
507e11c3f44Smeem 			    iflistp->il_ifs[i]);
508e11c3f44Smeem 			continue;
509e11c3f44Smeem 		}
510e11c3f44Smeem 
511e11c3f44Smeem 		if (ifinfop->if_flags & IPMP_IFFLAG_ACTIVE) {
512e11c3f44Smeem 			if (nactive++ != 0)
513e11c3f44Smeem 				(void) strlcat(buf, " ", bufsize);
514e11c3f44Smeem 			(void) strlcat(buf, ifinfop->if_name, bufsize);
515e11c3f44Smeem 		}
516e11c3f44Smeem 		ipmp_freeifinfo(ifinfop);
517e11c3f44Smeem 	}
518e11c3f44Smeem 	ipmp_freegroupinfo(grinfop);
5198002d411SSowmini Varadhan 	return (B_TRUE);
520e11c3f44Smeem }
521e11c3f44Smeem 
5228002d411SSowmini Varadhan static boolean_t
sfunc_group_name(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)5238002d411SSowmini Varadhan sfunc_group_name(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
524e11c3f44Smeem {
5258002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
526e11c3f44Smeem 	ipmp_groupinfo_t *grinfop = arg->sa_data;
527e11c3f44Smeem 
528e11c3f44Smeem 	(void) strlcpy(buf, grinfop->gr_name, bufsize);
5298002d411SSowmini Varadhan 	return (B_TRUE);
530e11c3f44Smeem }
531e11c3f44Smeem 
5328002d411SSowmini Varadhan static boolean_t
sfunc_group_ifname(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)5338002d411SSowmini Varadhan sfunc_group_ifname(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
534e11c3f44Smeem {
5358002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
536e11c3f44Smeem 	ipmp_groupinfo_t *grinfop = arg->sa_data;
537e11c3f44Smeem 
538e11c3f44Smeem 	(void) strlcpy(buf, grinfop->gr_ifname, bufsize);
5398002d411SSowmini Varadhan 	return (B_TRUE);
540e11c3f44Smeem }
541e11c3f44Smeem 
5428002d411SSowmini Varadhan static boolean_t
sfunc_group_state(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)5438002d411SSowmini Varadhan sfunc_group_state(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
544e11c3f44Smeem {
5458002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
546e11c3f44Smeem 	ipmp_groupinfo_t *grinfop = arg->sa_data;
547e11c3f44Smeem 
548e11c3f44Smeem 	enum2str(group_state, grinfop->gr_state, buf, bufsize);
5498002d411SSowmini Varadhan 	return (B_TRUE);
550e11c3f44Smeem }
551e11c3f44Smeem 
5528002d411SSowmini Varadhan static boolean_t
sfunc_group_fdt(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)5538002d411SSowmini Varadhan sfunc_group_fdt(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
554e11c3f44Smeem {
5558002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
556e11c3f44Smeem 	ipmp_groupinfo_t *grinfop = arg->sa_data;
557e11c3f44Smeem 
558e11c3f44Smeem 	if (grinfop->gr_fdt == 0)
5598002d411SSowmini Varadhan 		return (B_TRUE);
560e11c3f44Smeem 
561e11c3f44Smeem 	(void) snprintf(buf, bufsize, "%.2fs", MS2FLOATSEC(grinfop->gr_fdt));
5628002d411SSowmini Varadhan 	return (B_TRUE);
563e11c3f44Smeem }
564e11c3f44Smeem 
5658002d411SSowmini Varadhan static boolean_t
sfunc_group_interfaces(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)5668002d411SSowmini Varadhan sfunc_group_interfaces(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
567e11c3f44Smeem {
5688002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
569e11c3f44Smeem 	int err;
570e11c3f44Smeem 	uint_t i;
571e11c3f44Smeem 	char *active, *inactive, *unusable;
572e11c3f44Smeem 	uint_t nactive = 0, ninactive = 0, nunusable = 0;
573e11c3f44Smeem 	ipmp_groupinfo_t *grinfop = arg->sa_data;
574e11c3f44Smeem 	ipmp_iflist_t *iflistp = grinfop->gr_iflistp;
575e11c3f44Smeem 	ipmp_ifinfo_t *ifinfop;
576e11c3f44Smeem 
577e11c3f44Smeem 	active = alloca(bufsize);
578e11c3f44Smeem 	active[0] = '\0';
579e11c3f44Smeem 	inactive = alloca(bufsize);
580e11c3f44Smeem 	inactive[0] = '\0';
581e11c3f44Smeem 	unusable = alloca(bufsize);
582e11c3f44Smeem 	unusable[0] = '\0';
583e11c3f44Smeem 
584e11c3f44Smeem 	for (i = 0; i < iflistp->il_nif; i++) {
585e11c3f44Smeem 		err = ipmp_getifinfo(arg->sa_ih, iflistp->il_ifs[i], &ifinfop);
586e11c3f44Smeem 		if (err != IPMP_SUCCESS) {
587e11c3f44Smeem 			warn_ipmperr(err, "cannot get info for interface `%s'",
588e11c3f44Smeem 			    iflistp->il_ifs[i]);
589e11c3f44Smeem 			continue;
590e11c3f44Smeem 		}
591e11c3f44Smeem 
592e11c3f44Smeem 		if (ifinfop->if_flags & IPMP_IFFLAG_ACTIVE) {
593e11c3f44Smeem 			if (nactive++ != 0)
594e11c3f44Smeem 				(void) strlcat(active, " ", bufsize);
595e11c3f44Smeem 			(void) strlcat(active, ifinfop->if_name, bufsize);
596e11c3f44Smeem 		} else if (ifinfop->if_flags & IPMP_IFFLAG_INACTIVE) {
597e11c3f44Smeem 			if (ninactive++ != 0)
598e11c3f44Smeem 				(void) strlcat(inactive, " ", bufsize);
599e11c3f44Smeem 			(void) strlcat(inactive, ifinfop->if_name, bufsize);
600e11c3f44Smeem 		} else {
601e11c3f44Smeem 			if (nunusable++ != 0)
602e11c3f44Smeem 				(void) strlcat(unusable, " ", bufsize);
603e11c3f44Smeem 			(void) strlcat(unusable, ifinfop->if_name, bufsize);
604e11c3f44Smeem 		}
605e11c3f44Smeem 
606e11c3f44Smeem 		ipmp_freeifinfo(ifinfop);
607e11c3f44Smeem 	}
608e11c3f44Smeem 
609e11c3f44Smeem 	(void) strlcpy(buf, active, bufsize);
610e11c3f44Smeem 
611e11c3f44Smeem 	if (ninactive > 0) {
612e11c3f44Smeem 		if (nactive != 0)
613e11c3f44Smeem 			(void) strlcat(buf, " ", bufsize);
614e11c3f44Smeem 
615e11c3f44Smeem 		(void) strlcat(buf, "(", bufsize);
616e11c3f44Smeem 		(void) strlcat(buf, inactive, bufsize);
617e11c3f44Smeem 		(void) strlcat(buf, ")", bufsize);
618e11c3f44Smeem 	}
619e11c3f44Smeem 
620e11c3f44Smeem 	if (nunusable > 0) {
621e11c3f44Smeem 		if (nactive + ninactive != 0)
622e11c3f44Smeem 			(void) strlcat(buf, " ", bufsize);
623e11c3f44Smeem 
624e11c3f44Smeem 		(void) strlcat(buf, "[", bufsize);
625e11c3f44Smeem 		(void) strlcat(buf, unusable, bufsize);
626e11c3f44Smeem 		(void) strlcat(buf, "]", bufsize);
627e11c3f44Smeem 	}
6288002d411SSowmini Varadhan 	return (B_TRUE);
629e11c3f44Smeem }
630e11c3f44Smeem 
6318002d411SSowmini Varadhan static boolean_t
sfunc_if_name(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)6328002d411SSowmini Varadhan sfunc_if_name(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
633e11c3f44Smeem {
6348002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
635e11c3f44Smeem 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
636e11c3f44Smeem 
637e11c3f44Smeem 	(void) strlcpy(buf, ifinfop->if_name, bufsize);
6388002d411SSowmini Varadhan 	return (B_TRUE);
639e11c3f44Smeem }
640e11c3f44Smeem 
6418002d411SSowmini Varadhan static boolean_t
sfunc_if_active(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)6428002d411SSowmini Varadhan sfunc_if_active(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
643e11c3f44Smeem {
6448002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
645e11c3f44Smeem 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
646e11c3f44Smeem 
647e11c3f44Smeem 	if (ifinfop->if_flags & IPMP_IFFLAG_ACTIVE)
648e11c3f44Smeem 		(void) strlcpy(buf, "yes", bufsize);
649e11c3f44Smeem 	else
650e11c3f44Smeem 		(void) strlcpy(buf, "no", bufsize);
6518002d411SSowmini Varadhan 	return (B_TRUE);
652e11c3f44Smeem }
653e11c3f44Smeem 
6548002d411SSowmini Varadhan static boolean_t
sfunc_if_group(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)6558002d411SSowmini Varadhan sfunc_if_group(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
656e11c3f44Smeem {
6578002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
658e11c3f44Smeem 	int err;
659e11c3f44Smeem 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
660e11c3f44Smeem 	ipmp_groupinfo_t *grinfop;
661e11c3f44Smeem 
662e11c3f44Smeem 	err = ipmp_getgroupinfo(arg->sa_ih, ifinfop->if_group, &grinfop);
663e11c3f44Smeem 	if (err != IPMP_SUCCESS) {
664e11c3f44Smeem 		warn_ipmperr(err, "cannot get info for group `%s'",
665e11c3f44Smeem 		    ifinfop->if_group);
6668002d411SSowmini Varadhan 		return (B_TRUE);
667e11c3f44Smeem 	}
668e11c3f44Smeem 
669e11c3f44Smeem 	(void) strlcpy(buf, grinfop->gr_ifname, bufsize);
670e11c3f44Smeem 	ipmp_freegroupinfo(grinfop);
6718002d411SSowmini Varadhan 	return (B_TRUE);
672e11c3f44Smeem }
673e11c3f44Smeem 
6748002d411SSowmini Varadhan static boolean_t
sfunc_if_flags(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)6758002d411SSowmini Varadhan sfunc_if_flags(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
676e11c3f44Smeem {
6778002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
678e11c3f44Smeem 	int err;
679e11c3f44Smeem 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
680e11c3f44Smeem 	ipmp_groupinfo_t *grinfop;
681e11c3f44Smeem 
682e11c3f44Smeem 	assert(bufsize > IPMPSTAT_NUM_FLAGS);
683e11c3f44Smeem 
684e11c3f44Smeem 	(void) memset(buf, '-', IPMPSTAT_NUM_FLAGS);
685e11c3f44Smeem 	buf[IPMPSTAT_NUM_FLAGS] = '\0';
686e11c3f44Smeem 
687e11c3f44Smeem 	if (ifinfop->if_type == IPMP_IF_STANDBY)
688e11c3f44Smeem 		buf[IPMPSTAT_SFLAG_INDEX] = 's';
689e11c3f44Smeem 
690e11c3f44Smeem 	if (ifinfop->if_flags & IPMP_IFFLAG_INACTIVE)
691e11c3f44Smeem 		buf[IPMPSTAT_IFLAG_INDEX] = 'i';
692e11c3f44Smeem 
693e11c3f44Smeem 	if (ifinfop->if_flags & IPMP_IFFLAG_DOWN)
694e11c3f44Smeem 		buf[IPMPSTAT_DFLAG_INDEX] = 'd';
695e11c3f44Smeem 
696e11c3f44Smeem 	if (ifinfop->if_flags & IPMP_IFFLAG_HWADDRDUP)
697e11c3f44Smeem 		buf[IPMPSTAT_HFLAG_INDEX] = 'h';
698e11c3f44Smeem 
699e11c3f44Smeem 	err = ipmp_getgroupinfo(arg->sa_ih, ifinfop->if_group, &grinfop);
700e11c3f44Smeem 	if (err != IPMP_SUCCESS) {
701e11c3f44Smeem 		warn_ipmperr(err, "cannot get broadcast/multicast info for "
702e11c3f44Smeem 		    "group `%s'", ifinfop->if_group);
7038002d411SSowmini Varadhan 		return (B_TRUE);
704e11c3f44Smeem 	}
705e11c3f44Smeem 
706e11c3f44Smeem 	if (strcmp(grinfop->gr_m4ifname, ifinfop->if_name) == 0)
707e11c3f44Smeem 		buf[IPMPSTAT_M4FLAG_INDEX] = 'm';
708e11c3f44Smeem 
709e11c3f44Smeem 	if (strcmp(grinfop->gr_m6ifname, ifinfop->if_name) == 0)
710e11c3f44Smeem 		buf[IPMPSTAT_M6FLAG_INDEX] = 'M';
711e11c3f44Smeem 
712e11c3f44Smeem 	if (strcmp(grinfop->gr_bcifname, ifinfop->if_name) == 0)
713e11c3f44Smeem 		buf[IPMPSTAT_BFLAG_INDEX] = 'b';
714e11c3f44Smeem 
715e11c3f44Smeem 	ipmp_freegroupinfo(grinfop);
7168002d411SSowmini Varadhan 	return (B_TRUE);
717e11c3f44Smeem }
718e11c3f44Smeem 
7198002d411SSowmini Varadhan static boolean_t
sfunc_if_link(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)7208002d411SSowmini Varadhan sfunc_if_link(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
721e11c3f44Smeem {
7228002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
723e11c3f44Smeem 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
724e11c3f44Smeem 
725e11c3f44Smeem 	enum2str(if_link, ifinfop->if_linkstate, buf, bufsize);
7268002d411SSowmini Varadhan 	return (B_TRUE);
727e11c3f44Smeem }
728e11c3f44Smeem 
7298002d411SSowmini Varadhan static boolean_t
sfunc_if_probe(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)7308002d411SSowmini Varadhan sfunc_if_probe(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
731e11c3f44Smeem {
7328002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
733e11c3f44Smeem 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
734e11c3f44Smeem 
735e11c3f44Smeem 	enum2str(if_probe, ifinfop->if_probestate, buf, bufsize);
7368002d411SSowmini Varadhan 	return (B_TRUE);
737e11c3f44Smeem }
738e11c3f44Smeem 
7398002d411SSowmini Varadhan static boolean_t
sfunc_if_state(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)7408002d411SSowmini Varadhan sfunc_if_state(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
741e11c3f44Smeem {
7428002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
743e11c3f44Smeem 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
744e11c3f44Smeem 
745e11c3f44Smeem 	enum2str(if_state, ifinfop->if_state, buf, bufsize);
7468002d411SSowmini Varadhan 	return (B_TRUE);
747e11c3f44Smeem }
748e11c3f44Smeem 
7498002d411SSowmini Varadhan static boolean_t
sfunc_probe_id(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)7508002d411SSowmini Varadhan sfunc_probe_id(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
751e11c3f44Smeem {
7528002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
753e11c3f44Smeem 	uint32_t probe_id;
754e11c3f44Smeem 	nvlist_t *nvl = arg->sa_data;
755e11c3f44Smeem 
7568002d411SSowmini Varadhan 	if (nvlist_lookup_uint32(nvl, IPMP_PROBE_ID, &probe_id) != 0)
7578002d411SSowmini Varadhan 		return (sfunc_nvwarn("IPMP_PROBE_ID"));
758e11c3f44Smeem 
759e11c3f44Smeem 	(void) snprintf(buf, bufsize, "%u", probe_id);
7608002d411SSowmini Varadhan 	return (B_TRUE);
761e11c3f44Smeem }
762e11c3f44Smeem 
7638002d411SSowmini Varadhan static boolean_t
sfunc_probe_ifname(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)7648002d411SSowmini Varadhan sfunc_probe_ifname(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
765e11c3f44Smeem {
7668002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
767e11c3f44Smeem 	char *ifname;
768e11c3f44Smeem 	nvlist_t *nvl = arg->sa_data;
769e11c3f44Smeem 
7708002d411SSowmini Varadhan 	if (nvlist_lookup_string(nvl, IPMP_IF_NAME, &ifname) != 0)
7718002d411SSowmini Varadhan 		return (sfunc_nvwarn("IPMP_IF_NAME"));
772e11c3f44Smeem 
773e11c3f44Smeem 	(void) strlcpy(buf, ifname, bufsize);
7748002d411SSowmini Varadhan 	return (B_TRUE);
775e11c3f44Smeem }
776e11c3f44Smeem 
7778002d411SSowmini Varadhan static boolean_t
sfunc_probe_time(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)7788002d411SSowmini Varadhan sfunc_probe_time(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
779e11c3f44Smeem {
7808002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
781e11c3f44Smeem 	hrtime_t start;
782e11c3f44Smeem 	nvlist_t *nvl = arg->sa_data;
783e11c3f44Smeem 
7848002d411SSowmini Varadhan 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_START_TIME, &start) != 0)
7858002d411SSowmini Varadhan 		return (sfunc_nvwarn("IPMP_PROBE_START_TIME"));
786e11c3f44Smeem 
787e11c3f44Smeem 	(void) snprintf(buf, bufsize, "%.2fs",
788e11c3f44Smeem 	    (float)(start - probe_output_start) / NANOSEC);
7898002d411SSowmini Varadhan 	return (B_TRUE);
790e11c3f44Smeem }
791e11c3f44Smeem 
7928002d411SSowmini Varadhan static boolean_t
sfunc_probe_target(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)7938002d411SSowmini Varadhan sfunc_probe_target(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
794e11c3f44Smeem {
7958002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
796e11c3f44Smeem 	uint_t nelem;
797e11c3f44Smeem 	struct sockaddr_storage *target;
798e11c3f44Smeem 	nvlist_t *nvl = arg->sa_data;
799e11c3f44Smeem 
800e11c3f44Smeem 	if (nvlist_lookup_byte_array(nvl, IPMP_PROBE_TARGET,
8018002d411SSowmini Varadhan 	    (uchar_t **)&target, &nelem) != 0)
8028002d411SSowmini Varadhan 		return (sfunc_nvwarn("IPMP_PROBE_TARGET"));
803e11c3f44Smeem 
804e11c3f44Smeem 	sockaddr2str(target, buf, bufsize);
8058002d411SSowmini Varadhan 	return (B_TRUE);
806e11c3f44Smeem }
807e11c3f44Smeem 
8088002d411SSowmini Varadhan static boolean_t
sfunc_probe_rtt(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)8098002d411SSowmini Varadhan sfunc_probe_rtt(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
810e11c3f44Smeem {
8118002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
812e11c3f44Smeem 	hrtime_t start, ackproc;
813e11c3f44Smeem 	nvlist_t *nvl = arg->sa_data;
814e11c3f44Smeem 	uint32_t state;
815e11c3f44Smeem 
8168002d411SSowmini Varadhan 	if (nvlist_lookup_uint32(nvl, IPMP_PROBE_STATE, &state) != 0)
8178002d411SSowmini Varadhan 		return (sfunc_nvwarn("IPMP_PROBE_STATE"));
818e11c3f44Smeem 
819e11c3f44Smeem 	if (state != IPMP_PROBE_ACKED)
8208002d411SSowmini Varadhan 		return (B_TRUE);
821e11c3f44Smeem 
8228002d411SSowmini Varadhan 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_START_TIME, &start) != 0)
8238002d411SSowmini Varadhan 		return (sfunc_nvwarn("IPMP_PROBE_START_TIME"));
824e11c3f44Smeem 
8258002d411SSowmini Varadhan 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_ACKPROC_TIME, &ackproc) != 0)
8268002d411SSowmini Varadhan 		return (sfunc_nvwarn("IPMP_PROBE_ACKPROC_TIME"));
827e11c3f44Smeem 
828e11c3f44Smeem 	(void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(ackproc - start));
8298002d411SSowmini Varadhan 	return (B_TRUE);
830e11c3f44Smeem }
831e11c3f44Smeem 
8328002d411SSowmini Varadhan static boolean_t
sfunc_probe_netrtt(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)8338002d411SSowmini Varadhan sfunc_probe_netrtt(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
834e11c3f44Smeem {
8358002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
836e11c3f44Smeem 	hrtime_t sent, ackrecv;
837e11c3f44Smeem 	nvlist_t *nvl = arg->sa_data;
838e11c3f44Smeem 	uint32_t state;
839e11c3f44Smeem 
8408002d411SSowmini Varadhan 	if (nvlist_lookup_uint32(nvl, IPMP_PROBE_STATE, &state) != 0)
8418002d411SSowmini Varadhan 		return (sfunc_nvwarn("IPMP_PROBE_STATE"));
842e11c3f44Smeem 
843e11c3f44Smeem 	if (state != IPMP_PROBE_ACKED)
8448002d411SSowmini Varadhan 		return (B_TRUE);
845e11c3f44Smeem 
8468002d411SSowmini Varadhan 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_SENT_TIME, &sent) != 0)
8478002d411SSowmini Varadhan 		return (sfunc_nvwarn("IPMP_PROBE_SENT_TIME"));
848e11c3f44Smeem 
8498002d411SSowmini Varadhan 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_ACKRECV_TIME, &ackrecv) != 0)
8508002d411SSowmini Varadhan 		return (sfunc_nvwarn("IPMP_PROBE_ACKRECV_TIME"));
851e11c3f44Smeem 
852e11c3f44Smeem 	(void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(ackrecv - sent));
8538002d411SSowmini Varadhan 	return (B_TRUE);
854e11c3f44Smeem }
855e11c3f44Smeem 
8568002d411SSowmini Varadhan static boolean_t
sfunc_probe_rttavg(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)8578002d411SSowmini Varadhan sfunc_probe_rttavg(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
858e11c3f44Smeem {
8598002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
860e11c3f44Smeem 	int64_t rttavg;
861e11c3f44Smeem 	nvlist_t *nvl = arg->sa_data;
862e11c3f44Smeem 
8638002d411SSowmini Varadhan 	if (nvlist_lookup_int64(nvl, IPMP_PROBE_TARGET_RTTAVG, &rttavg) != 0)
8648002d411SSowmini Varadhan 		return (sfunc_nvwarn("IPMP_PROBE_TARGET_RTTAVG"));
865e11c3f44Smeem 
866e11c3f44Smeem 	if (rttavg != 0)
867e11c3f44Smeem 		(void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(rttavg));
8688002d411SSowmini Varadhan 	return (B_TRUE);
869e11c3f44Smeem }
870e11c3f44Smeem 
8718002d411SSowmini Varadhan static boolean_t
sfunc_probe_rttdev(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)8728002d411SSowmini Varadhan sfunc_probe_rttdev(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
873e11c3f44Smeem {
8748002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
875e11c3f44Smeem 	int64_t rttdev;
876e11c3f44Smeem 	nvlist_t *nvl = arg->sa_data;
877e11c3f44Smeem 
8788002d411SSowmini Varadhan 	if (nvlist_lookup_int64(nvl, IPMP_PROBE_TARGET_RTTDEV, &rttdev) != 0)
8798002d411SSowmini Varadhan 		return (sfunc_nvwarn("IPMP_PROBE_TARGET_RTTDEV"));
880e11c3f44Smeem 
881e11c3f44Smeem 	if (rttdev != 0)
882e11c3f44Smeem 		(void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(rttdev));
8838002d411SSowmini Varadhan 	return (B_TRUE);
884e11c3f44Smeem }
885e11c3f44Smeem 
886e11c3f44Smeem /* ARGSUSED */
887e11c3f44Smeem static void
probe_enabled_cbfunc(ipmp_handle_t ih,void * infop,void * arg)888e11c3f44Smeem probe_enabled_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
889e11c3f44Smeem {
890e11c3f44Smeem 	uint_t *nenabledp = arg;
891e11c3f44Smeem 	ipmp_ifinfo_t *ifinfop = infop;
892e11c3f44Smeem 
893e11c3f44Smeem 	if (ifinfop->if_probestate != IPMP_PROBE_DISABLED)
894e11c3f44Smeem 		(*nenabledp)++;
895e11c3f44Smeem }
896e11c3f44Smeem 
897e11c3f44Smeem static void
probe_output(ipmp_handle_t ih,ofmt_handle_t ofmt)8988002d411SSowmini Varadhan probe_output(ipmp_handle_t ih, ofmt_handle_t ofmt)
899e11c3f44Smeem {
900e11c3f44Smeem 	char sub[MAX_SUBID_LEN];
901e11c3f44Smeem 	evchan_t *evch;
902e11c3f44Smeem 	ipmpstat_probe_state_t ps = { ih, ofmt };
903e11c3f44Smeem 	uint_t nenabled = 0;
904e11c3f44Smeem 
905e11c3f44Smeem 	/*
906e11c3f44Smeem 	 * Check if any interfaces are enabled for probe-based failure
907e11c3f44Smeem 	 * detection.  If not, immediately fail.
908e11c3f44Smeem 	 */
909e11c3f44Smeem 	walk_if(ih, probe_enabled_cbfunc, &nenabled);
910e11c3f44Smeem 	if (nenabled == 0)
911e11c3f44Smeem 		die("probe-based failure detection is disabled\n");
912e11c3f44Smeem 
913e11c3f44Smeem 	probe_output_start = gethrtime();
914e11c3f44Smeem 
915e11c3f44Smeem 	/*
916e11c3f44Smeem 	 * Unfortunately, until 4791900 is fixed, only privileged processes
917e11c3f44Smeem 	 * can bind and thus receive sysevents.
918e11c3f44Smeem 	 */
919e11c3f44Smeem 	errno = sysevent_evc_bind(IPMP_EVENT_CHAN, &evch, EVCH_CREAT);
920e11c3f44Smeem 	if (errno != 0) {
921e11c3f44Smeem 		if (errno == EPERM)
922e11c3f44Smeem 			die("insufficient privileges for -p\n");
923e11c3f44Smeem 		die("sysevent_evc_bind to channel %s failed", IPMP_EVENT_CHAN);
924e11c3f44Smeem 	}
925e11c3f44Smeem 
926e11c3f44Smeem 	/*
927e11c3f44Smeem 	 * The subscriber must be unique in order for sysevent_evc_subscribe()
928e11c3f44Smeem 	 * to succeed, so combine our name and pid.
929e11c3f44Smeem 	 */
930e11c3f44Smeem 	(void) snprintf(sub, sizeof (sub), "%d-%s", getpid(), progname);
931e11c3f44Smeem 
932e11c3f44Smeem 	errno = sysevent_evc_subscribe(evch, sub, EC_IPMP, probe_event, &ps, 0);
933e11c3f44Smeem 	if (errno != 0)
934e11c3f44Smeem 		die("sysevent_evc_subscribe for class %s failed", EC_IPMP);
935e11c3f44Smeem 
936e11c3f44Smeem 	for (;;)
937e11c3f44Smeem 		(void) pause();
938e11c3f44Smeem }
939e11c3f44Smeem 
940e11c3f44Smeem static int
probe_event(sysevent_t * ev,void * arg)941e11c3f44Smeem probe_event(sysevent_t *ev, void *arg)
942e11c3f44Smeem {
943e11c3f44Smeem 	nvlist_t *nvl;
944e11c3f44Smeem 	uint32_t state;
945e11c3f44Smeem 	uint32_t version;
946e11c3f44Smeem 	ipmpstat_probe_state_t *psp = arg;
947e11c3f44Smeem 
948e11c3f44Smeem 	if (strcmp(sysevent_get_subclass_name(ev), ESC_IPMP_PROBE_STATE) != 0)
949e11c3f44Smeem 		return (0);
950e11c3f44Smeem 
951e11c3f44Smeem 	if (sysevent_get_attr_list(ev, &nvl) != 0) {
952e11c3f44Smeem 		warn("sysevent_get_attr_list failed; dropping event");
953e11c3f44Smeem 		return (0);
954e11c3f44Smeem 	}
955e11c3f44Smeem 
956e11c3f44Smeem 	if (nvlist_lookup_uint32(nvl, IPMP_EVENT_VERSION, &version) != 0) {
957e11c3f44Smeem 		warn("dropped event with no IPMP_EVENT_VERSION\n");
958e11c3f44Smeem 		goto out;
959e11c3f44Smeem 	}
960e11c3f44Smeem 
961e11c3f44Smeem 	if (version != IPMP_EVENT_CUR_VERSION) {
962e11c3f44Smeem 		warn("dropped event with unsupported IPMP_EVENT_VERSION %d\n",
963e11c3f44Smeem 		    version);
964e11c3f44Smeem 		goto out;
965e11c3f44Smeem 	}
966e11c3f44Smeem 
967e11c3f44Smeem 	if (nvlist_lookup_uint32(nvl, IPMP_PROBE_STATE, &state) != 0) {
968e11c3f44Smeem 		warn("dropped event with no IPMP_PROBE_STATE\n");
969e11c3f44Smeem 		goto out;
970e11c3f44Smeem 	}
971e11c3f44Smeem 
972e11c3f44Smeem 	if (state == IPMP_PROBE_ACKED || state == IPMP_PROBE_LOST)
973e11c3f44Smeem 		ofmt_output(psp->ps_ofmt, psp->ps_ih, nvl);
974e11c3f44Smeem out:
975e11c3f44Smeem 	nvlist_free(nvl);
976e11c3f44Smeem 	return (0);
977e11c3f44Smeem }
978e11c3f44Smeem 
9798002d411SSowmini Varadhan static boolean_t
sfunc_targ_ifname(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)9808002d411SSowmini Varadhan sfunc_targ_ifname(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
981e11c3f44Smeem {
9828002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
983e11c3f44Smeem 	ipmp_targinfo_t *targinfop = arg->sa_data;
984e11c3f44Smeem 
985e11c3f44Smeem 	(void) strlcpy(buf, targinfop->it_name, bufsize);
9868002d411SSowmini Varadhan 	return (B_TRUE);
987e11c3f44Smeem }
988e11c3f44Smeem 
9898002d411SSowmini Varadhan static boolean_t
sfunc_targ_mode(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)9908002d411SSowmini Varadhan sfunc_targ_mode(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
991e11c3f44Smeem {
9928002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
993e11c3f44Smeem 	ipmp_targinfo_t *targinfop = arg->sa_data;
994e11c3f44Smeem 
995e11c3f44Smeem 	enum2str(targ_mode, targinfop->it_targmode, buf, bufsize);
9968002d411SSowmini Varadhan 	return (B_TRUE);
997e11c3f44Smeem }
998e11c3f44Smeem 
9998002d411SSowmini Varadhan static boolean_t
sfunc_targ_testaddr(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)10008002d411SSowmini Varadhan sfunc_targ_testaddr(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
1001e11c3f44Smeem {
10028002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
1003e11c3f44Smeem 	ipmp_targinfo_t *targinfop = arg->sa_data;
1004e11c3f44Smeem 
1005e11c3f44Smeem 	if (targinfop->it_targmode != IPMP_TARG_DISABLED)
1006e11c3f44Smeem 		sockaddr2str(&targinfop->it_testaddr, buf, bufsize);
10078002d411SSowmini Varadhan 	return (B_TRUE);
1008e11c3f44Smeem }
1009e11c3f44Smeem 
10108002d411SSowmini Varadhan static boolean_t
sfunc_targ_targets(ofmt_arg_t * ofmtarg,char * buf,uint_t bufsize)10118002d411SSowmini Varadhan sfunc_targ_targets(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize)
1012e11c3f44Smeem {
10138002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg;
1014e11c3f44Smeem 	uint_t i;
1015e11c3f44Smeem 	char *targname = alloca(bufsize);
1016e11c3f44Smeem 	ipmp_targinfo_t *targinfop = arg->sa_data;
1017e11c3f44Smeem 	ipmp_addrlist_t *targlistp = targinfop->it_targlistp;
1018e11c3f44Smeem 
1019e11c3f44Smeem 	for (i = 0; i < targlistp->al_naddr; i++) {
1020e11c3f44Smeem 		sockaddr2str(&targlistp->al_addrs[i], targname, bufsize);
1021e11c3f44Smeem 		(void) strlcat(buf, targname, bufsize);
1022e11c3f44Smeem 		if ((i + 1) < targlistp->al_naddr)
1023e11c3f44Smeem 			(void) strlcat(buf, " ", bufsize);
1024e11c3f44Smeem 	}
10258002d411SSowmini Varadhan 	return (B_TRUE);
1026e11c3f44Smeem }
1027e11c3f44Smeem 
1028e11c3f44Smeem static void
info_output_cbfunc(ipmp_handle_t ih,void * infop,void * arg)1029e11c3f44Smeem info_output_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
1030e11c3f44Smeem {
1031e11c3f44Smeem 	ofmt_output(arg, ih, infop);
1032e11c3f44Smeem }
1033e11c3f44Smeem 
1034e11c3f44Smeem static void
targinfo_output_cbfunc(ipmp_handle_t ih,void * infop,void * arg)1035e11c3f44Smeem targinfo_output_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
1036e11c3f44Smeem {
1037e11c3f44Smeem 	ipmp_ifinfo_t *ifinfop = infop;
1038e11c3f44Smeem 	ipmp_if_targmode_t targmode4 = ifinfop->if_targinfo4.it_targmode;
1039e11c3f44Smeem 	ipmp_if_targmode_t targmode6 = ifinfop->if_targinfo6.it_targmode;
1040e11c3f44Smeem 
1041e11c3f44Smeem 	/*
1042e11c3f44Smeem 	 * Usually, either IPv4 or IPv6 probing will be enabled, but the admin
1043e11c3f44Smeem 	 * may enable both.  If only one is enabled, omit the other one so as
1044e11c3f44Smeem 	 * to not encourage the admin to enable both.  If neither is enabled,
1045e11c3f44Smeem 	 * we still print one just so the admin can see a MODE of "disabled".
1046e11c3f44Smeem 	 */
1047e11c3f44Smeem 	if (targmode4 != IPMP_TARG_DISABLED || targmode6 == IPMP_TARG_DISABLED)
1048e11c3f44Smeem 		ofmt_output(arg, ih, &ifinfop->if_targinfo4);
1049e11c3f44Smeem 	if (targmode6 != IPMP_TARG_DISABLED)
1050e11c3f44Smeem 		ofmt_output(arg, ih, &ifinfop->if_targinfo6);
1051e11c3f44Smeem }
1052e11c3f44Smeem 
1053e11c3f44Smeem /*
10548002d411SSowmini Varadhan  * Outputs one row of values.  The values to output are obtained through the
10558002d411SSowmini Varadhan  * callback function pointers.  The actual values are computed from the `ih'
10568002d411SSowmini Varadhan  * and `arg' structures passed to the callback function.
1057e11c3f44Smeem  */
1058e11c3f44Smeem static void
ofmt_output(const ofmt_handle_t ofmt,ipmp_handle_t ih,void * arg)10598002d411SSowmini Varadhan ofmt_output(const ofmt_handle_t ofmt, ipmp_handle_t ih, void *arg)
1060e11c3f44Smeem {
10618002d411SSowmini Varadhan 	ipmpstat_sfunc_arg_t	sfunc_arg;
1062e11c3f44Smeem 
10638002d411SSowmini Varadhan 	sfunc_arg.sa_ih = ih;
10648002d411SSowmini Varadhan 	sfunc_arg.sa_data = arg;
10658002d411SSowmini Varadhan 	ofmt_print(ofmt, &sfunc_arg);
1066e11c3f44Smeem }
1067e11c3f44Smeem 
1068e11c3f44Smeem /*
1069e11c3f44Smeem  * Uses `enums' to map `enumval' to a string, and stores at most `bufsize'
1070e11c3f44Smeem  * bytes of that string into `buf'.
1071e11c3f44Smeem  */
1072e11c3f44Smeem static void
enum2str(const ipmpstat_enum_t * enums,int enumval,char * buf,uint_t bufsize)1073e11c3f44Smeem enum2str(const ipmpstat_enum_t *enums, int enumval, char *buf, uint_t bufsize)
1074e11c3f44Smeem {
1075e11c3f44Smeem 	const ipmpstat_enum_t *enump;
1076e11c3f44Smeem 
1077e11c3f44Smeem 	for (enump = enums; enump->e_name != NULL; enump++) {
1078e11c3f44Smeem 		if (enump->e_val == enumval) {
1079e11c3f44Smeem 			(void) strlcpy(buf, enump->e_name, bufsize);
1080e11c3f44Smeem 			return;
1081e11c3f44Smeem 		}
1082e11c3f44Smeem 	}
1083e11c3f44Smeem 	(void) snprintf(buf, bufsize, "<%d>", enumval);
1084e11c3f44Smeem }
1085e11c3f44Smeem 
1086e11c3f44Smeem /*
1087e11c3f44Smeem  * Stores the stringified value of the sockaddr_storage pointed to by `ssp'
1088e11c3f44Smeem  * into at most `bufsize' bytes of `buf'.
1089e11c3f44Smeem  */
1090e11c3f44Smeem static void
sockaddr2str(const struct sockaddr_storage * ssp,char * buf,uint_t bufsize)1091e11c3f44Smeem sockaddr2str(const struct sockaddr_storage *ssp, char *buf, uint_t bufsize)
1092e11c3f44Smeem {
1093e11c3f44Smeem 	int flags = NI_NOFQDN;
1094e11c3f44Smeem 	socklen_t socklen;
1095e11c3f44Smeem 	struct sockaddr *sp = (struct sockaddr *)ssp;
1096e11c3f44Smeem 
1097e11c3f44Smeem 	/*
1098e11c3f44Smeem 	 * Sadly, getnameinfo() does not allow the socklen to be oversized for
1099e11c3f44Smeem 	 * a given family -- so we must determine the exact size to pass to it.
1100e11c3f44Smeem 	 */
1101e11c3f44Smeem 	switch (ssp->ss_family) {
1102e11c3f44Smeem 	case AF_INET:
1103e11c3f44Smeem 		socklen = sizeof (struct sockaddr_in);
1104e11c3f44Smeem 		break;
1105e11c3f44Smeem 	case AF_INET6:
1106e11c3f44Smeem 		socklen = sizeof (struct sockaddr_in6);
1107e11c3f44Smeem 		break;
1108e11c3f44Smeem 	default:
1109e11c3f44Smeem 		(void) strlcpy(buf, "?", bufsize);
1110e11c3f44Smeem 		return;
1111e11c3f44Smeem 	}
1112e11c3f44Smeem 
1113e11c3f44Smeem 	if (opt & IPMPSTAT_OPT_NUMERIC)
1114e11c3f44Smeem 		flags |= NI_NUMERICHOST;
1115e11c3f44Smeem 
1116e11c3f44Smeem 	(void) getnameinfo(sp, socklen, buf, bufsize, NULL, 0, flags);
1117e11c3f44Smeem }
1118e11c3f44Smeem 
1119e11c3f44Smeem static void
sighandler(int sig)1120e11c3f44Smeem sighandler(int sig)
1121e11c3f44Smeem {
1122e11c3f44Smeem 	assert(sig == SIGWINCH);
1123e11c3f44Smeem 
11248002d411SSowmini Varadhan 	ofmt_update_winsize(ofmt);
1125e11c3f44Smeem }
1126e11c3f44Smeem 
1127e11c3f44Smeem static void
usage(void)1128e11c3f44Smeem usage(void)
1129e11c3f44Smeem {
1130e11c3f44Smeem 	const char *argstr = gettext("[-n] [-o <field> [-P]] -a|-g|-i|-p|-t");
1131e11c3f44Smeem 
1132e11c3f44Smeem 	(void) fprintf(stderr, gettext("usage: %s %s\n"), progname, argstr);
1133ec382c61Smeem 	(void) fprintf(stderr, gettext("\n"
1134ec382c61Smeem 	    "  output modes:\t -a  display IPMP data address information\n"
1135ec382c61Smeem 	    "\t\t -g  display IPMP group information\n"
1136ec382c61Smeem 	    "\t\t -i  display IPMP-related IP interface information\n"
1137ec382c61Smeem 	    "\t\t -p  display IPMP probe information\n"
1138ec382c61Smeem 	    "\t\t -t  display IPMP target information\n\n"
1139ec382c61Smeem 	    "       options:\t -n  display IP addresses numerically\n"
1140ec382c61Smeem 	    "\t\t -o  display only the specified fields, in order\n"
1141ec382c61Smeem 	    "\t\t -P  display using parsable output mode\n"));
1142ec382c61Smeem 
1143e11c3f44Smeem 	exit(EXIT_FAILURE);
1144e11c3f44Smeem }
1145e11c3f44Smeem 
1146e11c3f44Smeem /* PRINTFLIKE1 */
1147e11c3f44Smeem static void
warn(const char * format,...)1148e11c3f44Smeem warn(const char *format, ...)
1149e11c3f44Smeem {
1150e11c3f44Smeem 	va_list alist;
1151e11c3f44Smeem 	int error = errno;
1152e11c3f44Smeem 
1153e11c3f44Smeem 	format = gettext(format);
1154e11c3f44Smeem 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
1155e11c3f44Smeem 
1156e11c3f44Smeem 	va_start(alist, format);
1157e11c3f44Smeem 	(void) vfprintf(stderr, format, alist);
1158e11c3f44Smeem 	va_end(alist);
1159e11c3f44Smeem 
1160e11c3f44Smeem 	if (strchr(format, '\n') == NULL)
1161e11c3f44Smeem 		(void) fprintf(stderr, ": %s\n", strerror(error));
1162e11c3f44Smeem }
1163e11c3f44Smeem 
1164e11c3f44Smeem /* PRINTFLIKE2 */
1165e11c3f44Smeem static void
warn_ipmperr(int ipmperr,const char * format,...)1166e11c3f44Smeem warn_ipmperr(int ipmperr, const char *format, ...)
1167e11c3f44Smeem {
1168e11c3f44Smeem 	va_list alist;
1169e11c3f44Smeem 
1170e11c3f44Smeem 	format = gettext(format);
1171e11c3f44Smeem 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
1172e11c3f44Smeem 
1173e11c3f44Smeem 	va_start(alist, format);
1174e11c3f44Smeem 	(void) vfprintf(stderr, format, alist);
1175e11c3f44Smeem 	va_end(alist);
1176e11c3f44Smeem 
1177e11c3f44Smeem 	(void) fprintf(stderr, ": %s\n", ipmp_errmsg(ipmperr));
1178e11c3f44Smeem }
1179e11c3f44Smeem 
1180e11c3f44Smeem /* PRINTFLIKE1 */
1181e11c3f44Smeem static void
die(const char * format,...)1182e11c3f44Smeem die(const char *format, ...)
1183e11c3f44Smeem {
1184e11c3f44Smeem 	va_list alist;
1185e11c3f44Smeem 	int error = errno;
1186e11c3f44Smeem 
1187e11c3f44Smeem 	format = gettext(format);
1188e11c3f44Smeem 	(void) fprintf(stderr, "%s: ", progname);
1189e11c3f44Smeem 
1190e11c3f44Smeem 	va_start(alist, format);
1191e11c3f44Smeem 	(void) vfprintf(stderr, format, alist);
1192e11c3f44Smeem 	va_end(alist);
1193e11c3f44Smeem 
1194e11c3f44Smeem 	if (strchr(format, '\n') == NULL)
1195e11c3f44Smeem 		(void) fprintf(stderr, ": %s\n", strerror(error));
1196e11c3f44Smeem 
1197e11c3f44Smeem 	exit(EXIT_FAILURE);
1198e11c3f44Smeem }
1199e11c3f44Smeem 
1200e11c3f44Smeem /* PRINTFLIKE2 */
1201e11c3f44Smeem static void
die_ipmperr(int ipmperr,const char * format,...)1202e11c3f44Smeem die_ipmperr(int ipmperr, const char *format, ...)
1203e11c3f44Smeem {
1204e11c3f44Smeem 	va_list alist;
1205e11c3f44Smeem 
1206e11c3f44Smeem 	format = gettext(format);
1207e11c3f44Smeem 	(void) fprintf(stderr, "%s: ", progname);
1208e11c3f44Smeem 
1209e11c3f44Smeem 	va_start(alist, format);
1210e11c3f44Smeem 	(void) vfprintf(stderr, format, alist);
1211e11c3f44Smeem 	va_end(alist);
1212e11c3f44Smeem 	(void) fprintf(stderr, ": %s\n", ipmp_errmsg(ipmperr));
1213e11c3f44Smeem 
1214e11c3f44Smeem 	exit(EXIT_FAILURE);
1215e11c3f44Smeem }
1216e11c3f44Smeem 
12178002d411SSowmini Varadhan static ofmt_field_t addr_fields[] = {
12188002d411SSowmini Varadhan 	{ "ADDRESS",    26,	0, sfunc_addr_address		},
12198002d411SSowmini Varadhan 	{ "STATE",	7,	0, sfunc_addr_state		},
12208002d411SSowmini Varadhan 	{ "GROUP",	12,	0, sfunc_addr_group		},
12218002d411SSowmini Varadhan 	{ "INBOUND",	12,	0, sfunc_addr_inbound		},
12228002d411SSowmini Varadhan 	{ "OUTBOUND",	23,	0, sfunc_addr_outbound		},
12238002d411SSowmini Varadhan 	{ NULL,		0, 	0, NULL				}
1224e11c3f44Smeem };
1225e11c3f44Smeem 
12268002d411SSowmini Varadhan static ofmt_field_t group_fields[] = {
12278002d411SSowmini Varadhan 	{ "GROUP",	12, 	0, sfunc_group_ifname		},
12288002d411SSowmini Varadhan 	{ "GROUPNAME",	12,	0, sfunc_group_name 		},
12298002d411SSowmini Varadhan 	{ "STATE",	10,	0, sfunc_group_state		},
12308002d411SSowmini Varadhan 	{ "FDT",	10,	0, sfunc_group_fdt		},
12318002d411SSowmini Varadhan 	{ "INTERFACES",	30,	0, sfunc_group_interfaces	},
12328002d411SSowmini Varadhan 	{ NULL,		0, 	0, NULL				}
1233e11c3f44Smeem };
1234e11c3f44Smeem 
12358002d411SSowmini Varadhan static ofmt_field_t if_fields[] = {
12368002d411SSowmini Varadhan 	{ "INTERFACE",	12,	0, sfunc_if_name		},
12378002d411SSowmini Varadhan 	{ "ACTIVE",	8, 	0, sfunc_if_active		},
12388002d411SSowmini Varadhan 	{ "GROUP",	12,	0, sfunc_if_group		},
12398002d411SSowmini Varadhan 	{ "FLAGS",	10,	0, sfunc_if_flags		},
12408002d411SSowmini Varadhan 	{ "LINK",	10,	0, sfunc_if_link		},
12418002d411SSowmini Varadhan 	{ "PROBE",	10,	0, sfunc_if_probe		},
12428002d411SSowmini Varadhan 	{ "STATE",	10, 	0, sfunc_if_state		},
12438002d411SSowmini Varadhan 	{ NULL,		0, 	0, NULL				}
1244e11c3f44Smeem };
1245e11c3f44Smeem 
12468002d411SSowmini Varadhan static ofmt_field_t probe_fields[] = {
12478002d411SSowmini Varadhan 	{ "TIME",	10,	0, sfunc_probe_time		},
12488002d411SSowmini Varadhan 	{ "INTERFACE",	12,	0, sfunc_probe_ifname		},
12498002d411SSowmini Varadhan 	{ "PROBE",	7,	0, sfunc_probe_id		},
12508002d411SSowmini Varadhan 	{ "NETRTT",	10,	0, sfunc_probe_netrtt		},
12518002d411SSowmini Varadhan 	{ "RTT",	10,	0, sfunc_probe_rtt		},
12528002d411SSowmini Varadhan 	{ "RTTAVG",	10,	0, sfunc_probe_rttavg		},
12538002d411SSowmini Varadhan 	{ "TARGET",	20,	0, sfunc_probe_target		},
12548002d411SSowmini Varadhan 	{ "RTTDEV",	10,	0, sfunc_probe_rttdev		},
12558002d411SSowmini Varadhan 	{ NULL,		0, 	0, NULL				}
1256e11c3f44Smeem };
1257e11c3f44Smeem 
12588002d411SSowmini Varadhan static ofmt_field_t targ_fields[] = {
12598002d411SSowmini Varadhan 	{ "INTERFACE",	12,	0, sfunc_targ_ifname		},
12608002d411SSowmini Varadhan 	{ "MODE",	10,	0, sfunc_targ_mode		},
12618002d411SSowmini Varadhan 	{ "TESTADDR",	20,	0, sfunc_targ_testaddr		},
12628002d411SSowmini Varadhan 	{ "TARGETS",	38,	0, sfunc_targ_targets		},
12638002d411SSowmini Varadhan 	{ NULL,		0, 	0, NULL				}
1264e11c3f44Smeem };
1265e11c3f44Smeem 
1266e11c3f44Smeem static ipmpstat_enum_t	addr_state[] = {
12678002d411SSowmini Varadhan 	{ "up",		IPMP_ADDR_UP				},
12688002d411SSowmini Varadhan 	{ "down",	IPMP_ADDR_DOWN				},
12698002d411SSowmini Varadhan 	{ NULL,		0 					}
1270e11c3f44Smeem };
1271e11c3f44Smeem 
1272e11c3f44Smeem static ipmpstat_enum_t	group_state[] = {
12738002d411SSowmini Varadhan 	{ "ok",		IPMP_GROUP_OK 				},
12748002d411SSowmini Varadhan 	{ "failed",	IPMP_GROUP_FAILED			},
12758002d411SSowmini Varadhan 	{ "degraded",	IPMP_GROUP_DEGRADED			},
12768002d411SSowmini Varadhan 	{ NULL,		0 					}
1277e11c3f44Smeem };
1278e11c3f44Smeem 
1279e11c3f44Smeem static ipmpstat_enum_t	if_link[] = {
12808002d411SSowmini Varadhan 	{ "up",		IPMP_LINK_UP 				},
12818002d411SSowmini Varadhan 	{ "down",	IPMP_LINK_DOWN				},
12828002d411SSowmini Varadhan 	{ "unknown",	IPMP_LINK_UNKNOWN			},
12838002d411SSowmini Varadhan 	{ NULL,		0 					}
1284e11c3f44Smeem };
1285e11c3f44Smeem 
1286e11c3f44Smeem static ipmpstat_enum_t	if_probe[] = {
12878002d411SSowmini Varadhan 	{ "ok",		IPMP_PROBE_OK 				},
12888002d411SSowmini Varadhan 	{ "failed",	IPMP_PROBE_FAILED			},
12898002d411SSowmini Varadhan 	{ "unknown",	IPMP_PROBE_UNKNOWN			},
12908002d411SSowmini Varadhan 	{ "disabled",	IPMP_PROBE_DISABLED			},
12918002d411SSowmini Varadhan 	{ NULL,		0 					}
1292e11c3f44Smeem };
1293e11c3f44Smeem 
1294e11c3f44Smeem static ipmpstat_enum_t	if_state[] = {
12958002d411SSowmini Varadhan 	{ "ok",		IPMP_IF_OK 				},
12968002d411SSowmini Varadhan 	{ "failed",	IPMP_IF_FAILED				},
12978002d411SSowmini Varadhan 	{ "unknown",	IPMP_IF_UNKNOWN				},
12988002d411SSowmini Varadhan 	{ "offline",	IPMP_IF_OFFLINE				},
12998002d411SSowmini Varadhan 	{ NULL,		0 					}
1300e11c3f44Smeem };
1301e11c3f44Smeem 
1302e11c3f44Smeem static ipmpstat_enum_t	targ_mode[] = {
13038002d411SSowmini Varadhan 	{ "disabled",	IPMP_TARG_DISABLED			},
13048002d411SSowmini Varadhan 	{ "routes",	IPMP_TARG_ROUTES			},
13058002d411SSowmini Varadhan 	{ "multicast",	IPMP_TARG_MULTICAST			},
13068002d411SSowmini Varadhan 	{ NULL,		0 					}
1307e11c3f44Smeem };
1308