xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/ipmpstat.c (revision 8485:633e5b5eb268)
1*8485SPeter.Memishian@Sun.COM /*
2*8485SPeter.Memishian@Sun.COM  * CDDL HEADER START
3*8485SPeter.Memishian@Sun.COM  *
4*8485SPeter.Memishian@Sun.COM  * The contents of this file are subject to the terms of the
5*8485SPeter.Memishian@Sun.COM  * Common Development and Distribution License (the "License").
6*8485SPeter.Memishian@Sun.COM  * You may not use this file except in compliance with the License.
7*8485SPeter.Memishian@Sun.COM  *
8*8485SPeter.Memishian@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*8485SPeter.Memishian@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*8485SPeter.Memishian@Sun.COM  * See the License for the specific language governing permissions
11*8485SPeter.Memishian@Sun.COM  * and limitations under the License.
12*8485SPeter.Memishian@Sun.COM  *
13*8485SPeter.Memishian@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*8485SPeter.Memishian@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*8485SPeter.Memishian@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*8485SPeter.Memishian@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*8485SPeter.Memishian@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*8485SPeter.Memishian@Sun.COM  *
19*8485SPeter.Memishian@Sun.COM  * CDDL HEADER END
20*8485SPeter.Memishian@Sun.COM  *
21*8485SPeter.Memishian@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
22*8485SPeter.Memishian@Sun.COM  * Use is subject to license terms.
23*8485SPeter.Memishian@Sun.COM  */
24*8485SPeter.Memishian@Sun.COM 
25*8485SPeter.Memishian@Sun.COM #include <alloca.h>
26*8485SPeter.Memishian@Sun.COM #include <arpa/inet.h>
27*8485SPeter.Memishian@Sun.COM #include <assert.h>
28*8485SPeter.Memishian@Sun.COM #include <errno.h>
29*8485SPeter.Memishian@Sun.COM #include <ipmp_admin.h>
30*8485SPeter.Memishian@Sun.COM #include <ipmp_query.h>
31*8485SPeter.Memishian@Sun.COM #include <libintl.h>
32*8485SPeter.Memishian@Sun.COM #include <libnvpair.h>
33*8485SPeter.Memishian@Sun.COM #include <libsysevent.h>
34*8485SPeter.Memishian@Sun.COM #include <locale.h>
35*8485SPeter.Memishian@Sun.COM #include <netdb.h>
36*8485SPeter.Memishian@Sun.COM #include <signal.h>
37*8485SPeter.Memishian@Sun.COM #include <stdarg.h>
38*8485SPeter.Memishian@Sun.COM #include <stdio.h>
39*8485SPeter.Memishian@Sun.COM #include <stdlib.h>
40*8485SPeter.Memishian@Sun.COM #include <string.h>
41*8485SPeter.Memishian@Sun.COM #include <unistd.h>
42*8485SPeter.Memishian@Sun.COM #include <sys/sysevent/eventdefs.h>
43*8485SPeter.Memishian@Sun.COM #include <sys/sysevent/ipmp.h>
44*8485SPeter.Memishian@Sun.COM #include <sys/sysmacros.h>
45*8485SPeter.Memishian@Sun.COM #include <sys/termios.h>
46*8485SPeter.Memishian@Sun.COM #include <sys/types.h>
47*8485SPeter.Memishian@Sun.COM 
48*8485SPeter.Memishian@Sun.COM /*
49*8485SPeter.Memishian@Sun.COM  * ipmpstat -- display IPMP subsystem status.
50*8485SPeter.Memishian@Sun.COM  *
51*8485SPeter.Memishian@Sun.COM  * This utility makes extensive use of libipmp and IPMP sysevents to gather
52*8485SPeter.Memishian@Sun.COM  * and pretty-print the status of the IPMP subsystem.  All output formats
53*8485SPeter.Memishian@Sun.COM  * except for -p (probe) use libipmp to create a point-in-time snapshot of the
54*8485SPeter.Memishian@Sun.COM  * IPMP subsystem (unless the test-special -L flag is used), and then output
55*8485SPeter.Memishian@Sun.COM  * the contents of that snapshot in a user-specified manner.  Because the
56*8485SPeter.Memishian@Sun.COM  * output format and requested fields aren't known until run-time, three sets
57*8485SPeter.Memishian@Sun.COM  * of function pointers and two core data structures are used. Specifically:
58*8485SPeter.Memishian@Sun.COM  *
59*8485SPeter.Memishian@Sun.COM  *      * The ipmpstat_walker_t function pointers (walk_*) iterate through
60*8485SPeter.Memishian@Sun.COM  *	  all instances of a given IPMP object (group, interface, or address).
61*8485SPeter.Memishian@Sun.COM  *	  At most one ipmpstat_walker_t is used per ipmpstat invocation.
62*8485SPeter.Memishian@Sun.COM  *	  Since target information is included with the interface information,
63*8485SPeter.Memishian@Sun.COM  *	  both -i and -t use the interface walker (walk_if()).
64*8485SPeter.Memishian@Sun.COM  *
65*8485SPeter.Memishian@Sun.COM  *      * The ipmpstat_sfunc_t function pointers (sfunc_*) obtain a given
66*8485SPeter.Memishian@Sun.COM  *	  value for a given IPMP object.  Each ipmpstat_sunc_t is passed a
67*8485SPeter.Memishian@Sun.COM  *	  buffer to write its result into, the buffer's size, and an
68*8485SPeter.Memishian@Sun.COM  *	  ipmpstat_sfunc_arg_t state structure.  The state structure consists
69*8485SPeter.Memishian@Sun.COM  *	  of a pointer to the IPMP object to obtain information from
70*8485SPeter.Memishian@Sun.COM  *	  (sa_data), and an open libipmp handle (sa_ih) which can be used to
71*8485SPeter.Memishian@Sun.COM  *	  do additional libipmp queries, if necessary (e.g., because the
72*8485SPeter.Memishian@Sun.COM  *	  object does not have all of the needed information).
73*8485SPeter.Memishian@Sun.COM  *
74*8485SPeter.Memishian@Sun.COM  *	* The ipmpstat_field_t structure provides the list of supported fields
75*8485SPeter.Memishian@Sun.COM  *	  for a given output format, along with output formatting information
76*8485SPeter.Memishian@Sun.COM  *	  (e.g., field width), and a pointer to an ipmpstat_sfunc_t function
77*8485SPeter.Memishian@Sun.COM  *	  that can obtain the value for a IPMP given object.  For a given
78*8485SPeter.Memishian@Sun.COM  *	  ipmpstat output format, there's a corresponding array of
79*8485SPeter.Memishian@Sun.COM  *	  ipmpstat_field_t structures.  Thus, one ipmpstat_field_t array is
80*8485SPeter.Memishian@Sun.COM  *	  used per ipmpstat invocation.
81*8485SPeter.Memishian@Sun.COM  *
82*8485SPeter.Memishian@Sun.COM  *	* The ipmpstat_ofmt_t provides an ordered list of the requested
83*8485SPeter.Memishian@Sun.COM  *	  ipmpstat_field_t's (e.g., via -o) for a given ipmpstat invocation.
84*8485SPeter.Memishian@Sun.COM  *	  It is built at runtime from the command-line arguments.  This
85*8485SPeter.Memishian@Sun.COM  *	  structure (and a given IPMP object) is used by ofmt_output() to
86*8485SPeter.Memishian@Sun.COM  *	  output a single line of information about that IPMP object.
87*8485SPeter.Memishian@Sun.COM  *
88*8485SPeter.Memishian@Sun.COM  *	* The ipmpstat_cbfunc_t function pointers (*_cbfunc) are called back
89*8485SPeter.Memishian@Sun.COM  *	  by the walkers.  They are used both internally to implement nested
90*8485SPeter.Memishian@Sun.COM  *	  walks, and by the ipmpstat output logic to provide the glue between
91*8485SPeter.Memishian@Sun.COM  *	  the IPMP object walkers and the ofmt_output() logic.  Usually, a
92*8485SPeter.Memishian@Sun.COM  *	  single line is output for each IPMP object, and thus ofmt_output()
93*8485SPeter.Memishian@Sun.COM  *	  can be directly invoked (see info_output_cbfunc()).  However, if
94*8485SPeter.Memishian@Sun.COM  *	  multiple lines need to be output, then a more complex cbfunc is
95*8485SPeter.Memishian@Sun.COM  *	  needed (see targinfo_output_cbfunc()).  At most one cbfunc is used
96*8485SPeter.Memishian@Sun.COM  *	  per ipmpstat invocation.
97*8485SPeter.Memishian@Sun.COM  */
98*8485SPeter.Memishian@Sun.COM 
99*8485SPeter.Memishian@Sun.COM /*
100*8485SPeter.Memishian@Sun.COM  * Data type used by the sfunc callbacks to obtain the requested information
101*8485SPeter.Memishian@Sun.COM  * from the agreed-upon object.
102*8485SPeter.Memishian@Sun.COM  */
103*8485SPeter.Memishian@Sun.COM typedef struct ipmpstat_sfunc_arg {
104*8485SPeter.Memishian@Sun.COM 	ipmp_handle_t		sa_ih;
105*8485SPeter.Memishian@Sun.COM 	void			*sa_data;
106*8485SPeter.Memishian@Sun.COM } ipmpstat_sfunc_arg_t;
107*8485SPeter.Memishian@Sun.COM 
108*8485SPeter.Memishian@Sun.COM typedef void ipmpstat_sfunc_t(ipmpstat_sfunc_arg_t *, char *, uint_t);
109*8485SPeter.Memishian@Sun.COM 
110*8485SPeter.Memishian@Sun.COM /*
111*8485SPeter.Memishian@Sun.COM  * Data type that describes how to output a field; used by ofmt_output*().
112*8485SPeter.Memishian@Sun.COM  */
113*8485SPeter.Memishian@Sun.COM typedef struct ipmpstat_field {
114*8485SPeter.Memishian@Sun.COM 	const char		*f_name;	/* field name */
115*8485SPeter.Memishian@Sun.COM 	uint_t			f_width;	/* output width */
116*8485SPeter.Memishian@Sun.COM 	ipmpstat_sfunc_t	*f_sfunc;	/* value->string function */
117*8485SPeter.Memishian@Sun.COM } ipmpstat_field_t;
118*8485SPeter.Memishian@Sun.COM 
119*8485SPeter.Memishian@Sun.COM /*
120*8485SPeter.Memishian@Sun.COM  * Data type that specifies the output field order; used by ofmt_output*()
121*8485SPeter.Memishian@Sun.COM  */
122*8485SPeter.Memishian@Sun.COM typedef struct ipmpstat_ofmt {
123*8485SPeter.Memishian@Sun.COM 	const ipmpstat_field_t	*o_field;	/* current field info */
124*8485SPeter.Memishian@Sun.COM 	struct ipmpstat_ofmt	*o_next;	/* next field */
125*8485SPeter.Memishian@Sun.COM } ipmpstat_ofmt_t;
126*8485SPeter.Memishian@Sun.COM 
127*8485SPeter.Memishian@Sun.COM /*
128*8485SPeter.Memishian@Sun.COM  * Function pointers used to iterate through IPMP objects.
129*8485SPeter.Memishian@Sun.COM  */
130*8485SPeter.Memishian@Sun.COM typedef void ipmpstat_cbfunc_t(ipmp_handle_t, void *, void *);
131*8485SPeter.Memishian@Sun.COM typedef void ipmpstat_walker_t(ipmp_handle_t, ipmpstat_cbfunc_t *, void *);
132*8485SPeter.Memishian@Sun.COM 
133*8485SPeter.Memishian@Sun.COM /*
134*8485SPeter.Memishian@Sun.COM  * Data type used to implement nested walks.
135*8485SPeter.Memishian@Sun.COM  */
136*8485SPeter.Memishian@Sun.COM typedef struct ipmpstat_walkdata {
137*8485SPeter.Memishian@Sun.COM 	ipmpstat_cbfunc_t	*iw_func; 	/* caller-specified callback */
138*8485SPeter.Memishian@Sun.COM 	void			*iw_funcarg; 	/* caller-specified arg */
139*8485SPeter.Memishian@Sun.COM } ipmpstat_walkdata_t;
140*8485SPeter.Memishian@Sun.COM 
141*8485SPeter.Memishian@Sun.COM /*
142*8485SPeter.Memishian@Sun.COM  * Data type used by enum2str() to map an enumerated value to a string.
143*8485SPeter.Memishian@Sun.COM  */
144*8485SPeter.Memishian@Sun.COM typedef struct ipmpstat_enum {
145*8485SPeter.Memishian@Sun.COM 	const char		*e_name;	/* string */
146*8485SPeter.Memishian@Sun.COM 	int			e_val;		/* value */
147*8485SPeter.Memishian@Sun.COM } ipmpstat_enum_t;
148*8485SPeter.Memishian@Sun.COM 
149*8485SPeter.Memishian@Sun.COM /*
150*8485SPeter.Memishian@Sun.COM  * Data type used to pass state between probe_output() and probe_event().
151*8485SPeter.Memishian@Sun.COM  */
152*8485SPeter.Memishian@Sun.COM typedef struct ipmpstat_probe_state {
153*8485SPeter.Memishian@Sun.COM 	ipmp_handle_t	ps_ih;			/* open IPMP handle */
154*8485SPeter.Memishian@Sun.COM 	ipmpstat_ofmt_t	*ps_ofmt; 		/* requested ofmt string */
155*8485SPeter.Memishian@Sun.COM } ipmpstat_probe_state_t;
156*8485SPeter.Memishian@Sun.COM 
157*8485SPeter.Memishian@Sun.COM /*
158*8485SPeter.Memishian@Sun.COM  * Options that modify the output mode; more than one may be lit.
159*8485SPeter.Memishian@Sun.COM  */
160*8485SPeter.Memishian@Sun.COM typedef enum {
161*8485SPeter.Memishian@Sun.COM 	IPMPSTAT_OPT_NUMERIC	= 0x1,
162*8485SPeter.Memishian@Sun.COM 	IPMPSTAT_OPT_PARSABLE 	= 0x2
163*8485SPeter.Memishian@Sun.COM } ipmpstat_opt_t;
164*8485SPeter.Memishian@Sun.COM 
165*8485SPeter.Memishian@Sun.COM /*
166*8485SPeter.Memishian@Sun.COM  * Indices for the FLAGS field of the `-i' output format.
167*8485SPeter.Memishian@Sun.COM  */
168*8485SPeter.Memishian@Sun.COM enum {
169*8485SPeter.Memishian@Sun.COM 	IPMPSTAT_IFLAG_INDEX,	IPMPSTAT_SFLAG_INDEX,	IPMPSTAT_M4FLAG_INDEX,
170*8485SPeter.Memishian@Sun.COM 	IPMPSTAT_BFLAG_INDEX,	IPMPSTAT_M6FLAG_INDEX,	IPMPSTAT_DFLAG_INDEX,
171*8485SPeter.Memishian@Sun.COM 	IPMPSTAT_HFLAG_INDEX,	IPMPSTAT_NUM_FLAGS
172*8485SPeter.Memishian@Sun.COM };
173*8485SPeter.Memishian@Sun.COM 
174*8485SPeter.Memishian@Sun.COM #define	IPMPSTAT_NCOL	80
175*8485SPeter.Memishian@Sun.COM #define	NS2FLOATMS(ns)	((float)(ns) / (NANOSEC / MILLISEC))
176*8485SPeter.Memishian@Sun.COM #define	MS2FLOATSEC(ms)	((float)(ms) / 1000)
177*8485SPeter.Memishian@Sun.COM 
178*8485SPeter.Memishian@Sun.COM static const char	*progname;
179*8485SPeter.Memishian@Sun.COM static hrtime_t		probe_output_start;
180*8485SPeter.Memishian@Sun.COM static struct winsize	winsize;
181*8485SPeter.Memishian@Sun.COM static ipmpstat_opt_t	opt;
182*8485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	addr_state[], group_state[], if_state[], if_link[];
183*8485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	if_probe[], targ_mode[];
184*8485SPeter.Memishian@Sun.COM static ipmpstat_field_t addr_fields[], group_fields[], if_fields[];
185*8485SPeter.Memishian@Sun.COM static ipmpstat_field_t probe_fields[], targ_fields[];
186*8485SPeter.Memishian@Sun.COM static ipmpstat_cbfunc_t walk_addr_cbfunc, walk_if_cbfunc;
187*8485SPeter.Memishian@Sun.COM static ipmpstat_cbfunc_t info_output_cbfunc, targinfo_output_cbfunc;
188*8485SPeter.Memishian@Sun.COM static ipmpstat_walker_t walk_addr, walk_if, walk_group;
189*8485SPeter.Memishian@Sun.COM 
190*8485SPeter.Memishian@Sun.COM static int probe_event(sysevent_t *, void *);
191*8485SPeter.Memishian@Sun.COM static void probe_output(ipmp_handle_t, ipmpstat_ofmt_t *);
192*8485SPeter.Memishian@Sun.COM static ipmpstat_field_t *field_find(ipmpstat_field_t *, const char *);
193*8485SPeter.Memishian@Sun.COM static ipmpstat_ofmt_t *ofmt_create(const char *, ipmpstat_field_t []);
194*8485SPeter.Memishian@Sun.COM static void ofmt_output(const ipmpstat_ofmt_t *, ipmp_handle_t, void *);
195*8485SPeter.Memishian@Sun.COM static void ofmt_destroy(ipmpstat_ofmt_t *);
196*8485SPeter.Memishian@Sun.COM static void enum2str(const ipmpstat_enum_t *, int, char *, uint_t);
197*8485SPeter.Memishian@Sun.COM static void sockaddr2str(const struct sockaddr_storage *, char *, uint_t);
198*8485SPeter.Memishian@Sun.COM static void sighandler(int);
199*8485SPeter.Memishian@Sun.COM static void usage(void);
200*8485SPeter.Memishian@Sun.COM static void die(const char *, ...);
201*8485SPeter.Memishian@Sun.COM static void die_ipmperr(int, const char *, ...);
202*8485SPeter.Memishian@Sun.COM static void warn(const char *, ...);
203*8485SPeter.Memishian@Sun.COM static void warn_ipmperr(int, const char *, ...);
204*8485SPeter.Memishian@Sun.COM 
205*8485SPeter.Memishian@Sun.COM int
206*8485SPeter.Memishian@Sun.COM main(int argc, char **argv)
207*8485SPeter.Memishian@Sun.COM {
208*8485SPeter.Memishian@Sun.COM 	int c;
209*8485SPeter.Memishian@Sun.COM 	int err;
210*8485SPeter.Memishian@Sun.COM 	const char *ofields = NULL;
211*8485SPeter.Memishian@Sun.COM 	ipmp_handle_t ih;
212*8485SPeter.Memishian@Sun.COM 	ipmp_qcontext_t qcontext = IPMP_QCONTEXT_SNAP;
213*8485SPeter.Memishian@Sun.COM 	ipmpstat_ofmt_t *ofmt;
214*8485SPeter.Memishian@Sun.COM 	ipmpstat_field_t *fields = NULL;
215*8485SPeter.Memishian@Sun.COM 	ipmpstat_cbfunc_t *cbfunc;
216*8485SPeter.Memishian@Sun.COM 	ipmpstat_walker_t *walker;
217*8485SPeter.Memishian@Sun.COM 
218*8485SPeter.Memishian@Sun.COM 	if ((progname = strrchr(argv[0], '/')) == NULL)
219*8485SPeter.Memishian@Sun.COM 		progname = argv[0];
220*8485SPeter.Memishian@Sun.COM 	else
221*8485SPeter.Memishian@Sun.COM 		progname++;
222*8485SPeter.Memishian@Sun.COM 
223*8485SPeter.Memishian@Sun.COM 	(void) setlocale(LC_ALL, "");
224*8485SPeter.Memishian@Sun.COM 	(void) textdomain(TEXT_DOMAIN);
225*8485SPeter.Memishian@Sun.COM 
226*8485SPeter.Memishian@Sun.COM 	while ((c = getopt(argc, argv, "nLPo:agipt")) != EOF) {
227*8485SPeter.Memishian@Sun.COM 		if (fields != NULL && strchr("agipt", c) != NULL)
228*8485SPeter.Memishian@Sun.COM 			die("only one output format may be specified\n");
229*8485SPeter.Memishian@Sun.COM 
230*8485SPeter.Memishian@Sun.COM 		switch (c) {
231*8485SPeter.Memishian@Sun.COM 		case 'n':
232*8485SPeter.Memishian@Sun.COM 			opt |= IPMPSTAT_OPT_NUMERIC;
233*8485SPeter.Memishian@Sun.COM 			break;
234*8485SPeter.Memishian@Sun.COM 		case 'L':
235*8485SPeter.Memishian@Sun.COM 			/* Undocumented option: for testing use ONLY */
236*8485SPeter.Memishian@Sun.COM 			qcontext = IPMP_QCONTEXT_LIVE;
237*8485SPeter.Memishian@Sun.COM 			break;
238*8485SPeter.Memishian@Sun.COM 		case 'P':
239*8485SPeter.Memishian@Sun.COM 			opt |= IPMPSTAT_OPT_PARSABLE;
240*8485SPeter.Memishian@Sun.COM 			break;
241*8485SPeter.Memishian@Sun.COM 		case 'o':
242*8485SPeter.Memishian@Sun.COM 			ofields = optarg;
243*8485SPeter.Memishian@Sun.COM 			break;
244*8485SPeter.Memishian@Sun.COM 		case 'a':
245*8485SPeter.Memishian@Sun.COM 			walker = walk_addr;
246*8485SPeter.Memishian@Sun.COM 			cbfunc = info_output_cbfunc;
247*8485SPeter.Memishian@Sun.COM 			fields = addr_fields;
248*8485SPeter.Memishian@Sun.COM 			break;
249*8485SPeter.Memishian@Sun.COM 		case 'g':
250*8485SPeter.Memishian@Sun.COM 			walker = walk_group;
251*8485SPeter.Memishian@Sun.COM 			cbfunc = info_output_cbfunc;
252*8485SPeter.Memishian@Sun.COM 			fields = group_fields;
253*8485SPeter.Memishian@Sun.COM 			break;
254*8485SPeter.Memishian@Sun.COM 		case 'i':
255*8485SPeter.Memishian@Sun.COM 			walker = walk_if;
256*8485SPeter.Memishian@Sun.COM 			cbfunc = info_output_cbfunc;
257*8485SPeter.Memishian@Sun.COM 			fields = if_fields;
258*8485SPeter.Memishian@Sun.COM 			break;
259*8485SPeter.Memishian@Sun.COM 		case 'p':
260*8485SPeter.Memishian@Sun.COM 			fields = probe_fields;
261*8485SPeter.Memishian@Sun.COM 			break;
262*8485SPeter.Memishian@Sun.COM 		case 't':
263*8485SPeter.Memishian@Sun.COM 			walker = walk_if;
264*8485SPeter.Memishian@Sun.COM 			cbfunc = targinfo_output_cbfunc;
265*8485SPeter.Memishian@Sun.COM 			fields = targ_fields;
266*8485SPeter.Memishian@Sun.COM 			break;
267*8485SPeter.Memishian@Sun.COM 		default:
268*8485SPeter.Memishian@Sun.COM 			usage();
269*8485SPeter.Memishian@Sun.COM 			break;
270*8485SPeter.Memishian@Sun.COM 		}
271*8485SPeter.Memishian@Sun.COM 	}
272*8485SPeter.Memishian@Sun.COM 
273*8485SPeter.Memishian@Sun.COM 	if (argc > optind || fields == NULL)
274*8485SPeter.Memishian@Sun.COM 		usage();
275*8485SPeter.Memishian@Sun.COM 
276*8485SPeter.Memishian@Sun.COM 	if (opt & IPMPSTAT_OPT_PARSABLE) {
277*8485SPeter.Memishian@Sun.COM 		if (ofields == NULL) {
278*8485SPeter.Memishian@Sun.COM 			die("output field list (-o) required in parsable "
279*8485SPeter.Memishian@Sun.COM 			    "output mode\n");
280*8485SPeter.Memishian@Sun.COM 		} else if (strcasecmp(ofields, "all") == 0) {
281*8485SPeter.Memishian@Sun.COM 			die("\"all\" not allowed in parsable output mode\n");
282*8485SPeter.Memishian@Sun.COM 		}
283*8485SPeter.Memishian@Sun.COM 	}
284*8485SPeter.Memishian@Sun.COM 
285*8485SPeter.Memishian@Sun.COM 	/*
286*8485SPeter.Memishian@Sun.COM 	 * Obtain the window size and monitor changes to the size.  This data
287*8485SPeter.Memishian@Sun.COM 	 * is used to redisplay the output headers when necessary.
288*8485SPeter.Memishian@Sun.COM 	 */
289*8485SPeter.Memishian@Sun.COM 	(void) sigset(SIGWINCH, sighandler);
290*8485SPeter.Memishian@Sun.COM 	sighandler(SIGWINCH);
291*8485SPeter.Memishian@Sun.COM 
292*8485SPeter.Memishian@Sun.COM 	if ((err = ipmp_open(&ih)) != IPMP_SUCCESS)
293*8485SPeter.Memishian@Sun.COM 		die_ipmperr(err, "cannot create IPMP handle");
294*8485SPeter.Memishian@Sun.COM 
295*8485SPeter.Memishian@Sun.COM 	if (ipmp_ping_daemon(ih) != IPMP_SUCCESS)
296*8485SPeter.Memishian@Sun.COM 		die("cannot contact in.mpathd(1M) -- is IPMP in use?\n");
297*8485SPeter.Memishian@Sun.COM 
298*8485SPeter.Memishian@Sun.COM 	/*
299*8485SPeter.Memishian@Sun.COM 	 * Create the ofmt linked list that will eventually be passed to
300*8485SPeter.Memishian@Sun.COM 	 * to ofmt_output() to output the fields.
301*8485SPeter.Memishian@Sun.COM 	 */
302*8485SPeter.Memishian@Sun.COM 	ofmt = ofmt_create(ofields, fields);
303*8485SPeter.Memishian@Sun.COM 
304*8485SPeter.Memishian@Sun.COM 	/*
305*8485SPeter.Memishian@Sun.COM 	 * If we've been asked to display probes, then call the probe output
306*8485SPeter.Memishian@Sun.COM 	 * function.  Otherwise, snapshot IPMP state (or use live state) and
307*8485SPeter.Memishian@Sun.COM 	 * invoke the specified walker with the specified callback function.
308*8485SPeter.Memishian@Sun.COM 	 */
309*8485SPeter.Memishian@Sun.COM 	if (fields == probe_fields) {
310*8485SPeter.Memishian@Sun.COM 		probe_output(ih, ofmt);
311*8485SPeter.Memishian@Sun.COM 	} else {
312*8485SPeter.Memishian@Sun.COM 		if ((err = ipmp_setqcontext(ih, qcontext)) != IPMP_SUCCESS) {
313*8485SPeter.Memishian@Sun.COM 			if (qcontext == IPMP_QCONTEXT_SNAP)
314*8485SPeter.Memishian@Sun.COM 				die_ipmperr(err, "cannot snapshot IPMP state");
315*8485SPeter.Memishian@Sun.COM 			else
316*8485SPeter.Memishian@Sun.COM 				die_ipmperr(err, "cannot use live IPMP state");
317*8485SPeter.Memishian@Sun.COM 		}
318*8485SPeter.Memishian@Sun.COM 		(*walker)(ih, cbfunc, ofmt);
319*8485SPeter.Memishian@Sun.COM 	}
320*8485SPeter.Memishian@Sun.COM 
321*8485SPeter.Memishian@Sun.COM 	ofmt_destroy(ofmt);
322*8485SPeter.Memishian@Sun.COM 	ipmp_close(ih);
323*8485SPeter.Memishian@Sun.COM 
324*8485SPeter.Memishian@Sun.COM 	return (EXIT_SUCCESS);
325*8485SPeter.Memishian@Sun.COM }
326*8485SPeter.Memishian@Sun.COM 
327*8485SPeter.Memishian@Sun.COM /*
328*8485SPeter.Memishian@Sun.COM  * Walks all IPMP groups on the system and invokes `cbfunc' on each, passing
329*8485SPeter.Memishian@Sun.COM  * it `ih', the ipmp_groupinfo_t pointer, and `arg'.
330*8485SPeter.Memishian@Sun.COM  */
331*8485SPeter.Memishian@Sun.COM static void
332*8485SPeter.Memishian@Sun.COM walk_group(ipmp_handle_t ih, ipmpstat_cbfunc_t *cbfunc, void *arg)
333*8485SPeter.Memishian@Sun.COM {
334*8485SPeter.Memishian@Sun.COM 	int err;
335*8485SPeter.Memishian@Sun.COM 	uint_t i;
336*8485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop;
337*8485SPeter.Memishian@Sun.COM 	ipmp_grouplist_t *grlistp;
338*8485SPeter.Memishian@Sun.COM 
339*8485SPeter.Memishian@Sun.COM 	if ((err = ipmp_getgrouplist(ih, &grlistp)) != IPMP_SUCCESS)
340*8485SPeter.Memishian@Sun.COM 		die_ipmperr(err, "cannot get IPMP group list");
341*8485SPeter.Memishian@Sun.COM 
342*8485SPeter.Memishian@Sun.COM 	for (i = 0; i < grlistp->gl_ngroup; i++) {
343*8485SPeter.Memishian@Sun.COM 		err = ipmp_getgroupinfo(ih, grlistp->gl_groups[i], &grinfop);
344*8485SPeter.Memishian@Sun.COM 		if (err != IPMP_SUCCESS) {
345*8485SPeter.Memishian@Sun.COM 			warn_ipmperr(err, "cannot get info for group `%s'",
346*8485SPeter.Memishian@Sun.COM 			    grlistp->gl_groups[i]);
347*8485SPeter.Memishian@Sun.COM 			continue;
348*8485SPeter.Memishian@Sun.COM 		}
349*8485SPeter.Memishian@Sun.COM 		(*cbfunc)(ih, grinfop, arg);
350*8485SPeter.Memishian@Sun.COM 		ipmp_freegroupinfo(grinfop);
351*8485SPeter.Memishian@Sun.COM 	}
352*8485SPeter.Memishian@Sun.COM 
353*8485SPeter.Memishian@Sun.COM 	ipmp_freegrouplist(grlistp);
354*8485SPeter.Memishian@Sun.COM }
355*8485SPeter.Memishian@Sun.COM 
356*8485SPeter.Memishian@Sun.COM /*
357*8485SPeter.Memishian@Sun.COM  * Walks all IPMP interfaces on the system and invokes `cbfunc' on each,
358*8485SPeter.Memishian@Sun.COM  * passing it `ih', the ipmp_ifinfo_t pointer, and `arg'.
359*8485SPeter.Memishian@Sun.COM  */
360*8485SPeter.Memishian@Sun.COM static void
361*8485SPeter.Memishian@Sun.COM walk_if(ipmp_handle_t ih, ipmpstat_cbfunc_t *cbfunc, void *arg)
362*8485SPeter.Memishian@Sun.COM {
363*8485SPeter.Memishian@Sun.COM 	ipmpstat_walkdata_t iw = { cbfunc, arg };
364*8485SPeter.Memishian@Sun.COM 
365*8485SPeter.Memishian@Sun.COM 	walk_group(ih, walk_if_cbfunc, &iw);
366*8485SPeter.Memishian@Sun.COM }
367*8485SPeter.Memishian@Sun.COM 
368*8485SPeter.Memishian@Sun.COM /*
369*8485SPeter.Memishian@Sun.COM  * Walks all IPMP data addresses on the system and invokes `cbfunc' on each.
370*8485SPeter.Memishian@Sun.COM  * passing it `ih', the ipmp_addrinfo_t pointer, and `arg'.
371*8485SPeter.Memishian@Sun.COM  */
372*8485SPeter.Memishian@Sun.COM static void
373*8485SPeter.Memishian@Sun.COM walk_addr(ipmp_handle_t ih, ipmpstat_cbfunc_t *cbfunc, void *arg)
374*8485SPeter.Memishian@Sun.COM {
375*8485SPeter.Memishian@Sun.COM 	ipmpstat_walkdata_t iw = { cbfunc, arg };
376*8485SPeter.Memishian@Sun.COM 
377*8485SPeter.Memishian@Sun.COM 	walk_group(ih, walk_addr_cbfunc, &iw);
378*8485SPeter.Memishian@Sun.COM }
379*8485SPeter.Memishian@Sun.COM 
380*8485SPeter.Memishian@Sun.COM /*
381*8485SPeter.Memishian@Sun.COM  * Nested walker callback function for walk_if().
382*8485SPeter.Memishian@Sun.COM  */
383*8485SPeter.Memishian@Sun.COM static void
384*8485SPeter.Memishian@Sun.COM walk_if_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
385*8485SPeter.Memishian@Sun.COM {
386*8485SPeter.Memishian@Sun.COM 	int err;
387*8485SPeter.Memishian@Sun.COM 	uint_t i;
388*8485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop = infop;
389*8485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop;
390*8485SPeter.Memishian@Sun.COM 	ipmp_iflist_t *iflistp = grinfop->gr_iflistp;
391*8485SPeter.Memishian@Sun.COM 	ipmpstat_walkdata_t *iwp = arg;
392*8485SPeter.Memishian@Sun.COM 
393*8485SPeter.Memishian@Sun.COM 	for (i = 0; i < iflistp->il_nif; i++) {
394*8485SPeter.Memishian@Sun.COM 		err = ipmp_getifinfo(ih, iflistp->il_ifs[i], &ifinfop);
395*8485SPeter.Memishian@Sun.COM 		if (err != IPMP_SUCCESS) {
396*8485SPeter.Memishian@Sun.COM 			warn_ipmperr(err, "cannot get info for interface `%s'",
397*8485SPeter.Memishian@Sun.COM 			    iflistp->il_ifs[i]);
398*8485SPeter.Memishian@Sun.COM 			continue;
399*8485SPeter.Memishian@Sun.COM 		}
400*8485SPeter.Memishian@Sun.COM 		(*iwp->iw_func)(ih, ifinfop, iwp->iw_funcarg);
401*8485SPeter.Memishian@Sun.COM 		ipmp_freeifinfo(ifinfop);
402*8485SPeter.Memishian@Sun.COM 	}
403*8485SPeter.Memishian@Sun.COM }
404*8485SPeter.Memishian@Sun.COM 
405*8485SPeter.Memishian@Sun.COM /*
406*8485SPeter.Memishian@Sun.COM  * Nested walker callback function for walk_addr().
407*8485SPeter.Memishian@Sun.COM  */
408*8485SPeter.Memishian@Sun.COM static void
409*8485SPeter.Memishian@Sun.COM walk_addr_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
410*8485SPeter.Memishian@Sun.COM {
411*8485SPeter.Memishian@Sun.COM 	int err;
412*8485SPeter.Memishian@Sun.COM 	uint_t i;
413*8485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop = infop;
414*8485SPeter.Memishian@Sun.COM 	ipmp_addrinfo_t *adinfop;
415*8485SPeter.Memishian@Sun.COM 	ipmp_addrlist_t *adlistp = grinfop->gr_adlistp;
416*8485SPeter.Memishian@Sun.COM 	ipmpstat_walkdata_t *iwp = arg;
417*8485SPeter.Memishian@Sun.COM 	char addr[INET6_ADDRSTRLEN];
418*8485SPeter.Memishian@Sun.COM 	struct sockaddr_storage *addrp;
419*8485SPeter.Memishian@Sun.COM 
420*8485SPeter.Memishian@Sun.COM 	for (i = 0; i < adlistp->al_naddr; i++) {
421*8485SPeter.Memishian@Sun.COM 		addrp = &adlistp->al_addrs[i];
422*8485SPeter.Memishian@Sun.COM 		err = ipmp_getaddrinfo(ih, grinfop->gr_name, addrp, &adinfop);
423*8485SPeter.Memishian@Sun.COM 		if (err != IPMP_SUCCESS) {
424*8485SPeter.Memishian@Sun.COM 			sockaddr2str(addrp, addr, sizeof (addr));
425*8485SPeter.Memishian@Sun.COM 			warn_ipmperr(err, "cannot get info for `%s'", addr);
426*8485SPeter.Memishian@Sun.COM 			continue;
427*8485SPeter.Memishian@Sun.COM 		}
428*8485SPeter.Memishian@Sun.COM 		(*iwp->iw_func)(ih, adinfop, iwp->iw_funcarg);
429*8485SPeter.Memishian@Sun.COM 		ipmp_freeaddrinfo(adinfop);
430*8485SPeter.Memishian@Sun.COM 	}
431*8485SPeter.Memishian@Sun.COM }
432*8485SPeter.Memishian@Sun.COM 
433*8485SPeter.Memishian@Sun.COM static void
434*8485SPeter.Memishian@Sun.COM sfunc_nvwarn(const char *nvname, char *buf, uint_t bufsize)
435*8485SPeter.Memishian@Sun.COM {
436*8485SPeter.Memishian@Sun.COM 	warn("cannot retrieve %s\n", nvname);
437*8485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, "?", bufsize);
438*8485SPeter.Memishian@Sun.COM }
439*8485SPeter.Memishian@Sun.COM 
440*8485SPeter.Memishian@Sun.COM static void
441*8485SPeter.Memishian@Sun.COM sfunc_addr_address(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
442*8485SPeter.Memishian@Sun.COM {
443*8485SPeter.Memishian@Sun.COM 	ipmp_addrinfo_t *adinfop = arg->sa_data;
444*8485SPeter.Memishian@Sun.COM 
445*8485SPeter.Memishian@Sun.COM 	sockaddr2str(&adinfop->ad_addr, buf, bufsize);
446*8485SPeter.Memishian@Sun.COM }
447*8485SPeter.Memishian@Sun.COM 
448*8485SPeter.Memishian@Sun.COM static void
449*8485SPeter.Memishian@Sun.COM sfunc_addr_group(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
450*8485SPeter.Memishian@Sun.COM {
451*8485SPeter.Memishian@Sun.COM 	int err;
452*8485SPeter.Memishian@Sun.COM 	ipmp_addrinfo_t *adinfop = arg->sa_data;
453*8485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop;
454*8485SPeter.Memishian@Sun.COM 
455*8485SPeter.Memishian@Sun.COM 	err = ipmp_getgroupinfo(arg->sa_ih, adinfop->ad_group, &grinfop);
456*8485SPeter.Memishian@Sun.COM 	if (err != IPMP_SUCCESS) {
457*8485SPeter.Memishian@Sun.COM 		warn_ipmperr(err, "cannot get info for group `%s'",
458*8485SPeter.Memishian@Sun.COM 		    adinfop->ad_group);
459*8485SPeter.Memishian@Sun.COM 		(void) strlcpy(buf, "?", bufsize);
460*8485SPeter.Memishian@Sun.COM 		return;
461*8485SPeter.Memishian@Sun.COM 	}
462*8485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, grinfop->gr_ifname, bufsize);
463*8485SPeter.Memishian@Sun.COM 	ipmp_freegroupinfo(grinfop);
464*8485SPeter.Memishian@Sun.COM }
465*8485SPeter.Memishian@Sun.COM 
466*8485SPeter.Memishian@Sun.COM static void
467*8485SPeter.Memishian@Sun.COM sfunc_addr_state(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
468*8485SPeter.Memishian@Sun.COM {
469*8485SPeter.Memishian@Sun.COM 	ipmp_addrinfo_t *adinfop = arg->sa_data;
470*8485SPeter.Memishian@Sun.COM 
471*8485SPeter.Memishian@Sun.COM 	enum2str(addr_state, adinfop->ad_state, buf, bufsize);
472*8485SPeter.Memishian@Sun.COM }
473*8485SPeter.Memishian@Sun.COM 
474*8485SPeter.Memishian@Sun.COM static void
475*8485SPeter.Memishian@Sun.COM sfunc_addr_inbound(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
476*8485SPeter.Memishian@Sun.COM {
477*8485SPeter.Memishian@Sun.COM 	ipmp_addrinfo_t *adinfop = arg->sa_data;
478*8485SPeter.Memishian@Sun.COM 
479*8485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, adinfop->ad_binding, bufsize);
480*8485SPeter.Memishian@Sun.COM }
481*8485SPeter.Memishian@Sun.COM 
482*8485SPeter.Memishian@Sun.COM static void
483*8485SPeter.Memishian@Sun.COM sfunc_addr_outbound(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
484*8485SPeter.Memishian@Sun.COM {
485*8485SPeter.Memishian@Sun.COM 	int err;
486*8485SPeter.Memishian@Sun.COM 	uint_t i, nactive = 0;
487*8485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop;
488*8485SPeter.Memishian@Sun.COM 	ipmp_iflist_t *iflistp;
489*8485SPeter.Memishian@Sun.COM 	ipmp_addrinfo_t *adinfop = arg->sa_data;
490*8485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop;
491*8485SPeter.Memishian@Sun.COM 
492*8485SPeter.Memishian@Sun.COM 	if (adinfop->ad_state == IPMP_ADDR_DOWN)
493*8485SPeter.Memishian@Sun.COM 		return;
494*8485SPeter.Memishian@Sun.COM 
495*8485SPeter.Memishian@Sun.COM 	/*
496*8485SPeter.Memishian@Sun.COM 	 * If there's no inbound interface for this address, there can't
497*8485SPeter.Memishian@Sun.COM 	 * be any outbound traffic.
498*8485SPeter.Memishian@Sun.COM 	 */
499*8485SPeter.Memishian@Sun.COM 	if (adinfop->ad_binding[0] == '\0')
500*8485SPeter.Memishian@Sun.COM 		return;
501*8485SPeter.Memishian@Sun.COM 
502*8485SPeter.Memishian@Sun.COM 	/*
503*8485SPeter.Memishian@Sun.COM 	 * The address can use any active interface in the group, so
504*8485SPeter.Memishian@Sun.COM 	 * obtain all of those.
505*8485SPeter.Memishian@Sun.COM 	 */
506*8485SPeter.Memishian@Sun.COM 	err = ipmp_getgroupinfo(arg->sa_ih, adinfop->ad_group, &grinfop);
507*8485SPeter.Memishian@Sun.COM 	if (err != IPMP_SUCCESS) {
508*8485SPeter.Memishian@Sun.COM 		warn_ipmperr(err, "cannot get info for group `%s'",
509*8485SPeter.Memishian@Sun.COM 		    adinfop->ad_group);
510*8485SPeter.Memishian@Sun.COM 		(void) strlcpy(buf, "?", bufsize);
511*8485SPeter.Memishian@Sun.COM 		return;
512*8485SPeter.Memishian@Sun.COM 	}
513*8485SPeter.Memishian@Sun.COM 
514*8485SPeter.Memishian@Sun.COM 	iflistp = grinfop->gr_iflistp;
515*8485SPeter.Memishian@Sun.COM 	for (i = 0; i < iflistp->il_nif; i++) {
516*8485SPeter.Memishian@Sun.COM 		err = ipmp_getifinfo(arg->sa_ih, iflistp->il_ifs[i], &ifinfop);
517*8485SPeter.Memishian@Sun.COM 		if (err != IPMP_SUCCESS) {
518*8485SPeter.Memishian@Sun.COM 			warn_ipmperr(err, "cannot get info for interface `%s'",
519*8485SPeter.Memishian@Sun.COM 			    iflistp->il_ifs[i]);
520*8485SPeter.Memishian@Sun.COM 			continue;
521*8485SPeter.Memishian@Sun.COM 		}
522*8485SPeter.Memishian@Sun.COM 
523*8485SPeter.Memishian@Sun.COM 		if (ifinfop->if_flags & IPMP_IFFLAG_ACTIVE) {
524*8485SPeter.Memishian@Sun.COM 			if (nactive++ != 0)
525*8485SPeter.Memishian@Sun.COM 				(void) strlcat(buf, " ", bufsize);
526*8485SPeter.Memishian@Sun.COM 			(void) strlcat(buf, ifinfop->if_name, bufsize);
527*8485SPeter.Memishian@Sun.COM 		}
528*8485SPeter.Memishian@Sun.COM 		ipmp_freeifinfo(ifinfop);
529*8485SPeter.Memishian@Sun.COM 	}
530*8485SPeter.Memishian@Sun.COM 	ipmp_freegroupinfo(grinfop);
531*8485SPeter.Memishian@Sun.COM }
532*8485SPeter.Memishian@Sun.COM 
533*8485SPeter.Memishian@Sun.COM static void
534*8485SPeter.Memishian@Sun.COM sfunc_group_name(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
535*8485SPeter.Memishian@Sun.COM {
536*8485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop = arg->sa_data;
537*8485SPeter.Memishian@Sun.COM 
538*8485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, grinfop->gr_name, bufsize);
539*8485SPeter.Memishian@Sun.COM }
540*8485SPeter.Memishian@Sun.COM 
541*8485SPeter.Memishian@Sun.COM static void
542*8485SPeter.Memishian@Sun.COM sfunc_group_ifname(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
543*8485SPeter.Memishian@Sun.COM {
544*8485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop = arg->sa_data;
545*8485SPeter.Memishian@Sun.COM 
546*8485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, grinfop->gr_ifname, bufsize);
547*8485SPeter.Memishian@Sun.COM }
548*8485SPeter.Memishian@Sun.COM 
549*8485SPeter.Memishian@Sun.COM static void
550*8485SPeter.Memishian@Sun.COM sfunc_group_state(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
551*8485SPeter.Memishian@Sun.COM {
552*8485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop = arg->sa_data;
553*8485SPeter.Memishian@Sun.COM 
554*8485SPeter.Memishian@Sun.COM 	enum2str(group_state, grinfop->gr_state, buf, bufsize);
555*8485SPeter.Memishian@Sun.COM }
556*8485SPeter.Memishian@Sun.COM 
557*8485SPeter.Memishian@Sun.COM static void
558*8485SPeter.Memishian@Sun.COM sfunc_group_fdt(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
559*8485SPeter.Memishian@Sun.COM {
560*8485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop = arg->sa_data;
561*8485SPeter.Memishian@Sun.COM 
562*8485SPeter.Memishian@Sun.COM 	if (grinfop->gr_fdt == 0)
563*8485SPeter.Memishian@Sun.COM 		return;
564*8485SPeter.Memishian@Sun.COM 
565*8485SPeter.Memishian@Sun.COM 	(void) snprintf(buf, bufsize, "%.2fs", MS2FLOATSEC(grinfop->gr_fdt));
566*8485SPeter.Memishian@Sun.COM }
567*8485SPeter.Memishian@Sun.COM 
568*8485SPeter.Memishian@Sun.COM static void
569*8485SPeter.Memishian@Sun.COM sfunc_group_interfaces(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
570*8485SPeter.Memishian@Sun.COM {
571*8485SPeter.Memishian@Sun.COM 	int err;
572*8485SPeter.Memishian@Sun.COM 	uint_t i;
573*8485SPeter.Memishian@Sun.COM 	char *active, *inactive, *unusable;
574*8485SPeter.Memishian@Sun.COM 	uint_t nactive = 0, ninactive = 0, nunusable = 0;
575*8485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop = arg->sa_data;
576*8485SPeter.Memishian@Sun.COM 	ipmp_iflist_t *iflistp = grinfop->gr_iflistp;
577*8485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop;
578*8485SPeter.Memishian@Sun.COM 
579*8485SPeter.Memishian@Sun.COM 	active = alloca(bufsize);
580*8485SPeter.Memishian@Sun.COM 	active[0] = '\0';
581*8485SPeter.Memishian@Sun.COM 	inactive = alloca(bufsize);
582*8485SPeter.Memishian@Sun.COM 	inactive[0] = '\0';
583*8485SPeter.Memishian@Sun.COM 	unusable = alloca(bufsize);
584*8485SPeter.Memishian@Sun.COM 	unusable[0] = '\0';
585*8485SPeter.Memishian@Sun.COM 
586*8485SPeter.Memishian@Sun.COM 	for (i = 0; i < iflistp->il_nif; i++) {
587*8485SPeter.Memishian@Sun.COM 		err = ipmp_getifinfo(arg->sa_ih, iflistp->il_ifs[i], &ifinfop);
588*8485SPeter.Memishian@Sun.COM 		if (err != IPMP_SUCCESS) {
589*8485SPeter.Memishian@Sun.COM 			warn_ipmperr(err, "cannot get info for interface `%s'",
590*8485SPeter.Memishian@Sun.COM 			    iflistp->il_ifs[i]);
591*8485SPeter.Memishian@Sun.COM 			continue;
592*8485SPeter.Memishian@Sun.COM 		}
593*8485SPeter.Memishian@Sun.COM 
594*8485SPeter.Memishian@Sun.COM 		if (ifinfop->if_flags & IPMP_IFFLAG_ACTIVE) {
595*8485SPeter.Memishian@Sun.COM 			if (nactive++ != 0)
596*8485SPeter.Memishian@Sun.COM 				(void) strlcat(active, " ", bufsize);
597*8485SPeter.Memishian@Sun.COM 			(void) strlcat(active, ifinfop->if_name, bufsize);
598*8485SPeter.Memishian@Sun.COM 		} else if (ifinfop->if_flags & IPMP_IFFLAG_INACTIVE) {
599*8485SPeter.Memishian@Sun.COM 			if (ninactive++ != 0)
600*8485SPeter.Memishian@Sun.COM 				(void) strlcat(inactive, " ", bufsize);
601*8485SPeter.Memishian@Sun.COM 			(void) strlcat(inactive, ifinfop->if_name, bufsize);
602*8485SPeter.Memishian@Sun.COM 		} else {
603*8485SPeter.Memishian@Sun.COM 			if (nunusable++ != 0)
604*8485SPeter.Memishian@Sun.COM 				(void) strlcat(unusable, " ", bufsize);
605*8485SPeter.Memishian@Sun.COM 			(void) strlcat(unusable, ifinfop->if_name, bufsize);
606*8485SPeter.Memishian@Sun.COM 		}
607*8485SPeter.Memishian@Sun.COM 
608*8485SPeter.Memishian@Sun.COM 		ipmp_freeifinfo(ifinfop);
609*8485SPeter.Memishian@Sun.COM 	}
610*8485SPeter.Memishian@Sun.COM 
611*8485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, active, bufsize);
612*8485SPeter.Memishian@Sun.COM 
613*8485SPeter.Memishian@Sun.COM 	if (ninactive > 0) {
614*8485SPeter.Memishian@Sun.COM 		if (nactive != 0)
615*8485SPeter.Memishian@Sun.COM 			(void) strlcat(buf, " ", bufsize);
616*8485SPeter.Memishian@Sun.COM 
617*8485SPeter.Memishian@Sun.COM 		(void) strlcat(buf, "(", bufsize);
618*8485SPeter.Memishian@Sun.COM 		(void) strlcat(buf, inactive, bufsize);
619*8485SPeter.Memishian@Sun.COM 		(void) strlcat(buf, ")", bufsize);
620*8485SPeter.Memishian@Sun.COM 	}
621*8485SPeter.Memishian@Sun.COM 
622*8485SPeter.Memishian@Sun.COM 	if (nunusable > 0) {
623*8485SPeter.Memishian@Sun.COM 		if (nactive + ninactive != 0)
624*8485SPeter.Memishian@Sun.COM 			(void) strlcat(buf, " ", bufsize);
625*8485SPeter.Memishian@Sun.COM 
626*8485SPeter.Memishian@Sun.COM 		(void) strlcat(buf, "[", bufsize);
627*8485SPeter.Memishian@Sun.COM 		(void) strlcat(buf, unusable, bufsize);
628*8485SPeter.Memishian@Sun.COM 		(void) strlcat(buf, "]", bufsize);
629*8485SPeter.Memishian@Sun.COM 	}
630*8485SPeter.Memishian@Sun.COM }
631*8485SPeter.Memishian@Sun.COM 
632*8485SPeter.Memishian@Sun.COM static void
633*8485SPeter.Memishian@Sun.COM sfunc_if_name(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
634*8485SPeter.Memishian@Sun.COM {
635*8485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
636*8485SPeter.Memishian@Sun.COM 
637*8485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, ifinfop->if_name, bufsize);
638*8485SPeter.Memishian@Sun.COM }
639*8485SPeter.Memishian@Sun.COM 
640*8485SPeter.Memishian@Sun.COM static void
641*8485SPeter.Memishian@Sun.COM sfunc_if_active(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
642*8485SPeter.Memishian@Sun.COM {
643*8485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
644*8485SPeter.Memishian@Sun.COM 
645*8485SPeter.Memishian@Sun.COM 	if (ifinfop->if_flags & IPMP_IFFLAG_ACTIVE)
646*8485SPeter.Memishian@Sun.COM 		(void) strlcpy(buf, "yes", bufsize);
647*8485SPeter.Memishian@Sun.COM 	else
648*8485SPeter.Memishian@Sun.COM 		(void) strlcpy(buf, "no", bufsize);
649*8485SPeter.Memishian@Sun.COM }
650*8485SPeter.Memishian@Sun.COM 
651*8485SPeter.Memishian@Sun.COM static void
652*8485SPeter.Memishian@Sun.COM sfunc_if_group(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
653*8485SPeter.Memishian@Sun.COM {
654*8485SPeter.Memishian@Sun.COM 	int err;
655*8485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
656*8485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop;
657*8485SPeter.Memishian@Sun.COM 
658*8485SPeter.Memishian@Sun.COM 	err = ipmp_getgroupinfo(arg->sa_ih, ifinfop->if_group, &grinfop);
659*8485SPeter.Memishian@Sun.COM 	if (err != IPMP_SUCCESS) {
660*8485SPeter.Memishian@Sun.COM 		warn_ipmperr(err, "cannot get info for group `%s'",
661*8485SPeter.Memishian@Sun.COM 		    ifinfop->if_group);
662*8485SPeter.Memishian@Sun.COM 		(void) strlcpy(buf, "?", bufsize);
663*8485SPeter.Memishian@Sun.COM 		return;
664*8485SPeter.Memishian@Sun.COM 	}
665*8485SPeter.Memishian@Sun.COM 
666*8485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, grinfop->gr_ifname, bufsize);
667*8485SPeter.Memishian@Sun.COM 	ipmp_freegroupinfo(grinfop);
668*8485SPeter.Memishian@Sun.COM }
669*8485SPeter.Memishian@Sun.COM 
670*8485SPeter.Memishian@Sun.COM static void
671*8485SPeter.Memishian@Sun.COM sfunc_if_flags(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
672*8485SPeter.Memishian@Sun.COM {
673*8485SPeter.Memishian@Sun.COM 	int err;
674*8485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
675*8485SPeter.Memishian@Sun.COM 	ipmp_groupinfo_t *grinfop;
676*8485SPeter.Memishian@Sun.COM 
677*8485SPeter.Memishian@Sun.COM 	assert(bufsize > IPMPSTAT_NUM_FLAGS);
678*8485SPeter.Memishian@Sun.COM 
679*8485SPeter.Memishian@Sun.COM 	(void) memset(buf, '-', IPMPSTAT_NUM_FLAGS);
680*8485SPeter.Memishian@Sun.COM 	buf[IPMPSTAT_NUM_FLAGS] = '\0';
681*8485SPeter.Memishian@Sun.COM 
682*8485SPeter.Memishian@Sun.COM 	if (ifinfop->if_type == IPMP_IF_STANDBY)
683*8485SPeter.Memishian@Sun.COM 		buf[IPMPSTAT_SFLAG_INDEX] = 's';
684*8485SPeter.Memishian@Sun.COM 
685*8485SPeter.Memishian@Sun.COM 	if (ifinfop->if_flags & IPMP_IFFLAG_INACTIVE)
686*8485SPeter.Memishian@Sun.COM 		buf[IPMPSTAT_IFLAG_INDEX] = 'i';
687*8485SPeter.Memishian@Sun.COM 
688*8485SPeter.Memishian@Sun.COM 	if (ifinfop->if_flags & IPMP_IFFLAG_DOWN)
689*8485SPeter.Memishian@Sun.COM 		buf[IPMPSTAT_DFLAG_INDEX] = 'd';
690*8485SPeter.Memishian@Sun.COM 
691*8485SPeter.Memishian@Sun.COM 	if (ifinfop->if_flags & IPMP_IFFLAG_HWADDRDUP)
692*8485SPeter.Memishian@Sun.COM 		buf[IPMPSTAT_HFLAG_INDEX] = 'h';
693*8485SPeter.Memishian@Sun.COM 
694*8485SPeter.Memishian@Sun.COM 	err = ipmp_getgroupinfo(arg->sa_ih, ifinfop->if_group, &grinfop);
695*8485SPeter.Memishian@Sun.COM 	if (err != IPMP_SUCCESS) {
696*8485SPeter.Memishian@Sun.COM 		warn_ipmperr(err, "cannot get broadcast/multicast info for "
697*8485SPeter.Memishian@Sun.COM 		    "group `%s'", ifinfop->if_group);
698*8485SPeter.Memishian@Sun.COM 		return;
699*8485SPeter.Memishian@Sun.COM 	}
700*8485SPeter.Memishian@Sun.COM 
701*8485SPeter.Memishian@Sun.COM 	if (strcmp(grinfop->gr_m4ifname, ifinfop->if_name) == 0)
702*8485SPeter.Memishian@Sun.COM 		buf[IPMPSTAT_M4FLAG_INDEX] = 'm';
703*8485SPeter.Memishian@Sun.COM 
704*8485SPeter.Memishian@Sun.COM 	if (strcmp(grinfop->gr_m6ifname, ifinfop->if_name) == 0)
705*8485SPeter.Memishian@Sun.COM 		buf[IPMPSTAT_M6FLAG_INDEX] = 'M';
706*8485SPeter.Memishian@Sun.COM 
707*8485SPeter.Memishian@Sun.COM 	if (strcmp(grinfop->gr_bcifname, ifinfop->if_name) == 0)
708*8485SPeter.Memishian@Sun.COM 		buf[IPMPSTAT_BFLAG_INDEX] = 'b';
709*8485SPeter.Memishian@Sun.COM 
710*8485SPeter.Memishian@Sun.COM 	ipmp_freegroupinfo(grinfop);
711*8485SPeter.Memishian@Sun.COM }
712*8485SPeter.Memishian@Sun.COM 
713*8485SPeter.Memishian@Sun.COM static void
714*8485SPeter.Memishian@Sun.COM sfunc_if_link(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
715*8485SPeter.Memishian@Sun.COM {
716*8485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
717*8485SPeter.Memishian@Sun.COM 
718*8485SPeter.Memishian@Sun.COM 	enum2str(if_link, ifinfop->if_linkstate, buf, bufsize);
719*8485SPeter.Memishian@Sun.COM }
720*8485SPeter.Memishian@Sun.COM 
721*8485SPeter.Memishian@Sun.COM static void
722*8485SPeter.Memishian@Sun.COM sfunc_if_probe(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
723*8485SPeter.Memishian@Sun.COM {
724*8485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
725*8485SPeter.Memishian@Sun.COM 
726*8485SPeter.Memishian@Sun.COM 	enum2str(if_probe, ifinfop->if_probestate, buf, bufsize);
727*8485SPeter.Memishian@Sun.COM }
728*8485SPeter.Memishian@Sun.COM 
729*8485SPeter.Memishian@Sun.COM static void
730*8485SPeter.Memishian@Sun.COM sfunc_if_state(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
731*8485SPeter.Memishian@Sun.COM {
732*8485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = arg->sa_data;
733*8485SPeter.Memishian@Sun.COM 
734*8485SPeter.Memishian@Sun.COM 	enum2str(if_state, ifinfop->if_state, buf, bufsize);
735*8485SPeter.Memishian@Sun.COM }
736*8485SPeter.Memishian@Sun.COM 
737*8485SPeter.Memishian@Sun.COM static void
738*8485SPeter.Memishian@Sun.COM sfunc_probe_id(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
739*8485SPeter.Memishian@Sun.COM {
740*8485SPeter.Memishian@Sun.COM 	uint32_t probe_id;
741*8485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
742*8485SPeter.Memishian@Sun.COM 
743*8485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_uint32(nvl, IPMP_PROBE_ID, &probe_id) != 0) {
744*8485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_ID", buf, bufsize);
745*8485SPeter.Memishian@Sun.COM 		return;
746*8485SPeter.Memishian@Sun.COM 	}
747*8485SPeter.Memishian@Sun.COM 
748*8485SPeter.Memishian@Sun.COM 	(void) snprintf(buf, bufsize, "%u", probe_id);
749*8485SPeter.Memishian@Sun.COM }
750*8485SPeter.Memishian@Sun.COM 
751*8485SPeter.Memishian@Sun.COM static void
752*8485SPeter.Memishian@Sun.COM sfunc_probe_ifname(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
753*8485SPeter.Memishian@Sun.COM {
754*8485SPeter.Memishian@Sun.COM 	char *ifname;
755*8485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
756*8485SPeter.Memishian@Sun.COM 
757*8485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_string(nvl, IPMP_IF_NAME, &ifname) != 0) {
758*8485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_IF_NAME", buf, bufsize);
759*8485SPeter.Memishian@Sun.COM 		return;
760*8485SPeter.Memishian@Sun.COM 	}
761*8485SPeter.Memishian@Sun.COM 
762*8485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, ifname, bufsize);
763*8485SPeter.Memishian@Sun.COM }
764*8485SPeter.Memishian@Sun.COM 
765*8485SPeter.Memishian@Sun.COM static void
766*8485SPeter.Memishian@Sun.COM sfunc_probe_time(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
767*8485SPeter.Memishian@Sun.COM {
768*8485SPeter.Memishian@Sun.COM 	hrtime_t start;
769*8485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
770*8485SPeter.Memishian@Sun.COM 
771*8485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_START_TIME, &start) != 0) {
772*8485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_START_TIME", buf, bufsize);
773*8485SPeter.Memishian@Sun.COM 		return;
774*8485SPeter.Memishian@Sun.COM 	}
775*8485SPeter.Memishian@Sun.COM 
776*8485SPeter.Memishian@Sun.COM 	(void) snprintf(buf, bufsize, "%.2fs",
777*8485SPeter.Memishian@Sun.COM 	    (float)(start - probe_output_start) / NANOSEC);
778*8485SPeter.Memishian@Sun.COM }
779*8485SPeter.Memishian@Sun.COM 
780*8485SPeter.Memishian@Sun.COM static void
781*8485SPeter.Memishian@Sun.COM sfunc_probe_target(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
782*8485SPeter.Memishian@Sun.COM {
783*8485SPeter.Memishian@Sun.COM 	uint_t nelem;
784*8485SPeter.Memishian@Sun.COM 	struct sockaddr_storage *target;
785*8485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
786*8485SPeter.Memishian@Sun.COM 
787*8485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_byte_array(nvl, IPMP_PROBE_TARGET,
788*8485SPeter.Memishian@Sun.COM 	    (uchar_t **)&target, &nelem) != 0) {
789*8485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_TARGET", buf, bufsize);
790*8485SPeter.Memishian@Sun.COM 		return;
791*8485SPeter.Memishian@Sun.COM 	}
792*8485SPeter.Memishian@Sun.COM 
793*8485SPeter.Memishian@Sun.COM 	sockaddr2str(target, buf, bufsize);
794*8485SPeter.Memishian@Sun.COM }
795*8485SPeter.Memishian@Sun.COM 
796*8485SPeter.Memishian@Sun.COM static void
797*8485SPeter.Memishian@Sun.COM sfunc_probe_rtt(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
798*8485SPeter.Memishian@Sun.COM {
799*8485SPeter.Memishian@Sun.COM 	hrtime_t start, ackproc;
800*8485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
801*8485SPeter.Memishian@Sun.COM 	uint32_t state;
802*8485SPeter.Memishian@Sun.COM 
803*8485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_uint32(nvl, IPMP_PROBE_STATE, &state) != 0) {
804*8485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_STATE", buf, bufsize);
805*8485SPeter.Memishian@Sun.COM 		return;
806*8485SPeter.Memishian@Sun.COM 	}
807*8485SPeter.Memishian@Sun.COM 
808*8485SPeter.Memishian@Sun.COM 	if (state != IPMP_PROBE_ACKED)
809*8485SPeter.Memishian@Sun.COM 		return;
810*8485SPeter.Memishian@Sun.COM 
811*8485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_START_TIME, &start) != 0) {
812*8485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_START_TIME", buf, bufsize);
813*8485SPeter.Memishian@Sun.COM 		return;
814*8485SPeter.Memishian@Sun.COM 	}
815*8485SPeter.Memishian@Sun.COM 
816*8485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_ACKPROC_TIME, &ackproc) != 0) {
817*8485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_ACKPROC_TIME", buf, bufsize);
818*8485SPeter.Memishian@Sun.COM 		return;
819*8485SPeter.Memishian@Sun.COM 	}
820*8485SPeter.Memishian@Sun.COM 
821*8485SPeter.Memishian@Sun.COM 	(void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(ackproc - start));
822*8485SPeter.Memishian@Sun.COM }
823*8485SPeter.Memishian@Sun.COM 
824*8485SPeter.Memishian@Sun.COM static void
825*8485SPeter.Memishian@Sun.COM sfunc_probe_netrtt(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
826*8485SPeter.Memishian@Sun.COM {
827*8485SPeter.Memishian@Sun.COM 	hrtime_t sent, ackrecv;
828*8485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
829*8485SPeter.Memishian@Sun.COM 	uint32_t state;
830*8485SPeter.Memishian@Sun.COM 
831*8485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_uint32(nvl, IPMP_PROBE_STATE, &state) != 0) {
832*8485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_STATE", buf, bufsize);
833*8485SPeter.Memishian@Sun.COM 		return;
834*8485SPeter.Memishian@Sun.COM 	}
835*8485SPeter.Memishian@Sun.COM 
836*8485SPeter.Memishian@Sun.COM 	if (state != IPMP_PROBE_ACKED)
837*8485SPeter.Memishian@Sun.COM 		return;
838*8485SPeter.Memishian@Sun.COM 
839*8485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_SENT_TIME, &sent) != 0) {
840*8485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_SENT_TIME", buf, bufsize);
841*8485SPeter.Memishian@Sun.COM 		return;
842*8485SPeter.Memishian@Sun.COM 	}
843*8485SPeter.Memishian@Sun.COM 
844*8485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_ACKRECV_TIME, &ackrecv) != 0) {
845*8485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_ACKRECV_TIME", buf, bufsize);
846*8485SPeter.Memishian@Sun.COM 		return;
847*8485SPeter.Memishian@Sun.COM 	}
848*8485SPeter.Memishian@Sun.COM 
849*8485SPeter.Memishian@Sun.COM 	(void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(ackrecv - sent));
850*8485SPeter.Memishian@Sun.COM }
851*8485SPeter.Memishian@Sun.COM 
852*8485SPeter.Memishian@Sun.COM static void
853*8485SPeter.Memishian@Sun.COM sfunc_probe_rttavg(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
854*8485SPeter.Memishian@Sun.COM {
855*8485SPeter.Memishian@Sun.COM 	int64_t rttavg;
856*8485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
857*8485SPeter.Memishian@Sun.COM 
858*8485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_int64(nvl, IPMP_PROBE_TARGET_RTTAVG, &rttavg) != 0) {
859*8485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_TARGET_RTTAVG", buf, bufsize);
860*8485SPeter.Memishian@Sun.COM 		return;
861*8485SPeter.Memishian@Sun.COM 	}
862*8485SPeter.Memishian@Sun.COM 
863*8485SPeter.Memishian@Sun.COM 	if (rttavg != 0)
864*8485SPeter.Memishian@Sun.COM 		(void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(rttavg));
865*8485SPeter.Memishian@Sun.COM }
866*8485SPeter.Memishian@Sun.COM 
867*8485SPeter.Memishian@Sun.COM static void
868*8485SPeter.Memishian@Sun.COM sfunc_probe_rttdev(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
869*8485SPeter.Memishian@Sun.COM {
870*8485SPeter.Memishian@Sun.COM 	int64_t rttdev;
871*8485SPeter.Memishian@Sun.COM 	nvlist_t *nvl = arg->sa_data;
872*8485SPeter.Memishian@Sun.COM 
873*8485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_int64(nvl, IPMP_PROBE_TARGET_RTTDEV, &rttdev) != 0) {
874*8485SPeter.Memishian@Sun.COM 		sfunc_nvwarn("IPMP_PROBE_TARGET_RTTDEV", buf, bufsize);
875*8485SPeter.Memishian@Sun.COM 		return;
876*8485SPeter.Memishian@Sun.COM 	}
877*8485SPeter.Memishian@Sun.COM 
878*8485SPeter.Memishian@Sun.COM 	if (rttdev != 0)
879*8485SPeter.Memishian@Sun.COM 		(void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(rttdev));
880*8485SPeter.Memishian@Sun.COM }
881*8485SPeter.Memishian@Sun.COM 
882*8485SPeter.Memishian@Sun.COM /* ARGSUSED */
883*8485SPeter.Memishian@Sun.COM static void
884*8485SPeter.Memishian@Sun.COM probe_enabled_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
885*8485SPeter.Memishian@Sun.COM {
886*8485SPeter.Memishian@Sun.COM 	uint_t *nenabledp = arg;
887*8485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = infop;
888*8485SPeter.Memishian@Sun.COM 
889*8485SPeter.Memishian@Sun.COM 	if (ifinfop->if_probestate != IPMP_PROBE_DISABLED)
890*8485SPeter.Memishian@Sun.COM 		(*nenabledp)++;
891*8485SPeter.Memishian@Sun.COM }
892*8485SPeter.Memishian@Sun.COM 
893*8485SPeter.Memishian@Sun.COM static void
894*8485SPeter.Memishian@Sun.COM probe_output(ipmp_handle_t ih, ipmpstat_ofmt_t *ofmt)
895*8485SPeter.Memishian@Sun.COM {
896*8485SPeter.Memishian@Sun.COM 	char sub[MAX_SUBID_LEN];
897*8485SPeter.Memishian@Sun.COM 	evchan_t *evch;
898*8485SPeter.Memishian@Sun.COM 	ipmpstat_probe_state_t ps = { ih, ofmt };
899*8485SPeter.Memishian@Sun.COM 	uint_t nenabled = 0;
900*8485SPeter.Memishian@Sun.COM 
901*8485SPeter.Memishian@Sun.COM 	/*
902*8485SPeter.Memishian@Sun.COM 	 * Check if any interfaces are enabled for probe-based failure
903*8485SPeter.Memishian@Sun.COM 	 * detection.  If not, immediately fail.
904*8485SPeter.Memishian@Sun.COM 	 */
905*8485SPeter.Memishian@Sun.COM 	walk_if(ih, probe_enabled_cbfunc, &nenabled);
906*8485SPeter.Memishian@Sun.COM 	if (nenabled == 0)
907*8485SPeter.Memishian@Sun.COM 		die("probe-based failure detection is disabled\n");
908*8485SPeter.Memishian@Sun.COM 
909*8485SPeter.Memishian@Sun.COM 	probe_output_start = gethrtime();
910*8485SPeter.Memishian@Sun.COM 
911*8485SPeter.Memishian@Sun.COM 	/*
912*8485SPeter.Memishian@Sun.COM 	 * Unfortunately, until 4791900 is fixed, only privileged processes
913*8485SPeter.Memishian@Sun.COM 	 * can bind and thus receive sysevents.
914*8485SPeter.Memishian@Sun.COM 	 */
915*8485SPeter.Memishian@Sun.COM 	errno = sysevent_evc_bind(IPMP_EVENT_CHAN, &evch, EVCH_CREAT);
916*8485SPeter.Memishian@Sun.COM 	if (errno != 0) {
917*8485SPeter.Memishian@Sun.COM 		if (errno == EPERM)
918*8485SPeter.Memishian@Sun.COM 			die("insufficient privileges for -p\n");
919*8485SPeter.Memishian@Sun.COM 		die("sysevent_evc_bind to channel %s failed", IPMP_EVENT_CHAN);
920*8485SPeter.Memishian@Sun.COM 	}
921*8485SPeter.Memishian@Sun.COM 
922*8485SPeter.Memishian@Sun.COM 	/*
923*8485SPeter.Memishian@Sun.COM 	 * The subscriber must be unique in order for sysevent_evc_subscribe()
924*8485SPeter.Memishian@Sun.COM 	 * to succeed, so combine our name and pid.
925*8485SPeter.Memishian@Sun.COM 	 */
926*8485SPeter.Memishian@Sun.COM 	(void) snprintf(sub, sizeof (sub), "%d-%s", getpid(), progname);
927*8485SPeter.Memishian@Sun.COM 
928*8485SPeter.Memishian@Sun.COM 	errno = sysevent_evc_subscribe(evch, sub, EC_IPMP, probe_event, &ps, 0);
929*8485SPeter.Memishian@Sun.COM 	if (errno != 0)
930*8485SPeter.Memishian@Sun.COM 		die("sysevent_evc_subscribe for class %s failed", EC_IPMP);
931*8485SPeter.Memishian@Sun.COM 
932*8485SPeter.Memishian@Sun.COM 	for (;;)
933*8485SPeter.Memishian@Sun.COM 		(void) pause();
934*8485SPeter.Memishian@Sun.COM }
935*8485SPeter.Memishian@Sun.COM 
936*8485SPeter.Memishian@Sun.COM static int
937*8485SPeter.Memishian@Sun.COM probe_event(sysevent_t *ev, void *arg)
938*8485SPeter.Memishian@Sun.COM {
939*8485SPeter.Memishian@Sun.COM 	nvlist_t *nvl;
940*8485SPeter.Memishian@Sun.COM 	uint32_t state;
941*8485SPeter.Memishian@Sun.COM 	uint32_t version;
942*8485SPeter.Memishian@Sun.COM 	ipmpstat_probe_state_t *psp = arg;
943*8485SPeter.Memishian@Sun.COM 
944*8485SPeter.Memishian@Sun.COM 	if (strcmp(sysevent_get_subclass_name(ev), ESC_IPMP_PROBE_STATE) != 0)
945*8485SPeter.Memishian@Sun.COM 		return (0);
946*8485SPeter.Memishian@Sun.COM 
947*8485SPeter.Memishian@Sun.COM 	if (sysevent_get_attr_list(ev, &nvl) != 0) {
948*8485SPeter.Memishian@Sun.COM 		warn("sysevent_get_attr_list failed; dropping event");
949*8485SPeter.Memishian@Sun.COM 		return (0);
950*8485SPeter.Memishian@Sun.COM 	}
951*8485SPeter.Memishian@Sun.COM 
952*8485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_uint32(nvl, IPMP_EVENT_VERSION, &version) != 0) {
953*8485SPeter.Memishian@Sun.COM 		warn("dropped event with no IPMP_EVENT_VERSION\n");
954*8485SPeter.Memishian@Sun.COM 		goto out;
955*8485SPeter.Memishian@Sun.COM 	}
956*8485SPeter.Memishian@Sun.COM 
957*8485SPeter.Memishian@Sun.COM 	if (version != IPMP_EVENT_CUR_VERSION) {
958*8485SPeter.Memishian@Sun.COM 		warn("dropped event with unsupported IPMP_EVENT_VERSION %d\n",
959*8485SPeter.Memishian@Sun.COM 		    version);
960*8485SPeter.Memishian@Sun.COM 		goto out;
961*8485SPeter.Memishian@Sun.COM 	}
962*8485SPeter.Memishian@Sun.COM 
963*8485SPeter.Memishian@Sun.COM 	if (nvlist_lookup_uint32(nvl, IPMP_PROBE_STATE, &state) != 0) {
964*8485SPeter.Memishian@Sun.COM 		warn("dropped event with no IPMP_PROBE_STATE\n");
965*8485SPeter.Memishian@Sun.COM 		goto out;
966*8485SPeter.Memishian@Sun.COM 	}
967*8485SPeter.Memishian@Sun.COM 
968*8485SPeter.Memishian@Sun.COM 	if (state == IPMP_PROBE_ACKED || state == IPMP_PROBE_LOST)
969*8485SPeter.Memishian@Sun.COM 		ofmt_output(psp->ps_ofmt, psp->ps_ih, nvl);
970*8485SPeter.Memishian@Sun.COM out:
971*8485SPeter.Memishian@Sun.COM 	nvlist_free(nvl);
972*8485SPeter.Memishian@Sun.COM 	return (0);
973*8485SPeter.Memishian@Sun.COM }
974*8485SPeter.Memishian@Sun.COM 
975*8485SPeter.Memishian@Sun.COM static void
976*8485SPeter.Memishian@Sun.COM sfunc_targ_ifname(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
977*8485SPeter.Memishian@Sun.COM {
978*8485SPeter.Memishian@Sun.COM 	ipmp_targinfo_t *targinfop = arg->sa_data;
979*8485SPeter.Memishian@Sun.COM 
980*8485SPeter.Memishian@Sun.COM 	(void) strlcpy(buf, targinfop->it_name, bufsize);
981*8485SPeter.Memishian@Sun.COM }
982*8485SPeter.Memishian@Sun.COM 
983*8485SPeter.Memishian@Sun.COM static void
984*8485SPeter.Memishian@Sun.COM sfunc_targ_mode(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
985*8485SPeter.Memishian@Sun.COM {
986*8485SPeter.Memishian@Sun.COM 	ipmp_targinfo_t *targinfop = arg->sa_data;
987*8485SPeter.Memishian@Sun.COM 
988*8485SPeter.Memishian@Sun.COM 	enum2str(targ_mode, targinfop->it_targmode, buf, bufsize);
989*8485SPeter.Memishian@Sun.COM }
990*8485SPeter.Memishian@Sun.COM 
991*8485SPeter.Memishian@Sun.COM static void
992*8485SPeter.Memishian@Sun.COM sfunc_targ_testaddr(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
993*8485SPeter.Memishian@Sun.COM {
994*8485SPeter.Memishian@Sun.COM 	ipmp_targinfo_t *targinfop = arg->sa_data;
995*8485SPeter.Memishian@Sun.COM 
996*8485SPeter.Memishian@Sun.COM 	if (targinfop->it_targmode != IPMP_TARG_DISABLED)
997*8485SPeter.Memishian@Sun.COM 		sockaddr2str(&targinfop->it_testaddr, buf, bufsize);
998*8485SPeter.Memishian@Sun.COM }
999*8485SPeter.Memishian@Sun.COM 
1000*8485SPeter.Memishian@Sun.COM static void
1001*8485SPeter.Memishian@Sun.COM sfunc_targ_targets(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize)
1002*8485SPeter.Memishian@Sun.COM {
1003*8485SPeter.Memishian@Sun.COM 	uint_t i;
1004*8485SPeter.Memishian@Sun.COM 	char *targname = alloca(bufsize);
1005*8485SPeter.Memishian@Sun.COM 	ipmp_targinfo_t *targinfop = arg->sa_data;
1006*8485SPeter.Memishian@Sun.COM 	ipmp_addrlist_t *targlistp = targinfop->it_targlistp;
1007*8485SPeter.Memishian@Sun.COM 
1008*8485SPeter.Memishian@Sun.COM 	for (i = 0; i < targlistp->al_naddr; i++) {
1009*8485SPeter.Memishian@Sun.COM 		sockaddr2str(&targlistp->al_addrs[i], targname, bufsize);
1010*8485SPeter.Memishian@Sun.COM 		(void) strlcat(buf, targname, bufsize);
1011*8485SPeter.Memishian@Sun.COM 		if ((i + 1) < targlistp->al_naddr)
1012*8485SPeter.Memishian@Sun.COM 			(void) strlcat(buf, " ", bufsize);
1013*8485SPeter.Memishian@Sun.COM 	}
1014*8485SPeter.Memishian@Sun.COM }
1015*8485SPeter.Memishian@Sun.COM 
1016*8485SPeter.Memishian@Sun.COM static void
1017*8485SPeter.Memishian@Sun.COM info_output_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
1018*8485SPeter.Memishian@Sun.COM {
1019*8485SPeter.Memishian@Sun.COM 	ofmt_output(arg, ih, infop);
1020*8485SPeter.Memishian@Sun.COM }
1021*8485SPeter.Memishian@Sun.COM 
1022*8485SPeter.Memishian@Sun.COM static void
1023*8485SPeter.Memishian@Sun.COM targinfo_output_cbfunc(ipmp_handle_t ih, void *infop, void *arg)
1024*8485SPeter.Memishian@Sun.COM {
1025*8485SPeter.Memishian@Sun.COM 	ipmp_ifinfo_t *ifinfop = infop;
1026*8485SPeter.Memishian@Sun.COM 	ipmp_if_targmode_t targmode4 = ifinfop->if_targinfo4.it_targmode;
1027*8485SPeter.Memishian@Sun.COM 	ipmp_if_targmode_t targmode6 = ifinfop->if_targinfo6.it_targmode;
1028*8485SPeter.Memishian@Sun.COM 
1029*8485SPeter.Memishian@Sun.COM 	/*
1030*8485SPeter.Memishian@Sun.COM 	 * Usually, either IPv4 or IPv6 probing will be enabled, but the admin
1031*8485SPeter.Memishian@Sun.COM 	 * may enable both.  If only one is enabled, omit the other one so as
1032*8485SPeter.Memishian@Sun.COM 	 * to not encourage the admin to enable both.  If neither is enabled,
1033*8485SPeter.Memishian@Sun.COM 	 * we still print one just so the admin can see a MODE of "disabled".
1034*8485SPeter.Memishian@Sun.COM 	 */
1035*8485SPeter.Memishian@Sun.COM 	if (targmode4 != IPMP_TARG_DISABLED || targmode6 == IPMP_TARG_DISABLED)
1036*8485SPeter.Memishian@Sun.COM 		ofmt_output(arg, ih, &ifinfop->if_targinfo4);
1037*8485SPeter.Memishian@Sun.COM 	if (targmode6 != IPMP_TARG_DISABLED)
1038*8485SPeter.Memishian@Sun.COM 		ofmt_output(arg, ih, &ifinfop->if_targinfo6);
1039*8485SPeter.Memishian@Sun.COM }
1040*8485SPeter.Memishian@Sun.COM 
1041*8485SPeter.Memishian@Sun.COM /*
1042*8485SPeter.Memishian@Sun.COM  * Creates an ipmpstat_ofmt_t field list from the comma-separated list of
1043*8485SPeter.Memishian@Sun.COM  * user-specified fields passed via `ofields'.  The table of known fields
1044*8485SPeter.Memishian@Sun.COM  * (and their attributes) is passed via `fields'.
1045*8485SPeter.Memishian@Sun.COM  */
1046*8485SPeter.Memishian@Sun.COM static ipmpstat_ofmt_t *
1047*8485SPeter.Memishian@Sun.COM ofmt_create(const char *ofields, ipmpstat_field_t fields[])
1048*8485SPeter.Memishian@Sun.COM {
1049*8485SPeter.Memishian@Sun.COM 	char *token, *lasts, *ofields_dup;
1050*8485SPeter.Memishian@Sun.COM 	const char *fieldname;
1051*8485SPeter.Memishian@Sun.COM 	ipmpstat_ofmt_t *ofmt, *ofmt_head = NULL, *ofmt_tail;
1052*8485SPeter.Memishian@Sun.COM 	ipmpstat_field_t *fieldp;
1053*8485SPeter.Memishian@Sun.COM 	uint_t cols = 0;
1054*8485SPeter.Memishian@Sun.COM 
1055*8485SPeter.Memishian@Sun.COM 	/*
1056*8485SPeter.Memishian@Sun.COM 	 * If "-o" was omitted or "-o all" was specified, build a list of
1057*8485SPeter.Memishian@Sun.COM 	 * field names.  If "-o" was omitted, stop building the list when
1058*8485SPeter.Memishian@Sun.COM 	 * we run out of columns.
1059*8485SPeter.Memishian@Sun.COM 	 */
1060*8485SPeter.Memishian@Sun.COM 	if (ofields == NULL || strcasecmp(ofields, "all") == 0) {
1061*8485SPeter.Memishian@Sun.COM 		for (fieldp = fields; fieldp->f_name != NULL; fieldp++) {
1062*8485SPeter.Memishian@Sun.COM 			cols += fieldp->f_width;
1063*8485SPeter.Memishian@Sun.COM 			if (ofields == NULL && cols > IPMPSTAT_NCOL)
1064*8485SPeter.Memishian@Sun.COM 				break;
1065*8485SPeter.Memishian@Sun.COM 
1066*8485SPeter.Memishian@Sun.COM 			if ((ofmt = calloc(sizeof (*ofmt), 1)) == NULL)
1067*8485SPeter.Memishian@Sun.COM 				die("cannot allocate output format list");
1068*8485SPeter.Memishian@Sun.COM 
1069*8485SPeter.Memishian@Sun.COM 			ofmt->o_field = fieldp;
1070*8485SPeter.Memishian@Sun.COM 			if (ofmt_head == NULL) {
1071*8485SPeter.Memishian@Sun.COM 				ofmt_head = ofmt;
1072*8485SPeter.Memishian@Sun.COM 				ofmt_tail = ofmt;
1073*8485SPeter.Memishian@Sun.COM 			} else {
1074*8485SPeter.Memishian@Sun.COM 				ofmt_tail->o_next = ofmt;
1075*8485SPeter.Memishian@Sun.COM 				ofmt_tail = ofmt;
1076*8485SPeter.Memishian@Sun.COM 			}
1077*8485SPeter.Memishian@Sun.COM 		}
1078*8485SPeter.Memishian@Sun.COM 		return (ofmt_head);
1079*8485SPeter.Memishian@Sun.COM 	}
1080*8485SPeter.Memishian@Sun.COM 
1081*8485SPeter.Memishian@Sun.COM 	if ((ofields_dup = strdup(ofields)) == NULL)
1082*8485SPeter.Memishian@Sun.COM 		die("cannot allocate output format list");
1083*8485SPeter.Memishian@Sun.COM 
1084*8485SPeter.Memishian@Sun.COM 	token = ofields_dup;
1085*8485SPeter.Memishian@Sun.COM 	while ((fieldname = strtok_r(token, ",", &lasts)) != NULL) {
1086*8485SPeter.Memishian@Sun.COM 		token = NULL;
1087*8485SPeter.Memishian@Sun.COM 
1088*8485SPeter.Memishian@Sun.COM 		if ((fieldp = field_find(fields, fieldname)) == NULL) {
1089*8485SPeter.Memishian@Sun.COM 			/*
1090*8485SPeter.Memishian@Sun.COM 			 * Since machine parsers are unlikely to be able to
1091*8485SPeter.Memishian@Sun.COM 			 * gracefully handle missing fields, die if we're in
1092*8485SPeter.Memishian@Sun.COM 			 * parsable mode.  Otherwise, just print a warning.
1093*8485SPeter.Memishian@Sun.COM 			 */
1094*8485SPeter.Memishian@Sun.COM 			if (opt & IPMPSTAT_OPT_PARSABLE)
1095*8485SPeter.Memishian@Sun.COM 				die("unknown output field `%s'\n", fieldname);
1096*8485SPeter.Memishian@Sun.COM 
1097*8485SPeter.Memishian@Sun.COM 			warn("ignoring unknown output field `%s'\n", fieldname);
1098*8485SPeter.Memishian@Sun.COM 			continue;
1099*8485SPeter.Memishian@Sun.COM 		}
1100*8485SPeter.Memishian@Sun.COM 
1101*8485SPeter.Memishian@Sun.COM 		if ((ofmt = calloc(sizeof (*ofmt), 1)) == NULL)
1102*8485SPeter.Memishian@Sun.COM 			die("cannot allocate output format list");
1103*8485SPeter.Memishian@Sun.COM 
1104*8485SPeter.Memishian@Sun.COM 		ofmt->o_field = fieldp;
1105*8485SPeter.Memishian@Sun.COM 		if (ofmt_head == NULL) {
1106*8485SPeter.Memishian@Sun.COM 			ofmt_head = ofmt;
1107*8485SPeter.Memishian@Sun.COM 			ofmt_tail = ofmt;
1108*8485SPeter.Memishian@Sun.COM 		} else {
1109*8485SPeter.Memishian@Sun.COM 			ofmt_tail->o_next = ofmt;
1110*8485SPeter.Memishian@Sun.COM 			ofmt_tail = ofmt;
1111*8485SPeter.Memishian@Sun.COM 		}
1112*8485SPeter.Memishian@Sun.COM 	}
1113*8485SPeter.Memishian@Sun.COM 
1114*8485SPeter.Memishian@Sun.COM 	free(ofields_dup);
1115*8485SPeter.Memishian@Sun.COM 	if (ofmt_head == NULL)
1116*8485SPeter.Memishian@Sun.COM 		die("no valid output fields specified\n");
1117*8485SPeter.Memishian@Sun.COM 
1118*8485SPeter.Memishian@Sun.COM 	return (ofmt_head);
1119*8485SPeter.Memishian@Sun.COM }
1120*8485SPeter.Memishian@Sun.COM 
1121*8485SPeter.Memishian@Sun.COM /*
1122*8485SPeter.Memishian@Sun.COM  * Destroys the provided `ofmt' field list.
1123*8485SPeter.Memishian@Sun.COM  */
1124*8485SPeter.Memishian@Sun.COM static void
1125*8485SPeter.Memishian@Sun.COM ofmt_destroy(ipmpstat_ofmt_t *ofmt)
1126*8485SPeter.Memishian@Sun.COM {
1127*8485SPeter.Memishian@Sun.COM 	ipmpstat_ofmt_t *ofmt_next;
1128*8485SPeter.Memishian@Sun.COM 
1129*8485SPeter.Memishian@Sun.COM 	for (; ofmt != NULL; ofmt = ofmt_next) {
1130*8485SPeter.Memishian@Sun.COM 		ofmt_next = ofmt->o_next;
1131*8485SPeter.Memishian@Sun.COM 		free(ofmt);
1132*8485SPeter.Memishian@Sun.COM 	}
1133*8485SPeter.Memishian@Sun.COM }
1134*8485SPeter.Memishian@Sun.COM 
1135*8485SPeter.Memishian@Sun.COM /*
1136*8485SPeter.Memishian@Sun.COM  * Outputs a header for the fields named by `ofmt'.
1137*8485SPeter.Memishian@Sun.COM  */
1138*8485SPeter.Memishian@Sun.COM static void
1139*8485SPeter.Memishian@Sun.COM ofmt_output_header(const ipmpstat_ofmt_t *ofmt)
1140*8485SPeter.Memishian@Sun.COM {
1141*8485SPeter.Memishian@Sun.COM 	const ipmpstat_field_t *fieldp;
1142*8485SPeter.Memishian@Sun.COM 
1143*8485SPeter.Memishian@Sun.COM 	for (; ofmt != NULL; ofmt = ofmt->o_next) {
1144*8485SPeter.Memishian@Sun.COM 		fieldp = ofmt->o_field;
1145*8485SPeter.Memishian@Sun.COM 
1146*8485SPeter.Memishian@Sun.COM 		if (ofmt->o_next == NULL)
1147*8485SPeter.Memishian@Sun.COM 			(void) printf("%s", fieldp->f_name);
1148*8485SPeter.Memishian@Sun.COM 		else
1149*8485SPeter.Memishian@Sun.COM 			(void) printf("%-*s", fieldp->f_width, fieldp->f_name);
1150*8485SPeter.Memishian@Sun.COM 	}
1151*8485SPeter.Memishian@Sun.COM 	(void) printf("\n");
1152*8485SPeter.Memishian@Sun.COM }
1153*8485SPeter.Memishian@Sun.COM 
1154*8485SPeter.Memishian@Sun.COM /*
1155*8485SPeter.Memishian@Sun.COM  * Outputs one row of values for the fields named by `ofmt'.  The values to
1156*8485SPeter.Memishian@Sun.COM  * output are obtained through the `ofmt' function pointers, which are
1157*8485SPeter.Memishian@Sun.COM  * indirectly passed the `ih' and `arg' structures for state; see the block
1158*8485SPeter.Memishian@Sun.COM  * comment at the start of this file for details.
1159*8485SPeter.Memishian@Sun.COM  */
1160*8485SPeter.Memishian@Sun.COM static void
1161*8485SPeter.Memishian@Sun.COM ofmt_output(const ipmpstat_ofmt_t *ofmt, ipmp_handle_t ih, void *arg)
1162*8485SPeter.Memishian@Sun.COM {
1163*8485SPeter.Memishian@Sun.COM 	int i;
1164*8485SPeter.Memishian@Sun.COM 	char buf[1024];
1165*8485SPeter.Memishian@Sun.COM 	boolean_t escsep;
1166*8485SPeter.Memishian@Sun.COM 	static int nrow;
1167*8485SPeter.Memishian@Sun.COM 	const char *value;
1168*8485SPeter.Memishian@Sun.COM 	uint_t width, valwidth;
1169*8485SPeter.Memishian@Sun.COM 	uint_t compress, overflow = 0;
1170*8485SPeter.Memishian@Sun.COM 	const ipmpstat_field_t *fieldp;
1171*8485SPeter.Memishian@Sun.COM 	ipmpstat_sfunc_arg_t sfunc_arg;
1172*8485SPeter.Memishian@Sun.COM 
1173*8485SPeter.Memishian@Sun.COM 	/*
1174*8485SPeter.Memishian@Sun.COM 	 * For each screenful of data, display the header.
1175*8485SPeter.Memishian@Sun.COM 	 */
1176*8485SPeter.Memishian@Sun.COM 	if ((nrow++ % winsize.ws_row) == 0 && !(opt & IPMPSTAT_OPT_PARSABLE)) {
1177*8485SPeter.Memishian@Sun.COM 		ofmt_output_header(ofmt);
1178*8485SPeter.Memishian@Sun.COM 		nrow++;
1179*8485SPeter.Memishian@Sun.COM 	}
1180*8485SPeter.Memishian@Sun.COM 
1181*8485SPeter.Memishian@Sun.COM 	/*
1182*8485SPeter.Memishian@Sun.COM 	 * Check if we'll be displaying multiple fields per line, and thus
1183*8485SPeter.Memishian@Sun.COM 	 * need to escape the field separator.
1184*8485SPeter.Memishian@Sun.COM 	 */
1185*8485SPeter.Memishian@Sun.COM 	escsep = (ofmt != NULL && ofmt->o_next != NULL);
1186*8485SPeter.Memishian@Sun.COM 
1187*8485SPeter.Memishian@Sun.COM 	for (; ofmt != NULL; ofmt = ofmt->o_next) {
1188*8485SPeter.Memishian@Sun.COM 		fieldp = ofmt->o_field;
1189*8485SPeter.Memishian@Sun.COM 
1190*8485SPeter.Memishian@Sun.COM 		sfunc_arg.sa_ih = ih;
1191*8485SPeter.Memishian@Sun.COM 		sfunc_arg.sa_data = arg;
1192*8485SPeter.Memishian@Sun.COM 
1193*8485SPeter.Memishian@Sun.COM 		buf[0] = '\0';
1194*8485SPeter.Memishian@Sun.COM 		(*fieldp->f_sfunc)(&sfunc_arg, buf, sizeof (buf));
1195*8485SPeter.Memishian@Sun.COM 
1196*8485SPeter.Memishian@Sun.COM 		if (opt & IPMPSTAT_OPT_PARSABLE) {
1197*8485SPeter.Memishian@Sun.COM 			for (i = 0; buf[i] != '\0'; i++) {
1198*8485SPeter.Memishian@Sun.COM 				if (escsep && (buf[i] == ':' || buf[i] == '\\'))
1199*8485SPeter.Memishian@Sun.COM 					(void) putchar('\\');
1200*8485SPeter.Memishian@Sun.COM 				(void) putchar(buf[i]);
1201*8485SPeter.Memishian@Sun.COM 			}
1202*8485SPeter.Memishian@Sun.COM 			if (ofmt->o_next != NULL)
1203*8485SPeter.Memishian@Sun.COM 				(void) putchar(':');
1204*8485SPeter.Memishian@Sun.COM 		} else {
1205*8485SPeter.Memishian@Sun.COM 			value = (buf[0] == '\0') ? "--" : buf;
1206*8485SPeter.Memishian@Sun.COM 
1207*8485SPeter.Memishian@Sun.COM 			/*
1208*8485SPeter.Memishian@Sun.COM 			 * To avoid needless line-wraps, for the last field,
1209*8485SPeter.Memishian@Sun.COM 			 * don't include any trailing whitespace.
1210*8485SPeter.Memishian@Sun.COM 			 */
1211*8485SPeter.Memishian@Sun.COM 			if (ofmt->o_next == NULL) {
1212*8485SPeter.Memishian@Sun.COM 				(void) printf("%s", value);
1213*8485SPeter.Memishian@Sun.COM 				continue;
1214*8485SPeter.Memishian@Sun.COM 			}
1215*8485SPeter.Memishian@Sun.COM 
1216*8485SPeter.Memishian@Sun.COM 			/*
1217*8485SPeter.Memishian@Sun.COM 			 * For other fields, grow the width as necessary to
1218*8485SPeter.Memishian@Sun.COM 			 * ensure the value completely fits.  However, if
1219*8485SPeter.Memishian@Sun.COM 			 * there's unused whitespace in subsequent fields,
1220*8485SPeter.Memishian@Sun.COM 			 * then "compress" that whitespace to attempt to get
1221*8485SPeter.Memishian@Sun.COM 			 * the columns to line up again.
1222*8485SPeter.Memishian@Sun.COM 			 */
1223*8485SPeter.Memishian@Sun.COM 			width = fieldp->f_width;
1224*8485SPeter.Memishian@Sun.COM 			valwidth = strlen(value);
1225*8485SPeter.Memishian@Sun.COM 
1226*8485SPeter.Memishian@Sun.COM 			if (valwidth + overflow >= width) {
1227*8485SPeter.Memishian@Sun.COM 				overflow += valwidth - width + 1;
1228*8485SPeter.Memishian@Sun.COM 				(void) printf("%s ", value);
1229*8485SPeter.Memishian@Sun.COM 				continue;
1230*8485SPeter.Memishian@Sun.COM 			}
1231*8485SPeter.Memishian@Sun.COM 
1232*8485SPeter.Memishian@Sun.COM 			if (overflow > 0) {
1233*8485SPeter.Memishian@Sun.COM 				compress = MIN(overflow, width - valwidth);
1234*8485SPeter.Memishian@Sun.COM 				overflow -= compress;
1235*8485SPeter.Memishian@Sun.COM 				width -= compress;
1236*8485SPeter.Memishian@Sun.COM 			}
1237*8485SPeter.Memishian@Sun.COM 			(void) printf("%-*s", width, value);
1238*8485SPeter.Memishian@Sun.COM 		}
1239*8485SPeter.Memishian@Sun.COM 	}
1240*8485SPeter.Memishian@Sun.COM 	(void) printf("\n");
1241*8485SPeter.Memishian@Sun.COM 
1242*8485SPeter.Memishian@Sun.COM 	/*
1243*8485SPeter.Memishian@Sun.COM 	 * In case stdout has been redirected to e.g. a pipe, flush stdout so
1244*8485SPeter.Memishian@Sun.COM 	 * that commands can act on our output immediately.
1245*8485SPeter.Memishian@Sun.COM 	 */
1246*8485SPeter.Memishian@Sun.COM 	(void) fflush(stdout);
1247*8485SPeter.Memishian@Sun.COM }
1248*8485SPeter.Memishian@Sun.COM 
1249*8485SPeter.Memishian@Sun.COM /*
1250*8485SPeter.Memishian@Sun.COM  * Searches the `fields' array for a field matching `fieldname'.  Returns
1251*8485SPeter.Memishian@Sun.COM  * a pointer to that field on success, or NULL on failure.
1252*8485SPeter.Memishian@Sun.COM  */
1253*8485SPeter.Memishian@Sun.COM static ipmpstat_field_t *
1254*8485SPeter.Memishian@Sun.COM field_find(ipmpstat_field_t *fields, const char *fieldname)
1255*8485SPeter.Memishian@Sun.COM {
1256*8485SPeter.Memishian@Sun.COM 	ipmpstat_field_t *fieldp;
1257*8485SPeter.Memishian@Sun.COM 
1258*8485SPeter.Memishian@Sun.COM 	for (fieldp = fields; fieldp->f_name != NULL; fieldp++) {
1259*8485SPeter.Memishian@Sun.COM 		if (strcasecmp(fieldp->f_name, fieldname) == 0)
1260*8485SPeter.Memishian@Sun.COM 			return (fieldp);
1261*8485SPeter.Memishian@Sun.COM 	}
1262*8485SPeter.Memishian@Sun.COM 	return (NULL);
1263*8485SPeter.Memishian@Sun.COM }
1264*8485SPeter.Memishian@Sun.COM 
1265*8485SPeter.Memishian@Sun.COM /*
1266*8485SPeter.Memishian@Sun.COM  * Uses `enums' to map `enumval' to a string, and stores at most `bufsize'
1267*8485SPeter.Memishian@Sun.COM  * bytes of that string into `buf'.
1268*8485SPeter.Memishian@Sun.COM  */
1269*8485SPeter.Memishian@Sun.COM static void
1270*8485SPeter.Memishian@Sun.COM enum2str(const ipmpstat_enum_t *enums, int enumval, char *buf, uint_t bufsize)
1271*8485SPeter.Memishian@Sun.COM {
1272*8485SPeter.Memishian@Sun.COM 	const ipmpstat_enum_t *enump;
1273*8485SPeter.Memishian@Sun.COM 
1274*8485SPeter.Memishian@Sun.COM 	for (enump = enums; enump->e_name != NULL; enump++) {
1275*8485SPeter.Memishian@Sun.COM 		if (enump->e_val == enumval) {
1276*8485SPeter.Memishian@Sun.COM 			(void) strlcpy(buf, enump->e_name, bufsize);
1277*8485SPeter.Memishian@Sun.COM 			return;
1278*8485SPeter.Memishian@Sun.COM 		}
1279*8485SPeter.Memishian@Sun.COM 	}
1280*8485SPeter.Memishian@Sun.COM 	(void) snprintf(buf, bufsize, "<%d>", enumval);
1281*8485SPeter.Memishian@Sun.COM }
1282*8485SPeter.Memishian@Sun.COM 
1283*8485SPeter.Memishian@Sun.COM /*
1284*8485SPeter.Memishian@Sun.COM  * Stores the stringified value of the sockaddr_storage pointed to by `ssp'
1285*8485SPeter.Memishian@Sun.COM  * into at most `bufsize' bytes of `buf'.
1286*8485SPeter.Memishian@Sun.COM  */
1287*8485SPeter.Memishian@Sun.COM static void
1288*8485SPeter.Memishian@Sun.COM sockaddr2str(const struct sockaddr_storage *ssp, char *buf, uint_t bufsize)
1289*8485SPeter.Memishian@Sun.COM {
1290*8485SPeter.Memishian@Sun.COM 	int flags = NI_NOFQDN;
1291*8485SPeter.Memishian@Sun.COM 	socklen_t socklen;
1292*8485SPeter.Memishian@Sun.COM 	struct sockaddr *sp = (struct sockaddr *)ssp;
1293*8485SPeter.Memishian@Sun.COM 
1294*8485SPeter.Memishian@Sun.COM 	/*
1295*8485SPeter.Memishian@Sun.COM 	 * Sadly, getnameinfo() does not allow the socklen to be oversized for
1296*8485SPeter.Memishian@Sun.COM 	 * a given family -- so we must determine the exact size to pass to it.
1297*8485SPeter.Memishian@Sun.COM 	 */
1298*8485SPeter.Memishian@Sun.COM 	switch (ssp->ss_family) {
1299*8485SPeter.Memishian@Sun.COM 	case AF_INET:
1300*8485SPeter.Memishian@Sun.COM 		socklen = sizeof (struct sockaddr_in);
1301*8485SPeter.Memishian@Sun.COM 		break;
1302*8485SPeter.Memishian@Sun.COM 	case AF_INET6:
1303*8485SPeter.Memishian@Sun.COM 		socklen = sizeof (struct sockaddr_in6);
1304*8485SPeter.Memishian@Sun.COM 		break;
1305*8485SPeter.Memishian@Sun.COM 	default:
1306*8485SPeter.Memishian@Sun.COM 		(void) strlcpy(buf, "?", bufsize);
1307*8485SPeter.Memishian@Sun.COM 		return;
1308*8485SPeter.Memishian@Sun.COM 	}
1309*8485SPeter.Memishian@Sun.COM 
1310*8485SPeter.Memishian@Sun.COM 	if (opt & IPMPSTAT_OPT_NUMERIC)
1311*8485SPeter.Memishian@Sun.COM 		flags |= NI_NUMERICHOST;
1312*8485SPeter.Memishian@Sun.COM 
1313*8485SPeter.Memishian@Sun.COM 	(void) getnameinfo(sp, socklen, buf, bufsize, NULL, 0, flags);
1314*8485SPeter.Memishian@Sun.COM }
1315*8485SPeter.Memishian@Sun.COM 
1316*8485SPeter.Memishian@Sun.COM static void
1317*8485SPeter.Memishian@Sun.COM sighandler(int sig)
1318*8485SPeter.Memishian@Sun.COM {
1319*8485SPeter.Memishian@Sun.COM 	assert(sig == SIGWINCH);
1320*8485SPeter.Memishian@Sun.COM 
1321*8485SPeter.Memishian@Sun.COM 	if (ioctl(1, TIOCGWINSZ, &winsize) == -1 ||
1322*8485SPeter.Memishian@Sun.COM 	    winsize.ws_col == 0 || winsize.ws_row == 0) {
1323*8485SPeter.Memishian@Sun.COM 		winsize.ws_col = 80;
1324*8485SPeter.Memishian@Sun.COM 		winsize.ws_row = 24;
1325*8485SPeter.Memishian@Sun.COM 	}
1326*8485SPeter.Memishian@Sun.COM }
1327*8485SPeter.Memishian@Sun.COM 
1328*8485SPeter.Memishian@Sun.COM static void
1329*8485SPeter.Memishian@Sun.COM usage(void)
1330*8485SPeter.Memishian@Sun.COM {
1331*8485SPeter.Memishian@Sun.COM 	const char *argstr = gettext("[-n] [-o <field> [-P]] -a|-g|-i|-p|-t");
1332*8485SPeter.Memishian@Sun.COM 
1333*8485SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, gettext("usage: %s %s\n"), progname, argstr);
1334*8485SPeter.Memishian@Sun.COM 	exit(EXIT_FAILURE);
1335*8485SPeter.Memishian@Sun.COM }
1336*8485SPeter.Memishian@Sun.COM 
1337*8485SPeter.Memishian@Sun.COM /* PRINTFLIKE1 */
1338*8485SPeter.Memishian@Sun.COM static void
1339*8485SPeter.Memishian@Sun.COM warn(const char *format, ...)
1340*8485SPeter.Memishian@Sun.COM {
1341*8485SPeter.Memishian@Sun.COM 	va_list alist;
1342*8485SPeter.Memishian@Sun.COM 	int error = errno;
1343*8485SPeter.Memishian@Sun.COM 
1344*8485SPeter.Memishian@Sun.COM 	format = gettext(format);
1345*8485SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
1346*8485SPeter.Memishian@Sun.COM 
1347*8485SPeter.Memishian@Sun.COM 	va_start(alist, format);
1348*8485SPeter.Memishian@Sun.COM 	(void) vfprintf(stderr, format, alist);
1349*8485SPeter.Memishian@Sun.COM 	va_end(alist);
1350*8485SPeter.Memishian@Sun.COM 
1351*8485SPeter.Memishian@Sun.COM 	if (strchr(format, '\n') == NULL)
1352*8485SPeter.Memishian@Sun.COM 		(void) fprintf(stderr, ": %s\n", strerror(error));
1353*8485SPeter.Memishian@Sun.COM }
1354*8485SPeter.Memishian@Sun.COM 
1355*8485SPeter.Memishian@Sun.COM /* PRINTFLIKE2 */
1356*8485SPeter.Memishian@Sun.COM static void
1357*8485SPeter.Memishian@Sun.COM warn_ipmperr(int ipmperr, const char *format, ...)
1358*8485SPeter.Memishian@Sun.COM {
1359*8485SPeter.Memishian@Sun.COM 	va_list alist;
1360*8485SPeter.Memishian@Sun.COM 
1361*8485SPeter.Memishian@Sun.COM 	format = gettext(format);
1362*8485SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, gettext("%s: warning: "), progname);
1363*8485SPeter.Memishian@Sun.COM 
1364*8485SPeter.Memishian@Sun.COM 	va_start(alist, format);
1365*8485SPeter.Memishian@Sun.COM 	(void) vfprintf(stderr, format, alist);
1366*8485SPeter.Memishian@Sun.COM 	va_end(alist);
1367*8485SPeter.Memishian@Sun.COM 
1368*8485SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, ": %s\n", ipmp_errmsg(ipmperr));
1369*8485SPeter.Memishian@Sun.COM }
1370*8485SPeter.Memishian@Sun.COM 
1371*8485SPeter.Memishian@Sun.COM /* PRINTFLIKE1 */
1372*8485SPeter.Memishian@Sun.COM static void
1373*8485SPeter.Memishian@Sun.COM die(const char *format, ...)
1374*8485SPeter.Memishian@Sun.COM {
1375*8485SPeter.Memishian@Sun.COM 	va_list alist;
1376*8485SPeter.Memishian@Sun.COM 	int error = errno;
1377*8485SPeter.Memishian@Sun.COM 
1378*8485SPeter.Memishian@Sun.COM 	format = gettext(format);
1379*8485SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, "%s: ", progname);
1380*8485SPeter.Memishian@Sun.COM 
1381*8485SPeter.Memishian@Sun.COM 	va_start(alist, format);
1382*8485SPeter.Memishian@Sun.COM 	(void) vfprintf(stderr, format, alist);
1383*8485SPeter.Memishian@Sun.COM 	va_end(alist);
1384*8485SPeter.Memishian@Sun.COM 
1385*8485SPeter.Memishian@Sun.COM 	if (strchr(format, '\n') == NULL)
1386*8485SPeter.Memishian@Sun.COM 		(void) fprintf(stderr, ": %s\n", strerror(error));
1387*8485SPeter.Memishian@Sun.COM 
1388*8485SPeter.Memishian@Sun.COM 	exit(EXIT_FAILURE);
1389*8485SPeter.Memishian@Sun.COM }
1390*8485SPeter.Memishian@Sun.COM 
1391*8485SPeter.Memishian@Sun.COM /* PRINTFLIKE2 */
1392*8485SPeter.Memishian@Sun.COM static void
1393*8485SPeter.Memishian@Sun.COM die_ipmperr(int ipmperr, const char *format, ...)
1394*8485SPeter.Memishian@Sun.COM {
1395*8485SPeter.Memishian@Sun.COM 	va_list alist;
1396*8485SPeter.Memishian@Sun.COM 
1397*8485SPeter.Memishian@Sun.COM 	format = gettext(format);
1398*8485SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, "%s: ", progname);
1399*8485SPeter.Memishian@Sun.COM 
1400*8485SPeter.Memishian@Sun.COM 	va_start(alist, format);
1401*8485SPeter.Memishian@Sun.COM 	(void) vfprintf(stderr, format, alist);
1402*8485SPeter.Memishian@Sun.COM 	va_end(alist);
1403*8485SPeter.Memishian@Sun.COM 	(void) fprintf(stderr, ": %s\n", ipmp_errmsg(ipmperr));
1404*8485SPeter.Memishian@Sun.COM 
1405*8485SPeter.Memishian@Sun.COM 	exit(EXIT_FAILURE);
1406*8485SPeter.Memishian@Sun.COM }
1407*8485SPeter.Memishian@Sun.COM 
1408*8485SPeter.Memishian@Sun.COM static ipmpstat_field_t addr_fields[] = {
1409*8485SPeter.Memishian@Sun.COM 	{ "ADDRESS",    26,	sfunc_addr_address	},
1410*8485SPeter.Memishian@Sun.COM 	{ "STATE",	7,	sfunc_addr_state	},
1411*8485SPeter.Memishian@Sun.COM 	{ "GROUP",	12,	sfunc_addr_group	},
1412*8485SPeter.Memishian@Sun.COM 	{ "INBOUND",	12,	sfunc_addr_inbound	},
1413*8485SPeter.Memishian@Sun.COM 	{ "OUTBOUND",	23,	sfunc_addr_outbound	},
1414*8485SPeter.Memishian@Sun.COM 	{ NULL,		0, 	NULL			}
1415*8485SPeter.Memishian@Sun.COM };
1416*8485SPeter.Memishian@Sun.COM 
1417*8485SPeter.Memishian@Sun.COM static ipmpstat_field_t group_fields[] = {
1418*8485SPeter.Memishian@Sun.COM 	{ "GROUP",	12, 	sfunc_group_ifname	},
1419*8485SPeter.Memishian@Sun.COM 	{ "GROUPNAME",	12,	sfunc_group_name 	},
1420*8485SPeter.Memishian@Sun.COM 	{ "STATE",	10,	sfunc_group_state	},
1421*8485SPeter.Memishian@Sun.COM 	{ "FDT",	10,	sfunc_group_fdt		},
1422*8485SPeter.Memishian@Sun.COM 	{ "INTERFACES",	30,	sfunc_group_interfaces	},
1423*8485SPeter.Memishian@Sun.COM 	{ NULL,		0, 	NULL			}
1424*8485SPeter.Memishian@Sun.COM };
1425*8485SPeter.Memishian@Sun.COM 
1426*8485SPeter.Memishian@Sun.COM static ipmpstat_field_t if_fields[] = {
1427*8485SPeter.Memishian@Sun.COM 	{ "INTERFACE",	12,	sfunc_if_name		},
1428*8485SPeter.Memishian@Sun.COM 	{ "ACTIVE",	8, 	sfunc_if_active		},
1429*8485SPeter.Memishian@Sun.COM 	{ "GROUP",	12,	sfunc_if_group		},
1430*8485SPeter.Memishian@Sun.COM 	{ "FLAGS",	10,	sfunc_if_flags		},
1431*8485SPeter.Memishian@Sun.COM 	{ "LINK",	10,	sfunc_if_link		},
1432*8485SPeter.Memishian@Sun.COM 	{ "PROBE",	10,	sfunc_if_probe		},
1433*8485SPeter.Memishian@Sun.COM 	{ "STATE",	10, 	sfunc_if_state		},
1434*8485SPeter.Memishian@Sun.COM 	{ NULL,		0, 	NULL			}
1435*8485SPeter.Memishian@Sun.COM };
1436*8485SPeter.Memishian@Sun.COM 
1437*8485SPeter.Memishian@Sun.COM static ipmpstat_field_t probe_fields[] = {
1438*8485SPeter.Memishian@Sun.COM 	{ "TIME",	10,	sfunc_probe_time	},
1439*8485SPeter.Memishian@Sun.COM 	{ "INTERFACE",	12,	sfunc_probe_ifname	},
1440*8485SPeter.Memishian@Sun.COM 	{ "PROBE",	7,	sfunc_probe_id		},
1441*8485SPeter.Memishian@Sun.COM 	{ "NETRTT",	10,	sfunc_probe_netrtt	},
1442*8485SPeter.Memishian@Sun.COM 	{ "RTT",	10,	sfunc_probe_rtt		},
1443*8485SPeter.Memishian@Sun.COM 	{ "RTTAVG",	10,	sfunc_probe_rttavg	},
1444*8485SPeter.Memishian@Sun.COM 	{ "TARGET",	20,	sfunc_probe_target	},
1445*8485SPeter.Memishian@Sun.COM 	{ "RTTDEV",	10,	sfunc_probe_rttdev	},
1446*8485SPeter.Memishian@Sun.COM 	{ NULL,		0, 	NULL			}
1447*8485SPeter.Memishian@Sun.COM };
1448*8485SPeter.Memishian@Sun.COM 
1449*8485SPeter.Memishian@Sun.COM static ipmpstat_field_t targ_fields[] = {
1450*8485SPeter.Memishian@Sun.COM 	{ "INTERFACE",	12,	sfunc_targ_ifname	},
1451*8485SPeter.Memishian@Sun.COM 	{ "MODE",	10,	sfunc_targ_mode		},
1452*8485SPeter.Memishian@Sun.COM 	{ "TESTADDR",	20,	sfunc_targ_testaddr	},
1453*8485SPeter.Memishian@Sun.COM 	{ "TARGETS",	38,	sfunc_targ_targets	},
1454*8485SPeter.Memishian@Sun.COM 	{ NULL,		0, 	NULL			}
1455*8485SPeter.Memishian@Sun.COM };
1456*8485SPeter.Memishian@Sun.COM 
1457*8485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	addr_state[] = {
1458*8485SPeter.Memishian@Sun.COM 	{ "up",		IPMP_ADDR_UP			},
1459*8485SPeter.Memishian@Sun.COM 	{ "down",	IPMP_ADDR_DOWN			},
1460*8485SPeter.Memishian@Sun.COM 	{ NULL,		0 				}
1461*8485SPeter.Memishian@Sun.COM };
1462*8485SPeter.Memishian@Sun.COM 
1463*8485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	group_state[] = {
1464*8485SPeter.Memishian@Sun.COM 	{ "ok",		IPMP_GROUP_OK 			},
1465*8485SPeter.Memishian@Sun.COM 	{ "failed",	IPMP_GROUP_FAILED		},
1466*8485SPeter.Memishian@Sun.COM 	{ "degraded",	IPMP_GROUP_DEGRADED		},
1467*8485SPeter.Memishian@Sun.COM 	{ NULL,		0 				}
1468*8485SPeter.Memishian@Sun.COM };
1469*8485SPeter.Memishian@Sun.COM 
1470*8485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	if_link[] = {
1471*8485SPeter.Memishian@Sun.COM 	{ "up",		IPMP_LINK_UP 			},
1472*8485SPeter.Memishian@Sun.COM 	{ "down",	IPMP_LINK_DOWN			},
1473*8485SPeter.Memishian@Sun.COM 	{ "unknown",	IPMP_LINK_UNKNOWN		},
1474*8485SPeter.Memishian@Sun.COM 	{ NULL,		0 				}
1475*8485SPeter.Memishian@Sun.COM };
1476*8485SPeter.Memishian@Sun.COM 
1477*8485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	if_probe[] = {
1478*8485SPeter.Memishian@Sun.COM 	{ "ok",		IPMP_PROBE_OK 			},
1479*8485SPeter.Memishian@Sun.COM 	{ "failed",	IPMP_PROBE_FAILED		},
1480*8485SPeter.Memishian@Sun.COM 	{ "unknown",	IPMP_PROBE_UNKNOWN		},
1481*8485SPeter.Memishian@Sun.COM 	{ "disabled",	IPMP_PROBE_DISABLED		},
1482*8485SPeter.Memishian@Sun.COM 	{ NULL,		0 				}
1483*8485SPeter.Memishian@Sun.COM };
1484*8485SPeter.Memishian@Sun.COM 
1485*8485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	if_state[] = {
1486*8485SPeter.Memishian@Sun.COM 	{ "ok",		IPMP_IF_OK 			},
1487*8485SPeter.Memishian@Sun.COM 	{ "failed",	IPMP_IF_FAILED			},
1488*8485SPeter.Memishian@Sun.COM 	{ "unknown",	IPMP_IF_UNKNOWN			},
1489*8485SPeter.Memishian@Sun.COM 	{ "offline",	IPMP_IF_OFFLINE			},
1490*8485SPeter.Memishian@Sun.COM 	{ NULL,		0 				}
1491*8485SPeter.Memishian@Sun.COM };
1492*8485SPeter.Memishian@Sun.COM 
1493*8485SPeter.Memishian@Sun.COM static ipmpstat_enum_t	targ_mode[] = {
1494*8485SPeter.Memishian@Sun.COM 	{ "disabled",	IPMP_TARG_DISABLED		},
1495*8485SPeter.Memishian@Sun.COM 	{ "routes",	IPMP_TARG_ROUTES		},
1496*8485SPeter.Memishian@Sun.COM 	{ "multicast",	IPMP_TARG_MULTICAST		},
1497*8485SPeter.Memishian@Sun.COM 	{ NULL,		0 				}
1498*8485SPeter.Memishian@Sun.COM };
1499