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