1*0dc2366fSVenugopal Iyer /* 2*0dc2366fSVenugopal Iyer * CDDL HEADER START 3*0dc2366fSVenugopal Iyer * 4*0dc2366fSVenugopal Iyer * The contents of this file are subject to the terms of the 5*0dc2366fSVenugopal Iyer * Common Development and Distribution License (the "License"). 6*0dc2366fSVenugopal Iyer * You may not use this file except in compliance with the License. 7*0dc2366fSVenugopal Iyer * 8*0dc2366fSVenugopal Iyer * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*0dc2366fSVenugopal Iyer * or http://www.opensolaris.org/os/licensing. 10*0dc2366fSVenugopal Iyer * See the License for the specific language governing permissions 11*0dc2366fSVenugopal Iyer * and limitations under the License. 12*0dc2366fSVenugopal Iyer * 13*0dc2366fSVenugopal Iyer * When distributing Covered Code, include this CDDL HEADER in each 14*0dc2366fSVenugopal Iyer * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*0dc2366fSVenugopal Iyer * If applicable, add the following below this CDDL HEADER, with the 16*0dc2366fSVenugopal Iyer * fields enclosed by brackets "[]" replaced with your own identifying 17*0dc2366fSVenugopal Iyer * information: Portions Copyright [yyyy] [name of copyright owner] 18*0dc2366fSVenugopal Iyer * 19*0dc2366fSVenugopal Iyer * CDDL HEADER END 20*0dc2366fSVenugopal Iyer */ 21*0dc2366fSVenugopal Iyer /* 22*0dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23*0dc2366fSVenugopal Iyer * Use is subject to license terms. 24*0dc2366fSVenugopal Iyer */ 25*0dc2366fSVenugopal Iyer 26*0dc2366fSVenugopal Iyer #include <stdio.h> 27*0dc2366fSVenugopal Iyer #include <locale.h> 28*0dc2366fSVenugopal Iyer #include <stdarg.h> 29*0dc2366fSVenugopal Iyer #include <stdlib.h> 30*0dc2366fSVenugopal Iyer #include <fcntl.h> 31*0dc2366fSVenugopal Iyer #include <string.h> 32*0dc2366fSVenugopal Iyer #include <stropts.h> 33*0dc2366fSVenugopal Iyer #include <errno.h> 34*0dc2366fSVenugopal Iyer #include <strings.h> 35*0dc2366fSVenugopal Iyer #include <getopt.h> 36*0dc2366fSVenugopal Iyer #include <unistd.h> 37*0dc2366fSVenugopal Iyer #include <priv.h> 38*0dc2366fSVenugopal Iyer #include <netdb.h> 39*0dc2366fSVenugopal Iyer #include <libintl.h> 40*0dc2366fSVenugopal Iyer #include <libdlflow.h> 41*0dc2366fSVenugopal Iyer #include <libdllink.h> 42*0dc2366fSVenugopal Iyer #include <libdlstat.h> 43*0dc2366fSVenugopal Iyer #include <sys/types.h> 44*0dc2366fSVenugopal Iyer #include <sys/socket.h> 45*0dc2366fSVenugopal Iyer #include <netinet/in.h> 46*0dc2366fSVenugopal Iyer #include <arpa/inet.h> 47*0dc2366fSVenugopal Iyer #include <sys/ethernet.h> 48*0dc2366fSVenugopal Iyer #include <inet/ip.h> 49*0dc2366fSVenugopal Iyer #include <inet/ip6.h> 50*0dc2366fSVenugopal Iyer #include <stddef.h> 51*0dc2366fSVenugopal Iyer #include <ofmt.h> 52*0dc2366fSVenugopal Iyer 53*0dc2366fSVenugopal Iyer typedef struct flow_chain_s { 54*0dc2366fSVenugopal Iyer char fc_flowname[MAXFLOWNAMELEN]; 55*0dc2366fSVenugopal Iyer boolean_t fc_visited; 56*0dc2366fSVenugopal Iyer flow_stat_t *fc_stat; 57*0dc2366fSVenugopal Iyer struct flow_chain_s *fc_next; 58*0dc2366fSVenugopal Iyer } flow_chain_t; 59*0dc2366fSVenugopal Iyer 60*0dc2366fSVenugopal Iyer typedef struct show_flow_state { 61*0dc2366fSVenugopal Iyer flow_chain_t *fs_flowchain; 62*0dc2366fSVenugopal Iyer ofmt_handle_t fs_ofmt; 63*0dc2366fSVenugopal Iyer char fs_unit; 64*0dc2366fSVenugopal Iyer boolean_t fs_parsable; 65*0dc2366fSVenugopal Iyer } show_flow_state_t; 66*0dc2366fSVenugopal Iyer 67*0dc2366fSVenugopal Iyer typedef struct show_history_state_s { 68*0dc2366fSVenugopal Iyer boolean_t us_plot; 69*0dc2366fSVenugopal Iyer boolean_t us_parsable; 70*0dc2366fSVenugopal Iyer boolean_t us_printheader; 71*0dc2366fSVenugopal Iyer boolean_t us_first; 72*0dc2366fSVenugopal Iyer boolean_t us_showall; 73*0dc2366fSVenugopal Iyer ofmt_handle_t us_ofmt; 74*0dc2366fSVenugopal Iyer } show_history_state_t; 75*0dc2366fSVenugopal Iyer 76*0dc2366fSVenugopal Iyer static void do_show_history(int, char **); 77*0dc2366fSVenugopal Iyer 78*0dc2366fSVenugopal Iyer static int query_flow_stats(dladm_handle_t, dladm_flow_attr_t *, void *); 79*0dc2366fSVenugopal Iyer static int query_link_flow_stats(dladm_handle_t, datalink_id_t, void *); 80*0dc2366fSVenugopal Iyer 81*0dc2366fSVenugopal Iyer static void die(const char *, ...); 82*0dc2366fSVenugopal Iyer static void die_optdup(int); 83*0dc2366fSVenugopal Iyer static void die_opterr(int, int, const char *); 84*0dc2366fSVenugopal Iyer static void die_dlerr(dladm_status_t, const char *, ...); 85*0dc2366fSVenugopal Iyer static void warn(const char *, ...); 86*0dc2366fSVenugopal Iyer 87*0dc2366fSVenugopal Iyer /* callback functions for printing output */ 88*0dc2366fSVenugopal Iyer static ofmt_cb_t print_default_cb, print_flow_stats_cb; 89*0dc2366fSVenugopal Iyer static void flowstat_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t); 90*0dc2366fSVenugopal Iyer 91*0dc2366fSVenugopal Iyer #define NULL_OFMT {NULL, 0, 0, NULL} 92*0dc2366fSVenugopal Iyer 93*0dc2366fSVenugopal Iyer /* 94*0dc2366fSVenugopal Iyer * structures for flowstat (printing live statistics) 95*0dc2366fSVenugopal Iyer */ 96*0dc2366fSVenugopal Iyer typedef enum { 97*0dc2366fSVenugopal Iyer FLOW_S_FLOW, 98*0dc2366fSVenugopal Iyer FLOW_S_IPKTS, 99*0dc2366fSVenugopal Iyer FLOW_S_RBYTES, 100*0dc2366fSVenugopal Iyer FLOW_S_IERRORS, 101*0dc2366fSVenugopal Iyer FLOW_S_OPKTS, 102*0dc2366fSVenugopal Iyer FLOW_S_OBYTES, 103*0dc2366fSVenugopal Iyer FLOW_S_OERRORS 104*0dc2366fSVenugopal Iyer } flow_s_field_index_t; 105*0dc2366fSVenugopal Iyer 106*0dc2366fSVenugopal Iyer static ofmt_field_t flow_s_fields[] = { 107*0dc2366fSVenugopal Iyer /* name, field width, index, callback */ 108*0dc2366fSVenugopal Iyer { "FLOW", 15, FLOW_S_FLOW, print_flow_stats_cb}, 109*0dc2366fSVenugopal Iyer { "IPKTS", 8, FLOW_S_IPKTS, print_flow_stats_cb}, 110*0dc2366fSVenugopal Iyer { "RBYTES", 8, FLOW_S_RBYTES, print_flow_stats_cb}, 111*0dc2366fSVenugopal Iyer { "IERRS", 8, FLOW_S_IERRORS, print_flow_stats_cb}, 112*0dc2366fSVenugopal Iyer { "OPKTS", 8, FLOW_S_OPKTS, print_flow_stats_cb}, 113*0dc2366fSVenugopal Iyer { "OBYTES", 8, FLOW_S_OBYTES, print_flow_stats_cb}, 114*0dc2366fSVenugopal Iyer { "OERRS", 8, FLOW_S_OERRORS, print_flow_stats_cb}, 115*0dc2366fSVenugopal Iyer NULL_OFMT} 116*0dc2366fSVenugopal Iyer ; 117*0dc2366fSVenugopal Iyer 118*0dc2366fSVenugopal Iyer typedef struct flow_args_s { 119*0dc2366fSVenugopal Iyer char *flow_s_flow; 120*0dc2366fSVenugopal Iyer flow_stat_t *flow_s_stat; 121*0dc2366fSVenugopal Iyer char flow_s_unit; 122*0dc2366fSVenugopal Iyer boolean_t flow_s_parsable; 123*0dc2366fSVenugopal Iyer } flow_args_t; 124*0dc2366fSVenugopal Iyer 125*0dc2366fSVenugopal Iyer /* 126*0dc2366fSVenugopal Iyer * structures for 'flowstat -h' 127*0dc2366fSVenugopal Iyer */ 128*0dc2366fSVenugopal Iyer typedef struct history_fields_buf_s { 129*0dc2366fSVenugopal Iyer char history_flow[12]; 130*0dc2366fSVenugopal Iyer char history_duration[10]; 131*0dc2366fSVenugopal Iyer char history_ipackets[9]; 132*0dc2366fSVenugopal Iyer char history_rbytes[10]; 133*0dc2366fSVenugopal Iyer char history_opackets[9]; 134*0dc2366fSVenugopal Iyer char history_obytes[10]; 135*0dc2366fSVenugopal Iyer char history_bandwidth[14]; 136*0dc2366fSVenugopal Iyer } history_fields_buf_t; 137*0dc2366fSVenugopal Iyer 138*0dc2366fSVenugopal Iyer static ofmt_field_t history_fields[] = { 139*0dc2366fSVenugopal Iyer /* name, field width, offset */ 140*0dc2366fSVenugopal Iyer { "FLOW", 13, 141*0dc2366fSVenugopal Iyer offsetof(history_fields_buf_t, history_flow), print_default_cb}, 142*0dc2366fSVenugopal Iyer { "DURATION", 11, 143*0dc2366fSVenugopal Iyer offsetof(history_fields_buf_t, history_duration), print_default_cb}, 144*0dc2366fSVenugopal Iyer { "IPACKETS", 10, 145*0dc2366fSVenugopal Iyer offsetof(history_fields_buf_t, history_ipackets), print_default_cb}, 146*0dc2366fSVenugopal Iyer { "RBYTES", 11, 147*0dc2366fSVenugopal Iyer offsetof(history_fields_buf_t, history_rbytes), print_default_cb}, 148*0dc2366fSVenugopal Iyer { "OPACKETS", 10, 149*0dc2366fSVenugopal Iyer offsetof(history_fields_buf_t, history_opackets), print_default_cb}, 150*0dc2366fSVenugopal Iyer { "OBYTES", 11, 151*0dc2366fSVenugopal Iyer offsetof(history_fields_buf_t, history_obytes), print_default_cb}, 152*0dc2366fSVenugopal Iyer { "BANDWIDTH", 15, 153*0dc2366fSVenugopal Iyer offsetof(history_fields_buf_t, history_bandwidth), print_default_cb}, 154*0dc2366fSVenugopal Iyer NULL_OFMT} 155*0dc2366fSVenugopal Iyer ; 156*0dc2366fSVenugopal Iyer 157*0dc2366fSVenugopal Iyer typedef struct history_l_fields_buf_s { 158*0dc2366fSVenugopal Iyer char history_l_flow[12]; 159*0dc2366fSVenugopal Iyer char history_l_stime[13]; 160*0dc2366fSVenugopal Iyer char history_l_etime[13]; 161*0dc2366fSVenugopal Iyer char history_l_rbytes[8]; 162*0dc2366fSVenugopal Iyer char history_l_obytes[8]; 163*0dc2366fSVenugopal Iyer char history_l_bandwidth[14]; 164*0dc2366fSVenugopal Iyer } history_l_fields_buf_t; 165*0dc2366fSVenugopal Iyer 166*0dc2366fSVenugopal Iyer static ofmt_field_t history_l_fields[] = { 167*0dc2366fSVenugopal Iyer /* name, field width, offset */ 168*0dc2366fSVenugopal Iyer { "FLOW", 13, 169*0dc2366fSVenugopal Iyer offsetof(history_l_fields_buf_t, history_l_flow), print_default_cb}, 170*0dc2366fSVenugopal Iyer { "START", 14, 171*0dc2366fSVenugopal Iyer offsetof(history_l_fields_buf_t, history_l_stime), print_default_cb}, 172*0dc2366fSVenugopal Iyer { "END", 14, 173*0dc2366fSVenugopal Iyer offsetof(history_l_fields_buf_t, history_l_etime), print_default_cb}, 174*0dc2366fSVenugopal Iyer { "RBYTES", 9, 175*0dc2366fSVenugopal Iyer offsetof(history_l_fields_buf_t, history_l_rbytes), print_default_cb}, 176*0dc2366fSVenugopal Iyer { "OBYTES", 9, 177*0dc2366fSVenugopal Iyer offsetof(history_l_fields_buf_t, history_l_obytes), print_default_cb}, 178*0dc2366fSVenugopal Iyer { "BANDWIDTH", 15, 179*0dc2366fSVenugopal Iyer offsetof(history_l_fields_buf_t, history_l_bandwidth), 180*0dc2366fSVenugopal Iyer print_default_cb}, 181*0dc2366fSVenugopal Iyer NULL_OFMT} 182*0dc2366fSVenugopal Iyer ; 183*0dc2366fSVenugopal Iyer 184*0dc2366fSVenugopal Iyer static char *progname; 185*0dc2366fSVenugopal Iyer 186*0dc2366fSVenugopal Iyer /* 187*0dc2366fSVenugopal Iyer * Handle to libdladm. Opened in main() before the sub-command 188*0dc2366fSVenugopal Iyer * specific function is called. 189*0dc2366fSVenugopal Iyer */ 190*0dc2366fSVenugopal Iyer static dladm_handle_t handle = NULL; 191*0dc2366fSVenugopal Iyer 192*0dc2366fSVenugopal Iyer const char *usage_ermsg = "flowstat [-r | -t] [-i interval] " 193*0dc2366fSVenugopal Iyer "[-l link] [flow]\n" 194*0dc2366fSVenugopal Iyer " flowstat [-S] [-A] [-i interval] [-p] [ -o field[,...]]\n" 195*0dc2366fSVenugopal Iyer " [-u R|K|M|G|T|P] [-l link] [flow]\n" 196*0dc2366fSVenugopal Iyer " flowstat -h [-a] [-d] [-F format]" 197*0dc2366fSVenugopal Iyer " [-s <DD/MM/YYYY,HH:MM:SS>]\n" 198*0dc2366fSVenugopal Iyer " [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> " 199*0dc2366fSVenugopal Iyer "[<flow>]"; 200*0dc2366fSVenugopal Iyer 201*0dc2366fSVenugopal Iyer static void 202*0dc2366fSVenugopal Iyer usage(void) 203*0dc2366fSVenugopal Iyer { 204*0dc2366fSVenugopal Iyer (void) fprintf(stderr, "%s\n", gettext(usage_ermsg)); 205*0dc2366fSVenugopal Iyer 206*0dc2366fSVenugopal Iyer /* close dladm handle if it was opened */ 207*0dc2366fSVenugopal Iyer if (handle != NULL) 208*0dc2366fSVenugopal Iyer dladm_close(handle); 209*0dc2366fSVenugopal Iyer 210*0dc2366fSVenugopal Iyer exit(1); 211*0dc2366fSVenugopal Iyer } 212*0dc2366fSVenugopal Iyer 213*0dc2366fSVenugopal Iyer boolean_t 214*0dc2366fSVenugopal Iyer flowstat_unit(char *oarg, char *unit) 215*0dc2366fSVenugopal Iyer { 216*0dc2366fSVenugopal Iyer if ((strcmp(oarg, "R") == 0) || (strcmp(oarg, "K") == 0) || 217*0dc2366fSVenugopal Iyer (strcmp(oarg, "M") == 0) || (strcmp(oarg, "G") == 0) || 218*0dc2366fSVenugopal Iyer (strcmp(oarg, "T") == 0) || (strcmp(oarg, "P") == 0)) { 219*0dc2366fSVenugopal Iyer *unit = oarg[0]; 220*0dc2366fSVenugopal Iyer return (B_TRUE); 221*0dc2366fSVenugopal Iyer } 222*0dc2366fSVenugopal Iyer 223*0dc2366fSVenugopal Iyer return (B_FALSE); 224*0dc2366fSVenugopal Iyer } 225*0dc2366fSVenugopal Iyer 226*0dc2366fSVenugopal Iyer void 227*0dc2366fSVenugopal Iyer map_to_units(char *buf, uint_t bufsize, double num, char unit, 228*0dc2366fSVenugopal Iyer boolean_t parsable) 229*0dc2366fSVenugopal Iyer { 230*0dc2366fSVenugopal Iyer if (parsable) { 231*0dc2366fSVenugopal Iyer (void) snprintf(buf, bufsize, "%.0lf", num); 232*0dc2366fSVenugopal Iyer return; 233*0dc2366fSVenugopal Iyer } 234*0dc2366fSVenugopal Iyer 235*0dc2366fSVenugopal Iyer if (unit == '\0') { 236*0dc2366fSVenugopal Iyer int index; 237*0dc2366fSVenugopal Iyer 238*0dc2366fSVenugopal Iyer for (index = 0; (int)(num/1000) != 0; index++, num /= 1000) 239*0dc2366fSVenugopal Iyer ; 240*0dc2366fSVenugopal Iyer 241*0dc2366fSVenugopal Iyer switch (index) { 242*0dc2366fSVenugopal Iyer case 0: 243*0dc2366fSVenugopal Iyer unit = '\0'; 244*0dc2366fSVenugopal Iyer break; 245*0dc2366fSVenugopal Iyer case 1: 246*0dc2366fSVenugopal Iyer unit = 'K'; 247*0dc2366fSVenugopal Iyer break; 248*0dc2366fSVenugopal Iyer case 2: 249*0dc2366fSVenugopal Iyer unit = 'M'; 250*0dc2366fSVenugopal Iyer break; 251*0dc2366fSVenugopal Iyer case 3: 252*0dc2366fSVenugopal Iyer unit = 'G'; 253*0dc2366fSVenugopal Iyer break; 254*0dc2366fSVenugopal Iyer case 4: 255*0dc2366fSVenugopal Iyer unit = 'T'; 256*0dc2366fSVenugopal Iyer break; 257*0dc2366fSVenugopal Iyer case 5: 258*0dc2366fSVenugopal Iyer /* Largest unit supported */ 259*0dc2366fSVenugopal Iyer default: 260*0dc2366fSVenugopal Iyer unit = 'P'; 261*0dc2366fSVenugopal Iyer break; 262*0dc2366fSVenugopal Iyer } 263*0dc2366fSVenugopal Iyer } else { 264*0dc2366fSVenugopal Iyer switch (unit) { 265*0dc2366fSVenugopal Iyer case 'R': 266*0dc2366fSVenugopal Iyer /* Already raw numbers */ 267*0dc2366fSVenugopal Iyer unit = '\0'; 268*0dc2366fSVenugopal Iyer break; 269*0dc2366fSVenugopal Iyer case 'K': 270*0dc2366fSVenugopal Iyer num /= 1000; 271*0dc2366fSVenugopal Iyer break; 272*0dc2366fSVenugopal Iyer case 'M': 273*0dc2366fSVenugopal Iyer num /= (1000*1000); 274*0dc2366fSVenugopal Iyer break; 275*0dc2366fSVenugopal Iyer case 'G': 276*0dc2366fSVenugopal Iyer num /= (1000*1000*1000); 277*0dc2366fSVenugopal Iyer break; 278*0dc2366fSVenugopal Iyer case 'T': 279*0dc2366fSVenugopal Iyer num /= (1000.0*1000.0*1000.0*1000.0); 280*0dc2366fSVenugopal Iyer break; 281*0dc2366fSVenugopal Iyer case 'P': 282*0dc2366fSVenugopal Iyer /* Largest unit supported */ 283*0dc2366fSVenugopal Iyer default: 284*0dc2366fSVenugopal Iyer num /= (1000.0*1000.0*1000.0*1000.0*1000.0); 285*0dc2366fSVenugopal Iyer break; 286*0dc2366fSVenugopal Iyer } 287*0dc2366fSVenugopal Iyer } 288*0dc2366fSVenugopal Iyer 289*0dc2366fSVenugopal Iyer if (unit == '\0') 290*0dc2366fSVenugopal Iyer (void) snprintf(buf, bufsize, " %7.0lf%c", num, unit); 291*0dc2366fSVenugopal Iyer else 292*0dc2366fSVenugopal Iyer (void) snprintf(buf, bufsize, " %6.2lf%c", num, unit); 293*0dc2366fSVenugopal Iyer } 294*0dc2366fSVenugopal Iyer 295*0dc2366fSVenugopal Iyer flow_chain_t * 296*0dc2366fSVenugopal Iyer get_flow_prev_stat(const char *flowname, void *arg) 297*0dc2366fSVenugopal Iyer { 298*0dc2366fSVenugopal Iyer show_flow_state_t *state = arg; 299*0dc2366fSVenugopal Iyer flow_chain_t *flow_curr = NULL; 300*0dc2366fSVenugopal Iyer 301*0dc2366fSVenugopal Iyer /* Scan prev flowname list and look for entry matching this entry */ 302*0dc2366fSVenugopal Iyer for (flow_curr = state->fs_flowchain; flow_curr; 303*0dc2366fSVenugopal Iyer flow_curr = flow_curr->fc_next) { 304*0dc2366fSVenugopal Iyer if (strcmp(flow_curr->fc_flowname, flowname) == 0) 305*0dc2366fSVenugopal Iyer break; 306*0dc2366fSVenugopal Iyer } 307*0dc2366fSVenugopal Iyer 308*0dc2366fSVenugopal Iyer /* New flow, add it */ 309*0dc2366fSVenugopal Iyer if (flow_curr == NULL) { 310*0dc2366fSVenugopal Iyer flow_curr = (flow_chain_t *)malloc(sizeof (flow_chain_t)); 311*0dc2366fSVenugopal Iyer if (flow_curr == NULL) 312*0dc2366fSVenugopal Iyer goto done; 313*0dc2366fSVenugopal Iyer (void) strncpy(flow_curr->fc_flowname, flowname, 314*0dc2366fSVenugopal Iyer MAXFLOWNAMELEN); 315*0dc2366fSVenugopal Iyer flow_curr->fc_stat = NULL; 316*0dc2366fSVenugopal Iyer flow_curr->fc_next = state->fs_flowchain; 317*0dc2366fSVenugopal Iyer state->fs_flowchain = flow_curr; 318*0dc2366fSVenugopal Iyer } 319*0dc2366fSVenugopal Iyer done: 320*0dc2366fSVenugopal Iyer return (flow_curr); 321*0dc2366fSVenugopal Iyer } 322*0dc2366fSVenugopal Iyer 323*0dc2366fSVenugopal Iyer /* 324*0dc2366fSVenugopal Iyer * Number of flows may change while flowstat -i is executing. 325*0dc2366fSVenugopal Iyer * Free memory allocated for flows that are no longer there. 326*0dc2366fSVenugopal Iyer * Prepare for next iteration by marking visited = false for 327*0dc2366fSVenugopal Iyer * existing stat entries. 328*0dc2366fSVenugopal Iyer */ 329*0dc2366fSVenugopal Iyer static void 330*0dc2366fSVenugopal Iyer cleanup_removed_flows(show_flow_state_t *state) 331*0dc2366fSVenugopal Iyer { 332*0dc2366fSVenugopal Iyer flow_chain_t *fcurr; 333*0dc2366fSVenugopal Iyer flow_chain_t *fprev; 334*0dc2366fSVenugopal Iyer flow_chain_t *tofree; 335*0dc2366fSVenugopal Iyer 336*0dc2366fSVenugopal Iyer /* Delete all nodes from the list that have fc_visited marked false */ 337*0dc2366fSVenugopal Iyer fcurr = state->fs_flowchain; 338*0dc2366fSVenugopal Iyer while (fcurr != NULL) { 339*0dc2366fSVenugopal Iyer if (fcurr->fc_visited) { 340*0dc2366fSVenugopal Iyer fcurr->fc_visited = B_FALSE; 341*0dc2366fSVenugopal Iyer fprev = fcurr; 342*0dc2366fSVenugopal Iyer fcurr = fcurr->fc_next; 343*0dc2366fSVenugopal Iyer continue; 344*0dc2366fSVenugopal Iyer } 345*0dc2366fSVenugopal Iyer 346*0dc2366fSVenugopal Iyer /* Is it head of the list? */ 347*0dc2366fSVenugopal Iyer if (fcurr == state->fs_flowchain) 348*0dc2366fSVenugopal Iyer state->fs_flowchain = fcurr->fc_next; 349*0dc2366fSVenugopal Iyer else 350*0dc2366fSVenugopal Iyer fprev->fc_next = fcurr->fc_next; 351*0dc2366fSVenugopal Iyer 352*0dc2366fSVenugopal Iyer /* fprev remains the same */ 353*0dc2366fSVenugopal Iyer tofree = fcurr; 354*0dc2366fSVenugopal Iyer fcurr = fcurr->fc_next; 355*0dc2366fSVenugopal Iyer 356*0dc2366fSVenugopal Iyer /* Free stats memory for the removed flow */ 357*0dc2366fSVenugopal Iyer dladm_flow_stat_free(tofree->fc_stat); 358*0dc2366fSVenugopal Iyer free(tofree); 359*0dc2366fSVenugopal Iyer } 360*0dc2366fSVenugopal Iyer } 361*0dc2366fSVenugopal Iyer 362*0dc2366fSVenugopal Iyer static boolean_t 363*0dc2366fSVenugopal Iyer print_flow_stats_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 364*0dc2366fSVenugopal Iyer { 365*0dc2366fSVenugopal Iyer flow_args_t *fargs = of_arg->ofmt_cbarg; 366*0dc2366fSVenugopal Iyer flow_stat_t *diff_stats = fargs->flow_s_stat; 367*0dc2366fSVenugopal Iyer char unit = fargs->flow_s_unit; 368*0dc2366fSVenugopal Iyer boolean_t parsable = fargs->flow_s_parsable; 369*0dc2366fSVenugopal Iyer 370*0dc2366fSVenugopal Iyer switch (of_arg->ofmt_id) { 371*0dc2366fSVenugopal Iyer case FLOW_S_FLOW: 372*0dc2366fSVenugopal Iyer (void) snprintf(buf, bufsize, "%s", fargs->flow_s_flow); 373*0dc2366fSVenugopal Iyer break; 374*0dc2366fSVenugopal Iyer case FLOW_S_IPKTS: 375*0dc2366fSVenugopal Iyer map_to_units(buf, bufsize, diff_stats->fl_ipackets, unit, 376*0dc2366fSVenugopal Iyer parsable); 377*0dc2366fSVenugopal Iyer break; 378*0dc2366fSVenugopal Iyer case FLOW_S_RBYTES: 379*0dc2366fSVenugopal Iyer map_to_units(buf, bufsize, diff_stats->fl_rbytes, unit, 380*0dc2366fSVenugopal Iyer parsable); 381*0dc2366fSVenugopal Iyer break; 382*0dc2366fSVenugopal Iyer case FLOW_S_IERRORS: 383*0dc2366fSVenugopal Iyer map_to_units(buf, bufsize, diff_stats->fl_ierrors, unit, 384*0dc2366fSVenugopal Iyer parsable); 385*0dc2366fSVenugopal Iyer break; 386*0dc2366fSVenugopal Iyer case FLOW_S_OPKTS: 387*0dc2366fSVenugopal Iyer map_to_units(buf, bufsize, diff_stats->fl_opackets, unit, 388*0dc2366fSVenugopal Iyer parsable); 389*0dc2366fSVenugopal Iyer break; 390*0dc2366fSVenugopal Iyer case FLOW_S_OBYTES: 391*0dc2366fSVenugopal Iyer map_to_units(buf, bufsize, diff_stats->fl_obytes, unit, 392*0dc2366fSVenugopal Iyer parsable); 393*0dc2366fSVenugopal Iyer break; 394*0dc2366fSVenugopal Iyer case FLOW_S_OERRORS: 395*0dc2366fSVenugopal Iyer map_to_units(buf, bufsize, diff_stats->fl_oerrors, unit, 396*0dc2366fSVenugopal Iyer parsable); 397*0dc2366fSVenugopal Iyer break; 398*0dc2366fSVenugopal Iyer default: 399*0dc2366fSVenugopal Iyer die("invalid input"); 400*0dc2366fSVenugopal Iyer break; 401*0dc2366fSVenugopal Iyer } 402*0dc2366fSVenugopal Iyer return (B_TRUE); 403*0dc2366fSVenugopal Iyer } 404*0dc2366fSVenugopal Iyer 405*0dc2366fSVenugopal Iyer /* ARGSUSED */ 406*0dc2366fSVenugopal Iyer static int 407*0dc2366fSVenugopal Iyer query_flow_stats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg) 408*0dc2366fSVenugopal Iyer { 409*0dc2366fSVenugopal Iyer show_flow_state_t *state = arg; 410*0dc2366fSVenugopal Iyer flow_chain_t *flow_node; 411*0dc2366fSVenugopal Iyer flow_stat_t *curr_stat; 412*0dc2366fSVenugopal Iyer flow_stat_t *prev_stat; 413*0dc2366fSVenugopal Iyer flow_stat_t *diff_stat; 414*0dc2366fSVenugopal Iyer char *flowname = attr->fa_flowname; 415*0dc2366fSVenugopal Iyer flow_args_t fargs; 416*0dc2366fSVenugopal Iyer 417*0dc2366fSVenugopal Iyer /* Get previous stats for the flow */ 418*0dc2366fSVenugopal Iyer flow_node = get_flow_prev_stat(flowname, arg); 419*0dc2366fSVenugopal Iyer if (flow_node == NULL) 420*0dc2366fSVenugopal Iyer goto done; 421*0dc2366fSVenugopal Iyer 422*0dc2366fSVenugopal Iyer flow_node->fc_visited = B_TRUE; 423*0dc2366fSVenugopal Iyer prev_stat = flow_node->fc_stat; 424*0dc2366fSVenugopal Iyer 425*0dc2366fSVenugopal Iyer /* Query library for current stats */ 426*0dc2366fSVenugopal Iyer curr_stat = dladm_flow_stat_query(flowname); 427*0dc2366fSVenugopal Iyer if (curr_stat == NULL) 428*0dc2366fSVenugopal Iyer goto done; 429*0dc2366fSVenugopal Iyer 430*0dc2366fSVenugopal Iyer /* current stats - prev iteration stats */ 431*0dc2366fSVenugopal Iyer diff_stat = dladm_flow_stat_diff(curr_stat, prev_stat); 432*0dc2366fSVenugopal Iyer 433*0dc2366fSVenugopal Iyer /* Free prev stats */ 434*0dc2366fSVenugopal Iyer dladm_flow_stat_free(prev_stat); 435*0dc2366fSVenugopal Iyer 436*0dc2366fSVenugopal Iyer /* Prev <- curr stats */ 437*0dc2366fSVenugopal Iyer flow_node->fc_stat = curr_stat; 438*0dc2366fSVenugopal Iyer 439*0dc2366fSVenugopal Iyer if (diff_stat == NULL) 440*0dc2366fSVenugopal Iyer goto done; 441*0dc2366fSVenugopal Iyer 442*0dc2366fSVenugopal Iyer /* Print stats */ 443*0dc2366fSVenugopal Iyer fargs.flow_s_flow = flowname; 444*0dc2366fSVenugopal Iyer fargs.flow_s_stat = diff_stat; 445*0dc2366fSVenugopal Iyer fargs.flow_s_unit = state->fs_unit; 446*0dc2366fSVenugopal Iyer fargs.flow_s_parsable = state->fs_parsable; 447*0dc2366fSVenugopal Iyer ofmt_print(state->fs_ofmt, &fargs); 448*0dc2366fSVenugopal Iyer 449*0dc2366fSVenugopal Iyer /* Free diff stats */ 450*0dc2366fSVenugopal Iyer dladm_flow_stat_free(diff_stat); 451*0dc2366fSVenugopal Iyer done: 452*0dc2366fSVenugopal Iyer return (DLADM_WALK_CONTINUE); 453*0dc2366fSVenugopal Iyer } 454*0dc2366fSVenugopal Iyer 455*0dc2366fSVenugopal Iyer /* 456*0dc2366fSVenugopal Iyer * Wrapper of dladm_walk_flow(query_flow_stats,...) to make it usable for 457*0dc2366fSVenugopal Iyer * dladm_walk_datalink_id(). Used for showing flow stats for 458*0dc2366fSVenugopal Iyer * all flows on all links. 459*0dc2366fSVenugopal Iyer */ 460*0dc2366fSVenugopal Iyer static int 461*0dc2366fSVenugopal Iyer query_link_flow_stats(dladm_handle_t dh, datalink_id_t linkid, void * arg) 462*0dc2366fSVenugopal Iyer { 463*0dc2366fSVenugopal Iyer if (dladm_walk_flow(query_flow_stats, dh, linkid, arg, B_FALSE) 464*0dc2366fSVenugopal Iyer == DLADM_STATUS_OK) 465*0dc2366fSVenugopal Iyer return (DLADM_WALK_CONTINUE); 466*0dc2366fSVenugopal Iyer else 467*0dc2366fSVenugopal Iyer return (DLADM_WALK_TERMINATE); 468*0dc2366fSVenugopal Iyer } 469*0dc2366fSVenugopal Iyer 470*0dc2366fSVenugopal Iyer void 471*0dc2366fSVenugopal Iyer print_all_stats(name_value_stat_entry_t *stat_entry) 472*0dc2366fSVenugopal Iyer { 473*0dc2366fSVenugopal Iyer name_value_stat_t *curr_stat; 474*0dc2366fSVenugopal Iyer 475*0dc2366fSVenugopal Iyer printf("%s\n", stat_entry->nve_header); 476*0dc2366fSVenugopal Iyer 477*0dc2366fSVenugopal Iyer for (curr_stat = stat_entry->nve_stats; curr_stat != NULL; 478*0dc2366fSVenugopal Iyer curr_stat = curr_stat->nv_nextstat) { 479*0dc2366fSVenugopal Iyer printf("\t%15s", curr_stat->nv_statname); 480*0dc2366fSVenugopal Iyer printf("\t%15llu\n", curr_stat->nv_statval); 481*0dc2366fSVenugopal Iyer } 482*0dc2366fSVenugopal Iyer } 483*0dc2366fSVenugopal Iyer 484*0dc2366fSVenugopal Iyer /* ARGSUSED */ 485*0dc2366fSVenugopal Iyer static int 486*0dc2366fSVenugopal Iyer dump_one_flow_stats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg) 487*0dc2366fSVenugopal Iyer { 488*0dc2366fSVenugopal Iyer char *flowname = attr->fa_flowname; 489*0dc2366fSVenugopal Iyer void *stat; 490*0dc2366fSVenugopal Iyer 491*0dc2366fSVenugopal Iyer stat = dladm_flow_stat_query_all(flowname); 492*0dc2366fSVenugopal Iyer if (stat == NULL) 493*0dc2366fSVenugopal Iyer goto done; 494*0dc2366fSVenugopal Iyer print_all_stats(stat); 495*0dc2366fSVenugopal Iyer dladm_flow_stat_query_all_free(stat); 496*0dc2366fSVenugopal Iyer 497*0dc2366fSVenugopal Iyer done: 498*0dc2366fSVenugopal Iyer return (DLADM_WALK_CONTINUE); 499*0dc2366fSVenugopal Iyer } 500*0dc2366fSVenugopal Iyer 501*0dc2366fSVenugopal Iyer /* 502*0dc2366fSVenugopal Iyer * Wrapper of dladm_walk_flow(query_flow_stats,...) to make it usable for 503*0dc2366fSVenugopal Iyer * dladm_walk_datalink_id(). Used for showing flow stats for 504*0dc2366fSVenugopal Iyer * all flows on all links. 505*0dc2366fSVenugopal Iyer */ 506*0dc2366fSVenugopal Iyer static int 507*0dc2366fSVenugopal Iyer dump_link_flow_stats(dladm_handle_t dh, datalink_id_t linkid, void * arg) 508*0dc2366fSVenugopal Iyer { 509*0dc2366fSVenugopal Iyer if (dladm_walk_flow(dump_one_flow_stats, dh, linkid, arg, B_FALSE) 510*0dc2366fSVenugopal Iyer == DLADM_STATUS_OK) 511*0dc2366fSVenugopal Iyer return (DLADM_WALK_CONTINUE); 512*0dc2366fSVenugopal Iyer else 513*0dc2366fSVenugopal Iyer return (DLADM_WALK_TERMINATE); 514*0dc2366fSVenugopal Iyer } 515*0dc2366fSVenugopal Iyer 516*0dc2366fSVenugopal Iyer static void 517*0dc2366fSVenugopal Iyer dump_all_flow_stats(dladm_flow_attr_t *attrp, void *arg, datalink_id_t linkid, 518*0dc2366fSVenugopal Iyer boolean_t flow_arg) 519*0dc2366fSVenugopal Iyer { 520*0dc2366fSVenugopal Iyer /* Show stats for named flow */ 521*0dc2366fSVenugopal Iyer if (flow_arg) { 522*0dc2366fSVenugopal Iyer (void) dump_one_flow_stats(handle, attrp, arg); 523*0dc2366fSVenugopal Iyer 524*0dc2366fSVenugopal Iyer /* Show stats for flows on one link */ 525*0dc2366fSVenugopal Iyer } else if (linkid != DATALINK_INVALID_LINKID) { 526*0dc2366fSVenugopal Iyer (void) dladm_walk_flow(dump_one_flow_stats, handle, linkid, 527*0dc2366fSVenugopal Iyer arg, B_FALSE); 528*0dc2366fSVenugopal Iyer 529*0dc2366fSVenugopal Iyer /* Show stats for all flows on all links */ 530*0dc2366fSVenugopal Iyer } else { 531*0dc2366fSVenugopal Iyer (void) dladm_walk_datalink_id(dump_link_flow_stats, 532*0dc2366fSVenugopal Iyer handle, arg, DATALINK_CLASS_ALL, 533*0dc2366fSVenugopal Iyer DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 534*0dc2366fSVenugopal Iyer } 535*0dc2366fSVenugopal Iyer } 536*0dc2366fSVenugopal Iyer 537*0dc2366fSVenugopal Iyer int 538*0dc2366fSVenugopal Iyer main(int argc, char *argv[]) 539*0dc2366fSVenugopal Iyer { 540*0dc2366fSVenugopal Iyer dladm_status_t status; 541*0dc2366fSVenugopal Iyer int option; 542*0dc2366fSVenugopal Iyer boolean_t r_arg = B_FALSE; 543*0dc2366fSVenugopal Iyer boolean_t t_arg = B_FALSE; 544*0dc2366fSVenugopal Iyer boolean_t p_arg = B_FALSE; 545*0dc2366fSVenugopal Iyer boolean_t i_arg = B_FALSE; 546*0dc2366fSVenugopal Iyer boolean_t o_arg = B_FALSE; 547*0dc2366fSVenugopal Iyer boolean_t u_arg = B_FALSE; 548*0dc2366fSVenugopal Iyer boolean_t A_arg = B_FALSE; 549*0dc2366fSVenugopal Iyer boolean_t S_arg = B_FALSE; 550*0dc2366fSVenugopal Iyer boolean_t flow_arg = B_FALSE; 551*0dc2366fSVenugopal Iyer datalink_id_t linkid = DATALINK_ALL_LINKID; 552*0dc2366fSVenugopal Iyer char linkname[MAXLINKNAMELEN]; 553*0dc2366fSVenugopal Iyer char flowname[MAXFLOWNAMELEN]; 554*0dc2366fSVenugopal Iyer uint32_t interval = 0; 555*0dc2366fSVenugopal Iyer char unit = '\0'; 556*0dc2366fSVenugopal Iyer show_flow_state_t state; 557*0dc2366fSVenugopal Iyer char *fields_str = NULL; 558*0dc2366fSVenugopal Iyer char *o_fields_str = NULL; 559*0dc2366fSVenugopal Iyer 560*0dc2366fSVenugopal Iyer char *total_stat_fields = 561*0dc2366fSVenugopal Iyer "flow,ipkts,rbytes,ierrs,opkts,obytes,oerrs"; 562*0dc2366fSVenugopal Iyer char *rx_stat_fields = 563*0dc2366fSVenugopal Iyer "flow,ipkts,rbytes,ierrs"; 564*0dc2366fSVenugopal Iyer char *tx_stat_fields = 565*0dc2366fSVenugopal Iyer "flow,opkts,obytes,oerrs"; 566*0dc2366fSVenugopal Iyer 567*0dc2366fSVenugopal Iyer ofmt_handle_t ofmt; 568*0dc2366fSVenugopal Iyer ofmt_status_t oferr; 569*0dc2366fSVenugopal Iyer uint_t ofmtflags = OFMT_RIGHTJUST; 570*0dc2366fSVenugopal Iyer 571*0dc2366fSVenugopal Iyer dladm_flow_attr_t attr; 572*0dc2366fSVenugopal Iyer 573*0dc2366fSVenugopal Iyer (void) setlocale(LC_ALL, ""); 574*0dc2366fSVenugopal Iyer #if !defined(TEXT_DOMAIN) 575*0dc2366fSVenugopal Iyer #define TEXT_DOMAIN "SYS_TEST" 576*0dc2366fSVenugopal Iyer #endif 577*0dc2366fSVenugopal Iyer (void) textdomain(TEXT_DOMAIN); 578*0dc2366fSVenugopal Iyer 579*0dc2366fSVenugopal Iyer progname = argv[0]; 580*0dc2366fSVenugopal Iyer 581*0dc2366fSVenugopal Iyer /* Open the libdladm handle */ 582*0dc2366fSVenugopal Iyer if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) 583*0dc2366fSVenugopal Iyer die_dlerr(status, "could not open /dev/dld"); 584*0dc2366fSVenugopal Iyer 585*0dc2366fSVenugopal Iyer bzero(&state, sizeof (state)); 586*0dc2366fSVenugopal Iyer 587*0dc2366fSVenugopal Iyer opterr = 0; 588*0dc2366fSVenugopal Iyer while ((option = getopt_long(argc, argv, ":rtApSi:o:u:l:h", 589*0dc2366fSVenugopal Iyer NULL, NULL)) != -1) { 590*0dc2366fSVenugopal Iyer switch (option) { 591*0dc2366fSVenugopal Iyer case 'r': 592*0dc2366fSVenugopal Iyer if (r_arg) 593*0dc2366fSVenugopal Iyer die_optdup(option); 594*0dc2366fSVenugopal Iyer 595*0dc2366fSVenugopal Iyer r_arg = B_TRUE; 596*0dc2366fSVenugopal Iyer break; 597*0dc2366fSVenugopal Iyer case 't': 598*0dc2366fSVenugopal Iyer if (t_arg) 599*0dc2366fSVenugopal Iyer die_optdup(option); 600*0dc2366fSVenugopal Iyer 601*0dc2366fSVenugopal Iyer t_arg = B_TRUE; 602*0dc2366fSVenugopal Iyer break; 603*0dc2366fSVenugopal Iyer case 'A': 604*0dc2366fSVenugopal Iyer if (A_arg) 605*0dc2366fSVenugopal Iyer die_optdup(option); 606*0dc2366fSVenugopal Iyer 607*0dc2366fSVenugopal Iyer A_arg = B_TRUE; 608*0dc2366fSVenugopal Iyer break; 609*0dc2366fSVenugopal Iyer case 'p': 610*0dc2366fSVenugopal Iyer if (p_arg) 611*0dc2366fSVenugopal Iyer die_optdup(option); 612*0dc2366fSVenugopal Iyer 613*0dc2366fSVenugopal Iyer p_arg = B_TRUE; 614*0dc2366fSVenugopal Iyer break; 615*0dc2366fSVenugopal Iyer case 'S': 616*0dc2366fSVenugopal Iyer if (S_arg) 617*0dc2366fSVenugopal Iyer die_optdup(option); 618*0dc2366fSVenugopal Iyer S_arg = B_TRUE; 619*0dc2366fSVenugopal Iyer break; 620*0dc2366fSVenugopal Iyer case 'i': 621*0dc2366fSVenugopal Iyer if (i_arg) 622*0dc2366fSVenugopal Iyer die_optdup(option); 623*0dc2366fSVenugopal Iyer 624*0dc2366fSVenugopal Iyer i_arg = B_TRUE; 625*0dc2366fSVenugopal Iyer if (!dladm_str2interval(optarg, &interval)) 626*0dc2366fSVenugopal Iyer die("invalid interval value '%s'", optarg); 627*0dc2366fSVenugopal Iyer break; 628*0dc2366fSVenugopal Iyer case 'o': 629*0dc2366fSVenugopal Iyer o_arg = B_TRUE; 630*0dc2366fSVenugopal Iyer o_fields_str = optarg; 631*0dc2366fSVenugopal Iyer break; 632*0dc2366fSVenugopal Iyer case 'u': 633*0dc2366fSVenugopal Iyer if (u_arg) 634*0dc2366fSVenugopal Iyer die_optdup(option); 635*0dc2366fSVenugopal Iyer 636*0dc2366fSVenugopal Iyer u_arg = B_TRUE; 637*0dc2366fSVenugopal Iyer if (!flowstat_unit(optarg, &unit)) 638*0dc2366fSVenugopal Iyer die("invalid unit value '%s'," 639*0dc2366fSVenugopal Iyer "unit must be R|K|M|G|T|P", optarg); 640*0dc2366fSVenugopal Iyer break; 641*0dc2366fSVenugopal Iyer case 'l': 642*0dc2366fSVenugopal Iyer if (strlcpy(linkname, optarg, MAXLINKNAMELEN) 643*0dc2366fSVenugopal Iyer >= MAXLINKNAMELEN) 644*0dc2366fSVenugopal Iyer die("link name too long\n"); 645*0dc2366fSVenugopal Iyer if (dladm_name2info(handle, linkname, &linkid, NULL, 646*0dc2366fSVenugopal Iyer NULL, NULL) != DLADM_STATUS_OK) 647*0dc2366fSVenugopal Iyer die("invalid link '%s'", linkname); 648*0dc2366fSVenugopal Iyer break; 649*0dc2366fSVenugopal Iyer case 'h': 650*0dc2366fSVenugopal Iyer if (r_arg || t_arg || p_arg || o_arg || u_arg || 651*0dc2366fSVenugopal Iyer i_arg || S_arg || A_arg) { 652*0dc2366fSVenugopal Iyer die("the option -h is not compatible with " 653*0dc2366fSVenugopal Iyer "-r, -t, -p, -o, -u, -i, -S, -A"); 654*0dc2366fSVenugopal Iyer } 655*0dc2366fSVenugopal Iyer do_show_history(argc, argv); 656*0dc2366fSVenugopal Iyer return (0); 657*0dc2366fSVenugopal Iyer break; 658*0dc2366fSVenugopal Iyer default: 659*0dc2366fSVenugopal Iyer die_opterr(optopt, option, usage_ermsg); 660*0dc2366fSVenugopal Iyer break; 661*0dc2366fSVenugopal Iyer } 662*0dc2366fSVenugopal Iyer } 663*0dc2366fSVenugopal Iyer 664*0dc2366fSVenugopal Iyer if (r_arg && t_arg) 665*0dc2366fSVenugopal Iyer die("the option -t and -r are not compatible"); 666*0dc2366fSVenugopal Iyer 667*0dc2366fSVenugopal Iyer if (u_arg && p_arg) 668*0dc2366fSVenugopal Iyer die("the option -u and -p are not compatible"); 669*0dc2366fSVenugopal Iyer 670*0dc2366fSVenugopal Iyer if (p_arg && !o_arg) 671*0dc2366fSVenugopal Iyer die("-p requires -o"); 672*0dc2366fSVenugopal Iyer 673*0dc2366fSVenugopal Iyer if (p_arg && strcasecmp(o_fields_str, "all") == 0) 674*0dc2366fSVenugopal Iyer die("\"-o all\" is invalid with -p"); 675*0dc2366fSVenugopal Iyer 676*0dc2366fSVenugopal Iyer if (S_arg && 677*0dc2366fSVenugopal Iyer (r_arg || t_arg || p_arg || o_arg || u_arg)) 678*0dc2366fSVenugopal Iyer die("the option -S is not compatible with " 679*0dc2366fSVenugopal Iyer "-r, -t, -p, -o, -u"); 680*0dc2366fSVenugopal Iyer 681*0dc2366fSVenugopal Iyer if (A_arg && 682*0dc2366fSVenugopal Iyer (r_arg || t_arg || p_arg || o_arg || u_arg || i_arg)) 683*0dc2366fSVenugopal Iyer die("the option -A is not compatible with " 684*0dc2366fSVenugopal Iyer "-r, -t, -p, -o, -u, -i"); 685*0dc2366fSVenugopal Iyer 686*0dc2366fSVenugopal Iyer /* get flow name (optional last argument) */ 687*0dc2366fSVenugopal Iyer if (optind == (argc-1)) { 688*0dc2366fSVenugopal Iyer if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN) 689*0dc2366fSVenugopal Iyer >= MAXFLOWNAMELEN) 690*0dc2366fSVenugopal Iyer die("flow name too long"); 691*0dc2366fSVenugopal Iyer flow_arg = B_TRUE; 692*0dc2366fSVenugopal Iyer } else if (optind != argc) { 693*0dc2366fSVenugopal Iyer usage(); 694*0dc2366fSVenugopal Iyer } 695*0dc2366fSVenugopal Iyer 696*0dc2366fSVenugopal Iyer if (S_arg) { 697*0dc2366fSVenugopal Iyer dladm_continuous(handle, linkid, (flow_arg ? flowname : NULL), 698*0dc2366fSVenugopal Iyer interval, FLOW_REPORT); 699*0dc2366fSVenugopal Iyer return (0); 700*0dc2366fSVenugopal Iyer } 701*0dc2366fSVenugopal Iyer 702*0dc2366fSVenugopal Iyer if (flow_arg && 703*0dc2366fSVenugopal Iyer dladm_flow_info(handle, flowname, &attr) != DLADM_STATUS_OK) 704*0dc2366fSVenugopal Iyer die("invalid flow %s", flowname); 705*0dc2366fSVenugopal Iyer 706*0dc2366fSVenugopal Iyer if (A_arg) { 707*0dc2366fSVenugopal Iyer dump_all_flow_stats(&attr, &state, linkid, flow_arg); 708*0dc2366fSVenugopal Iyer return (0); 709*0dc2366fSVenugopal Iyer } 710*0dc2366fSVenugopal Iyer 711*0dc2366fSVenugopal Iyer state.fs_unit = unit; 712*0dc2366fSVenugopal Iyer state.fs_parsable = p_arg; 713*0dc2366fSVenugopal Iyer 714*0dc2366fSVenugopal Iyer if (state.fs_parsable) 715*0dc2366fSVenugopal Iyer ofmtflags |= OFMT_PARSABLE; 716*0dc2366fSVenugopal Iyer 717*0dc2366fSVenugopal Iyer if (r_arg) 718*0dc2366fSVenugopal Iyer fields_str = rx_stat_fields; 719*0dc2366fSVenugopal Iyer else if (t_arg) 720*0dc2366fSVenugopal Iyer fields_str = tx_stat_fields; 721*0dc2366fSVenugopal Iyer else 722*0dc2366fSVenugopal Iyer fields_str = total_stat_fields; 723*0dc2366fSVenugopal Iyer 724*0dc2366fSVenugopal Iyer if (o_arg) { 725*0dc2366fSVenugopal Iyer fields_str = (strcasecmp(o_fields_str, "all") == 0) ? 726*0dc2366fSVenugopal Iyer fields_str : o_fields_str; 727*0dc2366fSVenugopal Iyer } 728*0dc2366fSVenugopal Iyer 729*0dc2366fSVenugopal Iyer oferr = ofmt_open(fields_str, flow_s_fields, ofmtflags, 0, &ofmt); 730*0dc2366fSVenugopal Iyer flowstat_ofmt_check(oferr, state.fs_parsable, ofmt); 731*0dc2366fSVenugopal Iyer state.fs_ofmt = ofmt; 732*0dc2366fSVenugopal Iyer 733*0dc2366fSVenugopal Iyer for (;;) { 734*0dc2366fSVenugopal Iyer /* Show stats for named flow */ 735*0dc2366fSVenugopal Iyer if (flow_arg) { 736*0dc2366fSVenugopal Iyer (void) query_flow_stats(handle, &attr, &state); 737*0dc2366fSVenugopal Iyer 738*0dc2366fSVenugopal Iyer /* Show stats for flows on one link */ 739*0dc2366fSVenugopal Iyer } else if (linkid != DATALINK_INVALID_LINKID) { 740*0dc2366fSVenugopal Iyer (void) dladm_walk_flow(query_flow_stats, handle, linkid, 741*0dc2366fSVenugopal Iyer &state, B_FALSE); 742*0dc2366fSVenugopal Iyer 743*0dc2366fSVenugopal Iyer /* Show stats for all flows on all links */ 744*0dc2366fSVenugopal Iyer } else { 745*0dc2366fSVenugopal Iyer (void) dladm_walk_datalink_id(query_link_flow_stats, 746*0dc2366fSVenugopal Iyer handle, &state, DATALINK_CLASS_ALL, 747*0dc2366fSVenugopal Iyer DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 748*0dc2366fSVenugopal Iyer } 749*0dc2366fSVenugopal Iyer 750*0dc2366fSVenugopal Iyer if (interval == 0) 751*0dc2366fSVenugopal Iyer break; 752*0dc2366fSVenugopal Iyer 753*0dc2366fSVenugopal Iyer (void) fflush(stdout); 754*0dc2366fSVenugopal Iyer cleanup_removed_flows(&state); 755*0dc2366fSVenugopal Iyer (void) sleep(interval); 756*0dc2366fSVenugopal Iyer } 757*0dc2366fSVenugopal Iyer ofmt_close(ofmt); 758*0dc2366fSVenugopal Iyer 759*0dc2366fSVenugopal Iyer dladm_close(handle); 760*0dc2366fSVenugopal Iyer return (0); 761*0dc2366fSVenugopal Iyer } 762*0dc2366fSVenugopal Iyer 763*0dc2366fSVenugopal Iyer /* ARGSUSED */ 764*0dc2366fSVenugopal Iyer static int 765*0dc2366fSVenugopal Iyer show_history_date(dladm_usage_t *history, void *arg) 766*0dc2366fSVenugopal Iyer { 767*0dc2366fSVenugopal Iyer show_history_state_t *state = (show_history_state_t *)arg; 768*0dc2366fSVenugopal Iyer time_t stime; 769*0dc2366fSVenugopal Iyer char timebuf[20]; 770*0dc2366fSVenugopal Iyer dladm_flow_attr_t attr; 771*0dc2366fSVenugopal Iyer dladm_status_t status; 772*0dc2366fSVenugopal Iyer 773*0dc2366fSVenugopal Iyer /* 774*0dc2366fSVenugopal Iyer * Only show historical information for existing flows unless '-a' 775*0dc2366fSVenugopal Iyer * is specified. 776*0dc2366fSVenugopal Iyer */ 777*0dc2366fSVenugopal Iyer if (!state->us_showall && ((status = dladm_flow_info(handle, 778*0dc2366fSVenugopal Iyer history->du_name, &attr)) != DLADM_STATUS_OK)) { 779*0dc2366fSVenugopal Iyer return (status); 780*0dc2366fSVenugopal Iyer } 781*0dc2366fSVenugopal Iyer 782*0dc2366fSVenugopal Iyer stime = history->du_stime; 783*0dc2366fSVenugopal Iyer (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y", 784*0dc2366fSVenugopal Iyer localtime(&stime)); 785*0dc2366fSVenugopal Iyer (void) printf("%s\n", timebuf); 786*0dc2366fSVenugopal Iyer 787*0dc2366fSVenugopal Iyer return (DLADM_STATUS_OK); 788*0dc2366fSVenugopal Iyer } 789*0dc2366fSVenugopal Iyer 790*0dc2366fSVenugopal Iyer static int 791*0dc2366fSVenugopal Iyer show_history_time(dladm_usage_t *history, void *arg) 792*0dc2366fSVenugopal Iyer { 793*0dc2366fSVenugopal Iyer show_history_state_t *state = (show_history_state_t *)arg; 794*0dc2366fSVenugopal Iyer char buf[DLADM_STRSIZE]; 795*0dc2366fSVenugopal Iyer history_l_fields_buf_t ubuf; 796*0dc2366fSVenugopal Iyer time_t time; 797*0dc2366fSVenugopal Iyer double bw; 798*0dc2366fSVenugopal Iyer dladm_flow_attr_t attr; 799*0dc2366fSVenugopal Iyer dladm_status_t status; 800*0dc2366fSVenugopal Iyer 801*0dc2366fSVenugopal Iyer /* 802*0dc2366fSVenugopal Iyer * Only show historical information for existing flows unless '-a' 803*0dc2366fSVenugopal Iyer * is specified. 804*0dc2366fSVenugopal Iyer */ 805*0dc2366fSVenugopal Iyer if (!state->us_showall && ((status = dladm_flow_info(handle, 806*0dc2366fSVenugopal Iyer history->du_name, &attr)) != DLADM_STATUS_OK)) { 807*0dc2366fSVenugopal Iyer return (status); 808*0dc2366fSVenugopal Iyer } 809*0dc2366fSVenugopal Iyer 810*0dc2366fSVenugopal Iyer if (state->us_plot) { 811*0dc2366fSVenugopal Iyer if (!state->us_printheader) { 812*0dc2366fSVenugopal Iyer if (state->us_first) { 813*0dc2366fSVenugopal Iyer (void) printf("# Time"); 814*0dc2366fSVenugopal Iyer state->us_first = B_FALSE; 815*0dc2366fSVenugopal Iyer } 816*0dc2366fSVenugopal Iyer (void) printf(" %s", history->du_name); 817*0dc2366fSVenugopal Iyer if (history->du_last) { 818*0dc2366fSVenugopal Iyer (void) printf("\n"); 819*0dc2366fSVenugopal Iyer state->us_first = B_TRUE; 820*0dc2366fSVenugopal Iyer state->us_printheader = B_TRUE; 821*0dc2366fSVenugopal Iyer } 822*0dc2366fSVenugopal Iyer } else { 823*0dc2366fSVenugopal Iyer if (state->us_first) { 824*0dc2366fSVenugopal Iyer time = history->du_etime; 825*0dc2366fSVenugopal Iyer (void) strftime(buf, sizeof (buf), "%T", 826*0dc2366fSVenugopal Iyer localtime(&time)); 827*0dc2366fSVenugopal Iyer state->us_first = B_FALSE; 828*0dc2366fSVenugopal Iyer (void) printf("%s", buf); 829*0dc2366fSVenugopal Iyer } 830*0dc2366fSVenugopal Iyer bw = (double)history->du_bandwidth/1000; 831*0dc2366fSVenugopal Iyer (void) printf(" %.2f", bw); 832*0dc2366fSVenugopal Iyer if (history->du_last) { 833*0dc2366fSVenugopal Iyer (void) printf("\n"); 834*0dc2366fSVenugopal Iyer state->us_first = B_TRUE; 835*0dc2366fSVenugopal Iyer } 836*0dc2366fSVenugopal Iyer } 837*0dc2366fSVenugopal Iyer return (DLADM_STATUS_OK); 838*0dc2366fSVenugopal Iyer } 839*0dc2366fSVenugopal Iyer 840*0dc2366fSVenugopal Iyer bzero(&ubuf, sizeof (ubuf)); 841*0dc2366fSVenugopal Iyer 842*0dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_l_flow, sizeof (ubuf.history_l_flow), "%s", 843*0dc2366fSVenugopal Iyer history->du_name); 844*0dc2366fSVenugopal Iyer time = history->du_stime; 845*0dc2366fSVenugopal Iyer (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 846*0dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_l_stime, sizeof (ubuf.history_l_stime), 847*0dc2366fSVenugopal Iyer "%s", buf); 848*0dc2366fSVenugopal Iyer time = history->du_etime; 849*0dc2366fSVenugopal Iyer (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 850*0dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_l_etime, sizeof (ubuf.history_l_etime), 851*0dc2366fSVenugopal Iyer "%s", buf); 852*0dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_l_rbytes, sizeof (ubuf.history_l_rbytes), 853*0dc2366fSVenugopal Iyer "%llu", history->du_rbytes); 854*0dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_l_obytes, sizeof (ubuf.history_l_obytes), 855*0dc2366fSVenugopal Iyer "%llu", history->du_obytes); 856*0dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_l_bandwidth, 857*0dc2366fSVenugopal Iyer sizeof (ubuf.history_l_bandwidth), "%s Mbps", 858*0dc2366fSVenugopal Iyer dladm_bw2str(history->du_bandwidth, buf)); 859*0dc2366fSVenugopal Iyer 860*0dc2366fSVenugopal Iyer ofmt_print(state->us_ofmt, (void *)&ubuf); 861*0dc2366fSVenugopal Iyer return (DLADM_STATUS_OK); 862*0dc2366fSVenugopal Iyer } 863*0dc2366fSVenugopal Iyer 864*0dc2366fSVenugopal Iyer static int 865*0dc2366fSVenugopal Iyer show_history_res(dladm_usage_t *history, void *arg) 866*0dc2366fSVenugopal Iyer { 867*0dc2366fSVenugopal Iyer show_history_state_t *state = (show_history_state_t *)arg; 868*0dc2366fSVenugopal Iyer char buf[DLADM_STRSIZE]; 869*0dc2366fSVenugopal Iyer history_fields_buf_t ubuf; 870*0dc2366fSVenugopal Iyer dladm_flow_attr_t attr; 871*0dc2366fSVenugopal Iyer dladm_status_t status; 872*0dc2366fSVenugopal Iyer 873*0dc2366fSVenugopal Iyer /* 874*0dc2366fSVenugopal Iyer * Only show historical information for existing flows unless '-a' 875*0dc2366fSVenugopal Iyer * is specified. 876*0dc2366fSVenugopal Iyer */ 877*0dc2366fSVenugopal Iyer if (!state->us_showall && ((status = dladm_flow_info(handle, 878*0dc2366fSVenugopal Iyer history->du_name, &attr)) != DLADM_STATUS_OK)) { 879*0dc2366fSVenugopal Iyer return (status); 880*0dc2366fSVenugopal Iyer } 881*0dc2366fSVenugopal Iyer 882*0dc2366fSVenugopal Iyer bzero(&ubuf, sizeof (ubuf)); 883*0dc2366fSVenugopal Iyer 884*0dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_flow, sizeof (ubuf.history_flow), "%s", 885*0dc2366fSVenugopal Iyer history->du_name); 886*0dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_duration, sizeof (ubuf.history_duration), 887*0dc2366fSVenugopal Iyer "%llu", history->du_duration); 888*0dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_ipackets, sizeof (ubuf.history_ipackets), 889*0dc2366fSVenugopal Iyer "%llu", history->du_ipackets); 890*0dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_rbytes, sizeof (ubuf.history_rbytes), 891*0dc2366fSVenugopal Iyer "%llu", history->du_rbytes); 892*0dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_opackets, sizeof (ubuf.history_opackets), 893*0dc2366fSVenugopal Iyer "%llu", history->du_opackets); 894*0dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_obytes, sizeof (ubuf.history_obytes), 895*0dc2366fSVenugopal Iyer "%llu", history->du_obytes); 896*0dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_bandwidth, sizeof (ubuf.history_bandwidth), 897*0dc2366fSVenugopal Iyer "%s Mbps", dladm_bw2str(history->du_bandwidth, buf)); 898*0dc2366fSVenugopal Iyer 899*0dc2366fSVenugopal Iyer ofmt_print(state->us_ofmt, (void *)&ubuf); 900*0dc2366fSVenugopal Iyer 901*0dc2366fSVenugopal Iyer return (DLADM_STATUS_OK); 902*0dc2366fSVenugopal Iyer } 903*0dc2366fSVenugopal Iyer 904*0dc2366fSVenugopal Iyer static boolean_t 905*0dc2366fSVenugopal Iyer valid_formatspec(char *formatspec_str) 906*0dc2366fSVenugopal Iyer { 907*0dc2366fSVenugopal Iyer return (strcmp(formatspec_str, "gnuplot") == 0); 908*0dc2366fSVenugopal Iyer } 909*0dc2366fSVenugopal Iyer 910*0dc2366fSVenugopal Iyer /* ARGSUSED */ 911*0dc2366fSVenugopal Iyer static void 912*0dc2366fSVenugopal Iyer do_show_history(int argc, char *argv[]) 913*0dc2366fSVenugopal Iyer { 914*0dc2366fSVenugopal Iyer char *file = NULL; 915*0dc2366fSVenugopal Iyer int opt; 916*0dc2366fSVenugopal Iyer dladm_status_t status; 917*0dc2366fSVenugopal Iyer boolean_t d_arg = B_FALSE; 918*0dc2366fSVenugopal Iyer char *stime = NULL; 919*0dc2366fSVenugopal Iyer char *etime = NULL; 920*0dc2366fSVenugopal Iyer char *resource = NULL; 921*0dc2366fSVenugopal Iyer show_history_state_t state; 922*0dc2366fSVenugopal Iyer boolean_t o_arg = B_FALSE; 923*0dc2366fSVenugopal Iyer boolean_t F_arg = B_FALSE; 924*0dc2366fSVenugopal Iyer char *fields_str = NULL; 925*0dc2366fSVenugopal Iyer char *formatspec_str = NULL; 926*0dc2366fSVenugopal Iyer char *all_fields = 927*0dc2366fSVenugopal Iyer "flow,duration,ipackets,rbytes,opackets,obytes,bandwidth"; 928*0dc2366fSVenugopal Iyer char *all_l_fields = 929*0dc2366fSVenugopal Iyer "flow,start,end,rbytes,obytes,bandwidth"; 930*0dc2366fSVenugopal Iyer ofmt_handle_t ofmt; 931*0dc2366fSVenugopal Iyer ofmt_status_t oferr; 932*0dc2366fSVenugopal Iyer uint_t ofmtflags = 0; 933*0dc2366fSVenugopal Iyer 934*0dc2366fSVenugopal Iyer bzero(&state, sizeof (show_history_state_t)); 935*0dc2366fSVenugopal Iyer state.us_parsable = B_FALSE; 936*0dc2366fSVenugopal Iyer state.us_printheader = B_FALSE; 937*0dc2366fSVenugopal Iyer state.us_plot = B_FALSE; 938*0dc2366fSVenugopal Iyer state.us_first = B_TRUE; 939*0dc2366fSVenugopal Iyer 940*0dc2366fSVenugopal Iyer while ((opt = getopt(argc, argv, "das:e:o:f:F:")) != -1) { 941*0dc2366fSVenugopal Iyer switch (opt) { 942*0dc2366fSVenugopal Iyer case 'd': 943*0dc2366fSVenugopal Iyer d_arg = B_TRUE; 944*0dc2366fSVenugopal Iyer break; 945*0dc2366fSVenugopal Iyer case 'a': 946*0dc2366fSVenugopal Iyer state.us_showall = B_TRUE; 947*0dc2366fSVenugopal Iyer break; 948*0dc2366fSVenugopal Iyer case 'f': 949*0dc2366fSVenugopal Iyer file = optarg; 950*0dc2366fSVenugopal Iyer break; 951*0dc2366fSVenugopal Iyer case 's': 952*0dc2366fSVenugopal Iyer stime = optarg; 953*0dc2366fSVenugopal Iyer break; 954*0dc2366fSVenugopal Iyer case 'e': 955*0dc2366fSVenugopal Iyer etime = optarg; 956*0dc2366fSVenugopal Iyer break; 957*0dc2366fSVenugopal Iyer case 'o': 958*0dc2366fSVenugopal Iyer o_arg = B_TRUE; 959*0dc2366fSVenugopal Iyer fields_str = optarg; 960*0dc2366fSVenugopal Iyer break; 961*0dc2366fSVenugopal Iyer case 'F': 962*0dc2366fSVenugopal Iyer state.us_plot = F_arg = B_TRUE; 963*0dc2366fSVenugopal Iyer formatspec_str = optarg; 964*0dc2366fSVenugopal Iyer break; 965*0dc2366fSVenugopal Iyer default: 966*0dc2366fSVenugopal Iyer die_opterr(optopt, opt, usage_ermsg); 967*0dc2366fSVenugopal Iyer } 968*0dc2366fSVenugopal Iyer } 969*0dc2366fSVenugopal Iyer 970*0dc2366fSVenugopal Iyer if (file == NULL) 971*0dc2366fSVenugopal Iyer die("-h requires a file"); 972*0dc2366fSVenugopal Iyer 973*0dc2366fSVenugopal Iyer if (optind == (argc-1)) { 974*0dc2366fSVenugopal Iyer dladm_flow_attr_t attr; 975*0dc2366fSVenugopal Iyer 976*0dc2366fSVenugopal Iyer resource = argv[optind]; 977*0dc2366fSVenugopal Iyer if (!state.us_showall && 978*0dc2366fSVenugopal Iyer dladm_flow_info(handle, resource, &attr) != 979*0dc2366fSVenugopal Iyer DLADM_STATUS_OK) { 980*0dc2366fSVenugopal Iyer die("invalid flow: '%s'", resource); 981*0dc2366fSVenugopal Iyer } 982*0dc2366fSVenugopal Iyer } 983*0dc2366fSVenugopal Iyer 984*0dc2366fSVenugopal Iyer if (state.us_parsable) 985*0dc2366fSVenugopal Iyer ofmtflags |= OFMT_PARSABLE; 986*0dc2366fSVenugopal Iyer if (resource == NULL && stime == NULL && etime == NULL) { 987*0dc2366fSVenugopal Iyer if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 988*0dc2366fSVenugopal Iyer fields_str = all_fields; 989*0dc2366fSVenugopal Iyer oferr = ofmt_open(fields_str, history_fields, ofmtflags, 990*0dc2366fSVenugopal Iyer 0, &ofmt); 991*0dc2366fSVenugopal Iyer } else { 992*0dc2366fSVenugopal Iyer if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 993*0dc2366fSVenugopal Iyer fields_str = all_l_fields; 994*0dc2366fSVenugopal Iyer oferr = ofmt_open(fields_str, history_l_fields, ofmtflags, 995*0dc2366fSVenugopal Iyer 0, &ofmt); 996*0dc2366fSVenugopal Iyer } 997*0dc2366fSVenugopal Iyer 998*0dc2366fSVenugopal Iyer flowstat_ofmt_check(oferr, state.us_parsable, ofmt); 999*0dc2366fSVenugopal Iyer state.us_ofmt = ofmt; 1000*0dc2366fSVenugopal Iyer 1001*0dc2366fSVenugopal Iyer if (F_arg && d_arg) 1002*0dc2366fSVenugopal Iyer die("incompatible -d and -F options"); 1003*0dc2366fSVenugopal Iyer 1004*0dc2366fSVenugopal Iyer if (F_arg && !valid_formatspec(formatspec_str)) 1005*0dc2366fSVenugopal Iyer die("Format specifier %s not supported", formatspec_str); 1006*0dc2366fSVenugopal Iyer 1007*0dc2366fSVenugopal Iyer if (d_arg) { 1008*0dc2366fSVenugopal Iyer /* Print log dates */ 1009*0dc2366fSVenugopal Iyer status = dladm_usage_dates(show_history_date, 1010*0dc2366fSVenugopal Iyer DLADM_LOGTYPE_FLOW, file, resource, &state); 1011*0dc2366fSVenugopal Iyer } else if (resource == NULL && stime == NULL && etime == NULL && 1012*0dc2366fSVenugopal Iyer !F_arg) { 1013*0dc2366fSVenugopal Iyer /* Print summary */ 1014*0dc2366fSVenugopal Iyer status = dladm_usage_summary(show_history_res, 1015*0dc2366fSVenugopal Iyer DLADM_LOGTYPE_FLOW, file, &state); 1016*0dc2366fSVenugopal Iyer } else if (resource != NULL) { 1017*0dc2366fSVenugopal Iyer /* Print log entries for named resource */ 1018*0dc2366fSVenugopal Iyer status = dladm_walk_usage_res(show_history_time, 1019*0dc2366fSVenugopal Iyer DLADM_LOGTYPE_FLOW, file, resource, stime, etime, &state); 1020*0dc2366fSVenugopal Iyer } else { 1021*0dc2366fSVenugopal Iyer /* Print time and information for each flow */ 1022*0dc2366fSVenugopal Iyer status = dladm_walk_usage_time(show_history_time, 1023*0dc2366fSVenugopal Iyer DLADM_LOGTYPE_FLOW, file, stime, etime, &state); 1024*0dc2366fSVenugopal Iyer } 1025*0dc2366fSVenugopal Iyer 1026*0dc2366fSVenugopal Iyer ofmt_close(ofmt); 1027*0dc2366fSVenugopal Iyer if (status != DLADM_STATUS_OK) 1028*0dc2366fSVenugopal Iyer die_dlerr(status, "-h"); 1029*0dc2366fSVenugopal Iyer dladm_close(handle); 1030*0dc2366fSVenugopal Iyer } 1031*0dc2366fSVenugopal Iyer 1032*0dc2366fSVenugopal Iyer static void 1033*0dc2366fSVenugopal Iyer warn(const char *format, ...) 1034*0dc2366fSVenugopal Iyer { 1035*0dc2366fSVenugopal Iyer va_list alist; 1036*0dc2366fSVenugopal Iyer 1037*0dc2366fSVenugopal Iyer format = gettext(format); 1038*0dc2366fSVenugopal Iyer (void) fprintf(stderr, "%s: warning: ", progname); 1039*0dc2366fSVenugopal Iyer 1040*0dc2366fSVenugopal Iyer va_start(alist, format); 1041*0dc2366fSVenugopal Iyer (void) vfprintf(stderr, format, alist); 1042*0dc2366fSVenugopal Iyer va_end(alist); 1043*0dc2366fSVenugopal Iyer 1044*0dc2366fSVenugopal Iyer (void) putc('\n', stderr); 1045*0dc2366fSVenugopal Iyer } 1046*0dc2366fSVenugopal Iyer 1047*0dc2366fSVenugopal Iyer /* PRINTFLIKE1 */ 1048*0dc2366fSVenugopal Iyer static void 1049*0dc2366fSVenugopal Iyer die(const char *format, ...) 1050*0dc2366fSVenugopal Iyer { 1051*0dc2366fSVenugopal Iyer va_list alist; 1052*0dc2366fSVenugopal Iyer 1053*0dc2366fSVenugopal Iyer format = gettext(format); 1054*0dc2366fSVenugopal Iyer (void) fprintf(stderr, "%s: ", progname); 1055*0dc2366fSVenugopal Iyer 1056*0dc2366fSVenugopal Iyer va_start(alist, format); 1057*0dc2366fSVenugopal Iyer (void) vfprintf(stderr, format, alist); 1058*0dc2366fSVenugopal Iyer va_end(alist); 1059*0dc2366fSVenugopal Iyer 1060*0dc2366fSVenugopal Iyer (void) putc('\n', stderr); 1061*0dc2366fSVenugopal Iyer 1062*0dc2366fSVenugopal Iyer /* close dladm handle if it was opened */ 1063*0dc2366fSVenugopal Iyer if (handle != NULL) 1064*0dc2366fSVenugopal Iyer dladm_close(handle); 1065*0dc2366fSVenugopal Iyer 1066*0dc2366fSVenugopal Iyer exit(EXIT_FAILURE); 1067*0dc2366fSVenugopal Iyer } 1068*0dc2366fSVenugopal Iyer 1069*0dc2366fSVenugopal Iyer static void 1070*0dc2366fSVenugopal Iyer die_optdup(int opt) 1071*0dc2366fSVenugopal Iyer { 1072*0dc2366fSVenugopal Iyer die("the option -%c cannot be specified more than once", opt); 1073*0dc2366fSVenugopal Iyer } 1074*0dc2366fSVenugopal Iyer 1075*0dc2366fSVenugopal Iyer static void 1076*0dc2366fSVenugopal Iyer die_opterr(int opt, int opterr, const char *usage) 1077*0dc2366fSVenugopal Iyer { 1078*0dc2366fSVenugopal Iyer switch (opterr) { 1079*0dc2366fSVenugopal Iyer case ':': 1080*0dc2366fSVenugopal Iyer die("option '-%c' requires a value\nusage: %s", opt, 1081*0dc2366fSVenugopal Iyer gettext(usage)); 1082*0dc2366fSVenugopal Iyer break; 1083*0dc2366fSVenugopal Iyer case '?': 1084*0dc2366fSVenugopal Iyer default: 1085*0dc2366fSVenugopal Iyer die("unrecognized option '-%c'\nusage: %s", opt, 1086*0dc2366fSVenugopal Iyer gettext(usage)); 1087*0dc2366fSVenugopal Iyer break; 1088*0dc2366fSVenugopal Iyer } 1089*0dc2366fSVenugopal Iyer } 1090*0dc2366fSVenugopal Iyer 1091*0dc2366fSVenugopal Iyer /* PRINTFLIKE2 */ 1092*0dc2366fSVenugopal Iyer static void 1093*0dc2366fSVenugopal Iyer die_dlerr(dladm_status_t err, const char *format, ...) 1094*0dc2366fSVenugopal Iyer { 1095*0dc2366fSVenugopal Iyer va_list alist; 1096*0dc2366fSVenugopal Iyer char errmsg[DLADM_STRSIZE]; 1097*0dc2366fSVenugopal Iyer 1098*0dc2366fSVenugopal Iyer format = gettext(format); 1099*0dc2366fSVenugopal Iyer (void) fprintf(stderr, "%s: ", progname); 1100*0dc2366fSVenugopal Iyer 1101*0dc2366fSVenugopal Iyer va_start(alist, format); 1102*0dc2366fSVenugopal Iyer (void) vfprintf(stderr, format, alist); 1103*0dc2366fSVenugopal Iyer va_end(alist); 1104*0dc2366fSVenugopal Iyer (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 1105*0dc2366fSVenugopal Iyer 1106*0dc2366fSVenugopal Iyer /* close dladm handle if it was opened */ 1107*0dc2366fSVenugopal Iyer if (handle != NULL) 1108*0dc2366fSVenugopal Iyer dladm_close(handle); 1109*0dc2366fSVenugopal Iyer 1110*0dc2366fSVenugopal Iyer exit(EXIT_FAILURE); 1111*0dc2366fSVenugopal Iyer } 1112*0dc2366fSVenugopal Iyer 1113*0dc2366fSVenugopal Iyer 1114*0dc2366fSVenugopal Iyer /* 1115*0dc2366fSVenugopal Iyer * default output callback function that, when invoked from dladm_print_output, 1116*0dc2366fSVenugopal Iyer * prints string which is offset by of_arg->ofmt_id within buf. 1117*0dc2366fSVenugopal Iyer */ 1118*0dc2366fSVenugopal Iyer static boolean_t 1119*0dc2366fSVenugopal Iyer print_default_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 1120*0dc2366fSVenugopal Iyer { 1121*0dc2366fSVenugopal Iyer char *value; 1122*0dc2366fSVenugopal Iyer 1123*0dc2366fSVenugopal Iyer value = (char *)of_arg->ofmt_cbarg + of_arg->ofmt_id; 1124*0dc2366fSVenugopal Iyer (void) strlcpy(buf, value, bufsize); 1125*0dc2366fSVenugopal Iyer return (B_TRUE); 1126*0dc2366fSVenugopal Iyer } 1127*0dc2366fSVenugopal Iyer 1128*0dc2366fSVenugopal Iyer static void 1129*0dc2366fSVenugopal Iyer flowstat_ofmt_check(ofmt_status_t oferr, boolean_t parsable, 1130*0dc2366fSVenugopal Iyer ofmt_handle_t ofmt) 1131*0dc2366fSVenugopal Iyer { 1132*0dc2366fSVenugopal Iyer char buf[OFMT_BUFSIZE]; 1133*0dc2366fSVenugopal Iyer 1134*0dc2366fSVenugopal Iyer if (oferr == OFMT_SUCCESS) 1135*0dc2366fSVenugopal Iyer return; 1136*0dc2366fSVenugopal Iyer (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf)); 1137*0dc2366fSVenugopal Iyer /* 1138*0dc2366fSVenugopal Iyer * All errors are considered fatal in parsable mode. 1139*0dc2366fSVenugopal Iyer * NOMEM errors are always fatal, regardless of mode. 1140*0dc2366fSVenugopal Iyer * For other errors, we print diagnostics in human-readable 1141*0dc2366fSVenugopal Iyer * mode and processs what we can. 1142*0dc2366fSVenugopal Iyer */ 1143*0dc2366fSVenugopal Iyer if (parsable || oferr == OFMT_ENOFIELDS) { 1144*0dc2366fSVenugopal Iyer ofmt_close(ofmt); 1145*0dc2366fSVenugopal Iyer die(buf); 1146*0dc2366fSVenugopal Iyer } else { 1147*0dc2366fSVenugopal Iyer warn(buf); 1148*0dc2366fSVenugopal Iyer } 1149*0dc2366fSVenugopal Iyer } 1150