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