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