10dc2366fSVenugopal Iyer /* 20dc2366fSVenugopal Iyer * CDDL HEADER START 30dc2366fSVenugopal Iyer * 40dc2366fSVenugopal Iyer * The contents of this file are subject to the terms of the 50dc2366fSVenugopal Iyer * Common Development and Distribution License (the "License"). 60dc2366fSVenugopal Iyer * You may not use this file except in compliance with the License. 70dc2366fSVenugopal Iyer * 80dc2366fSVenugopal Iyer * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90dc2366fSVenugopal Iyer * or http://www.opensolaris.org/os/licensing. 100dc2366fSVenugopal Iyer * See the License for the specific language governing permissions 110dc2366fSVenugopal Iyer * and limitations under the License. 120dc2366fSVenugopal Iyer * 130dc2366fSVenugopal Iyer * When distributing Covered Code, include this CDDL HEADER in each 140dc2366fSVenugopal Iyer * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150dc2366fSVenugopal Iyer * If applicable, add the following below this CDDL HEADER, with the 160dc2366fSVenugopal Iyer * fields enclosed by brackets "[]" replaced with your own identifying 170dc2366fSVenugopal Iyer * information: Portions Copyright [yyyy] [name of copyright owner] 180dc2366fSVenugopal Iyer * 190dc2366fSVenugopal Iyer * CDDL HEADER END 200dc2366fSVenugopal Iyer */ 210dc2366fSVenugopal Iyer /* 220dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 230dc2366fSVenugopal Iyer * Use is subject to license terms. 240dc2366fSVenugopal Iyer */ 250dc2366fSVenugopal Iyer 260dc2366fSVenugopal Iyer #include <stdio.h> 270dc2366fSVenugopal Iyer #include <locale.h> 280dc2366fSVenugopal Iyer #include <stdarg.h> 290dc2366fSVenugopal Iyer #include <stdlib.h> 300dc2366fSVenugopal Iyer #include <fcntl.h> 310dc2366fSVenugopal Iyer #include <string.h> 320dc2366fSVenugopal Iyer #include <stropts.h> 330dc2366fSVenugopal Iyer #include <errno.h> 340dc2366fSVenugopal Iyer #include <strings.h> 350dc2366fSVenugopal Iyer #include <getopt.h> 360dc2366fSVenugopal Iyer #include <unistd.h> 370dc2366fSVenugopal Iyer #include <priv.h> 380dc2366fSVenugopal Iyer #include <netdb.h> 390dc2366fSVenugopal Iyer #include <libintl.h> 400dc2366fSVenugopal Iyer #include <libdlflow.h> 410dc2366fSVenugopal Iyer #include <libdllink.h> 420dc2366fSVenugopal Iyer #include <libdlstat.h> 430dc2366fSVenugopal Iyer #include <sys/types.h> 440dc2366fSVenugopal Iyer #include <sys/socket.h> 450dc2366fSVenugopal Iyer #include <netinet/in.h> 460dc2366fSVenugopal Iyer #include <arpa/inet.h> 470dc2366fSVenugopal Iyer #include <sys/ethernet.h> 480dc2366fSVenugopal Iyer #include <inet/ip.h> 490dc2366fSVenugopal Iyer #include <inet/ip6.h> 500dc2366fSVenugopal Iyer #include <stddef.h> 510dc2366fSVenugopal Iyer #include <ofmt.h> 520dc2366fSVenugopal Iyer 530dc2366fSVenugopal Iyer typedef struct flow_chain_s { 540dc2366fSVenugopal Iyer char fc_flowname[MAXFLOWNAMELEN]; 550dc2366fSVenugopal Iyer boolean_t fc_visited; 560dc2366fSVenugopal Iyer flow_stat_t *fc_stat; 570dc2366fSVenugopal Iyer struct flow_chain_s *fc_next; 580dc2366fSVenugopal Iyer } flow_chain_t; 590dc2366fSVenugopal Iyer 600dc2366fSVenugopal Iyer typedef struct show_flow_state { 610dc2366fSVenugopal Iyer flow_chain_t *fs_flowchain; 620dc2366fSVenugopal Iyer ofmt_handle_t fs_ofmt; 630dc2366fSVenugopal Iyer char fs_unit; 640dc2366fSVenugopal Iyer boolean_t fs_parsable; 650dc2366fSVenugopal Iyer } show_flow_state_t; 660dc2366fSVenugopal Iyer 670dc2366fSVenugopal Iyer typedef struct show_history_state_s { 680dc2366fSVenugopal Iyer boolean_t us_plot; 690dc2366fSVenugopal Iyer boolean_t us_parsable; 700dc2366fSVenugopal Iyer boolean_t us_printheader; 710dc2366fSVenugopal Iyer boolean_t us_first; 720dc2366fSVenugopal Iyer boolean_t us_showall; 730dc2366fSVenugopal Iyer ofmt_handle_t us_ofmt; 740dc2366fSVenugopal Iyer } show_history_state_t; 750dc2366fSVenugopal Iyer 760dc2366fSVenugopal Iyer static void do_show_history(int, char **); 770dc2366fSVenugopal Iyer 780dc2366fSVenugopal Iyer static int query_flow_stats(dladm_handle_t, dladm_flow_attr_t *, void *); 790dc2366fSVenugopal Iyer static int query_link_flow_stats(dladm_handle_t, datalink_id_t, void *); 800dc2366fSVenugopal Iyer 810dc2366fSVenugopal Iyer static void die(const char *, ...); 820dc2366fSVenugopal Iyer static void die_optdup(int); 830dc2366fSVenugopal Iyer static void die_opterr(int, int, const char *); 840dc2366fSVenugopal Iyer static void die_dlerr(dladm_status_t, const char *, ...); 850dc2366fSVenugopal Iyer static void warn(const char *, ...); 860dc2366fSVenugopal Iyer 870dc2366fSVenugopal Iyer /* callback functions for printing output */ 880dc2366fSVenugopal Iyer static ofmt_cb_t print_default_cb, print_flow_stats_cb; 890dc2366fSVenugopal Iyer static void flowstat_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t); 900dc2366fSVenugopal Iyer 910dc2366fSVenugopal Iyer #define NULL_OFMT {NULL, 0, 0, NULL} 920dc2366fSVenugopal Iyer 930dc2366fSVenugopal Iyer /* 940dc2366fSVenugopal Iyer * structures for flowstat (printing live statistics) 950dc2366fSVenugopal Iyer */ 960dc2366fSVenugopal Iyer typedef enum { 970dc2366fSVenugopal Iyer FLOW_S_FLOW, 980dc2366fSVenugopal Iyer FLOW_S_IPKTS, 990dc2366fSVenugopal Iyer FLOW_S_RBYTES, 1000dc2366fSVenugopal Iyer FLOW_S_IERRORS, 1010dc2366fSVenugopal Iyer FLOW_S_OPKTS, 1020dc2366fSVenugopal Iyer FLOW_S_OBYTES, 1030dc2366fSVenugopal Iyer FLOW_S_OERRORS 1040dc2366fSVenugopal Iyer } flow_s_field_index_t; 1050dc2366fSVenugopal Iyer 1060dc2366fSVenugopal Iyer static ofmt_field_t flow_s_fields[] = { 1070dc2366fSVenugopal Iyer /* name, field width, index, callback */ 1080dc2366fSVenugopal Iyer { "FLOW", 15, FLOW_S_FLOW, print_flow_stats_cb}, 1090dc2366fSVenugopal Iyer { "IPKTS", 8, FLOW_S_IPKTS, print_flow_stats_cb}, 1100dc2366fSVenugopal Iyer { "RBYTES", 8, FLOW_S_RBYTES, print_flow_stats_cb}, 1110dc2366fSVenugopal Iyer { "IERRS", 8, FLOW_S_IERRORS, print_flow_stats_cb}, 1120dc2366fSVenugopal Iyer { "OPKTS", 8, FLOW_S_OPKTS, print_flow_stats_cb}, 1130dc2366fSVenugopal Iyer { "OBYTES", 8, FLOW_S_OBYTES, print_flow_stats_cb}, 1140dc2366fSVenugopal Iyer { "OERRS", 8, FLOW_S_OERRORS, print_flow_stats_cb}, 1150dc2366fSVenugopal Iyer NULL_OFMT} 1160dc2366fSVenugopal Iyer ; 1170dc2366fSVenugopal Iyer 1180dc2366fSVenugopal Iyer typedef struct flow_args_s { 1190dc2366fSVenugopal Iyer char *flow_s_flow; 1200dc2366fSVenugopal Iyer flow_stat_t *flow_s_stat; 1210dc2366fSVenugopal Iyer char flow_s_unit; 1220dc2366fSVenugopal Iyer boolean_t flow_s_parsable; 1230dc2366fSVenugopal Iyer } flow_args_t; 1240dc2366fSVenugopal Iyer 1250dc2366fSVenugopal Iyer /* 1260dc2366fSVenugopal Iyer * structures for 'flowstat -h' 1270dc2366fSVenugopal Iyer */ 1280dc2366fSVenugopal Iyer typedef struct history_fields_buf_s { 1290dc2366fSVenugopal Iyer char history_flow[12]; 1300dc2366fSVenugopal Iyer char history_duration[10]; 1310dc2366fSVenugopal Iyer char history_ipackets[9]; 1320dc2366fSVenugopal Iyer char history_rbytes[10]; 1330dc2366fSVenugopal Iyer char history_opackets[9]; 1340dc2366fSVenugopal Iyer char history_obytes[10]; 1350dc2366fSVenugopal Iyer char history_bandwidth[14]; 1360dc2366fSVenugopal Iyer } history_fields_buf_t; 1370dc2366fSVenugopal Iyer 1380dc2366fSVenugopal Iyer static ofmt_field_t history_fields[] = { 1390dc2366fSVenugopal Iyer /* name, field width, offset */ 1400dc2366fSVenugopal Iyer { "FLOW", 13, 1410dc2366fSVenugopal Iyer offsetof(history_fields_buf_t, history_flow), print_default_cb}, 1420dc2366fSVenugopal Iyer { "DURATION", 11, 1430dc2366fSVenugopal Iyer offsetof(history_fields_buf_t, history_duration), print_default_cb}, 1440dc2366fSVenugopal Iyer { "IPACKETS", 10, 1450dc2366fSVenugopal Iyer offsetof(history_fields_buf_t, history_ipackets), print_default_cb}, 1460dc2366fSVenugopal Iyer { "RBYTES", 11, 1470dc2366fSVenugopal Iyer offsetof(history_fields_buf_t, history_rbytes), print_default_cb}, 1480dc2366fSVenugopal Iyer { "OPACKETS", 10, 1490dc2366fSVenugopal Iyer offsetof(history_fields_buf_t, history_opackets), print_default_cb}, 1500dc2366fSVenugopal Iyer { "OBYTES", 11, 1510dc2366fSVenugopal Iyer offsetof(history_fields_buf_t, history_obytes), print_default_cb}, 1520dc2366fSVenugopal Iyer { "BANDWIDTH", 15, 1530dc2366fSVenugopal Iyer offsetof(history_fields_buf_t, history_bandwidth), print_default_cb}, 1540dc2366fSVenugopal Iyer NULL_OFMT} 1550dc2366fSVenugopal Iyer ; 1560dc2366fSVenugopal Iyer 1570dc2366fSVenugopal Iyer typedef struct history_l_fields_buf_s { 1580dc2366fSVenugopal Iyer char history_l_flow[12]; 1590dc2366fSVenugopal Iyer char history_l_stime[13]; 1600dc2366fSVenugopal Iyer char history_l_etime[13]; 1610dc2366fSVenugopal Iyer char history_l_rbytes[8]; 1620dc2366fSVenugopal Iyer char history_l_obytes[8]; 1630dc2366fSVenugopal Iyer char history_l_bandwidth[14]; 1640dc2366fSVenugopal Iyer } history_l_fields_buf_t; 1650dc2366fSVenugopal Iyer 1660dc2366fSVenugopal Iyer static ofmt_field_t history_l_fields[] = { 1670dc2366fSVenugopal Iyer /* name, field width, offset */ 1680dc2366fSVenugopal Iyer { "FLOW", 13, 1690dc2366fSVenugopal Iyer offsetof(history_l_fields_buf_t, history_l_flow), print_default_cb}, 1700dc2366fSVenugopal Iyer { "START", 14, 1710dc2366fSVenugopal Iyer offsetof(history_l_fields_buf_t, history_l_stime), print_default_cb}, 1720dc2366fSVenugopal Iyer { "END", 14, 1730dc2366fSVenugopal Iyer offsetof(history_l_fields_buf_t, history_l_etime), print_default_cb}, 1740dc2366fSVenugopal Iyer { "RBYTES", 9, 1750dc2366fSVenugopal Iyer offsetof(history_l_fields_buf_t, history_l_rbytes), print_default_cb}, 1760dc2366fSVenugopal Iyer { "OBYTES", 9, 1770dc2366fSVenugopal Iyer offsetof(history_l_fields_buf_t, history_l_obytes), print_default_cb}, 1780dc2366fSVenugopal Iyer { "BANDWIDTH", 15, 1790dc2366fSVenugopal Iyer offsetof(history_l_fields_buf_t, history_l_bandwidth), 1800dc2366fSVenugopal Iyer print_default_cb}, 1810dc2366fSVenugopal Iyer NULL_OFMT} 1820dc2366fSVenugopal Iyer ; 1830dc2366fSVenugopal Iyer 1840dc2366fSVenugopal Iyer static char *progname; 1850dc2366fSVenugopal Iyer 1860dc2366fSVenugopal Iyer /* 1870dc2366fSVenugopal Iyer * Handle to libdladm. Opened in main() before the sub-command 1880dc2366fSVenugopal Iyer * specific function is called. 1890dc2366fSVenugopal Iyer */ 1900dc2366fSVenugopal Iyer static dladm_handle_t handle = NULL; 1910dc2366fSVenugopal Iyer 1920dc2366fSVenugopal Iyer const char *usage_ermsg = "flowstat [-r | -t] [-i interval] " 1930dc2366fSVenugopal Iyer "[-l link] [flow]\n" 194*62ef8476SYuri Pankov " flowstat [-A] [-i interval] [-p] [ -o field[,...]]\n" 1950dc2366fSVenugopal Iyer " [-u R|K|M|G|T|P] [-l link] [flow]\n" 1960dc2366fSVenugopal Iyer " flowstat -h [-a] [-d] [-F format]" 1970dc2366fSVenugopal Iyer " [-s <DD/MM/YYYY,HH:MM:SS>]\n" 1980dc2366fSVenugopal Iyer " [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> " 1990dc2366fSVenugopal Iyer "[<flow>]"; 2000dc2366fSVenugopal Iyer 2010dc2366fSVenugopal Iyer static void 2020dc2366fSVenugopal Iyer usage(void) 2030dc2366fSVenugopal Iyer { 2040dc2366fSVenugopal Iyer (void) fprintf(stderr, "%s\n", gettext(usage_ermsg)); 2050dc2366fSVenugopal Iyer 2060dc2366fSVenugopal Iyer /* close dladm handle if it was opened */ 2070dc2366fSVenugopal Iyer if (handle != NULL) 2080dc2366fSVenugopal Iyer dladm_close(handle); 2090dc2366fSVenugopal Iyer 2100dc2366fSVenugopal Iyer exit(1); 2110dc2366fSVenugopal Iyer } 2120dc2366fSVenugopal Iyer 2130dc2366fSVenugopal Iyer boolean_t 2140dc2366fSVenugopal Iyer flowstat_unit(char *oarg, char *unit) 2150dc2366fSVenugopal Iyer { 2160dc2366fSVenugopal Iyer if ((strcmp(oarg, "R") == 0) || (strcmp(oarg, "K") == 0) || 2170dc2366fSVenugopal Iyer (strcmp(oarg, "M") == 0) || (strcmp(oarg, "G") == 0) || 2180dc2366fSVenugopal Iyer (strcmp(oarg, "T") == 0) || (strcmp(oarg, "P") == 0)) { 2190dc2366fSVenugopal Iyer *unit = oarg[0]; 2200dc2366fSVenugopal Iyer return (B_TRUE); 2210dc2366fSVenugopal Iyer } 2220dc2366fSVenugopal Iyer 2230dc2366fSVenugopal Iyer return (B_FALSE); 2240dc2366fSVenugopal Iyer } 2250dc2366fSVenugopal Iyer 2260dc2366fSVenugopal Iyer void 2270dc2366fSVenugopal Iyer map_to_units(char *buf, uint_t bufsize, double num, char unit, 2280dc2366fSVenugopal Iyer boolean_t parsable) 2290dc2366fSVenugopal Iyer { 2300dc2366fSVenugopal Iyer if (parsable) { 2310dc2366fSVenugopal Iyer (void) snprintf(buf, bufsize, "%.0lf", num); 2320dc2366fSVenugopal Iyer return; 2330dc2366fSVenugopal Iyer } 2340dc2366fSVenugopal Iyer 2350dc2366fSVenugopal Iyer if (unit == '\0') { 2360dc2366fSVenugopal Iyer int index; 2370dc2366fSVenugopal Iyer 2380dc2366fSVenugopal Iyer for (index = 0; (int)(num/1000) != 0; index++, num /= 1000) 2390dc2366fSVenugopal Iyer ; 2400dc2366fSVenugopal Iyer 2410dc2366fSVenugopal Iyer switch (index) { 2420dc2366fSVenugopal Iyer case 0: 2430dc2366fSVenugopal Iyer unit = '\0'; 2440dc2366fSVenugopal Iyer break; 2450dc2366fSVenugopal Iyer case 1: 2460dc2366fSVenugopal Iyer unit = 'K'; 2470dc2366fSVenugopal Iyer break; 2480dc2366fSVenugopal Iyer case 2: 2490dc2366fSVenugopal Iyer unit = 'M'; 2500dc2366fSVenugopal Iyer break; 2510dc2366fSVenugopal Iyer case 3: 2520dc2366fSVenugopal Iyer unit = 'G'; 2530dc2366fSVenugopal Iyer break; 2540dc2366fSVenugopal Iyer case 4: 2550dc2366fSVenugopal Iyer unit = 'T'; 2560dc2366fSVenugopal Iyer break; 2570dc2366fSVenugopal Iyer case 5: 2580dc2366fSVenugopal Iyer /* Largest unit supported */ 2590dc2366fSVenugopal Iyer default: 2600dc2366fSVenugopal Iyer unit = 'P'; 2610dc2366fSVenugopal Iyer break; 2620dc2366fSVenugopal Iyer } 2630dc2366fSVenugopal Iyer } else { 2640dc2366fSVenugopal Iyer switch (unit) { 2650dc2366fSVenugopal Iyer case 'R': 2660dc2366fSVenugopal Iyer /* Already raw numbers */ 2670dc2366fSVenugopal Iyer unit = '\0'; 2680dc2366fSVenugopal Iyer break; 2690dc2366fSVenugopal Iyer case 'K': 2700dc2366fSVenugopal Iyer num /= 1000; 2710dc2366fSVenugopal Iyer break; 2720dc2366fSVenugopal Iyer case 'M': 2730dc2366fSVenugopal Iyer num /= (1000*1000); 2740dc2366fSVenugopal Iyer break; 2750dc2366fSVenugopal Iyer case 'G': 2760dc2366fSVenugopal Iyer num /= (1000*1000*1000); 2770dc2366fSVenugopal Iyer break; 2780dc2366fSVenugopal Iyer case 'T': 2790dc2366fSVenugopal Iyer num /= (1000.0*1000.0*1000.0*1000.0); 2800dc2366fSVenugopal Iyer break; 2810dc2366fSVenugopal Iyer case 'P': 2820dc2366fSVenugopal Iyer /* Largest unit supported */ 2830dc2366fSVenugopal Iyer default: 2840dc2366fSVenugopal Iyer num /= (1000.0*1000.0*1000.0*1000.0*1000.0); 2850dc2366fSVenugopal Iyer break; 2860dc2366fSVenugopal Iyer } 2870dc2366fSVenugopal Iyer } 2880dc2366fSVenugopal Iyer 2890dc2366fSVenugopal Iyer if (unit == '\0') 2900dc2366fSVenugopal Iyer (void) snprintf(buf, bufsize, " %7.0lf%c", num, unit); 2910dc2366fSVenugopal Iyer else 2920dc2366fSVenugopal Iyer (void) snprintf(buf, bufsize, " %6.2lf%c", num, unit); 2930dc2366fSVenugopal Iyer } 2940dc2366fSVenugopal Iyer 2950dc2366fSVenugopal Iyer flow_chain_t * 2960dc2366fSVenugopal Iyer get_flow_prev_stat(const char *flowname, void *arg) 2970dc2366fSVenugopal Iyer { 2980dc2366fSVenugopal Iyer show_flow_state_t *state = arg; 2990dc2366fSVenugopal Iyer flow_chain_t *flow_curr = NULL; 3000dc2366fSVenugopal Iyer 3010dc2366fSVenugopal Iyer /* Scan prev flowname list and look for entry matching this entry */ 3020dc2366fSVenugopal Iyer for (flow_curr = state->fs_flowchain; flow_curr; 3030dc2366fSVenugopal Iyer flow_curr = flow_curr->fc_next) { 3040dc2366fSVenugopal Iyer if (strcmp(flow_curr->fc_flowname, flowname) == 0) 3050dc2366fSVenugopal Iyer break; 3060dc2366fSVenugopal Iyer } 3070dc2366fSVenugopal Iyer 3080dc2366fSVenugopal Iyer /* New flow, add it */ 3090dc2366fSVenugopal Iyer if (flow_curr == NULL) { 3100dc2366fSVenugopal Iyer flow_curr = (flow_chain_t *)malloc(sizeof (flow_chain_t)); 3110dc2366fSVenugopal Iyer if (flow_curr == NULL) 3120dc2366fSVenugopal Iyer goto done; 3130dc2366fSVenugopal Iyer (void) strncpy(flow_curr->fc_flowname, flowname, 3140dc2366fSVenugopal Iyer MAXFLOWNAMELEN); 3150dc2366fSVenugopal Iyer flow_curr->fc_stat = NULL; 3160dc2366fSVenugopal Iyer flow_curr->fc_next = state->fs_flowchain; 3170dc2366fSVenugopal Iyer state->fs_flowchain = flow_curr; 3180dc2366fSVenugopal Iyer } 3190dc2366fSVenugopal Iyer done: 3200dc2366fSVenugopal Iyer return (flow_curr); 3210dc2366fSVenugopal Iyer } 3220dc2366fSVenugopal Iyer 3230dc2366fSVenugopal Iyer /* 3240dc2366fSVenugopal Iyer * Number of flows may change while flowstat -i is executing. 3250dc2366fSVenugopal Iyer * Free memory allocated for flows that are no longer there. 3260dc2366fSVenugopal Iyer * Prepare for next iteration by marking visited = false for 3270dc2366fSVenugopal Iyer * existing stat entries. 3280dc2366fSVenugopal Iyer */ 3290dc2366fSVenugopal Iyer static void 3300dc2366fSVenugopal Iyer cleanup_removed_flows(show_flow_state_t *state) 3310dc2366fSVenugopal Iyer { 3320dc2366fSVenugopal Iyer flow_chain_t *fcurr; 3330dc2366fSVenugopal Iyer flow_chain_t *fprev; 3340dc2366fSVenugopal Iyer flow_chain_t *tofree; 3350dc2366fSVenugopal Iyer 3360dc2366fSVenugopal Iyer /* Delete all nodes from the list that have fc_visited marked false */ 3370dc2366fSVenugopal Iyer fcurr = state->fs_flowchain; 3380dc2366fSVenugopal Iyer while (fcurr != NULL) { 3390dc2366fSVenugopal Iyer if (fcurr->fc_visited) { 3400dc2366fSVenugopal Iyer fcurr->fc_visited = B_FALSE; 3410dc2366fSVenugopal Iyer fprev = fcurr; 3420dc2366fSVenugopal Iyer fcurr = fcurr->fc_next; 3430dc2366fSVenugopal Iyer continue; 3440dc2366fSVenugopal Iyer } 3450dc2366fSVenugopal Iyer 3460dc2366fSVenugopal Iyer /* Is it head of the list? */ 3470dc2366fSVenugopal Iyer if (fcurr == state->fs_flowchain) 3480dc2366fSVenugopal Iyer state->fs_flowchain = fcurr->fc_next; 3490dc2366fSVenugopal Iyer else 3500dc2366fSVenugopal Iyer fprev->fc_next = fcurr->fc_next; 3510dc2366fSVenugopal Iyer 3520dc2366fSVenugopal Iyer /* fprev remains the same */ 3530dc2366fSVenugopal Iyer tofree = fcurr; 3540dc2366fSVenugopal Iyer fcurr = fcurr->fc_next; 3550dc2366fSVenugopal Iyer 3560dc2366fSVenugopal Iyer /* Free stats memory for the removed flow */ 3570dc2366fSVenugopal Iyer dladm_flow_stat_free(tofree->fc_stat); 3580dc2366fSVenugopal Iyer free(tofree); 3590dc2366fSVenugopal Iyer } 3600dc2366fSVenugopal Iyer } 3610dc2366fSVenugopal Iyer 3620dc2366fSVenugopal Iyer static boolean_t 3630dc2366fSVenugopal Iyer print_flow_stats_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 3640dc2366fSVenugopal Iyer { 3650dc2366fSVenugopal Iyer flow_args_t *fargs = of_arg->ofmt_cbarg; 3660dc2366fSVenugopal Iyer flow_stat_t *diff_stats = fargs->flow_s_stat; 3670dc2366fSVenugopal Iyer char unit = fargs->flow_s_unit; 3680dc2366fSVenugopal Iyer boolean_t parsable = fargs->flow_s_parsable; 3690dc2366fSVenugopal Iyer 3700dc2366fSVenugopal Iyer switch (of_arg->ofmt_id) { 3710dc2366fSVenugopal Iyer case FLOW_S_FLOW: 3720dc2366fSVenugopal Iyer (void) snprintf(buf, bufsize, "%s", fargs->flow_s_flow); 3730dc2366fSVenugopal Iyer break; 3740dc2366fSVenugopal Iyer case FLOW_S_IPKTS: 3750dc2366fSVenugopal Iyer map_to_units(buf, bufsize, diff_stats->fl_ipackets, unit, 3760dc2366fSVenugopal Iyer parsable); 3770dc2366fSVenugopal Iyer break; 3780dc2366fSVenugopal Iyer case FLOW_S_RBYTES: 3790dc2366fSVenugopal Iyer map_to_units(buf, bufsize, diff_stats->fl_rbytes, unit, 3800dc2366fSVenugopal Iyer parsable); 3810dc2366fSVenugopal Iyer break; 3820dc2366fSVenugopal Iyer case FLOW_S_IERRORS: 3830dc2366fSVenugopal Iyer map_to_units(buf, bufsize, diff_stats->fl_ierrors, unit, 3840dc2366fSVenugopal Iyer parsable); 3850dc2366fSVenugopal Iyer break; 3860dc2366fSVenugopal Iyer case FLOW_S_OPKTS: 3870dc2366fSVenugopal Iyer map_to_units(buf, bufsize, diff_stats->fl_opackets, unit, 3880dc2366fSVenugopal Iyer parsable); 3890dc2366fSVenugopal Iyer break; 3900dc2366fSVenugopal Iyer case FLOW_S_OBYTES: 3910dc2366fSVenugopal Iyer map_to_units(buf, bufsize, diff_stats->fl_obytes, unit, 3920dc2366fSVenugopal Iyer parsable); 3930dc2366fSVenugopal Iyer break; 3940dc2366fSVenugopal Iyer case FLOW_S_OERRORS: 3950dc2366fSVenugopal Iyer map_to_units(buf, bufsize, diff_stats->fl_oerrors, unit, 3960dc2366fSVenugopal Iyer parsable); 3970dc2366fSVenugopal Iyer break; 3980dc2366fSVenugopal Iyer default: 3990dc2366fSVenugopal Iyer die("invalid input"); 4000dc2366fSVenugopal Iyer break; 4010dc2366fSVenugopal Iyer } 4020dc2366fSVenugopal Iyer return (B_TRUE); 4030dc2366fSVenugopal Iyer } 4040dc2366fSVenugopal Iyer 4050dc2366fSVenugopal Iyer /* ARGSUSED */ 4060dc2366fSVenugopal Iyer static int 4070dc2366fSVenugopal Iyer query_flow_stats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg) 4080dc2366fSVenugopal Iyer { 4090dc2366fSVenugopal Iyer show_flow_state_t *state = arg; 4100dc2366fSVenugopal Iyer flow_chain_t *flow_node; 4110dc2366fSVenugopal Iyer flow_stat_t *curr_stat; 4120dc2366fSVenugopal Iyer flow_stat_t *prev_stat; 4130dc2366fSVenugopal Iyer flow_stat_t *diff_stat; 4140dc2366fSVenugopal Iyer char *flowname = attr->fa_flowname; 4150dc2366fSVenugopal Iyer flow_args_t fargs; 4160dc2366fSVenugopal Iyer 4170dc2366fSVenugopal Iyer /* Get previous stats for the flow */ 4180dc2366fSVenugopal Iyer flow_node = get_flow_prev_stat(flowname, arg); 4190dc2366fSVenugopal Iyer if (flow_node == NULL) 4200dc2366fSVenugopal Iyer goto done; 4210dc2366fSVenugopal Iyer 4220dc2366fSVenugopal Iyer flow_node->fc_visited = B_TRUE; 4230dc2366fSVenugopal Iyer prev_stat = flow_node->fc_stat; 4240dc2366fSVenugopal Iyer 4250dc2366fSVenugopal Iyer /* Query library for current stats */ 4260dc2366fSVenugopal Iyer curr_stat = dladm_flow_stat_query(flowname); 4270dc2366fSVenugopal Iyer if (curr_stat == NULL) 4280dc2366fSVenugopal Iyer goto done; 4290dc2366fSVenugopal Iyer 4300dc2366fSVenugopal Iyer /* current stats - prev iteration stats */ 4310dc2366fSVenugopal Iyer diff_stat = dladm_flow_stat_diff(curr_stat, prev_stat); 4320dc2366fSVenugopal Iyer 4330dc2366fSVenugopal Iyer /* Free prev stats */ 4340dc2366fSVenugopal Iyer dladm_flow_stat_free(prev_stat); 4350dc2366fSVenugopal Iyer 4360dc2366fSVenugopal Iyer /* Prev <- curr stats */ 4370dc2366fSVenugopal Iyer flow_node->fc_stat = curr_stat; 4380dc2366fSVenugopal Iyer 4390dc2366fSVenugopal Iyer if (diff_stat == NULL) 4400dc2366fSVenugopal Iyer goto done; 4410dc2366fSVenugopal Iyer 4420dc2366fSVenugopal Iyer /* Print stats */ 4430dc2366fSVenugopal Iyer fargs.flow_s_flow = flowname; 4440dc2366fSVenugopal Iyer fargs.flow_s_stat = diff_stat; 4450dc2366fSVenugopal Iyer fargs.flow_s_unit = state->fs_unit; 4460dc2366fSVenugopal Iyer fargs.flow_s_parsable = state->fs_parsable; 4470dc2366fSVenugopal Iyer ofmt_print(state->fs_ofmt, &fargs); 4480dc2366fSVenugopal Iyer 4490dc2366fSVenugopal Iyer /* Free diff stats */ 4500dc2366fSVenugopal Iyer dladm_flow_stat_free(diff_stat); 4510dc2366fSVenugopal Iyer done: 4520dc2366fSVenugopal Iyer return (DLADM_WALK_CONTINUE); 4530dc2366fSVenugopal Iyer } 4540dc2366fSVenugopal Iyer 4550dc2366fSVenugopal Iyer /* 4560dc2366fSVenugopal Iyer * Wrapper of dladm_walk_flow(query_flow_stats,...) to make it usable for 4570dc2366fSVenugopal Iyer * dladm_walk_datalink_id(). Used for showing flow stats for 4580dc2366fSVenugopal Iyer * all flows on all links. 4590dc2366fSVenugopal Iyer */ 4600dc2366fSVenugopal Iyer static int 4610dc2366fSVenugopal Iyer query_link_flow_stats(dladm_handle_t dh, datalink_id_t linkid, void * arg) 4620dc2366fSVenugopal Iyer { 4630dc2366fSVenugopal Iyer if (dladm_walk_flow(query_flow_stats, dh, linkid, arg, B_FALSE) 4640dc2366fSVenugopal Iyer == DLADM_STATUS_OK) 4650dc2366fSVenugopal Iyer return (DLADM_WALK_CONTINUE); 4660dc2366fSVenugopal Iyer else 4670dc2366fSVenugopal Iyer return (DLADM_WALK_TERMINATE); 4680dc2366fSVenugopal Iyer } 4690dc2366fSVenugopal Iyer 4700dc2366fSVenugopal Iyer void 4710dc2366fSVenugopal Iyer print_all_stats(name_value_stat_entry_t *stat_entry) 4720dc2366fSVenugopal Iyer { 4730dc2366fSVenugopal Iyer name_value_stat_t *curr_stat; 4740dc2366fSVenugopal Iyer 4750dc2366fSVenugopal Iyer printf("%s\n", stat_entry->nve_header); 4760dc2366fSVenugopal Iyer 4770dc2366fSVenugopal Iyer for (curr_stat = stat_entry->nve_stats; curr_stat != NULL; 4780dc2366fSVenugopal Iyer curr_stat = curr_stat->nv_nextstat) { 4790dc2366fSVenugopal Iyer printf("\t%15s", curr_stat->nv_statname); 4800dc2366fSVenugopal Iyer printf("\t%15llu\n", curr_stat->nv_statval); 4810dc2366fSVenugopal Iyer } 4820dc2366fSVenugopal Iyer } 4830dc2366fSVenugopal Iyer 4840dc2366fSVenugopal Iyer /* ARGSUSED */ 4850dc2366fSVenugopal Iyer static int 4860dc2366fSVenugopal Iyer dump_one_flow_stats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg) 4870dc2366fSVenugopal Iyer { 4880dc2366fSVenugopal Iyer char *flowname = attr->fa_flowname; 4890dc2366fSVenugopal Iyer void *stat; 4900dc2366fSVenugopal Iyer 4910dc2366fSVenugopal Iyer stat = dladm_flow_stat_query_all(flowname); 4920dc2366fSVenugopal Iyer if (stat == NULL) 4930dc2366fSVenugopal Iyer goto done; 4940dc2366fSVenugopal Iyer print_all_stats(stat); 4950dc2366fSVenugopal Iyer dladm_flow_stat_query_all_free(stat); 4960dc2366fSVenugopal Iyer 4970dc2366fSVenugopal Iyer done: 4980dc2366fSVenugopal Iyer return (DLADM_WALK_CONTINUE); 4990dc2366fSVenugopal Iyer } 5000dc2366fSVenugopal Iyer 5010dc2366fSVenugopal Iyer /* 5020dc2366fSVenugopal Iyer * Wrapper of dladm_walk_flow(query_flow_stats,...) to make it usable for 5030dc2366fSVenugopal Iyer * dladm_walk_datalink_id(). Used for showing flow stats for 5040dc2366fSVenugopal Iyer * all flows on all links. 5050dc2366fSVenugopal Iyer */ 5060dc2366fSVenugopal Iyer static int 5070dc2366fSVenugopal Iyer dump_link_flow_stats(dladm_handle_t dh, datalink_id_t linkid, void * arg) 5080dc2366fSVenugopal Iyer { 5090dc2366fSVenugopal Iyer if (dladm_walk_flow(dump_one_flow_stats, dh, linkid, arg, B_FALSE) 5100dc2366fSVenugopal Iyer == DLADM_STATUS_OK) 5110dc2366fSVenugopal Iyer return (DLADM_WALK_CONTINUE); 5120dc2366fSVenugopal Iyer else 5130dc2366fSVenugopal Iyer return (DLADM_WALK_TERMINATE); 5140dc2366fSVenugopal Iyer } 5150dc2366fSVenugopal Iyer 5160dc2366fSVenugopal Iyer static void 5170dc2366fSVenugopal Iyer dump_all_flow_stats(dladm_flow_attr_t *attrp, void *arg, datalink_id_t linkid, 5180dc2366fSVenugopal Iyer boolean_t flow_arg) 5190dc2366fSVenugopal Iyer { 5200dc2366fSVenugopal Iyer /* Show stats for named flow */ 5210dc2366fSVenugopal Iyer if (flow_arg) { 5220dc2366fSVenugopal Iyer (void) dump_one_flow_stats(handle, attrp, arg); 5230dc2366fSVenugopal Iyer 5240dc2366fSVenugopal Iyer /* Show stats for flows on one link */ 5250dc2366fSVenugopal Iyer } else if (linkid != DATALINK_INVALID_LINKID) { 5260dc2366fSVenugopal Iyer (void) dladm_walk_flow(dump_one_flow_stats, handle, linkid, 5270dc2366fSVenugopal Iyer arg, B_FALSE); 5280dc2366fSVenugopal Iyer 5290dc2366fSVenugopal Iyer /* Show stats for all flows on all links */ 5300dc2366fSVenugopal Iyer } else { 5310dc2366fSVenugopal Iyer (void) dladm_walk_datalink_id(dump_link_flow_stats, 5320dc2366fSVenugopal Iyer handle, arg, DATALINK_CLASS_ALL, 5330dc2366fSVenugopal Iyer DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 5340dc2366fSVenugopal Iyer } 5350dc2366fSVenugopal Iyer } 5360dc2366fSVenugopal Iyer 5370dc2366fSVenugopal Iyer int 5380dc2366fSVenugopal Iyer main(int argc, char *argv[]) 5390dc2366fSVenugopal Iyer { 5400dc2366fSVenugopal Iyer dladm_status_t status; 5410dc2366fSVenugopal Iyer int option; 5420dc2366fSVenugopal Iyer boolean_t r_arg = B_FALSE; 5430dc2366fSVenugopal Iyer boolean_t t_arg = B_FALSE; 5440dc2366fSVenugopal Iyer boolean_t p_arg = B_FALSE; 5450dc2366fSVenugopal Iyer boolean_t i_arg = B_FALSE; 5460dc2366fSVenugopal Iyer boolean_t o_arg = B_FALSE; 5470dc2366fSVenugopal Iyer boolean_t u_arg = B_FALSE; 5480dc2366fSVenugopal Iyer boolean_t A_arg = B_FALSE; 5490dc2366fSVenugopal Iyer boolean_t flow_arg = B_FALSE; 5500dc2366fSVenugopal Iyer datalink_id_t linkid = DATALINK_ALL_LINKID; 5510dc2366fSVenugopal Iyer char linkname[MAXLINKNAMELEN]; 5520dc2366fSVenugopal Iyer char flowname[MAXFLOWNAMELEN]; 5530dc2366fSVenugopal Iyer uint32_t interval = 0; 5540dc2366fSVenugopal Iyer char unit = '\0'; 5550dc2366fSVenugopal Iyer show_flow_state_t state; 5560dc2366fSVenugopal Iyer char *fields_str = NULL; 5570dc2366fSVenugopal Iyer char *o_fields_str = NULL; 5580dc2366fSVenugopal Iyer 5590dc2366fSVenugopal Iyer char *total_stat_fields = 5600dc2366fSVenugopal Iyer "flow,ipkts,rbytes,ierrs,opkts,obytes,oerrs"; 5610dc2366fSVenugopal Iyer char *rx_stat_fields = 5620dc2366fSVenugopal Iyer "flow,ipkts,rbytes,ierrs"; 5630dc2366fSVenugopal Iyer char *tx_stat_fields = 5640dc2366fSVenugopal Iyer "flow,opkts,obytes,oerrs"; 5650dc2366fSVenugopal Iyer 5660dc2366fSVenugopal Iyer ofmt_handle_t ofmt; 5670dc2366fSVenugopal Iyer ofmt_status_t oferr; 5680dc2366fSVenugopal Iyer uint_t ofmtflags = OFMT_RIGHTJUST; 5690dc2366fSVenugopal Iyer 5700dc2366fSVenugopal Iyer dladm_flow_attr_t attr; 5710dc2366fSVenugopal Iyer 5720dc2366fSVenugopal Iyer (void) setlocale(LC_ALL, ""); 5730dc2366fSVenugopal Iyer #if !defined(TEXT_DOMAIN) 5740dc2366fSVenugopal Iyer #define TEXT_DOMAIN "SYS_TEST" 5750dc2366fSVenugopal Iyer #endif 5760dc2366fSVenugopal Iyer (void) textdomain(TEXT_DOMAIN); 5770dc2366fSVenugopal Iyer 5780dc2366fSVenugopal Iyer progname = argv[0]; 5790dc2366fSVenugopal Iyer 5800dc2366fSVenugopal Iyer /* Open the libdladm handle */ 5810dc2366fSVenugopal Iyer if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) 5820dc2366fSVenugopal Iyer die_dlerr(status, "could not open /dev/dld"); 5830dc2366fSVenugopal Iyer 5840dc2366fSVenugopal Iyer bzero(&state, sizeof (state)); 5850dc2366fSVenugopal Iyer 5860dc2366fSVenugopal Iyer opterr = 0; 587*62ef8476SYuri Pankov while ((option = getopt_long(argc, argv, ":rtApi:o:u:l:h", 5880dc2366fSVenugopal Iyer NULL, NULL)) != -1) { 5890dc2366fSVenugopal Iyer switch (option) { 5900dc2366fSVenugopal Iyer case 'r': 5910dc2366fSVenugopal Iyer if (r_arg) 5920dc2366fSVenugopal Iyer die_optdup(option); 5930dc2366fSVenugopal Iyer 5940dc2366fSVenugopal Iyer r_arg = B_TRUE; 5950dc2366fSVenugopal Iyer break; 5960dc2366fSVenugopal Iyer case 't': 5970dc2366fSVenugopal Iyer if (t_arg) 5980dc2366fSVenugopal Iyer die_optdup(option); 5990dc2366fSVenugopal Iyer 6000dc2366fSVenugopal Iyer t_arg = B_TRUE; 6010dc2366fSVenugopal Iyer break; 6020dc2366fSVenugopal Iyer case 'A': 6030dc2366fSVenugopal Iyer if (A_arg) 6040dc2366fSVenugopal Iyer die_optdup(option); 6050dc2366fSVenugopal Iyer 6060dc2366fSVenugopal Iyer A_arg = B_TRUE; 6070dc2366fSVenugopal Iyer break; 6080dc2366fSVenugopal Iyer case 'p': 6090dc2366fSVenugopal Iyer if (p_arg) 6100dc2366fSVenugopal Iyer die_optdup(option); 6110dc2366fSVenugopal Iyer 6120dc2366fSVenugopal Iyer p_arg = B_TRUE; 6130dc2366fSVenugopal Iyer break; 6140dc2366fSVenugopal Iyer case 'i': 6150dc2366fSVenugopal Iyer if (i_arg) 6160dc2366fSVenugopal Iyer die_optdup(option); 6170dc2366fSVenugopal Iyer 6180dc2366fSVenugopal Iyer i_arg = B_TRUE; 6190dc2366fSVenugopal Iyer if (!dladm_str2interval(optarg, &interval)) 6200dc2366fSVenugopal Iyer die("invalid interval value '%s'", optarg); 6210dc2366fSVenugopal Iyer break; 6220dc2366fSVenugopal Iyer case 'o': 6230dc2366fSVenugopal Iyer o_arg = B_TRUE; 6240dc2366fSVenugopal Iyer o_fields_str = optarg; 6250dc2366fSVenugopal Iyer break; 6260dc2366fSVenugopal Iyer case 'u': 6270dc2366fSVenugopal Iyer if (u_arg) 6280dc2366fSVenugopal Iyer die_optdup(option); 6290dc2366fSVenugopal Iyer 6300dc2366fSVenugopal Iyer u_arg = B_TRUE; 6310dc2366fSVenugopal Iyer if (!flowstat_unit(optarg, &unit)) 6320dc2366fSVenugopal Iyer die("invalid unit value '%s'," 6330dc2366fSVenugopal Iyer "unit must be R|K|M|G|T|P", optarg); 6340dc2366fSVenugopal Iyer break; 6350dc2366fSVenugopal Iyer case 'l': 6360dc2366fSVenugopal Iyer if (strlcpy(linkname, optarg, MAXLINKNAMELEN) 6370dc2366fSVenugopal Iyer >= MAXLINKNAMELEN) 6380dc2366fSVenugopal Iyer die("link name too long\n"); 6390dc2366fSVenugopal Iyer if (dladm_name2info(handle, linkname, &linkid, NULL, 6400dc2366fSVenugopal Iyer NULL, NULL) != DLADM_STATUS_OK) 6410dc2366fSVenugopal Iyer die("invalid link '%s'", linkname); 6420dc2366fSVenugopal Iyer break; 6430dc2366fSVenugopal Iyer case 'h': 6440dc2366fSVenugopal Iyer if (r_arg || t_arg || p_arg || o_arg || u_arg || 645*62ef8476SYuri Pankov i_arg || A_arg) { 6460dc2366fSVenugopal Iyer die("the option -h is not compatible with " 647*62ef8476SYuri Pankov "-r, -t, -p, -o, -u, -i, -A"); 6480dc2366fSVenugopal Iyer } 6490dc2366fSVenugopal Iyer do_show_history(argc, argv); 6500dc2366fSVenugopal Iyer return (0); 6510dc2366fSVenugopal Iyer break; 6520dc2366fSVenugopal Iyer default: 6530dc2366fSVenugopal Iyer die_opterr(optopt, option, usage_ermsg); 6540dc2366fSVenugopal Iyer break; 6550dc2366fSVenugopal Iyer } 6560dc2366fSVenugopal Iyer } 6570dc2366fSVenugopal Iyer 6580dc2366fSVenugopal Iyer if (r_arg && t_arg) 6590dc2366fSVenugopal Iyer die("the option -t and -r are not compatible"); 6600dc2366fSVenugopal Iyer 6610dc2366fSVenugopal Iyer if (u_arg && p_arg) 6620dc2366fSVenugopal Iyer die("the option -u and -p are not compatible"); 6630dc2366fSVenugopal Iyer 6640dc2366fSVenugopal Iyer if (p_arg && !o_arg) 6650dc2366fSVenugopal Iyer die("-p requires -o"); 6660dc2366fSVenugopal Iyer 6670dc2366fSVenugopal Iyer if (p_arg && strcasecmp(o_fields_str, "all") == 0) 6680dc2366fSVenugopal Iyer die("\"-o all\" is invalid with -p"); 6690dc2366fSVenugopal Iyer 6700dc2366fSVenugopal Iyer if (A_arg && 6710dc2366fSVenugopal Iyer (r_arg || t_arg || p_arg || o_arg || u_arg || i_arg)) 6720dc2366fSVenugopal Iyer die("the option -A is not compatible with " 6730dc2366fSVenugopal Iyer "-r, -t, -p, -o, -u, -i"); 6740dc2366fSVenugopal Iyer 6750dc2366fSVenugopal Iyer /* get flow name (optional last argument) */ 6760dc2366fSVenugopal Iyer if (optind == (argc-1)) { 6770dc2366fSVenugopal Iyer if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN) 6780dc2366fSVenugopal Iyer >= MAXFLOWNAMELEN) 6790dc2366fSVenugopal Iyer die("flow name too long"); 6800dc2366fSVenugopal Iyer flow_arg = B_TRUE; 6810dc2366fSVenugopal Iyer } else if (optind != argc) { 6820dc2366fSVenugopal Iyer usage(); 6830dc2366fSVenugopal Iyer } 6840dc2366fSVenugopal Iyer 6850dc2366fSVenugopal Iyer if (flow_arg && 6860dc2366fSVenugopal Iyer dladm_flow_info(handle, flowname, &attr) != DLADM_STATUS_OK) 6870dc2366fSVenugopal Iyer die("invalid flow %s", flowname); 6880dc2366fSVenugopal Iyer 6890dc2366fSVenugopal Iyer if (A_arg) { 6900dc2366fSVenugopal Iyer dump_all_flow_stats(&attr, &state, linkid, flow_arg); 6910dc2366fSVenugopal Iyer return (0); 6920dc2366fSVenugopal Iyer } 6930dc2366fSVenugopal Iyer 6940dc2366fSVenugopal Iyer state.fs_unit = unit; 6950dc2366fSVenugopal Iyer state.fs_parsable = p_arg; 6960dc2366fSVenugopal Iyer 6970dc2366fSVenugopal Iyer if (state.fs_parsable) 6980dc2366fSVenugopal Iyer ofmtflags |= OFMT_PARSABLE; 6990dc2366fSVenugopal Iyer 7000dc2366fSVenugopal Iyer if (r_arg) 7010dc2366fSVenugopal Iyer fields_str = rx_stat_fields; 7020dc2366fSVenugopal Iyer else if (t_arg) 7030dc2366fSVenugopal Iyer fields_str = tx_stat_fields; 7040dc2366fSVenugopal Iyer else 7050dc2366fSVenugopal Iyer fields_str = total_stat_fields; 7060dc2366fSVenugopal Iyer 7070dc2366fSVenugopal Iyer if (o_arg) { 7080dc2366fSVenugopal Iyer fields_str = (strcasecmp(o_fields_str, "all") == 0) ? 7090dc2366fSVenugopal Iyer fields_str : o_fields_str; 7100dc2366fSVenugopal Iyer } 7110dc2366fSVenugopal Iyer 7120dc2366fSVenugopal Iyer oferr = ofmt_open(fields_str, flow_s_fields, ofmtflags, 0, &ofmt); 7130dc2366fSVenugopal Iyer flowstat_ofmt_check(oferr, state.fs_parsable, ofmt); 7140dc2366fSVenugopal Iyer state.fs_ofmt = ofmt; 7150dc2366fSVenugopal Iyer 7160dc2366fSVenugopal Iyer for (;;) { 7170dc2366fSVenugopal Iyer /* Show stats for named flow */ 7180dc2366fSVenugopal Iyer if (flow_arg) { 7190dc2366fSVenugopal Iyer (void) query_flow_stats(handle, &attr, &state); 7200dc2366fSVenugopal Iyer 7210dc2366fSVenugopal Iyer /* Show stats for flows on one link */ 7220dc2366fSVenugopal Iyer } else if (linkid != DATALINK_INVALID_LINKID) { 7230dc2366fSVenugopal Iyer (void) dladm_walk_flow(query_flow_stats, handle, linkid, 7240dc2366fSVenugopal Iyer &state, B_FALSE); 7250dc2366fSVenugopal Iyer 7260dc2366fSVenugopal Iyer /* Show stats for all flows on all links */ 7270dc2366fSVenugopal Iyer } else { 7280dc2366fSVenugopal Iyer (void) dladm_walk_datalink_id(query_link_flow_stats, 7290dc2366fSVenugopal Iyer handle, &state, DATALINK_CLASS_ALL, 7300dc2366fSVenugopal Iyer DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 7310dc2366fSVenugopal Iyer } 7320dc2366fSVenugopal Iyer 7330dc2366fSVenugopal Iyer if (interval == 0) 7340dc2366fSVenugopal Iyer break; 7350dc2366fSVenugopal Iyer 7360dc2366fSVenugopal Iyer (void) fflush(stdout); 7370dc2366fSVenugopal Iyer cleanup_removed_flows(&state); 7380dc2366fSVenugopal Iyer (void) sleep(interval); 7390dc2366fSVenugopal Iyer } 7400dc2366fSVenugopal Iyer ofmt_close(ofmt); 7410dc2366fSVenugopal Iyer 7420dc2366fSVenugopal Iyer dladm_close(handle); 7430dc2366fSVenugopal Iyer return (0); 7440dc2366fSVenugopal Iyer } 7450dc2366fSVenugopal Iyer 7460dc2366fSVenugopal Iyer /* ARGSUSED */ 7470dc2366fSVenugopal Iyer static int 7480dc2366fSVenugopal Iyer show_history_date(dladm_usage_t *history, void *arg) 7490dc2366fSVenugopal Iyer { 7500dc2366fSVenugopal Iyer show_history_state_t *state = (show_history_state_t *)arg; 7510dc2366fSVenugopal Iyer time_t stime; 7520dc2366fSVenugopal Iyer char timebuf[20]; 7530dc2366fSVenugopal Iyer dladm_flow_attr_t attr; 7540dc2366fSVenugopal Iyer dladm_status_t status; 7550dc2366fSVenugopal Iyer 7560dc2366fSVenugopal Iyer /* 7570dc2366fSVenugopal Iyer * Only show historical information for existing flows unless '-a' 7580dc2366fSVenugopal Iyer * is specified. 7590dc2366fSVenugopal Iyer */ 7600dc2366fSVenugopal Iyer if (!state->us_showall && ((status = dladm_flow_info(handle, 7610dc2366fSVenugopal Iyer history->du_name, &attr)) != DLADM_STATUS_OK)) { 7620dc2366fSVenugopal Iyer return (status); 7630dc2366fSVenugopal Iyer } 7640dc2366fSVenugopal Iyer 7650dc2366fSVenugopal Iyer stime = history->du_stime; 7660dc2366fSVenugopal Iyer (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y", 7670dc2366fSVenugopal Iyer localtime(&stime)); 7680dc2366fSVenugopal Iyer (void) printf("%s\n", timebuf); 7690dc2366fSVenugopal Iyer 7700dc2366fSVenugopal Iyer return (DLADM_STATUS_OK); 7710dc2366fSVenugopal Iyer } 7720dc2366fSVenugopal Iyer 7730dc2366fSVenugopal Iyer static int 7740dc2366fSVenugopal Iyer show_history_time(dladm_usage_t *history, void *arg) 7750dc2366fSVenugopal Iyer { 7760dc2366fSVenugopal Iyer show_history_state_t *state = (show_history_state_t *)arg; 7770dc2366fSVenugopal Iyer char buf[DLADM_STRSIZE]; 7780dc2366fSVenugopal Iyer history_l_fields_buf_t ubuf; 7790dc2366fSVenugopal Iyer time_t time; 7800dc2366fSVenugopal Iyer double bw; 7810dc2366fSVenugopal Iyer dladm_flow_attr_t attr; 7820dc2366fSVenugopal Iyer dladm_status_t status; 7830dc2366fSVenugopal Iyer 7840dc2366fSVenugopal Iyer /* 7850dc2366fSVenugopal Iyer * Only show historical information for existing flows unless '-a' 7860dc2366fSVenugopal Iyer * is specified. 7870dc2366fSVenugopal Iyer */ 7880dc2366fSVenugopal Iyer if (!state->us_showall && ((status = dladm_flow_info(handle, 7890dc2366fSVenugopal Iyer history->du_name, &attr)) != DLADM_STATUS_OK)) { 7900dc2366fSVenugopal Iyer return (status); 7910dc2366fSVenugopal Iyer } 7920dc2366fSVenugopal Iyer 7930dc2366fSVenugopal Iyer if (state->us_plot) { 7940dc2366fSVenugopal Iyer if (!state->us_printheader) { 7950dc2366fSVenugopal Iyer if (state->us_first) { 7960dc2366fSVenugopal Iyer (void) printf("# Time"); 7970dc2366fSVenugopal Iyer state->us_first = B_FALSE; 7980dc2366fSVenugopal Iyer } 7990dc2366fSVenugopal Iyer (void) printf(" %s", history->du_name); 8000dc2366fSVenugopal Iyer if (history->du_last) { 8010dc2366fSVenugopal Iyer (void) printf("\n"); 8020dc2366fSVenugopal Iyer state->us_first = B_TRUE; 8030dc2366fSVenugopal Iyer state->us_printheader = B_TRUE; 8040dc2366fSVenugopal Iyer } 8050dc2366fSVenugopal Iyer } else { 8060dc2366fSVenugopal Iyer if (state->us_first) { 8070dc2366fSVenugopal Iyer time = history->du_etime; 8080dc2366fSVenugopal Iyer (void) strftime(buf, sizeof (buf), "%T", 8090dc2366fSVenugopal Iyer localtime(&time)); 8100dc2366fSVenugopal Iyer state->us_first = B_FALSE; 8110dc2366fSVenugopal Iyer (void) printf("%s", buf); 8120dc2366fSVenugopal Iyer } 8130dc2366fSVenugopal Iyer bw = (double)history->du_bandwidth/1000; 8140dc2366fSVenugopal Iyer (void) printf(" %.2f", bw); 8150dc2366fSVenugopal Iyer if (history->du_last) { 8160dc2366fSVenugopal Iyer (void) printf("\n"); 8170dc2366fSVenugopal Iyer state->us_first = B_TRUE; 8180dc2366fSVenugopal Iyer } 8190dc2366fSVenugopal Iyer } 8200dc2366fSVenugopal Iyer return (DLADM_STATUS_OK); 8210dc2366fSVenugopal Iyer } 8220dc2366fSVenugopal Iyer 8230dc2366fSVenugopal Iyer bzero(&ubuf, sizeof (ubuf)); 8240dc2366fSVenugopal Iyer 8250dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_l_flow, sizeof (ubuf.history_l_flow), "%s", 8260dc2366fSVenugopal Iyer history->du_name); 8270dc2366fSVenugopal Iyer time = history->du_stime; 8280dc2366fSVenugopal Iyer (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 8290dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_l_stime, sizeof (ubuf.history_l_stime), 8300dc2366fSVenugopal Iyer "%s", buf); 8310dc2366fSVenugopal Iyer time = history->du_etime; 8320dc2366fSVenugopal Iyer (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 8330dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_l_etime, sizeof (ubuf.history_l_etime), 8340dc2366fSVenugopal Iyer "%s", buf); 8350dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_l_rbytes, sizeof (ubuf.history_l_rbytes), 8360dc2366fSVenugopal Iyer "%llu", history->du_rbytes); 8370dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_l_obytes, sizeof (ubuf.history_l_obytes), 8380dc2366fSVenugopal Iyer "%llu", history->du_obytes); 8390dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_l_bandwidth, 8400dc2366fSVenugopal Iyer sizeof (ubuf.history_l_bandwidth), "%s Mbps", 8410dc2366fSVenugopal Iyer dladm_bw2str(history->du_bandwidth, buf)); 8420dc2366fSVenugopal Iyer 8430dc2366fSVenugopal Iyer ofmt_print(state->us_ofmt, (void *)&ubuf); 8440dc2366fSVenugopal Iyer return (DLADM_STATUS_OK); 8450dc2366fSVenugopal Iyer } 8460dc2366fSVenugopal Iyer 8470dc2366fSVenugopal Iyer static int 8480dc2366fSVenugopal Iyer show_history_res(dladm_usage_t *history, void *arg) 8490dc2366fSVenugopal Iyer { 8500dc2366fSVenugopal Iyer show_history_state_t *state = (show_history_state_t *)arg; 8510dc2366fSVenugopal Iyer char buf[DLADM_STRSIZE]; 8520dc2366fSVenugopal Iyer history_fields_buf_t ubuf; 8530dc2366fSVenugopal Iyer dladm_flow_attr_t attr; 8540dc2366fSVenugopal Iyer dladm_status_t status; 8550dc2366fSVenugopal Iyer 8560dc2366fSVenugopal Iyer /* 8570dc2366fSVenugopal Iyer * Only show historical information for existing flows unless '-a' 8580dc2366fSVenugopal Iyer * is specified. 8590dc2366fSVenugopal Iyer */ 8600dc2366fSVenugopal Iyer if (!state->us_showall && ((status = dladm_flow_info(handle, 8610dc2366fSVenugopal Iyer history->du_name, &attr)) != DLADM_STATUS_OK)) { 8620dc2366fSVenugopal Iyer return (status); 8630dc2366fSVenugopal Iyer } 8640dc2366fSVenugopal Iyer 8650dc2366fSVenugopal Iyer bzero(&ubuf, sizeof (ubuf)); 8660dc2366fSVenugopal Iyer 8670dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_flow, sizeof (ubuf.history_flow), "%s", 8680dc2366fSVenugopal Iyer history->du_name); 8690dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_duration, sizeof (ubuf.history_duration), 8700dc2366fSVenugopal Iyer "%llu", history->du_duration); 8710dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_ipackets, sizeof (ubuf.history_ipackets), 8720dc2366fSVenugopal Iyer "%llu", history->du_ipackets); 8730dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_rbytes, sizeof (ubuf.history_rbytes), 8740dc2366fSVenugopal Iyer "%llu", history->du_rbytes); 8750dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_opackets, sizeof (ubuf.history_opackets), 8760dc2366fSVenugopal Iyer "%llu", history->du_opackets); 8770dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_obytes, sizeof (ubuf.history_obytes), 8780dc2366fSVenugopal Iyer "%llu", history->du_obytes); 8790dc2366fSVenugopal Iyer (void) snprintf(ubuf.history_bandwidth, sizeof (ubuf.history_bandwidth), 8800dc2366fSVenugopal Iyer "%s Mbps", dladm_bw2str(history->du_bandwidth, buf)); 8810dc2366fSVenugopal Iyer 8820dc2366fSVenugopal Iyer ofmt_print(state->us_ofmt, (void *)&ubuf); 8830dc2366fSVenugopal Iyer 8840dc2366fSVenugopal Iyer return (DLADM_STATUS_OK); 8850dc2366fSVenugopal Iyer } 8860dc2366fSVenugopal Iyer 8870dc2366fSVenugopal Iyer static boolean_t 8880dc2366fSVenugopal Iyer valid_formatspec(char *formatspec_str) 8890dc2366fSVenugopal Iyer { 8900dc2366fSVenugopal Iyer return (strcmp(formatspec_str, "gnuplot") == 0); 8910dc2366fSVenugopal Iyer } 8920dc2366fSVenugopal Iyer 8930dc2366fSVenugopal Iyer /* ARGSUSED */ 8940dc2366fSVenugopal Iyer static void 8950dc2366fSVenugopal Iyer do_show_history(int argc, char *argv[]) 8960dc2366fSVenugopal Iyer { 8970dc2366fSVenugopal Iyer char *file = NULL; 8980dc2366fSVenugopal Iyer int opt; 8990dc2366fSVenugopal Iyer dladm_status_t status; 9000dc2366fSVenugopal Iyer boolean_t d_arg = B_FALSE; 9010dc2366fSVenugopal Iyer char *stime = NULL; 9020dc2366fSVenugopal Iyer char *etime = NULL; 9030dc2366fSVenugopal Iyer char *resource = NULL; 9040dc2366fSVenugopal Iyer show_history_state_t state; 9050dc2366fSVenugopal Iyer boolean_t o_arg = B_FALSE; 9060dc2366fSVenugopal Iyer boolean_t F_arg = B_FALSE; 9070dc2366fSVenugopal Iyer char *fields_str = NULL; 9080dc2366fSVenugopal Iyer char *formatspec_str = NULL; 9090dc2366fSVenugopal Iyer char *all_fields = 9100dc2366fSVenugopal Iyer "flow,duration,ipackets,rbytes,opackets,obytes,bandwidth"; 9110dc2366fSVenugopal Iyer char *all_l_fields = 9120dc2366fSVenugopal Iyer "flow,start,end,rbytes,obytes,bandwidth"; 9130dc2366fSVenugopal Iyer ofmt_handle_t ofmt; 9140dc2366fSVenugopal Iyer ofmt_status_t oferr; 9150dc2366fSVenugopal Iyer uint_t ofmtflags = 0; 9160dc2366fSVenugopal Iyer 9170dc2366fSVenugopal Iyer bzero(&state, sizeof (show_history_state_t)); 9180dc2366fSVenugopal Iyer state.us_parsable = B_FALSE; 9190dc2366fSVenugopal Iyer state.us_printheader = B_FALSE; 9200dc2366fSVenugopal Iyer state.us_plot = B_FALSE; 9210dc2366fSVenugopal Iyer state.us_first = B_TRUE; 9220dc2366fSVenugopal Iyer 9230dc2366fSVenugopal Iyer while ((opt = getopt(argc, argv, "das:e:o:f:F:")) != -1) { 9240dc2366fSVenugopal Iyer switch (opt) { 9250dc2366fSVenugopal Iyer case 'd': 9260dc2366fSVenugopal Iyer d_arg = B_TRUE; 9270dc2366fSVenugopal Iyer break; 9280dc2366fSVenugopal Iyer case 'a': 9290dc2366fSVenugopal Iyer state.us_showall = B_TRUE; 9300dc2366fSVenugopal Iyer break; 9310dc2366fSVenugopal Iyer case 'f': 9320dc2366fSVenugopal Iyer file = optarg; 9330dc2366fSVenugopal Iyer break; 9340dc2366fSVenugopal Iyer case 's': 9350dc2366fSVenugopal Iyer stime = optarg; 9360dc2366fSVenugopal Iyer break; 9370dc2366fSVenugopal Iyer case 'e': 9380dc2366fSVenugopal Iyer etime = optarg; 9390dc2366fSVenugopal Iyer break; 9400dc2366fSVenugopal Iyer case 'o': 9410dc2366fSVenugopal Iyer o_arg = B_TRUE; 9420dc2366fSVenugopal Iyer fields_str = optarg; 9430dc2366fSVenugopal Iyer break; 9440dc2366fSVenugopal Iyer case 'F': 9450dc2366fSVenugopal Iyer state.us_plot = F_arg = B_TRUE; 9460dc2366fSVenugopal Iyer formatspec_str = optarg; 9470dc2366fSVenugopal Iyer break; 9480dc2366fSVenugopal Iyer default: 9490dc2366fSVenugopal Iyer die_opterr(optopt, opt, usage_ermsg); 9500dc2366fSVenugopal Iyer } 9510dc2366fSVenugopal Iyer } 9520dc2366fSVenugopal Iyer 9530dc2366fSVenugopal Iyer if (file == NULL) 9540dc2366fSVenugopal Iyer die("-h requires a file"); 9550dc2366fSVenugopal Iyer 9560dc2366fSVenugopal Iyer if (optind == (argc-1)) { 9570dc2366fSVenugopal Iyer dladm_flow_attr_t attr; 9580dc2366fSVenugopal Iyer 9590dc2366fSVenugopal Iyer resource = argv[optind]; 9600dc2366fSVenugopal Iyer if (!state.us_showall && 9610dc2366fSVenugopal Iyer dladm_flow_info(handle, resource, &attr) != 9620dc2366fSVenugopal Iyer DLADM_STATUS_OK) { 9630dc2366fSVenugopal Iyer die("invalid flow: '%s'", resource); 9640dc2366fSVenugopal Iyer } 9650dc2366fSVenugopal Iyer } 9660dc2366fSVenugopal Iyer 9670dc2366fSVenugopal Iyer if (state.us_parsable) 9680dc2366fSVenugopal Iyer ofmtflags |= OFMT_PARSABLE; 9690dc2366fSVenugopal Iyer if (resource == NULL && stime == NULL && etime == NULL) { 9700dc2366fSVenugopal Iyer if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 9710dc2366fSVenugopal Iyer fields_str = all_fields; 9720dc2366fSVenugopal Iyer oferr = ofmt_open(fields_str, history_fields, ofmtflags, 9730dc2366fSVenugopal Iyer 0, &ofmt); 9740dc2366fSVenugopal Iyer } else { 9750dc2366fSVenugopal Iyer if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 9760dc2366fSVenugopal Iyer fields_str = all_l_fields; 9770dc2366fSVenugopal Iyer oferr = ofmt_open(fields_str, history_l_fields, ofmtflags, 9780dc2366fSVenugopal Iyer 0, &ofmt); 9790dc2366fSVenugopal Iyer } 9800dc2366fSVenugopal Iyer 9810dc2366fSVenugopal Iyer flowstat_ofmt_check(oferr, state.us_parsable, ofmt); 9820dc2366fSVenugopal Iyer state.us_ofmt = ofmt; 9830dc2366fSVenugopal Iyer 9840dc2366fSVenugopal Iyer if (F_arg && d_arg) 9850dc2366fSVenugopal Iyer die("incompatible -d and -F options"); 9860dc2366fSVenugopal Iyer 9870dc2366fSVenugopal Iyer if (F_arg && !valid_formatspec(formatspec_str)) 9880dc2366fSVenugopal Iyer die("Format specifier %s not supported", formatspec_str); 9890dc2366fSVenugopal Iyer 9900dc2366fSVenugopal Iyer if (d_arg) { 9910dc2366fSVenugopal Iyer /* Print log dates */ 9920dc2366fSVenugopal Iyer status = dladm_usage_dates(show_history_date, 9930dc2366fSVenugopal Iyer DLADM_LOGTYPE_FLOW, file, resource, &state); 9940dc2366fSVenugopal Iyer } else if (resource == NULL && stime == NULL && etime == NULL && 9950dc2366fSVenugopal Iyer !F_arg) { 9960dc2366fSVenugopal Iyer /* Print summary */ 9970dc2366fSVenugopal Iyer status = dladm_usage_summary(show_history_res, 9980dc2366fSVenugopal Iyer DLADM_LOGTYPE_FLOW, file, &state); 9990dc2366fSVenugopal Iyer } else if (resource != NULL) { 10000dc2366fSVenugopal Iyer /* Print log entries for named resource */ 10010dc2366fSVenugopal Iyer status = dladm_walk_usage_res(show_history_time, 10020dc2366fSVenugopal Iyer DLADM_LOGTYPE_FLOW, file, resource, stime, etime, &state); 10030dc2366fSVenugopal Iyer } else { 10040dc2366fSVenugopal Iyer /* Print time and information for each flow */ 10050dc2366fSVenugopal Iyer status = dladm_walk_usage_time(show_history_time, 10060dc2366fSVenugopal Iyer DLADM_LOGTYPE_FLOW, file, stime, etime, &state); 10070dc2366fSVenugopal Iyer } 10080dc2366fSVenugopal Iyer 10090dc2366fSVenugopal Iyer ofmt_close(ofmt); 10100dc2366fSVenugopal Iyer if (status != DLADM_STATUS_OK) 10110dc2366fSVenugopal Iyer die_dlerr(status, "-h"); 10120dc2366fSVenugopal Iyer dladm_close(handle); 10130dc2366fSVenugopal Iyer } 10140dc2366fSVenugopal Iyer 10150dc2366fSVenugopal Iyer static void 10160dc2366fSVenugopal Iyer warn(const char *format, ...) 10170dc2366fSVenugopal Iyer { 10180dc2366fSVenugopal Iyer va_list alist; 10190dc2366fSVenugopal Iyer 10200dc2366fSVenugopal Iyer format = gettext(format); 10210dc2366fSVenugopal Iyer (void) fprintf(stderr, "%s: warning: ", progname); 10220dc2366fSVenugopal Iyer 10230dc2366fSVenugopal Iyer va_start(alist, format); 10240dc2366fSVenugopal Iyer (void) vfprintf(stderr, format, alist); 10250dc2366fSVenugopal Iyer va_end(alist); 10260dc2366fSVenugopal Iyer 10270dc2366fSVenugopal Iyer (void) putc('\n', stderr); 10280dc2366fSVenugopal Iyer } 10290dc2366fSVenugopal Iyer 10300dc2366fSVenugopal Iyer /* PRINTFLIKE1 */ 10310dc2366fSVenugopal Iyer static void 10320dc2366fSVenugopal Iyer die(const char *format, ...) 10330dc2366fSVenugopal Iyer { 10340dc2366fSVenugopal Iyer va_list alist; 10350dc2366fSVenugopal Iyer 10360dc2366fSVenugopal Iyer format = gettext(format); 10370dc2366fSVenugopal Iyer (void) fprintf(stderr, "%s: ", progname); 10380dc2366fSVenugopal Iyer 10390dc2366fSVenugopal Iyer va_start(alist, format); 10400dc2366fSVenugopal Iyer (void) vfprintf(stderr, format, alist); 10410dc2366fSVenugopal Iyer va_end(alist); 10420dc2366fSVenugopal Iyer 10430dc2366fSVenugopal Iyer (void) putc('\n', stderr); 10440dc2366fSVenugopal Iyer 10450dc2366fSVenugopal Iyer /* close dladm handle if it was opened */ 10460dc2366fSVenugopal Iyer if (handle != NULL) 10470dc2366fSVenugopal Iyer dladm_close(handle); 10480dc2366fSVenugopal Iyer 10490dc2366fSVenugopal Iyer exit(EXIT_FAILURE); 10500dc2366fSVenugopal Iyer } 10510dc2366fSVenugopal Iyer 10520dc2366fSVenugopal Iyer static void 10530dc2366fSVenugopal Iyer die_optdup(int opt) 10540dc2366fSVenugopal Iyer { 10550dc2366fSVenugopal Iyer die("the option -%c cannot be specified more than once", opt); 10560dc2366fSVenugopal Iyer } 10570dc2366fSVenugopal Iyer 10580dc2366fSVenugopal Iyer static void 10590dc2366fSVenugopal Iyer die_opterr(int opt, int opterr, const char *usage) 10600dc2366fSVenugopal Iyer { 10610dc2366fSVenugopal Iyer switch (opterr) { 10620dc2366fSVenugopal Iyer case ':': 10630dc2366fSVenugopal Iyer die("option '-%c' requires a value\nusage: %s", opt, 10640dc2366fSVenugopal Iyer gettext(usage)); 10650dc2366fSVenugopal Iyer break; 10660dc2366fSVenugopal Iyer case '?': 10670dc2366fSVenugopal Iyer default: 10680dc2366fSVenugopal Iyer die("unrecognized option '-%c'\nusage: %s", opt, 10690dc2366fSVenugopal Iyer gettext(usage)); 10700dc2366fSVenugopal Iyer break; 10710dc2366fSVenugopal Iyer } 10720dc2366fSVenugopal Iyer } 10730dc2366fSVenugopal Iyer 10740dc2366fSVenugopal Iyer /* PRINTFLIKE2 */ 10750dc2366fSVenugopal Iyer static void 10760dc2366fSVenugopal Iyer die_dlerr(dladm_status_t err, const char *format, ...) 10770dc2366fSVenugopal Iyer { 10780dc2366fSVenugopal Iyer va_list alist; 10790dc2366fSVenugopal Iyer char errmsg[DLADM_STRSIZE]; 10800dc2366fSVenugopal Iyer 10810dc2366fSVenugopal Iyer format = gettext(format); 10820dc2366fSVenugopal Iyer (void) fprintf(stderr, "%s: ", progname); 10830dc2366fSVenugopal Iyer 10840dc2366fSVenugopal Iyer va_start(alist, format); 10850dc2366fSVenugopal Iyer (void) vfprintf(stderr, format, alist); 10860dc2366fSVenugopal Iyer va_end(alist); 10870dc2366fSVenugopal Iyer (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 10880dc2366fSVenugopal Iyer 10890dc2366fSVenugopal Iyer /* close dladm handle if it was opened */ 10900dc2366fSVenugopal Iyer if (handle != NULL) 10910dc2366fSVenugopal Iyer dladm_close(handle); 10920dc2366fSVenugopal Iyer 10930dc2366fSVenugopal Iyer exit(EXIT_FAILURE); 10940dc2366fSVenugopal Iyer } 10950dc2366fSVenugopal Iyer 10960dc2366fSVenugopal Iyer 10970dc2366fSVenugopal Iyer /* 10980dc2366fSVenugopal Iyer * default output callback function that, when invoked from dladm_print_output, 10990dc2366fSVenugopal Iyer * prints string which is offset by of_arg->ofmt_id within buf. 11000dc2366fSVenugopal Iyer */ 11010dc2366fSVenugopal Iyer static boolean_t 11020dc2366fSVenugopal Iyer print_default_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 11030dc2366fSVenugopal Iyer { 11040dc2366fSVenugopal Iyer char *value; 11050dc2366fSVenugopal Iyer 11060dc2366fSVenugopal Iyer value = (char *)of_arg->ofmt_cbarg + of_arg->ofmt_id; 11070dc2366fSVenugopal Iyer (void) strlcpy(buf, value, bufsize); 11080dc2366fSVenugopal Iyer return (B_TRUE); 11090dc2366fSVenugopal Iyer } 11100dc2366fSVenugopal Iyer 11110dc2366fSVenugopal Iyer static void 11120dc2366fSVenugopal Iyer flowstat_ofmt_check(ofmt_status_t oferr, boolean_t parsable, 11130dc2366fSVenugopal Iyer ofmt_handle_t ofmt) 11140dc2366fSVenugopal Iyer { 11150dc2366fSVenugopal Iyer char buf[OFMT_BUFSIZE]; 11160dc2366fSVenugopal Iyer 11170dc2366fSVenugopal Iyer if (oferr == OFMT_SUCCESS) 11180dc2366fSVenugopal Iyer return; 11190dc2366fSVenugopal Iyer (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf)); 11200dc2366fSVenugopal Iyer /* 11210dc2366fSVenugopal Iyer * All errors are considered fatal in parsable mode. 11220dc2366fSVenugopal Iyer * NOMEM errors are always fatal, regardless of mode. 11230dc2366fSVenugopal Iyer * For other errors, we print diagnostics in human-readable 11240dc2366fSVenugopal Iyer * mode and processs what we can. 11250dc2366fSVenugopal Iyer */ 11260dc2366fSVenugopal Iyer if (parsable || oferr == OFMT_ENOFIELDS) { 11270dc2366fSVenugopal Iyer ofmt_close(ofmt); 11280dc2366fSVenugopal Iyer die(buf); 11290dc2366fSVenugopal Iyer } else { 11300dc2366fSVenugopal Iyer warn(buf); 11310dc2366fSVenugopal Iyer } 11320dc2366fSVenugopal Iyer } 1133