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