1da14cebeSEric Cheng /* 2da14cebeSEric Cheng * CDDL HEADER START 3da14cebeSEric Cheng * 4da14cebeSEric Cheng * The contents of this file are subject to the terms of the 5da14cebeSEric Cheng * Common Development and Distribution License (the "License"). 6da14cebeSEric Cheng * You may not use this file except in compliance with the License. 7da14cebeSEric Cheng * 8da14cebeSEric Cheng * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da14cebeSEric Cheng * or http://www.opensolaris.org/os/licensing. 10da14cebeSEric Cheng * See the License for the specific language governing permissions 11da14cebeSEric Cheng * and limitations under the License. 12da14cebeSEric Cheng * 13da14cebeSEric Cheng * When distributing Covered Code, include this CDDL HEADER in each 14da14cebeSEric Cheng * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da14cebeSEric Cheng * If applicable, add the following below this CDDL HEADER, with the 16da14cebeSEric Cheng * fields enclosed by brackets "[]" replaced with your own identifying 17da14cebeSEric Cheng * information: Portions Copyright [yyyy] [name of copyright owner] 18da14cebeSEric Cheng * 19da14cebeSEric Cheng * CDDL HEADER END 20da14cebeSEric Cheng */ 21da14cebeSEric Cheng /* 22da000602SGirish Moodalbail * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23da14cebeSEric Cheng * Use is subject to license terms. 24da14cebeSEric Cheng */ 25da14cebeSEric Cheng 26da14cebeSEric Cheng #include <stdio.h> 27da14cebeSEric Cheng #include <locale.h> 28da14cebeSEric Cheng #include <stdarg.h> 29da14cebeSEric Cheng #include <stdlib.h> 30da14cebeSEric Cheng #include <fcntl.h> 31da14cebeSEric Cheng #include <string.h> 32da14cebeSEric Cheng #include <stropts.h> 33da14cebeSEric Cheng #include <errno.h> 34da14cebeSEric Cheng #include <kstat.h> 35da14cebeSEric Cheng #include <strings.h> 36da14cebeSEric Cheng #include <getopt.h> 37da14cebeSEric Cheng #include <unistd.h> 38da14cebeSEric Cheng #include <priv.h> 39da14cebeSEric Cheng #include <netdb.h> 40da14cebeSEric Cheng #include <libintl.h> 41da14cebeSEric Cheng #include <libdlflow.h> 42da14cebeSEric Cheng #include <libdllink.h> 43da14cebeSEric Cheng #include <libdlstat.h> 44da14cebeSEric Cheng #include <sys/types.h> 45da14cebeSEric Cheng #include <sys/socket.h> 46da14cebeSEric Cheng #include <netinet/in.h> 47da14cebeSEric Cheng #include <arpa/inet.h> 48da14cebeSEric Cheng #include <sys/ethernet.h> 49da14cebeSEric Cheng #include <inet/ip.h> 50da14cebeSEric Cheng #include <inet/ip6.h> 51da14cebeSEric Cheng #include <stddef.h> 528002d411SSowmini Varadhan #include <ofmt.h> 53da14cebeSEric Cheng 54da14cebeSEric Cheng typedef struct show_usage_state_s { 55da14cebeSEric Cheng boolean_t us_plot; 568002d411SSowmini Varadhan boolean_t us_parsable; 57da14cebeSEric Cheng boolean_t us_printheader; 58da14cebeSEric Cheng boolean_t us_first; 59ae6aa22aSVenugopal Iyer boolean_t us_showall; 608002d411SSowmini Varadhan ofmt_handle_t us_ofmt; 61da14cebeSEric Cheng } show_usage_state_t; 62da14cebeSEric Cheng 63ae6aa22aSVenugopal Iyer typedef struct show_flow_state { 64ae6aa22aSVenugopal Iyer boolean_t fs_firstonly; 65ae6aa22aSVenugopal Iyer boolean_t fs_donefirst; 66ae6aa22aSVenugopal Iyer pktsum_t fs_prevstats; 67ae6aa22aSVenugopal Iyer uint32_t fs_flags; 68ae6aa22aSVenugopal Iyer dladm_status_t fs_status; 698002d411SSowmini Varadhan ofmt_handle_t fs_ofmt; 70ae6aa22aSVenugopal Iyer const char *fs_flow; 71ae6aa22aSVenugopal Iyer const char *fs_link; 728002d411SSowmini Varadhan boolean_t fs_parsable; 73ae6aa22aSVenugopal Iyer boolean_t fs_persist; 74ae6aa22aSVenugopal Iyer boolean_t fs_stats; 75ae6aa22aSVenugopal Iyer uint64_t fs_mask; 76ae6aa22aSVenugopal Iyer } show_flow_state_t; 77ae6aa22aSVenugopal Iyer 78da14cebeSEric Cheng typedef void cmdfunc_t(int, char **); 79da14cebeSEric Cheng 80da14cebeSEric Cheng static cmdfunc_t do_add_flow, do_remove_flow, do_init_flow, do_show_flow; 81da14cebeSEric Cheng static cmdfunc_t do_show_flowprop, do_set_flowprop, do_reset_flowprop; 82da14cebeSEric Cheng static cmdfunc_t do_show_usage; 83da14cebeSEric Cheng 84c3affd82SMichael Lim static int show_flow(dladm_handle_t, dladm_flow_attr_t *, void *); 854ac67f02SAnurag S. Maskey static int show_flows_onelink(dladm_handle_t, datalink_id_t, void *); 86da14cebeSEric Cheng 87ae6aa22aSVenugopal Iyer static void flow_stats(const char *, datalink_id_t, uint_t, char *, 88ae6aa22aSVenugopal Iyer show_flow_state_t *); 89da14cebeSEric Cheng static void get_flow_stats(const char *, pktsum_t *); 90c3affd82SMichael Lim static int show_flow_stats(dladm_handle_t, dladm_flow_attr_t *, void *); 914ac67f02SAnurag S. Maskey static int show_link_flow_stats(dladm_handle_t, datalink_id_t, void *); 92da14cebeSEric Cheng 93c3affd82SMichael Lim static int remove_flow(dladm_handle_t, dladm_flow_attr_t *, void *); 94da14cebeSEric Cheng 95c3affd82SMichael Lim static int show_flowprop(dladm_handle_t, dladm_flow_attr_t *, void *); 96da14cebeSEric Cheng static void show_flowprop_one_flow(void *, const char *); 974ac67f02SAnurag S. Maskey static int show_flowprop_onelink(dladm_handle_t, datalink_id_t, void *); 98da14cebeSEric Cheng 99da14cebeSEric Cheng static void die(const char *, ...); 100da14cebeSEric Cheng static void die_optdup(int); 101da14cebeSEric Cheng static void die_opterr(int, int); 102da14cebeSEric Cheng static void die_dlerr(dladm_status_t, const char *, ...); 103da14cebeSEric Cheng static void warn(const char *, ...); 104da14cebeSEric Cheng static void warn_dlerr(dladm_status_t, const char *, ...); 105da14cebeSEric Cheng 1068002d411SSowmini Varadhan /* callback functions for printing output */ 1078002d411SSowmini Varadhan static ofmt_cb_t print_flowprop_cb, print_default_cb, print_flow_stats_cb; 1088002d411SSowmini Varadhan static void flowadm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t); 1098002d411SSowmini Varadhan 110da14cebeSEric Cheng typedef struct cmd { 111da14cebeSEric Cheng char *c_name; 112da14cebeSEric Cheng void (*c_fn)(int, char **); 113da14cebeSEric Cheng } cmd_t; 114da14cebeSEric Cheng 115da14cebeSEric Cheng static cmd_t cmds[] = { 116da14cebeSEric Cheng { "add-flow", do_add_flow }, 117da14cebeSEric Cheng { "remove-flow", do_remove_flow }, 118da14cebeSEric Cheng { "show-flowprop", do_show_flowprop }, 119da14cebeSEric Cheng { "set-flowprop", do_set_flowprop }, 120da14cebeSEric Cheng { "reset-flowprop", do_reset_flowprop }, 121da14cebeSEric Cheng { "show-flow", do_show_flow }, 122da14cebeSEric Cheng { "init-flow", do_init_flow }, 123da14cebeSEric Cheng { "show-usage", do_show_usage } 124da14cebeSEric Cheng }; 125da14cebeSEric Cheng 126da14cebeSEric Cheng static const struct option longopts[] = { 127da14cebeSEric Cheng {"link", required_argument, 0, 'l'}, 1288002d411SSowmini Varadhan {"parsable", no_argument, 0, 'p'}, 129da14cebeSEric Cheng {"parseable", no_argument, 0, 'p'}, 130da14cebeSEric Cheng {"statistics", no_argument, 0, 's'}, 131da14cebeSEric Cheng {"interval", required_argument, 0, 'i'}, 132da14cebeSEric Cheng {"temporary", no_argument, 0, 't'}, 133da14cebeSEric Cheng {"root-dir", required_argument, 0, 'R'}, 134da14cebeSEric Cheng { 0, 0, 0, 0 } 135da14cebeSEric Cheng }; 136da14cebeSEric Cheng 137da14cebeSEric Cheng static const struct option prop_longopts[] = { 138da14cebeSEric Cheng {"link", required_argument, 0, 'l'}, 139da14cebeSEric Cheng {"temporary", no_argument, 0, 't'}, 140da14cebeSEric Cheng {"root-dir", required_argument, 0, 'R'}, 141da14cebeSEric Cheng {"prop", required_argument, 0, 'p'}, 142da14cebeSEric Cheng {"attr", required_argument, 0, 'a'}, 143da14cebeSEric Cheng { 0, 0, 0, 0 } 144da14cebeSEric Cheng }; 145da14cebeSEric Cheng 146da14cebeSEric Cheng /* 147da14cebeSEric Cheng * structures for 'flowadm remove-flow' 148da14cebeSEric Cheng */ 149da14cebeSEric Cheng typedef struct remove_flow_state { 150da14cebeSEric Cheng boolean_t fs_tempop; 151da14cebeSEric Cheng const char *fs_altroot; 152da14cebeSEric Cheng dladm_status_t fs_status; 153da14cebeSEric Cheng } remove_flow_state_t; 154da14cebeSEric Cheng 155da14cebeSEric Cheng #define PROTO_MAXSTR_LEN 7 156da14cebeSEric Cheng #define PORT_MAXSTR_LEN 6 157da14cebeSEric Cheng #define DSFIELD_MAXSTR_LEN 10 1588002d411SSowmini Varadhan #define NULL_OFMT {NULL, 0, 0, NULL} 159da14cebeSEric Cheng 160da14cebeSEric Cheng typedef struct flow_fields_buf_s 161da14cebeSEric Cheng { 162da000602SGirish Moodalbail char flow_name[MAXFLOWNAMELEN]; 163da14cebeSEric Cheng char flow_link[MAXLINKNAMELEN]; 164da14cebeSEric Cheng char flow_ipaddr[INET6_ADDRSTRLEN+4]; 165da14cebeSEric Cheng char flow_proto[PROTO_MAXSTR_LEN]; 166*25ec3e3dSEric Cheng char flow_lport[PORT_MAXSTR_LEN]; 167*25ec3e3dSEric Cheng char flow_rport[PORT_MAXSTR_LEN]; 168da14cebeSEric Cheng char flow_dsfield[DSFIELD_MAXSTR_LEN]; 169da14cebeSEric Cheng } flow_fields_buf_t; 170da14cebeSEric Cheng 1718002d411SSowmini Varadhan static ofmt_field_t flow_fields[] = { 1728002d411SSowmini Varadhan /* name, field width, index */ 1738002d411SSowmini Varadhan { "FLOW", 12, 1748002d411SSowmini Varadhan offsetof(flow_fields_buf_t, flow_name), print_default_cb}, 1758002d411SSowmini Varadhan { "LINK", 12, 1768002d411SSowmini Varadhan offsetof(flow_fields_buf_t, flow_link), print_default_cb}, 177*25ec3e3dSEric Cheng { "IPADDR", 25, 1788002d411SSowmini Varadhan offsetof(flow_fields_buf_t, flow_ipaddr), print_default_cb}, 1798002d411SSowmini Varadhan { "PROTO", 7, 1808002d411SSowmini Varadhan offsetof(flow_fields_buf_t, flow_proto), print_default_cb}, 181*25ec3e3dSEric Cheng { "LPORT", 8, 182*25ec3e3dSEric Cheng offsetof(flow_fields_buf_t, flow_lport), print_default_cb}, 183*25ec3e3dSEric Cheng { "RPORT", 8, 184*25ec3e3dSEric Cheng offsetof(flow_fields_buf_t, flow_rport), print_default_cb}, 1858002d411SSowmini Varadhan { "DSFLD", 10, 1868002d411SSowmini Varadhan offsetof(flow_fields_buf_t, flow_dsfield), print_default_cb}, 1878002d411SSowmini Varadhan NULL_OFMT} 188da14cebeSEric Cheng ; 189da14cebeSEric Cheng 190da14cebeSEric Cheng /* 191da14cebeSEric Cheng * structures for 'flowadm show-flowprop' 192da14cebeSEric Cheng */ 193da14cebeSEric Cheng typedef enum { 194da14cebeSEric Cheng FLOWPROP_FLOW, 195da14cebeSEric Cheng FLOWPROP_PROPERTY, 196da14cebeSEric Cheng FLOWPROP_VALUE, 197da14cebeSEric Cheng FLOWPROP_DEFAULT, 198da14cebeSEric Cheng FLOWPROP_POSSIBLE 199da14cebeSEric Cheng } flowprop_field_index_t; 200da14cebeSEric Cheng 2018002d411SSowmini Varadhan static ofmt_field_t flowprop_fields[] = { 2028002d411SSowmini Varadhan /* name, fieldwidth, index, callback */ 2038002d411SSowmini Varadhan { "FLOW", 13, FLOWPROP_FLOW, print_flowprop_cb}, 2048002d411SSowmini Varadhan { "PROPERTY", 16, FLOWPROP_PROPERTY, print_flowprop_cb}, 2058002d411SSowmini Varadhan { "VALUE", 15, FLOWPROP_VALUE, print_flowprop_cb}, 2068002d411SSowmini Varadhan { "DEFAULT", 15, FLOWPROP_DEFAULT, print_flowprop_cb}, 2078002d411SSowmini Varadhan { "POSSIBLE", 21, FLOWPROP_POSSIBLE, print_flowprop_cb}, 2088002d411SSowmini Varadhan NULL_OFMT} 209da14cebeSEric Cheng ; 210da14cebeSEric Cheng 211da14cebeSEric Cheng #define MAX_PROP_LINE 512 212da14cebeSEric Cheng 213da14cebeSEric Cheng typedef struct show_flowprop_state { 214da14cebeSEric Cheng const char *fs_flow; 215da14cebeSEric Cheng datalink_id_t fs_linkid; 216da14cebeSEric Cheng char *fs_line; 217da14cebeSEric Cheng char **fs_propvals; 218da14cebeSEric Cheng dladm_arg_list_t *fs_proplist; 2198002d411SSowmini Varadhan boolean_t fs_parsable; 220da14cebeSEric Cheng boolean_t fs_persist; 221da14cebeSEric Cheng boolean_t fs_header; 222da14cebeSEric Cheng dladm_status_t fs_status; 223da14cebeSEric Cheng dladm_status_t fs_retstatus; 2248002d411SSowmini Varadhan ofmt_handle_t fs_ofmt; 225da14cebeSEric Cheng } show_flowprop_state_t; 226da14cebeSEric Cheng 227da14cebeSEric Cheng typedef struct set_flowprop_state { 228da14cebeSEric Cheng const char *fs_name; 229da14cebeSEric Cheng boolean_t fs_reset; 230da14cebeSEric Cheng boolean_t fs_temp; 231da14cebeSEric Cheng dladm_status_t fs_status; 232da14cebeSEric Cheng } set_flowprop_state_t; 233da14cebeSEric Cheng 234da14cebeSEric Cheng typedef struct flowprop_args_s { 235da14cebeSEric Cheng show_flowprop_state_t *fs_state; 236da14cebeSEric Cheng char *fs_propname; 237da14cebeSEric Cheng char *fs_flowname; 238da14cebeSEric Cheng } flowprop_args_t; 239ae6aa22aSVenugopal Iyer /* 240ae6aa22aSVenugopal Iyer * structures for 'flowadm show-flow -s' (print statistics) 241ae6aa22aSVenugopal Iyer */ 242ae6aa22aSVenugopal Iyer typedef enum { 243ae6aa22aSVenugopal Iyer FLOW_S_FLOW, 244ae6aa22aSVenugopal Iyer FLOW_S_IPKTS, 245ae6aa22aSVenugopal Iyer FLOW_S_RBYTES, 246ae6aa22aSVenugopal Iyer FLOW_S_IERRORS, 247ae6aa22aSVenugopal Iyer FLOW_S_OPKTS, 248ae6aa22aSVenugopal Iyer FLOW_S_OBYTES, 249ae6aa22aSVenugopal Iyer FLOW_S_OERRORS 250ae6aa22aSVenugopal Iyer } flow_s_field_index_t; 251ae6aa22aSVenugopal Iyer 2528002d411SSowmini Varadhan static ofmt_field_t flow_s_fields[] = { 2538002d411SSowmini Varadhan /* name, field width, index, callback */ 2548002d411SSowmini Varadhan { "FLOW", 15, FLOW_S_FLOW, print_flow_stats_cb}, 2558002d411SSowmini Varadhan { "IPACKETS", 10, FLOW_S_IPKTS, print_flow_stats_cb}, 2568002d411SSowmini Varadhan { "RBYTES", 8, FLOW_S_RBYTES, print_flow_stats_cb}, 2578002d411SSowmini Varadhan { "IERRORS", 10, FLOW_S_IERRORS, print_flow_stats_cb}, 2588002d411SSowmini Varadhan { "OPACKETS", 12, FLOW_S_OPKTS, print_flow_stats_cb}, 2598002d411SSowmini Varadhan { "OBYTES", 12, FLOW_S_OBYTES, print_flow_stats_cb}, 2608002d411SSowmini Varadhan { "OERRORS", 8, FLOW_S_OERRORS, print_flow_stats_cb}, 2618002d411SSowmini Varadhan NULL_OFMT} 262ae6aa22aSVenugopal Iyer ; 263ae6aa22aSVenugopal Iyer 264ae6aa22aSVenugopal Iyer typedef struct flow_args_s { 265ae6aa22aSVenugopal Iyer char *flow_s_flow; 266ae6aa22aSVenugopal Iyer pktsum_t *flow_s_psum; 267ae6aa22aSVenugopal Iyer } flow_args_t; 268da14cebeSEric Cheng 269da14cebeSEric Cheng /* 270ae6aa22aSVenugopal Iyer * structures for 'flowadm show-usage' 271da14cebeSEric Cheng */ 272da14cebeSEric Cheng typedef struct usage_fields_buf_s { 273da14cebeSEric Cheng char usage_flow[12]; 274da14cebeSEric Cheng char usage_duration[10]; 275da14cebeSEric Cheng char usage_ipackets[9]; 276da14cebeSEric Cheng char usage_rbytes[10]; 277da14cebeSEric Cheng char usage_opackets[9]; 278da14cebeSEric Cheng char usage_obytes[10]; 279da14cebeSEric Cheng char usage_bandwidth[14]; 280da14cebeSEric Cheng } usage_fields_buf_t; 281da14cebeSEric Cheng 2828002d411SSowmini Varadhan static ofmt_field_t usage_fields[] = { 2838002d411SSowmini Varadhan /* name, field width, offset */ 2848002d411SSowmini Varadhan { "FLOW", 13, 2858002d411SSowmini Varadhan offsetof(usage_fields_buf_t, usage_flow), print_default_cb}, 2868002d411SSowmini Varadhan { "DURATION", 11, 2878002d411SSowmini Varadhan offsetof(usage_fields_buf_t, usage_duration), print_default_cb}, 2888002d411SSowmini Varadhan { "IPACKETS", 10, 2898002d411SSowmini Varadhan offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb}, 2908002d411SSowmini Varadhan { "RBYTES", 11, 2918002d411SSowmini Varadhan offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb}, 2928002d411SSowmini Varadhan { "OPACKETS", 10, 2938002d411SSowmini Varadhan offsetof(usage_fields_buf_t, usage_opackets), print_default_cb}, 2948002d411SSowmini Varadhan { "OBYTES", 11, 2958002d411SSowmini Varadhan offsetof(usage_fields_buf_t, usage_obytes), print_default_cb}, 2968002d411SSowmini Varadhan { "BANDWIDTH", 15, 2978002d411SSowmini Varadhan offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb}, 2988002d411SSowmini Varadhan NULL_OFMT} 299da14cebeSEric Cheng ; 300da14cebeSEric Cheng 301da14cebeSEric Cheng /* 302da14cebeSEric Cheng * structures for 'dladm show-usage link' 303da14cebeSEric Cheng */ 304da14cebeSEric Cheng 305da14cebeSEric Cheng typedef struct usage_l_fields_buf_s { 306da14cebeSEric Cheng char usage_l_flow[12]; 307da14cebeSEric Cheng char usage_l_stime[13]; 308da14cebeSEric Cheng char usage_l_etime[13]; 309da14cebeSEric Cheng char usage_l_rbytes[8]; 310da14cebeSEric Cheng char usage_l_obytes[8]; 311da14cebeSEric Cheng char usage_l_bandwidth[14]; 312da14cebeSEric Cheng } usage_l_fields_buf_t; 313da14cebeSEric Cheng 3148002d411SSowmini Varadhan static ofmt_field_t usage_l_fields[] = { 3158002d411SSowmini Varadhan /* name, field width, offset */ 3168002d411SSowmini Varadhan { "FLOW", 13, 3178002d411SSowmini Varadhan offsetof(usage_l_fields_buf_t, usage_l_flow), print_default_cb}, 3188002d411SSowmini Varadhan { "START", 14, 3198002d411SSowmini Varadhan offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb}, 3208002d411SSowmini Varadhan { "END", 14, 3218002d411SSowmini Varadhan offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb}, 3228002d411SSowmini Varadhan { "RBYTES", 9, 3238002d411SSowmini Varadhan offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb}, 3248002d411SSowmini Varadhan { "OBYTES", 9, 3258002d411SSowmini Varadhan offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb}, 3268002d411SSowmini Varadhan { "BANDWIDTH", 15, 3278002d411SSowmini Varadhan offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb}, 3288002d411SSowmini Varadhan NULL_OFMT} 329da14cebeSEric Cheng ; 330da14cebeSEric Cheng 331da14cebeSEric Cheng #define PRI_HI 100 332da14cebeSEric Cheng #define PRI_LO 10 333da14cebeSEric Cheng #define PRI_NORM 50 334da14cebeSEric Cheng 335da14cebeSEric Cheng #define FLOWADM_CONF "/etc/dladm/flowadm.conf" 336da14cebeSEric Cheng #define BLANK_LINE(s) ((s[0] == '\0') || (s[0] == '#') || (s[0] == '\n')) 337da14cebeSEric Cheng 338da14cebeSEric Cheng static char *progname; 339da14cebeSEric Cheng 340da14cebeSEric Cheng boolean_t t_arg = B_FALSE; /* changes are persistent */ 341da14cebeSEric Cheng char *altroot = NULL; 342da14cebeSEric Cheng 3434ac67f02SAnurag S. Maskey /* 3444ac67f02SAnurag S. Maskey * Handle to libdladm. Opened in main() before the sub-command 3454ac67f02SAnurag S. Maskey * specific function is called. 3464ac67f02SAnurag S. Maskey */ 3474ac67f02SAnurag S. Maskey static dladm_handle_t handle = NULL; 3484ac67f02SAnurag S. Maskey 349da14cebeSEric Cheng static const char *attr_table[] = 350*25ec3e3dSEric Cheng {"local_ip", "remote_ip", "transport", "local_port", "remote_port", 351*25ec3e3dSEric Cheng "dsfield"}; 352da14cebeSEric Cheng 353da14cebeSEric Cheng #define NATTR (sizeof (attr_table)/sizeof (char *)) 354da14cebeSEric Cheng 355da14cebeSEric Cheng static void 356da14cebeSEric Cheng usage(void) 357da14cebeSEric Cheng { 358da14cebeSEric Cheng (void) fprintf(stderr, gettext("usage: flowadm <subcommand>" 359da14cebeSEric Cheng " <args>...\n" 3600790b6dcSAnurag S. Maskey " add-flow [-t] -l <link> -a <attr>=<value>[,...]\n" 3610790b6dcSAnurag S. Maskey "\t\t [-p <prop>=<value>,...] <flow>\n" 3620790b6dcSAnurag S. Maskey " remove-flow [-t] {-l <link> | <flow>}\n" 3630790b6dcSAnurag S. Maskey " show-flow [-p] [-s [-i <interval>]] [-l <link>] " 3640790b6dcSAnurag S. Maskey "[<flow>]\n\n" 3650790b6dcSAnurag S. Maskey " set-flowprop [-t] -p <prop>=<value>[,...] <flow>\n" 3660790b6dcSAnurag S. Maskey " reset-flowprop [-t] [-p <prop>,...] <flow>\n" 3670790b6dcSAnurag S. Maskey " show-flowprop [-cP] [-l <link>] [-p <prop>,...] " 3680790b6dcSAnurag S. Maskey "[<flow>]\n\n" 369ae6aa22aSVenugopal Iyer " show-usage [-a] [-d | -F <format>] " 3700790b6dcSAnurag S. Maskey "[-s <DD/MM/YYYY,HH:MM:SS>]\n" 3710790b6dcSAnurag S. Maskey "\t\t [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<flow>]\n")); 3724ac67f02SAnurag S. Maskey 3734ac67f02SAnurag S. Maskey /* close dladm handle if it was opened */ 3744ac67f02SAnurag S. Maskey if (handle != NULL) 3754ac67f02SAnurag S. Maskey dladm_close(handle); 3764ac67f02SAnurag S. Maskey 377da14cebeSEric Cheng exit(1); 378da14cebeSEric Cheng } 379da14cebeSEric Cheng 380da14cebeSEric Cheng int 381da14cebeSEric Cheng main(int argc, char *argv[]) 382da14cebeSEric Cheng { 383da14cebeSEric Cheng int i, arglen, cmdlen; 384da14cebeSEric Cheng cmd_t *cmdp; 3854ac67f02SAnurag S. Maskey dladm_status_t status; 386da14cebeSEric Cheng 387da14cebeSEric Cheng (void) setlocale(LC_ALL, ""); 388da14cebeSEric Cheng #if !defined(TEXT_DOMAIN) 389da14cebeSEric Cheng #define TEXT_DOMAIN "SYS_TEST" 390da14cebeSEric Cheng #endif 391da14cebeSEric Cheng (void) textdomain(TEXT_DOMAIN); 392da14cebeSEric Cheng 393da14cebeSEric Cheng progname = argv[0]; 394da14cebeSEric Cheng 395da14cebeSEric Cheng if (argc < 2) 396da14cebeSEric Cheng usage(); 397da14cebeSEric Cheng 398da14cebeSEric Cheng for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 399da14cebeSEric Cheng cmdp = &cmds[i]; 400da14cebeSEric Cheng arglen = strlen(argv[1]); 401da14cebeSEric Cheng cmdlen = strlen(cmdp->c_name); 402da14cebeSEric Cheng if ((arglen == cmdlen) && (strncmp(argv[1], cmdp->c_name, 403da14cebeSEric Cheng cmdlen) == 0)) { 4044ac67f02SAnurag S. Maskey /* Open the libdladm handle */ 4054ac67f02SAnurag S. Maskey if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) { 4064ac67f02SAnurag S. Maskey die_dlerr(status, 4074ac67f02SAnurag S. Maskey "could not open /dev/dld"); 4084ac67f02SAnurag S. Maskey } 4094ac67f02SAnurag S. Maskey 410da14cebeSEric Cheng cmdp->c_fn(argc - 1, &argv[1]); 4114ac67f02SAnurag S. Maskey 4124ac67f02SAnurag S. Maskey dladm_close(handle); 413ad091ee1SMichael Lim exit(EXIT_SUCCESS); 414da14cebeSEric Cheng } 415da14cebeSEric Cheng } 416da14cebeSEric Cheng 417da14cebeSEric Cheng (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 418da14cebeSEric Cheng progname, argv[1]); 419da14cebeSEric Cheng usage(); 420da14cebeSEric Cheng 421da14cebeSEric Cheng return (0); 422da14cebeSEric Cheng } 423da14cebeSEric Cheng 424da14cebeSEric Cheng static const char * 425da14cebeSEric Cheng match_attr(char *attr) 426da14cebeSEric Cheng { 427da14cebeSEric Cheng int i; 428da14cebeSEric Cheng 429da14cebeSEric Cheng for (i = 0; i < NATTR; i++) { 430da14cebeSEric Cheng if (strlen(attr) == strlen(attr_table[i]) && 431da14cebeSEric Cheng strncmp(attr, attr_table[i], strlen(attr_table[i])) == 0) { 432da14cebeSEric Cheng return (attr); 433da14cebeSEric Cheng } 434da14cebeSEric Cheng } 435da14cebeSEric Cheng return (NULL); 436da14cebeSEric Cheng } 437da14cebeSEric Cheng 438da14cebeSEric Cheng /* ARGSUSED */ 439da14cebeSEric Cheng static void 440da14cebeSEric Cheng do_init_flow(int argc, char *argv[]) 441da14cebeSEric Cheng { 442da14cebeSEric Cheng dladm_status_t status; 443da14cebeSEric Cheng 4444ac67f02SAnurag S. Maskey status = dladm_flow_init(handle); 445da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 446da14cebeSEric Cheng die_dlerr(status, "flows initialization failed"); 447da14cebeSEric Cheng } 448da14cebeSEric Cheng 449da14cebeSEric Cheng /* ARGSUSED */ 450da14cebeSEric Cheng static int 451da14cebeSEric Cheng show_usage_date(dladm_usage_t *usage, void *arg) 452da14cebeSEric Cheng { 453ae6aa22aSVenugopal Iyer show_usage_state_t *state = (show_usage_state_t *)arg; 454da14cebeSEric Cheng time_t stime; 455da14cebeSEric Cheng char timebuf[20]; 456ae6aa22aSVenugopal Iyer dladm_flow_attr_t attr; 457ae6aa22aSVenugopal Iyer dladm_status_t status; 458ae6aa22aSVenugopal Iyer 459ae6aa22aSVenugopal Iyer /* 460ae6aa22aSVenugopal Iyer * Only show usage information for existing flows unless '-a' 461ae6aa22aSVenugopal Iyer * is specified. 462ae6aa22aSVenugopal Iyer */ 463ae6aa22aSVenugopal Iyer if (!state->us_showall && ((status = dladm_flow_info(handle, 464ae6aa22aSVenugopal Iyer usage->du_name, &attr)) != DLADM_STATUS_OK)) { 465ae6aa22aSVenugopal Iyer return (status); 466ae6aa22aSVenugopal Iyer } 467da14cebeSEric Cheng 468da14cebeSEric Cheng stime = usage->du_stime; 469da14cebeSEric Cheng (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y", 470da14cebeSEric Cheng localtime(&stime)); 471da14cebeSEric Cheng (void) printf("%s\n", timebuf); 472da14cebeSEric Cheng 473da14cebeSEric Cheng return (DLADM_STATUS_OK); 474da14cebeSEric Cheng } 475da14cebeSEric Cheng 476da14cebeSEric Cheng static int 477da14cebeSEric Cheng show_usage_time(dladm_usage_t *usage, void *arg) 478da14cebeSEric Cheng { 479da14cebeSEric Cheng show_usage_state_t *state = (show_usage_state_t *)arg; 480da14cebeSEric Cheng char buf[DLADM_STRSIZE]; 481da14cebeSEric Cheng usage_l_fields_buf_t ubuf; 482da14cebeSEric Cheng time_t time; 483da14cebeSEric Cheng double bw; 484ae6aa22aSVenugopal Iyer dladm_flow_attr_t attr; 485ae6aa22aSVenugopal Iyer dladm_status_t status; 486ae6aa22aSVenugopal Iyer 487ae6aa22aSVenugopal Iyer /* 488ae6aa22aSVenugopal Iyer * Only show usage information for existing flows unless '-a' 489ae6aa22aSVenugopal Iyer * is specified. 490ae6aa22aSVenugopal Iyer */ 491ae6aa22aSVenugopal Iyer if (!state->us_showall && ((status = dladm_flow_info(handle, 492ae6aa22aSVenugopal Iyer usage->du_name, &attr)) != DLADM_STATUS_OK)) { 493ae6aa22aSVenugopal Iyer return (status); 494ae6aa22aSVenugopal Iyer } 495da14cebeSEric Cheng 496da14cebeSEric Cheng if (state->us_plot) { 497da14cebeSEric Cheng if (!state->us_printheader) { 498da14cebeSEric Cheng if (state->us_first) { 499da14cebeSEric Cheng (void) printf("# Time"); 500da14cebeSEric Cheng state->us_first = B_FALSE; 501da14cebeSEric Cheng } 502da14cebeSEric Cheng (void) printf(" %s", usage->du_name); 503da14cebeSEric Cheng if (usage->du_last) { 504da14cebeSEric Cheng (void) printf("\n"); 505da14cebeSEric Cheng state->us_first = B_TRUE; 506da14cebeSEric Cheng state->us_printheader = B_TRUE; 507da14cebeSEric Cheng } 508da14cebeSEric Cheng } else { 509da14cebeSEric Cheng if (state->us_first) { 510da14cebeSEric Cheng time = usage->du_etime; 511da14cebeSEric Cheng (void) strftime(buf, sizeof (buf), "%T", 512da14cebeSEric Cheng localtime(&time)); 513da14cebeSEric Cheng state->us_first = B_FALSE; 514da14cebeSEric Cheng (void) printf("%s", buf); 515da14cebeSEric Cheng } 516da14cebeSEric Cheng bw = (double)usage->du_bandwidth/1000; 517da14cebeSEric Cheng (void) printf(" %.2f", bw); 518da14cebeSEric Cheng if (usage->du_last) { 519da14cebeSEric Cheng (void) printf("\n"); 520da14cebeSEric Cheng state->us_first = B_TRUE; 521da14cebeSEric Cheng } 522da14cebeSEric Cheng } 523da14cebeSEric Cheng return (DLADM_STATUS_OK); 524da14cebeSEric Cheng } 525da14cebeSEric Cheng 526da14cebeSEric Cheng bzero(&ubuf, sizeof (ubuf)); 527da14cebeSEric Cheng 528da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_flow, sizeof (ubuf.usage_l_flow), "%s", 529da14cebeSEric Cheng usage->du_name); 530da14cebeSEric Cheng time = usage->du_stime; 531da14cebeSEric Cheng (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 532da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s", 533da14cebeSEric Cheng buf); 534da14cebeSEric Cheng time = usage->du_etime; 535da14cebeSEric Cheng (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 536da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s", 537da14cebeSEric Cheng buf); 538da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes), 539da14cebeSEric Cheng "%llu", usage->du_rbytes); 540da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes), 541da14cebeSEric Cheng "%llu", usage->du_obytes); 542da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth), 543da14cebeSEric Cheng "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 544da14cebeSEric Cheng 5458002d411SSowmini Varadhan ofmt_print(state->us_ofmt, (void *)&ubuf); 546da14cebeSEric Cheng return (DLADM_STATUS_OK); 547da14cebeSEric Cheng } 548da14cebeSEric Cheng 549da14cebeSEric Cheng static int 550da14cebeSEric Cheng show_usage_res(dladm_usage_t *usage, void *arg) 551da14cebeSEric Cheng { 552da14cebeSEric Cheng show_usage_state_t *state = (show_usage_state_t *)arg; 553da14cebeSEric Cheng char buf[DLADM_STRSIZE]; 554da14cebeSEric Cheng usage_fields_buf_t ubuf; 555ae6aa22aSVenugopal Iyer dladm_flow_attr_t attr; 556ae6aa22aSVenugopal Iyer dladm_status_t status; 557ae6aa22aSVenugopal Iyer 558ae6aa22aSVenugopal Iyer /* 559ae6aa22aSVenugopal Iyer * Only show usage information for existing flows unless '-a' 560ae6aa22aSVenugopal Iyer * is specified. 561ae6aa22aSVenugopal Iyer */ 562ae6aa22aSVenugopal Iyer if (!state->us_showall && ((status = dladm_flow_info(handle, 563ae6aa22aSVenugopal Iyer usage->du_name, &attr)) != DLADM_STATUS_OK)) { 564ae6aa22aSVenugopal Iyer return (status); 565ae6aa22aSVenugopal Iyer } 566da14cebeSEric Cheng 567da14cebeSEric Cheng bzero(&ubuf, sizeof (ubuf)); 568da14cebeSEric Cheng 569da14cebeSEric Cheng (void) snprintf(ubuf.usage_flow, sizeof (ubuf.usage_flow), "%s", 570da14cebeSEric Cheng usage->du_name); 571da14cebeSEric Cheng (void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration), 572da14cebeSEric Cheng "%llu", usage->du_duration); 573da14cebeSEric Cheng (void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets), 574da14cebeSEric Cheng "%llu", usage->du_ipackets); 575da14cebeSEric Cheng (void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes), 576da14cebeSEric Cheng "%llu", usage->du_rbytes); 577da14cebeSEric Cheng (void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets), 578da14cebeSEric Cheng "%llu", usage->du_opackets); 579da14cebeSEric Cheng (void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes), 580da14cebeSEric Cheng "%llu", usage->du_obytes); 581da14cebeSEric Cheng (void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth), 582da14cebeSEric Cheng "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 583da14cebeSEric Cheng 5848002d411SSowmini Varadhan ofmt_print(state->us_ofmt, (void *)&ubuf); 585da14cebeSEric Cheng 586da14cebeSEric Cheng return (DLADM_STATUS_OK); 587da14cebeSEric Cheng } 588da14cebeSEric Cheng 589da14cebeSEric Cheng static boolean_t 590da14cebeSEric Cheng valid_formatspec(char *formatspec_str) 591da14cebeSEric Cheng { 592da14cebeSEric Cheng if (strcmp(formatspec_str, "gnuplot") == 0) 593da14cebeSEric Cheng return (B_TRUE); 594da14cebeSEric Cheng return (B_FALSE); 595da14cebeSEric Cheng } 596da14cebeSEric Cheng 597da14cebeSEric Cheng /* ARGSUSED */ 598da14cebeSEric Cheng static void 599da14cebeSEric Cheng do_show_usage(int argc, char *argv[]) 600da14cebeSEric Cheng { 601da14cebeSEric Cheng char *file = NULL; 602da14cebeSEric Cheng int opt; 603da14cebeSEric Cheng dladm_status_t status; 604da14cebeSEric Cheng boolean_t d_arg = B_FALSE; 605da14cebeSEric Cheng char *stime = NULL; 606da14cebeSEric Cheng char *etime = NULL; 607da14cebeSEric Cheng char *resource = NULL; 608da14cebeSEric Cheng show_usage_state_t state; 609da14cebeSEric Cheng boolean_t o_arg = B_FALSE; 610da14cebeSEric Cheng boolean_t F_arg = B_FALSE; 611da14cebeSEric Cheng char *fields_str = NULL; 612da14cebeSEric Cheng char *formatspec_str = NULL; 613da14cebeSEric Cheng char *all_fields = 614da14cebeSEric Cheng "flow,duration,ipackets,rbytes,opackets,obytes,bandwidth"; 615da14cebeSEric Cheng char *all_l_fields = 616da14cebeSEric Cheng "flow,start,end,rbytes,obytes,bandwidth"; 6178002d411SSowmini Varadhan ofmt_handle_t ofmt; 6188002d411SSowmini Varadhan ofmt_status_t oferr; 6198002d411SSowmini Varadhan uint_t ofmtflags = 0; 620da14cebeSEric Cheng 621da14cebeSEric Cheng bzero(&state, sizeof (show_usage_state_t)); 6228002d411SSowmini Varadhan state.us_parsable = B_FALSE; 623da14cebeSEric Cheng state.us_printheader = B_FALSE; 624da14cebeSEric Cheng state.us_plot = B_FALSE; 625da14cebeSEric Cheng state.us_first = B_TRUE; 626da14cebeSEric Cheng 627ae6aa22aSVenugopal Iyer while ((opt = getopt(argc, argv, "das:e:o:f:F:")) != -1) { 628da14cebeSEric Cheng switch (opt) { 629da14cebeSEric Cheng case 'd': 630da14cebeSEric Cheng d_arg = B_TRUE; 631da14cebeSEric Cheng break; 632ae6aa22aSVenugopal Iyer case 'a': 633ae6aa22aSVenugopal Iyer state.us_showall = B_TRUE; 634da14cebeSEric Cheng break; 635da14cebeSEric Cheng case 'f': 636da14cebeSEric Cheng file = optarg; 637da14cebeSEric Cheng break; 638da14cebeSEric Cheng case 's': 639da14cebeSEric Cheng stime = optarg; 640da14cebeSEric Cheng break; 641da14cebeSEric Cheng case 'e': 642da14cebeSEric Cheng etime = optarg; 643da14cebeSEric Cheng break; 644da14cebeSEric Cheng case 'o': 645da14cebeSEric Cheng o_arg = B_TRUE; 646da14cebeSEric Cheng fields_str = optarg; 647da14cebeSEric Cheng break; 648da14cebeSEric Cheng case 'F': 649ae6aa22aSVenugopal Iyer state.us_plot = F_arg = B_TRUE; 650da14cebeSEric Cheng formatspec_str = optarg; 651da14cebeSEric Cheng break; 652da14cebeSEric Cheng default: 653da14cebeSEric Cheng die_opterr(optopt, opt); 654da14cebeSEric Cheng } 655da14cebeSEric Cheng } 656da14cebeSEric Cheng 657da14cebeSEric Cheng if (file == NULL) 658da14cebeSEric Cheng die("show-usage requires a file"); 659da14cebeSEric Cheng 660da14cebeSEric Cheng if (optind == (argc-1)) { 661ae6aa22aSVenugopal Iyer dladm_flow_attr_t attr; 662ae6aa22aSVenugopal Iyer 663ae6aa22aSVenugopal Iyer if (!state.us_showall && 664ae6aa22aSVenugopal Iyer dladm_flow_info(handle, resource, &attr) != 665ae6aa22aSVenugopal Iyer DLADM_STATUS_OK) { 666ae6aa22aSVenugopal Iyer die("invalid flow: '%s'", resource); 667ae6aa22aSVenugopal Iyer } 668da14cebeSEric Cheng resource = argv[optind]; 669da14cebeSEric Cheng } 670da14cebeSEric Cheng 6718002d411SSowmini Varadhan if (state.us_parsable) 6728002d411SSowmini Varadhan ofmtflags |= OFMT_PARSABLE; 673da14cebeSEric Cheng if (resource == NULL && stime == NULL && etime == NULL) { 674da14cebeSEric Cheng if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 675da14cebeSEric Cheng fields_str = all_fields; 6768002d411SSowmini Varadhan oferr = ofmt_open(fields_str, usage_fields, ofmtflags, 6778002d411SSowmini Varadhan 0, &ofmt); 678da14cebeSEric Cheng } else { 679da14cebeSEric Cheng if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 680da14cebeSEric Cheng fields_str = all_l_fields; 6818002d411SSowmini Varadhan oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags, 6828002d411SSowmini Varadhan 0, &ofmt); 683da14cebeSEric Cheng } 684da14cebeSEric Cheng 6858002d411SSowmini Varadhan flowadm_ofmt_check(oferr, state.us_parsable, ofmt); 6868002d411SSowmini Varadhan state.us_ofmt = ofmt; 687da14cebeSEric Cheng 688ae6aa22aSVenugopal Iyer if (F_arg && d_arg) 689ae6aa22aSVenugopal Iyer die("incompatible -d and -F options"); 690da14cebeSEric Cheng 691da14cebeSEric Cheng if (F_arg && valid_formatspec(formatspec_str) == B_FALSE) 692da14cebeSEric Cheng die("Format specifier %s not supported", formatspec_str); 693da14cebeSEric Cheng 694da14cebeSEric Cheng if (d_arg) { 695da14cebeSEric Cheng /* Print log dates */ 696da14cebeSEric Cheng status = dladm_usage_dates(show_usage_date, 697da14cebeSEric Cheng DLADM_LOGTYPE_FLOW, file, resource, &state); 698da14cebeSEric Cheng } else if (resource == NULL && stime == NULL && etime == NULL && 699ae6aa22aSVenugopal Iyer !F_arg) { 700da14cebeSEric Cheng /* Print summary */ 701da14cebeSEric Cheng status = dladm_usage_summary(show_usage_res, 702da14cebeSEric Cheng DLADM_LOGTYPE_FLOW, file, &state); 703da14cebeSEric Cheng } else if (resource != NULL) { 704da14cebeSEric Cheng /* Print log entries for named resource */ 705da14cebeSEric Cheng status = dladm_walk_usage_res(show_usage_time, 706da14cebeSEric Cheng DLADM_LOGTYPE_FLOW, file, resource, stime, etime, &state); 707da14cebeSEric Cheng } else { 708da14cebeSEric Cheng /* Print time and information for each link */ 709da14cebeSEric Cheng status = dladm_walk_usage_time(show_usage_time, 710da14cebeSEric Cheng DLADM_LOGTYPE_FLOW, file, stime, etime, &state); 711da14cebeSEric Cheng } 712da14cebeSEric Cheng 7138002d411SSowmini Varadhan ofmt_close(ofmt); 714da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 715da14cebeSEric Cheng die_dlerr(status, "show-usage"); 716da14cebeSEric Cheng } 717da14cebeSEric Cheng 718da14cebeSEric Cheng static void 719da14cebeSEric Cheng do_add_flow(int argc, char *argv[]) 720da14cebeSEric Cheng { 721da000602SGirish Moodalbail char devname[MAXLINKNAMELEN]; 722da14cebeSEric Cheng char *name = NULL; 723da14cebeSEric Cheng uint_t index; 724da14cebeSEric Cheng datalink_id_t linkid; 725da14cebeSEric Cheng 726da14cebeSEric Cheng char option; 727da14cebeSEric Cheng boolean_t l_arg = B_FALSE; 72863a6526dSMichael Lim char propstr[DLADM_STRSIZE]; 72963a6526dSMichael Lim char attrstr[DLADM_STRSIZE]; 730da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 731da14cebeSEric Cheng dladm_arg_list_t *attrlist = NULL; 732da14cebeSEric Cheng dladm_status_t status; 733da14cebeSEric Cheng 73463a6526dSMichael Lim bzero(propstr, DLADM_STRSIZE); 73563a6526dSMichael Lim bzero(attrstr, DLADM_STRSIZE); 73663a6526dSMichael Lim 737da14cebeSEric Cheng while ((option = getopt_long(argc, argv, "tR:l:a:p:", 738da14cebeSEric Cheng prop_longopts, NULL)) != -1) { 739da14cebeSEric Cheng switch (option) { 740da14cebeSEric Cheng case 't': 741da14cebeSEric Cheng t_arg = B_TRUE; 742da14cebeSEric Cheng break; 743da14cebeSEric Cheng case 'R': 744da14cebeSEric Cheng altroot = optarg; 745da14cebeSEric Cheng break; 746da14cebeSEric Cheng case 'l': 747da14cebeSEric Cheng if (strlcpy(devname, optarg, 748da000602SGirish Moodalbail MAXLINKNAMELEN) >= MAXLINKNAMELEN) { 749da14cebeSEric Cheng die("link name too long"); 750da14cebeSEric Cheng } 7514ac67f02SAnurag S. Maskey if (dladm_name2info(handle, devname, &linkid, NULL, 752da14cebeSEric Cheng NULL, NULL) != DLADM_STATUS_OK) 753da14cebeSEric Cheng die("invalid link '%s'", devname); 754da14cebeSEric Cheng l_arg = B_TRUE; 755da14cebeSEric Cheng break; 756da14cebeSEric Cheng case 'a': 75763a6526dSMichael Lim (void) strlcat(attrstr, optarg, DLADM_STRSIZE); 75863a6526dSMichael Lim if (strlcat(attrstr, ",", DLADM_STRSIZE) >= 75963a6526dSMichael Lim DLADM_STRSIZE) 76063a6526dSMichael Lim die("attribute list too long '%s'", attrstr); 761da14cebeSEric Cheng break; 762da14cebeSEric Cheng case 'p': 76363a6526dSMichael Lim (void) strlcat(propstr, optarg, DLADM_STRSIZE); 76463a6526dSMichael Lim if (strlcat(propstr, ",", DLADM_STRSIZE) >= 76563a6526dSMichael Lim DLADM_STRSIZE) 76663a6526dSMichael Lim die("property list too long '%s'", propstr); 767da14cebeSEric Cheng break; 768da14cebeSEric Cheng default: 769da14cebeSEric Cheng die_opterr(optopt, option); 770da14cebeSEric Cheng } 771da14cebeSEric Cheng } 772da14cebeSEric Cheng if (!l_arg) { 773da14cebeSEric Cheng die("link is required"); 774da14cebeSEric Cheng } 775da14cebeSEric Cheng 776da14cebeSEric Cheng opterr = 0; 777da14cebeSEric Cheng index = optind; 778da14cebeSEric Cheng 779da14cebeSEric Cheng if ((index != (argc - 1)) || match_attr(argv[index]) != NULL) { 780da14cebeSEric Cheng die("flow name is required"); 781da14cebeSEric Cheng } else { 782da14cebeSEric Cheng /* get flow name; required last argument */ 783da000602SGirish Moodalbail if (strlen(argv[index]) >= MAXFLOWNAMELEN) 784da14cebeSEric Cheng die("flow name too long"); 785da14cebeSEric Cheng name = argv[index]; 786da14cebeSEric Cheng } 787da14cebeSEric Cheng 78863a6526dSMichael Lim if (dladm_parse_flow_attrs(attrstr, &attrlist, B_FALSE) 78963a6526dSMichael Lim != DLADM_STATUS_OK) 79063a6526dSMichael Lim die("invalid flow attribute specified"); 79163a6526dSMichael Lim if (dladm_parse_flow_props(propstr, &proplist, B_FALSE) 79263a6526dSMichael Lim != DLADM_STATUS_OK) 79363a6526dSMichael Lim die("invalid flow property specified"); 79463a6526dSMichael Lim 7954ac67f02SAnurag S. Maskey status = dladm_flow_add(handle, linkid, attrlist, proplist, name, 796da14cebeSEric Cheng t_arg, altroot); 797da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 798da14cebeSEric Cheng die_dlerr(status, "add flow failed"); 799da14cebeSEric Cheng 800da14cebeSEric Cheng dladm_free_attrs(attrlist); 801da14cebeSEric Cheng dladm_free_props(proplist); 802da14cebeSEric Cheng } 803da14cebeSEric Cheng 804da14cebeSEric Cheng static void 805da14cebeSEric Cheng do_remove_flow(int argc, char *argv[]) 806da14cebeSEric Cheng { 807da14cebeSEric Cheng char option; 808da14cebeSEric Cheng char *flowname = NULL; 809da000602SGirish Moodalbail char linkname[MAXLINKNAMELEN]; 810da14cebeSEric Cheng datalink_id_t linkid = DATALINK_ALL_LINKID; 811da14cebeSEric Cheng boolean_t l_arg = B_FALSE; 812da14cebeSEric Cheng remove_flow_state_t state; 813da14cebeSEric Cheng dladm_status_t status; 814da14cebeSEric Cheng 815da14cebeSEric Cheng bzero(&state, sizeof (state)); 816da14cebeSEric Cheng 817da14cebeSEric Cheng opterr = 0; 818da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":tR:l:", 819da14cebeSEric Cheng longopts, NULL)) != -1) { 820da14cebeSEric Cheng switch (option) { 821da14cebeSEric Cheng case 't': 822da14cebeSEric Cheng t_arg = B_TRUE; 823da14cebeSEric Cheng break; 824da14cebeSEric Cheng case 'R': 825da14cebeSEric Cheng altroot = optarg; 826da14cebeSEric Cheng break; 827da14cebeSEric Cheng case 'l': 828da14cebeSEric Cheng if (strlcpy(linkname, optarg, 829da14cebeSEric Cheng MAXLINKNAMELEN) >= MAXLINKNAMELEN) { 830da14cebeSEric Cheng die("link name too long"); 831da14cebeSEric Cheng } 8324ac67f02SAnurag S. Maskey if (dladm_name2info(handle, linkname, &linkid, NULL, 833da14cebeSEric Cheng NULL, NULL) != DLADM_STATUS_OK) { 834da14cebeSEric Cheng die("invalid link '%s'", linkname); 835da14cebeSEric Cheng } 836da14cebeSEric Cheng l_arg = B_TRUE; 837da14cebeSEric Cheng break; 838da14cebeSEric Cheng default: 839da14cebeSEric Cheng die_opterr(optopt, option); 840da14cebeSEric Cheng break; 841da14cebeSEric Cheng } 842da14cebeSEric Cheng } 843da14cebeSEric Cheng 844da14cebeSEric Cheng /* when link not specified get flow name */ 845da14cebeSEric Cheng if (!l_arg) { 846da14cebeSEric Cheng if (optind != (argc-1)) { 847da14cebeSEric Cheng usage(); 848da14cebeSEric Cheng } else { 849da000602SGirish Moodalbail if (strlen(argv[optind]) >= MAXFLOWNAMELEN) 850da14cebeSEric Cheng die("flow name too long"); 851da14cebeSEric Cheng flowname = argv[optind]; 852da14cebeSEric Cheng } 8534ac67f02SAnurag S. Maskey status = dladm_flow_remove(handle, flowname, t_arg, altroot); 854da14cebeSEric Cheng } else { 855da14cebeSEric Cheng /* if link is specified then flow name should not be there */ 856da14cebeSEric Cheng if (optind == argc-1) 857da14cebeSEric Cheng usage(); 858da14cebeSEric Cheng /* walk the link to find flows and remove them */ 859da14cebeSEric Cheng state.fs_tempop = t_arg; 860da14cebeSEric Cheng state.fs_altroot = altroot; 861da14cebeSEric Cheng state.fs_status = DLADM_STATUS_OK; 8624ac67f02SAnurag S. Maskey status = dladm_walk_flow(remove_flow, handle, linkid, &state, 8634ac67f02SAnurag S. Maskey B_FALSE); 864da14cebeSEric Cheng /* 865da14cebeSEric Cheng * check if dladm_walk_flow terminated early and see if the 866da14cebeSEric Cheng * walker function as any status for us 867da14cebeSEric Cheng */ 868da14cebeSEric Cheng if (status == DLADM_STATUS_OK) 869da14cebeSEric Cheng status = state.fs_status; 870da14cebeSEric Cheng } 871da14cebeSEric Cheng 872da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 873da14cebeSEric Cheng die_dlerr(status, "remove flow failed"); 874da14cebeSEric Cheng } 875da14cebeSEric Cheng 876da14cebeSEric Cheng /* 877da14cebeSEric Cheng * Walker function for removing a flow through dladm_walk_flow(); 878da14cebeSEric Cheng */ 879c3affd82SMichael Lim /*ARGSUSED*/ 880da14cebeSEric Cheng static int 881c3affd82SMichael Lim remove_flow(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg) 882da14cebeSEric Cheng { 883da14cebeSEric Cheng remove_flow_state_t *state = (remove_flow_state_t *)arg; 884da14cebeSEric Cheng 8854ac67f02SAnurag S. Maskey state->fs_status = dladm_flow_remove(handle, attr->fa_flowname, 886da14cebeSEric Cheng state->fs_tempop, state->fs_altroot); 887da14cebeSEric Cheng 888da14cebeSEric Cheng if (state->fs_status == DLADM_STATUS_OK) 889da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 890da14cebeSEric Cheng else 891da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 892da14cebeSEric Cheng } 893da14cebeSEric Cheng 894da14cebeSEric Cheng /*ARGSUSED*/ 895da14cebeSEric Cheng static dladm_status_t 896da14cebeSEric Cheng print_flow(show_flow_state_t *state, dladm_flow_attr_t *attr, 897da14cebeSEric Cheng flow_fields_buf_t *fbuf) 898da14cebeSEric Cheng { 899da14cebeSEric Cheng char link[MAXLINKNAMELEN]; 900da14cebeSEric Cheng dladm_status_t status; 901da14cebeSEric Cheng 9024ac67f02SAnurag S. Maskey if ((status = dladm_datalink_id2info(handle, attr->fa_linkid, NULL, 9034ac67f02SAnurag S. Maskey NULL, NULL, link, sizeof (link))) != DLADM_STATUS_OK) { 904da14cebeSEric Cheng return (status); 905da14cebeSEric Cheng } 906da14cebeSEric Cheng 907da14cebeSEric Cheng (void) snprintf(fbuf->flow_name, sizeof (fbuf->flow_name), 908da14cebeSEric Cheng "%s", attr->fa_flowname); 909da14cebeSEric Cheng (void) snprintf(fbuf->flow_link, sizeof (fbuf->flow_link), 910da14cebeSEric Cheng "%s", link); 911da14cebeSEric Cheng 912da14cebeSEric Cheng (void) dladm_flow_attr_ip2str(attr, fbuf->flow_ipaddr, 913da14cebeSEric Cheng sizeof (fbuf->flow_ipaddr)); 914da14cebeSEric Cheng (void) dladm_flow_attr_proto2str(attr, fbuf->flow_proto, 915da14cebeSEric Cheng sizeof (fbuf->flow_proto)); 916*25ec3e3dSEric Cheng if ((attr->fa_flow_desc.fd_mask & FLOW_ULP_PORT_LOCAL) != 0) { 917*25ec3e3dSEric Cheng (void) dladm_flow_attr_port2str(attr, fbuf->flow_lport, 918*25ec3e3dSEric Cheng sizeof (fbuf->flow_lport)); 919*25ec3e3dSEric Cheng } 920*25ec3e3dSEric Cheng if ((attr->fa_flow_desc.fd_mask & FLOW_ULP_PORT_REMOTE) != 0) { 921*25ec3e3dSEric Cheng (void) dladm_flow_attr_port2str(attr, fbuf->flow_rport, 922*25ec3e3dSEric Cheng sizeof (fbuf->flow_rport)); 923*25ec3e3dSEric Cheng } 924da14cebeSEric Cheng (void) dladm_flow_attr_dsfield2str(attr, fbuf->flow_dsfield, 925da14cebeSEric Cheng sizeof (fbuf->flow_dsfield)); 926da14cebeSEric Cheng 927da14cebeSEric Cheng return (DLADM_STATUS_OK); 928da14cebeSEric Cheng } 929da14cebeSEric Cheng 930da14cebeSEric Cheng /* 931da14cebeSEric Cheng * Walker function for showing flow attributes through dladm_walk_flow(). 932da14cebeSEric Cheng */ 933c3affd82SMichael Lim /*ARGSUSED*/ 934da14cebeSEric Cheng static int 935c3affd82SMichael Lim show_flow(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg) 936da14cebeSEric Cheng { 937da14cebeSEric Cheng show_flow_state_t *statep = arg; 938da14cebeSEric Cheng dladm_status_t status; 939da14cebeSEric Cheng flow_fields_buf_t fbuf; 940da14cebeSEric Cheng 941da14cebeSEric Cheng /* 942da14cebeSEric Cheng * first get all the flow attributes into fbuf; 943da14cebeSEric Cheng */ 944da14cebeSEric Cheng bzero(&fbuf, sizeof (fbuf)); 945da14cebeSEric Cheng status = print_flow(statep, attr, &fbuf); 946da14cebeSEric Cheng 947da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 948da14cebeSEric Cheng goto done; 949da14cebeSEric Cheng 9508002d411SSowmini Varadhan ofmt_print(statep->fs_ofmt, (void *)&fbuf); 951da14cebeSEric Cheng 952da14cebeSEric Cheng done: 953da14cebeSEric Cheng statep->fs_status = status; 954da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 955da14cebeSEric Cheng } 956da14cebeSEric Cheng 957da14cebeSEric Cheng static void 958da14cebeSEric Cheng show_one_flow(void *arg, const char *name) 959da14cebeSEric Cheng { 960da14cebeSEric Cheng dladm_flow_attr_t attr; 961da14cebeSEric Cheng 9624ac67f02SAnurag S. Maskey if (dladm_flow_info(handle, name, &attr) != DLADM_STATUS_OK) 963da14cebeSEric Cheng die("invalid flow: '%s'", name); 964da14cebeSEric Cheng else 965c3affd82SMichael Lim (void) show_flow(handle, &attr, arg); 966da14cebeSEric Cheng } 967da14cebeSEric Cheng 968da14cebeSEric Cheng /* 969da14cebeSEric Cheng * Wrapper of dladm_walk_flow(show_flow,...) to make it usable to 970da14cebeSEric Cheng * dladm_walk_datalink_id(). Used for showing flow attributes for 971da14cebeSEric Cheng * all flows on all links. 972da14cebeSEric Cheng */ 973da14cebeSEric Cheng static int 9744ac67f02SAnurag S. Maskey show_flows_onelink(dladm_handle_t dh, datalink_id_t linkid, void *arg) 975da14cebeSEric Cheng { 976da14cebeSEric Cheng show_flow_state_t *state = arg; 977da14cebeSEric Cheng 9784ac67f02SAnurag S. Maskey (void) dladm_walk_flow(show_flow, dh, linkid, arg, state->fs_persist); 979da14cebeSEric Cheng 980da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 981da14cebeSEric Cheng } 982da14cebeSEric Cheng 983da14cebeSEric Cheng static void 984da14cebeSEric Cheng get_flow_stats(const char *flowname, pktsum_t *stats) 985da14cebeSEric Cheng { 986da14cebeSEric Cheng kstat_ctl_t *kcp; 987da14cebeSEric Cheng kstat_t *ksp; 988da14cebeSEric Cheng 989da14cebeSEric Cheng bzero(stats, sizeof (*stats)); 990da14cebeSEric Cheng 991da14cebeSEric Cheng if ((kcp = kstat_open()) == NULL) { 992da14cebeSEric Cheng warn("kstat open operation failed"); 993da14cebeSEric Cheng return; 994da14cebeSEric Cheng } 995da14cebeSEric Cheng 996da14cebeSEric Cheng ksp = dladm_kstat_lookup(kcp, NULL, -1, flowname, "flow"); 997da14cebeSEric Cheng 998da14cebeSEric Cheng if (ksp != NULL) 999da14cebeSEric Cheng dladm_get_stats(kcp, ksp, stats); 1000da14cebeSEric Cheng 1001da14cebeSEric Cheng (void) kstat_close(kcp); 1002da14cebeSEric Cheng } 1003da14cebeSEric Cheng 10048002d411SSowmini Varadhan static boolean_t 10058002d411SSowmini Varadhan print_flow_stats_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 1006ae6aa22aSVenugopal Iyer { 10078002d411SSowmini Varadhan flow_args_t *fargs = of_arg->ofmt_cbarg; 1008ae6aa22aSVenugopal Iyer pktsum_t *diff_stats = fargs->flow_s_psum; 1009ae6aa22aSVenugopal Iyer 10108002d411SSowmini Varadhan switch (of_arg->ofmt_id) { 1011ae6aa22aSVenugopal Iyer case FLOW_S_FLOW: 10128002d411SSowmini Varadhan (void) snprintf(buf, bufsize, "%s", fargs->flow_s_flow); 1013ae6aa22aSVenugopal Iyer break; 1014ae6aa22aSVenugopal Iyer case FLOW_S_IPKTS: 10158002d411SSowmini Varadhan (void) snprintf(buf, bufsize, "%llu", 1016ae6aa22aSVenugopal Iyer diff_stats->ipackets); 1017ae6aa22aSVenugopal Iyer break; 1018ae6aa22aSVenugopal Iyer case FLOW_S_RBYTES: 10198002d411SSowmini Varadhan (void) snprintf(buf, bufsize, "%llu", 1020ae6aa22aSVenugopal Iyer diff_stats->rbytes); 1021ae6aa22aSVenugopal Iyer break; 1022ae6aa22aSVenugopal Iyer case FLOW_S_IERRORS: 10238002d411SSowmini Varadhan (void) snprintf(buf, bufsize, "%u", 1024ae6aa22aSVenugopal Iyer diff_stats->ierrors); 1025ae6aa22aSVenugopal Iyer break; 1026ae6aa22aSVenugopal Iyer case FLOW_S_OPKTS: 10278002d411SSowmini Varadhan (void) snprintf(buf, bufsize, "%llu", 1028ae6aa22aSVenugopal Iyer diff_stats->opackets); 1029ae6aa22aSVenugopal Iyer break; 1030ae6aa22aSVenugopal Iyer case FLOW_S_OBYTES: 10318002d411SSowmini Varadhan (void) snprintf(buf, bufsize, "%llu", 1032ae6aa22aSVenugopal Iyer diff_stats->obytes); 1033ae6aa22aSVenugopal Iyer break; 1034ae6aa22aSVenugopal Iyer case FLOW_S_OERRORS: 10358002d411SSowmini Varadhan (void) snprintf(buf, bufsize, "%u", 1036ae6aa22aSVenugopal Iyer diff_stats->oerrors); 1037ae6aa22aSVenugopal Iyer break; 1038ae6aa22aSVenugopal Iyer default: 1039ae6aa22aSVenugopal Iyer die("invalid input"); 1040ae6aa22aSVenugopal Iyer break; 1041ae6aa22aSVenugopal Iyer } 10428002d411SSowmini Varadhan return (B_TRUE); 1043ae6aa22aSVenugopal Iyer } 10448002d411SSowmini Varadhan 1045da14cebeSEric Cheng /* ARGSUSED */ 1046da14cebeSEric Cheng static int 1047c3affd82SMichael Lim show_flow_stats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg) 1048da14cebeSEric Cheng { 1049da14cebeSEric Cheng show_flow_state_t *state = (show_flow_state_t *)arg; 1050ae6aa22aSVenugopal Iyer char *name = attr->fa_flowname; 1051da14cebeSEric Cheng pktsum_t stats, diff_stats; 1052ae6aa22aSVenugopal Iyer flow_args_t fargs; 1053da14cebeSEric Cheng 1054da14cebeSEric Cheng if (state->fs_firstonly) { 1055da14cebeSEric Cheng if (state->fs_donefirst) 1056da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 1057da14cebeSEric Cheng state->fs_donefirst = B_TRUE; 1058da14cebeSEric Cheng } else { 1059da14cebeSEric Cheng bzero(&state->fs_prevstats, sizeof (state->fs_prevstats)); 1060da14cebeSEric Cheng } 1061da14cebeSEric Cheng 1062da14cebeSEric Cheng get_flow_stats(name, &stats); 1063da14cebeSEric Cheng dladm_stats_diff(&diff_stats, &stats, &state->fs_prevstats); 1064da14cebeSEric Cheng 1065ae6aa22aSVenugopal Iyer fargs.flow_s_flow = name; 1066ae6aa22aSVenugopal Iyer fargs.flow_s_psum = &diff_stats; 10678002d411SSowmini Varadhan ofmt_print(state->fs_ofmt, (void *)&fargs); 1068da14cebeSEric Cheng state->fs_prevstats = stats; 1069da14cebeSEric Cheng 1070da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1071da14cebeSEric Cheng } 1072da14cebeSEric Cheng 1073da14cebeSEric Cheng /* 1074da14cebeSEric Cheng * Wrapper of dladm_walk_flow(show_flow,...) to make it usable for 1075da14cebeSEric Cheng * dladm_walk_datalink_id(). Used for showing flow stats for 1076da14cebeSEric Cheng * all flows on all links. 1077da14cebeSEric Cheng */ 1078da14cebeSEric Cheng static int 10794ac67f02SAnurag S. Maskey show_link_flow_stats(dladm_handle_t dh, datalink_id_t linkid, void * arg) 1080da14cebeSEric Cheng { 10814ac67f02SAnurag S. Maskey if (dladm_walk_flow(show_flow_stats, dh, linkid, arg, B_FALSE) 1082da14cebeSEric Cheng == DLADM_STATUS_OK) 1083da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1084da14cebeSEric Cheng else 1085da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 1086da14cebeSEric Cheng } 1087da14cebeSEric Cheng 1088da14cebeSEric Cheng /* ARGSUSED */ 1089da14cebeSEric Cheng static void 1090ae6aa22aSVenugopal Iyer flow_stats(const char *flow, datalink_id_t linkid, uint_t interval, 1091ae6aa22aSVenugopal Iyer char *fields_str, show_flow_state_t *state) 1092da14cebeSEric Cheng { 1093da14cebeSEric Cheng dladm_flow_attr_t attr; 10948002d411SSowmini Varadhan ofmt_handle_t ofmt; 10958002d411SSowmini Varadhan ofmt_status_t oferr; 10968002d411SSowmini Varadhan uint_t ofmtflags = 0; 1097ae6aa22aSVenugopal Iyer 10988002d411SSowmini Varadhan oferr = ofmt_open(fields_str, flow_s_fields, ofmtflags, 0, &ofmt); 10998002d411SSowmini Varadhan flowadm_ofmt_check(oferr, state->fs_parsable, ofmt); 11008002d411SSowmini Varadhan state->fs_ofmt = ofmt; 1101da14cebeSEric Cheng 11024ac67f02SAnurag S. Maskey if (flow != NULL && 11034ac67f02SAnurag S. Maskey dladm_flow_info(handle, flow, &attr) != DLADM_STATUS_OK) 1104da14cebeSEric Cheng die("invalid flow %s", flow); 1105da14cebeSEric Cheng 1106da14cebeSEric Cheng /* 1107da14cebeSEric Cheng * If an interval is specified, continuously show the stats 1108da14cebeSEric Cheng * for only the first flow. 1109da14cebeSEric Cheng */ 1110ae6aa22aSVenugopal Iyer state->fs_firstonly = (interval != 0); 1111da14cebeSEric Cheng 1112da14cebeSEric Cheng for (;;) { 1113ae6aa22aSVenugopal Iyer state->fs_donefirst = B_FALSE; 1114da14cebeSEric Cheng 1115da14cebeSEric Cheng /* Show stats for named flow */ 1116da14cebeSEric Cheng if (flow != NULL) { 1117ae6aa22aSVenugopal Iyer state->fs_flow = flow; 1118c3affd82SMichael Lim (void) show_flow_stats(handle, &attr, state); 1119da14cebeSEric Cheng 1120da14cebeSEric Cheng /* Show all stats on a link */ 1121da14cebeSEric Cheng } else if (linkid != DATALINK_INVALID_LINKID) { 11224ac67f02SAnurag S. Maskey (void) dladm_walk_flow(show_flow_stats, handle, linkid, 1123ae6aa22aSVenugopal Iyer state, B_FALSE); 1124da14cebeSEric Cheng 1125da14cebeSEric Cheng /* Show all stats by datalink */ 1126da14cebeSEric Cheng } else { 1127da14cebeSEric Cheng (void) dladm_walk_datalink_id(show_link_flow_stats, 1128ae6aa22aSVenugopal Iyer handle, state, DATALINK_CLASS_ALL, 11294ac67f02SAnurag S. Maskey DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 1130da14cebeSEric Cheng } 1131da14cebeSEric Cheng 1132da14cebeSEric Cheng if (interval == 0) 1133da14cebeSEric Cheng break; 1134da14cebeSEric Cheng 1135c3affd82SMichael Lim (void) fflush(stdout); 1136da14cebeSEric Cheng (void) sleep(interval); 1137da14cebeSEric Cheng } 11388002d411SSowmini Varadhan ofmt_close(ofmt); 1139da14cebeSEric Cheng } 1140da14cebeSEric Cheng 1141da14cebeSEric Cheng static void 1142da14cebeSEric Cheng do_show_flow(int argc, char *argv[]) 1143da14cebeSEric Cheng { 1144da000602SGirish Moodalbail char flowname[MAXFLOWNAMELEN]; 1145da000602SGirish Moodalbail char linkname[MAXLINKNAMELEN]; 1146da14cebeSEric Cheng datalink_id_t linkid = DATALINK_ALL_LINKID; 1147da14cebeSEric Cheng int option; 1148da14cebeSEric Cheng boolean_t s_arg = B_FALSE; 1149da14cebeSEric Cheng boolean_t S_arg = B_FALSE; 1150da14cebeSEric Cheng boolean_t i_arg = B_FALSE; 1151da14cebeSEric Cheng boolean_t l_arg = B_FALSE; 1152da14cebeSEric Cheng boolean_t o_arg = B_FALSE; 1153da14cebeSEric Cheng uint32_t interval = 0; 1154da14cebeSEric Cheng show_flow_state_t state; 1155da14cebeSEric Cheng char *fields_str = NULL; 11568002d411SSowmini Varadhan ofmt_handle_t ofmt; 11578002d411SSowmini Varadhan ofmt_status_t oferr; 11588002d411SSowmini Varadhan uint_t ofmtflags = 0; 1159da14cebeSEric Cheng 1160da14cebeSEric Cheng bzero(&state, sizeof (state)); 1161da14cebeSEric Cheng 1162da14cebeSEric Cheng opterr = 0; 1163da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":pPsSi:l:o:", 1164da14cebeSEric Cheng longopts, NULL)) != -1) { 1165da14cebeSEric Cheng switch (option) { 1166da14cebeSEric Cheng case 'p': 11678002d411SSowmini Varadhan state.fs_parsable = B_TRUE; 11688002d411SSowmini Varadhan ofmtflags |= OFMT_PARSABLE; 1169da14cebeSEric Cheng break; 1170da14cebeSEric Cheng case 'P': 1171da14cebeSEric Cheng state.fs_persist = B_TRUE; 1172da14cebeSEric Cheng break; 1173da14cebeSEric Cheng case 's': 1174da14cebeSEric Cheng if (s_arg) 1175da14cebeSEric Cheng die_optdup(option); 1176da14cebeSEric Cheng 1177da14cebeSEric Cheng s_arg = B_TRUE; 1178da14cebeSEric Cheng break; 1179da14cebeSEric Cheng case 'S': 1180da14cebeSEric Cheng if (S_arg) 1181da14cebeSEric Cheng die_optdup(option); 1182da14cebeSEric Cheng 1183da14cebeSEric Cheng S_arg = B_TRUE; 1184da14cebeSEric Cheng break; 1185da14cebeSEric Cheng case 'o': 1186da14cebeSEric Cheng if (o_arg) 1187da14cebeSEric Cheng die_optdup(option); 1188da14cebeSEric Cheng 1189da14cebeSEric Cheng o_arg = B_TRUE; 1190da14cebeSEric Cheng fields_str = optarg; 1191da14cebeSEric Cheng break; 1192da14cebeSEric Cheng case 'i': 1193da14cebeSEric Cheng if (i_arg) 1194da14cebeSEric Cheng die_optdup(option); 1195da14cebeSEric Cheng 1196da14cebeSEric Cheng i_arg = B_TRUE; 1197da14cebeSEric Cheng 119863a6526dSMichael Lim if (!dladm_str2interval(optarg, &interval)) 119963a6526dSMichael Lim die("invalid interval value '%s'", optarg); 1200da14cebeSEric Cheng break; 1201da14cebeSEric Cheng case 'l': 1202da14cebeSEric Cheng if (strlcpy(linkname, optarg, MAXLINKNAMELEN) 1203da14cebeSEric Cheng >= MAXLINKNAMELEN) 1204da14cebeSEric Cheng die("link name too long\n"); 12054ac67f02SAnurag S. Maskey if (dladm_name2info(handle, linkname, &linkid, NULL, 1206da14cebeSEric Cheng NULL, NULL) != DLADM_STATUS_OK) 1207da14cebeSEric Cheng die("invalid link '%s'", linkname); 1208da14cebeSEric Cheng l_arg = B_TRUE; 1209da14cebeSEric Cheng break; 1210da14cebeSEric Cheng default: 1211da14cebeSEric Cheng die_opterr(optopt, option); 1212da14cebeSEric Cheng break; 1213da14cebeSEric Cheng } 1214da14cebeSEric Cheng } 1215da14cebeSEric Cheng if (i_arg && !(s_arg || S_arg)) 1216da14cebeSEric Cheng die("the -i option can be used only with -s or -S"); 1217da14cebeSEric Cheng 1218da14cebeSEric Cheng if (s_arg && S_arg) 1219da14cebeSEric Cheng die("the -s option cannot be used with -S"); 1220da14cebeSEric Cheng 1221da14cebeSEric Cheng /* get flow name (optional last argument */ 1222da14cebeSEric Cheng if (optind == (argc-1)) { 1223da000602SGirish Moodalbail if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN) 1224da000602SGirish Moodalbail >= MAXFLOWNAMELEN) 1225da14cebeSEric Cheng die("flow name too long"); 1226da14cebeSEric Cheng state.fs_flow = flowname; 1227da14cebeSEric Cheng } 1228da14cebeSEric Cheng 1229da14cebeSEric Cheng if (S_arg) { 12304ac67f02SAnurag S. Maskey dladm_continuous(handle, linkid, state.fs_flow, interval, 12314ac67f02SAnurag S. Maskey FLOW_REPORT); 1232da14cebeSEric Cheng return; 1233da14cebeSEric Cheng } 1234da14cebeSEric Cheng 1235ae6aa22aSVenugopal Iyer if (s_arg) { 1236ae6aa22aSVenugopal Iyer flow_stats(state.fs_flow, linkid, interval, fields_str, &state); 1237ae6aa22aSVenugopal Iyer return; 1238ae6aa22aSVenugopal Iyer } 1239da14cebeSEric Cheng 12408002d411SSowmini Varadhan oferr = ofmt_open(fields_str, flow_fields, ofmtflags, 0, &ofmt); 12418002d411SSowmini Varadhan flowadm_ofmt_check(oferr, state.fs_parsable, ofmt); 12428002d411SSowmini Varadhan state.fs_ofmt = ofmt; 1243da14cebeSEric Cheng 1244da14cebeSEric Cheng /* Show attributes of one flow */ 1245da14cebeSEric Cheng if (state.fs_flow != NULL) { 1246da14cebeSEric Cheng show_one_flow(&state, state.fs_flow); 1247da14cebeSEric Cheng 1248da14cebeSEric Cheng /* Show attributes of flows on one link */ 1249da14cebeSEric Cheng } else if (l_arg) { 12504ac67f02SAnurag S. Maskey (void) show_flows_onelink(handle, linkid, &state); 1251da14cebeSEric Cheng 1252da14cebeSEric Cheng /* Show attributes of all flows on all links */ 1253da14cebeSEric Cheng } else { 12544ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(show_flows_onelink, handle, 12554ac67f02SAnurag S. Maskey &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 1256da14cebeSEric Cheng DLADM_OPT_ACTIVE); 1257da14cebeSEric Cheng } 12588002d411SSowmini Varadhan ofmt_close(ofmt); 1259da14cebeSEric Cheng } 1260da14cebeSEric Cheng 1261da14cebeSEric Cheng static dladm_status_t 1262da14cebeSEric Cheng set_flowprop_persist(const char *flow, const char *prop_name, char **prop_val, 1263da14cebeSEric Cheng uint_t val_cnt, boolean_t reset) 1264da14cebeSEric Cheng { 1265da14cebeSEric Cheng dladm_status_t status; 1266da14cebeSEric Cheng char *errprop; 1267da14cebeSEric Cheng 12684ac67f02SAnurag S. Maskey status = dladm_set_flowprop(handle, flow, prop_name, prop_val, val_cnt, 1269da14cebeSEric Cheng DLADM_OPT_PERSIST, &errprop); 1270da14cebeSEric Cheng 1271da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 1272da14cebeSEric Cheng warn_dlerr(status, "cannot persistently %s flow " 1273da14cebeSEric Cheng "property '%s' on '%s'", reset? "reset": "set", 1274da14cebeSEric Cheng errprop, flow); 1275da14cebeSEric Cheng } 1276da14cebeSEric Cheng return (status); 1277da14cebeSEric Cheng } 1278da14cebeSEric Cheng 1279da14cebeSEric Cheng static void 1280da14cebeSEric Cheng set_flowprop(int argc, char **argv, boolean_t reset) 1281da14cebeSEric Cheng { 1282da14cebeSEric Cheng int i, option; 1283da14cebeSEric Cheng char errmsg[DLADM_STRSIZE]; 1284da14cebeSEric Cheng const char *flow = NULL; 128563a6526dSMichael Lim char propstr[DLADM_STRSIZE]; 1286da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 1287da14cebeSEric Cheng boolean_t temp = B_FALSE; 1288da14cebeSEric Cheng dladm_status_t status = DLADM_STATUS_OK; 1289da14cebeSEric Cheng 1290da14cebeSEric Cheng opterr = 0; 129163a6526dSMichael Lim bzero(propstr, DLADM_STRSIZE); 129263a6526dSMichael Lim 1293da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":p:R:t", 1294da14cebeSEric Cheng prop_longopts, NULL)) != -1) { 1295da14cebeSEric Cheng switch (option) { 1296da14cebeSEric Cheng case 'p': 129763a6526dSMichael Lim (void) strlcat(propstr, optarg, DLADM_STRSIZE); 129863a6526dSMichael Lim if (strlcat(propstr, ",", DLADM_STRSIZE) >= 129963a6526dSMichael Lim DLADM_STRSIZE) 130063a6526dSMichael Lim die("property list too long '%s'", propstr); 1301da14cebeSEric Cheng break; 1302da14cebeSEric Cheng case 't': 1303da14cebeSEric Cheng temp = B_TRUE; 1304da14cebeSEric Cheng break; 1305da14cebeSEric Cheng case 'R': 1306da14cebeSEric Cheng status = dladm_set_rootdir(optarg); 1307da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 1308da14cebeSEric Cheng die_dlerr(status, "invalid directory " 1309da14cebeSEric Cheng "specified"); 1310da14cebeSEric Cheng } 1311da14cebeSEric Cheng break; 1312da14cebeSEric Cheng default: 1313da14cebeSEric Cheng die_opterr(optopt, option); 1314da14cebeSEric Cheng break; 1315da14cebeSEric Cheng } 1316da14cebeSEric Cheng } 1317da14cebeSEric Cheng 1318da14cebeSEric Cheng if (optind == (argc - 1)) { 1319da000602SGirish Moodalbail if (strlen(argv[optind]) >= MAXFLOWNAMELEN) 1320da14cebeSEric Cheng die("flow name too long"); 1321da14cebeSEric Cheng flow = argv[optind]; 1322da14cebeSEric Cheng } else if (optind != argc) { 1323da14cebeSEric Cheng usage(); 1324da14cebeSEric Cheng } 1325da14cebeSEric Cheng if (flow == NULL) 1326da14cebeSEric Cheng die("flow name must be specified"); 1327da14cebeSEric Cheng 132863a6526dSMichael Lim if (dladm_parse_flow_props(propstr, &proplist, reset) 132963a6526dSMichael Lim != DLADM_STATUS_OK) 133063a6526dSMichael Lim die("invalid flow property specified"); 133163a6526dSMichael Lim 1332da14cebeSEric Cheng if (proplist == NULL) { 1333da14cebeSEric Cheng char *errprop; 1334da14cebeSEric Cheng 1335da14cebeSEric Cheng if (!reset) 1336da14cebeSEric Cheng die("flow property must be specified"); 1337da14cebeSEric Cheng 13384ac67f02SAnurag S. Maskey status = dladm_set_flowprop(handle, flow, NULL, NULL, 0, 1339da14cebeSEric Cheng DLADM_OPT_ACTIVE, &errprop); 1340da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 1341da14cebeSEric Cheng warn_dlerr(status, "cannot reset flow property '%s' " 1342da14cebeSEric Cheng "on '%s'", errprop, flow); 1343da14cebeSEric Cheng } 1344da14cebeSEric Cheng if (!temp) { 1345da14cebeSEric Cheng dladm_status_t s; 1346da14cebeSEric Cheng 1347da14cebeSEric Cheng s = set_flowprop_persist(flow, NULL, NULL, 0, reset); 1348da14cebeSEric Cheng if (s != DLADM_STATUS_OK) 1349da14cebeSEric Cheng status = s; 1350da14cebeSEric Cheng } 1351da14cebeSEric Cheng goto done; 1352da14cebeSEric Cheng } 1353da14cebeSEric Cheng 1354da14cebeSEric Cheng for (i = 0; i < proplist->al_count; i++) { 1355da14cebeSEric Cheng dladm_arg_info_t *aip = &proplist->al_info[i]; 1356da14cebeSEric Cheng char **val; 1357da14cebeSEric Cheng uint_t count; 1358da14cebeSEric Cheng dladm_status_t s; 1359da14cebeSEric Cheng 1360da14cebeSEric Cheng if (reset) { 1361da14cebeSEric Cheng val = NULL; 1362da14cebeSEric Cheng count = 0; 1363da14cebeSEric Cheng } else { 1364da14cebeSEric Cheng val = aip->ai_val; 1365da14cebeSEric Cheng count = aip->ai_count; 1366da14cebeSEric Cheng if (count == 0) { 1367da14cebeSEric Cheng warn("no value specified for '%s'", 1368da14cebeSEric Cheng aip->ai_name); 1369da14cebeSEric Cheng status = DLADM_STATUS_BADARG; 1370da14cebeSEric Cheng continue; 1371da14cebeSEric Cheng } 1372da14cebeSEric Cheng } 13734ac67f02SAnurag S. Maskey s = dladm_set_flowprop(handle, flow, aip->ai_name, val, count, 1374da14cebeSEric Cheng DLADM_OPT_ACTIVE, NULL); 1375da14cebeSEric Cheng if (s == DLADM_STATUS_OK) { 1376da14cebeSEric Cheng if (!temp) { 1377da14cebeSEric Cheng s = set_flowprop_persist(flow, 1378da14cebeSEric Cheng aip->ai_name, val, count, reset); 1379da14cebeSEric Cheng if (s != DLADM_STATUS_OK) 1380da14cebeSEric Cheng status = s; 1381da14cebeSEric Cheng } 1382da14cebeSEric Cheng continue; 1383da14cebeSEric Cheng } 1384da14cebeSEric Cheng status = s; 1385da14cebeSEric Cheng switch (s) { 1386da14cebeSEric Cheng case DLADM_STATUS_NOTFOUND: 1387da14cebeSEric Cheng warn("invalid flow property '%s'", aip->ai_name); 1388da14cebeSEric Cheng break; 1389da14cebeSEric Cheng case DLADM_STATUS_BADVAL: { 1390da14cebeSEric Cheng int j; 1391da14cebeSEric Cheng char *ptr, *lim; 1392da14cebeSEric Cheng char **propvals = NULL; 1393da14cebeSEric Cheng uint_t valcnt = DLADM_MAX_PROP_VALCNT; 1394da14cebeSEric Cheng 1395da14cebeSEric Cheng ptr = malloc((sizeof (char *) + 1396da14cebeSEric Cheng DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 1397da14cebeSEric Cheng MAX_PROP_LINE); 1398da14cebeSEric Cheng 1399da14cebeSEric Cheng if (ptr == NULL) 1400da14cebeSEric Cheng die("insufficient memory"); 1401da14cebeSEric Cheng propvals = (char **)(void *)ptr; 1402da14cebeSEric Cheng 1403da14cebeSEric Cheng for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 1404da14cebeSEric Cheng propvals[j] = ptr + sizeof (char *) * 1405da14cebeSEric Cheng DLADM_MAX_PROP_VALCNT + 1406da14cebeSEric Cheng j * DLADM_PROP_VAL_MAX; 1407da14cebeSEric Cheng } 14084ac67f02SAnurag S. Maskey s = dladm_get_flowprop(handle, flow, 14094ac67f02SAnurag S. Maskey DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals, 14104ac67f02SAnurag S. Maskey &valcnt); 1411da14cebeSEric Cheng 1412da14cebeSEric Cheng ptr = errmsg; 1413da14cebeSEric Cheng lim = ptr + DLADM_STRSIZE; 1414da14cebeSEric Cheng *ptr = '\0'; 1415da14cebeSEric Cheng for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) { 1416da14cebeSEric Cheng ptr += snprintf(ptr, lim - ptr, "%s,", 1417da14cebeSEric Cheng propvals[j]); 1418da14cebeSEric Cheng if (ptr >= lim) 1419da14cebeSEric Cheng break; 1420da14cebeSEric Cheng } 1421da14cebeSEric Cheng if (ptr > errmsg) { 1422da14cebeSEric Cheng *(ptr - 1) = '\0'; 1423da14cebeSEric Cheng warn("flow property '%s' must be one of: %s", 1424da14cebeSEric Cheng aip->ai_name, errmsg); 1425da14cebeSEric Cheng } else 1426da14cebeSEric Cheng warn("%s is an invalid value for " 1427da14cebeSEric Cheng "flow property %s", *val, aip->ai_name); 1428da14cebeSEric Cheng free(propvals); 1429da14cebeSEric Cheng break; 1430da14cebeSEric Cheng } 1431da14cebeSEric Cheng default: 1432da14cebeSEric Cheng if (reset) { 1433da14cebeSEric Cheng warn_dlerr(status, "cannot reset flow property " 1434da14cebeSEric Cheng "'%s' on '%s'", aip->ai_name, flow); 1435da14cebeSEric Cheng } else { 1436da14cebeSEric Cheng warn_dlerr(status, "cannot set flow property " 1437da14cebeSEric Cheng "'%s' on '%s'", aip->ai_name, flow); 1438da14cebeSEric Cheng } 1439da14cebeSEric Cheng break; 1440da14cebeSEric Cheng } 1441da14cebeSEric Cheng } 1442da14cebeSEric Cheng done: 1443da14cebeSEric Cheng dladm_free_props(proplist); 14444ac67f02SAnurag S. Maskey if (status != DLADM_STATUS_OK) { 14454ac67f02SAnurag S. Maskey dladm_close(handle); 1446ad091ee1SMichael Lim exit(EXIT_FAILURE); 1447da14cebeSEric Cheng } 14484ac67f02SAnurag S. Maskey } 1449da14cebeSEric Cheng 1450da14cebeSEric Cheng static void 1451da14cebeSEric Cheng do_set_flowprop(int argc, char **argv) 1452da14cebeSEric Cheng { 1453da14cebeSEric Cheng set_flowprop(argc, argv, B_FALSE); 1454da14cebeSEric Cheng } 1455da14cebeSEric Cheng 1456da14cebeSEric Cheng static void 1457da14cebeSEric Cheng do_reset_flowprop(int argc, char **argv) 1458da14cebeSEric Cheng { 1459da14cebeSEric Cheng set_flowprop(argc, argv, B_TRUE); 1460da14cebeSEric Cheng } 1461da14cebeSEric Cheng 1462da14cebeSEric Cheng static void 1463da14cebeSEric Cheng warn(const char *format, ...) 1464da14cebeSEric Cheng { 1465da14cebeSEric Cheng va_list alist; 1466da14cebeSEric Cheng 1467da14cebeSEric Cheng format = gettext(format); 1468da14cebeSEric Cheng (void) fprintf(stderr, "%s: warning: ", progname); 1469da14cebeSEric Cheng 1470da14cebeSEric Cheng va_start(alist, format); 1471da14cebeSEric Cheng (void) vfprintf(stderr, format, alist); 1472da14cebeSEric Cheng va_end(alist); 1473da14cebeSEric Cheng 1474da14cebeSEric Cheng (void) putchar('\n'); 1475da14cebeSEric Cheng } 1476da14cebeSEric Cheng 1477da14cebeSEric Cheng /* PRINTFLIKE2 */ 1478da14cebeSEric Cheng static void 1479da14cebeSEric Cheng warn_dlerr(dladm_status_t err, const char *format, ...) 1480da14cebeSEric Cheng { 1481da14cebeSEric Cheng va_list alist; 1482da14cebeSEric Cheng char errmsg[DLADM_STRSIZE]; 1483da14cebeSEric Cheng 1484da14cebeSEric Cheng format = gettext(format); 1485da14cebeSEric Cheng (void) fprintf(stderr, gettext("%s: warning: "), progname); 1486da14cebeSEric Cheng 1487da14cebeSEric Cheng va_start(alist, format); 1488da14cebeSEric Cheng (void) vfprintf(stderr, format, alist); 1489da14cebeSEric Cheng va_end(alist); 1490da14cebeSEric Cheng (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 1491da14cebeSEric Cheng } 1492da14cebeSEric Cheng 1493da14cebeSEric Cheng /* PRINTFLIKE1 */ 1494da14cebeSEric Cheng static void 1495da14cebeSEric Cheng die(const char *format, ...) 1496da14cebeSEric Cheng { 1497da14cebeSEric Cheng va_list alist; 1498da14cebeSEric Cheng 1499da14cebeSEric Cheng format = gettext(format); 1500da14cebeSEric Cheng (void) fprintf(stderr, "%s: ", progname); 1501da14cebeSEric Cheng 1502da14cebeSEric Cheng va_start(alist, format); 1503da14cebeSEric Cheng (void) vfprintf(stderr, format, alist); 1504da14cebeSEric Cheng va_end(alist); 1505da14cebeSEric Cheng 1506da14cebeSEric Cheng (void) putchar('\n'); 15074ac67f02SAnurag S. Maskey 15084ac67f02SAnurag S. Maskey /* close dladm handle if it was opened */ 15094ac67f02SAnurag S. Maskey if (handle != NULL) 15104ac67f02SAnurag S. Maskey dladm_close(handle); 15114ac67f02SAnurag S. Maskey 1512da14cebeSEric Cheng exit(EXIT_FAILURE); 1513da14cebeSEric Cheng } 1514da14cebeSEric Cheng 1515da14cebeSEric Cheng static void 1516da14cebeSEric Cheng die_optdup(int opt) 1517da14cebeSEric Cheng { 1518da14cebeSEric Cheng die("the option -%c cannot be specified more than once", opt); 1519da14cebeSEric Cheng } 1520da14cebeSEric Cheng 1521da14cebeSEric Cheng static void 1522da14cebeSEric Cheng die_opterr(int opt, int opterr) 1523da14cebeSEric Cheng { 1524da14cebeSEric Cheng switch (opterr) { 1525da14cebeSEric Cheng case ':': 1526da14cebeSEric Cheng die("option '-%c' requires a value", opt); 1527da14cebeSEric Cheng break; 1528da14cebeSEric Cheng case '?': 1529da14cebeSEric Cheng default: 1530da14cebeSEric Cheng die("unrecognized option '-%c'", opt); 1531da14cebeSEric Cheng break; 1532da14cebeSEric Cheng } 1533da14cebeSEric Cheng } 1534da14cebeSEric Cheng 1535da14cebeSEric Cheng /* PRINTFLIKE2 */ 1536da14cebeSEric Cheng static void 1537da14cebeSEric Cheng die_dlerr(dladm_status_t err, const char *format, ...) 1538da14cebeSEric Cheng { 1539da14cebeSEric Cheng va_list alist; 1540da14cebeSEric Cheng char errmsg[DLADM_STRSIZE]; 1541da14cebeSEric Cheng 1542da14cebeSEric Cheng format = gettext(format); 1543da14cebeSEric Cheng (void) fprintf(stderr, "%s: ", progname); 1544da14cebeSEric Cheng 1545da14cebeSEric Cheng va_start(alist, format); 1546da14cebeSEric Cheng (void) vfprintf(stderr, format, alist); 1547da14cebeSEric Cheng va_end(alist); 1548da14cebeSEric Cheng (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 1549da14cebeSEric Cheng 15504ac67f02SAnurag S. Maskey /* close dladm handle if it was opened */ 15514ac67f02SAnurag S. Maskey if (handle != NULL) 15524ac67f02SAnurag S. Maskey dladm_close(handle); 15534ac67f02SAnurag S. Maskey 1554da14cebeSEric Cheng exit(EXIT_FAILURE); 1555da14cebeSEric Cheng } 1556da14cebeSEric Cheng 1557da14cebeSEric Cheng static void 1558da14cebeSEric Cheng print_flowprop(const char *flowname, show_flowprop_state_t *statep, 1559da14cebeSEric Cheng const char *propname, dladm_prop_type_t type, 1560da14cebeSEric Cheng const char *format, char **pptr) 1561da14cebeSEric Cheng { 1562da14cebeSEric Cheng int i; 1563da14cebeSEric Cheng char *ptr, *lim; 1564da14cebeSEric Cheng char buf[DLADM_STRSIZE]; 1565da14cebeSEric Cheng char *unknown = "--", *notsup = ""; 1566da14cebeSEric Cheng char **propvals = statep->fs_propvals; 1567da14cebeSEric Cheng uint_t valcnt = DLADM_MAX_PROP_VALCNT; 1568da14cebeSEric Cheng dladm_status_t status; 1569da14cebeSEric Cheng 15704ac67f02SAnurag S. Maskey status = dladm_get_flowprop(handle, flowname, type, propname, propvals, 1571da14cebeSEric Cheng &valcnt); 1572da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 1573da14cebeSEric Cheng if (status == DLADM_STATUS_TEMPONLY) { 1574da14cebeSEric Cheng if (type == DLADM_PROP_VAL_MODIFIABLE && 1575da14cebeSEric Cheng statep->fs_persist) { 1576da14cebeSEric Cheng valcnt = 1; 1577da14cebeSEric Cheng propvals = &unknown; 1578da14cebeSEric Cheng } else { 1579da14cebeSEric Cheng statep->fs_status = status; 1580da14cebeSEric Cheng statep->fs_retstatus = status; 1581da14cebeSEric Cheng return; 1582da14cebeSEric Cheng } 1583da14cebeSEric Cheng } else if (status == DLADM_STATUS_NOTSUP || 1584da14cebeSEric Cheng statep->fs_persist) { 1585da14cebeSEric Cheng valcnt = 1; 1586da14cebeSEric Cheng if (type == DLADM_PROP_VAL_CURRENT) 1587da14cebeSEric Cheng propvals = &unknown; 1588da14cebeSEric Cheng else 1589da14cebeSEric Cheng propvals = ¬sup; 1590da14cebeSEric Cheng } else { 1591da14cebeSEric Cheng if ((statep->fs_proplist != NULL) && 1592da14cebeSEric Cheng statep->fs_status == DLADM_STATUS_OK) { 1593da14cebeSEric Cheng warn("invalid flow property '%s'", propname); 1594da14cebeSEric Cheng } 1595da14cebeSEric Cheng statep->fs_status = status; 1596da14cebeSEric Cheng statep->fs_retstatus = status; 1597da14cebeSEric Cheng return; 1598da14cebeSEric Cheng } 1599da14cebeSEric Cheng } 1600da14cebeSEric Cheng 1601da14cebeSEric Cheng statep->fs_status = DLADM_STATUS_OK; 1602da14cebeSEric Cheng 1603da14cebeSEric Cheng ptr = buf; 1604da14cebeSEric Cheng lim = buf + DLADM_STRSIZE; 1605da14cebeSEric Cheng for (i = 0; i < valcnt; i++) { 16068002d411SSowmini Varadhan if (propvals[i][0] == '\0' && !statep->fs_parsable) 16078002d411SSowmini Varadhan ptr += snprintf(ptr, lim - ptr, "--,"); 1608da14cebeSEric Cheng else 1609da14cebeSEric Cheng ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 1610da14cebeSEric Cheng if (ptr >= lim) 1611da14cebeSEric Cheng break; 1612da14cebeSEric Cheng } 1613da14cebeSEric Cheng if (valcnt > 0) 1614da14cebeSEric Cheng buf[strlen(buf) - 1] = '\0'; 1615da14cebeSEric Cheng 1616da14cebeSEric Cheng lim = statep->fs_line + MAX_PROP_LINE; 16178002d411SSowmini Varadhan if (statep->fs_parsable) { 1618da14cebeSEric Cheng *pptr += snprintf(*pptr, lim - *pptr, 1619da14cebeSEric Cheng "%s", buf); 1620da14cebeSEric Cheng } else { 1621da14cebeSEric Cheng *pptr += snprintf(*pptr, lim - *pptr, format, buf); 1622da14cebeSEric Cheng } 1623da14cebeSEric Cheng } 1624da14cebeSEric Cheng 16258002d411SSowmini Varadhan static boolean_t 16268002d411SSowmini Varadhan print_flowprop_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 1627da14cebeSEric Cheng { 16288002d411SSowmini Varadhan flowprop_args_t *arg = of_arg->ofmt_cbarg; 1629da14cebeSEric Cheng char *propname = arg->fs_propname; 1630da14cebeSEric Cheng show_flowprop_state_t *statep = arg->fs_state; 1631da14cebeSEric Cheng char *ptr = statep->fs_line; 1632da14cebeSEric Cheng char *lim = ptr + MAX_PROP_LINE; 1633da14cebeSEric Cheng char *flowname = arg->fs_flowname; 1634da14cebeSEric Cheng 16358002d411SSowmini Varadhan switch (of_arg->ofmt_id) { 1636da14cebeSEric Cheng case FLOWPROP_FLOW: 1637da14cebeSEric Cheng (void) snprintf(ptr, lim - ptr, "%s", statep->fs_flow); 1638da14cebeSEric Cheng break; 1639da14cebeSEric Cheng case FLOWPROP_PROPERTY: 1640da14cebeSEric Cheng (void) snprintf(ptr, lim - ptr, "%s", propname); 1641da14cebeSEric Cheng break; 1642da14cebeSEric Cheng case FLOWPROP_VALUE: 1643da14cebeSEric Cheng print_flowprop(flowname, statep, propname, 1644da14cebeSEric Cheng statep->fs_persist ? DLADM_PROP_VAL_PERSISTENT : 1645da14cebeSEric Cheng DLADM_PROP_VAL_CURRENT, "%s", &ptr); 1646da14cebeSEric Cheng /* 1647da14cebeSEric Cheng * If we failed to query the flow property, for example, query 1648da14cebeSEric Cheng * the persistent value of a non-persistable flow property, 1649da14cebeSEric Cheng * simply skip the output. 1650da14cebeSEric Cheng */ 1651da14cebeSEric Cheng if (statep->fs_status != DLADM_STATUS_OK) 1652da14cebeSEric Cheng goto skip; 1653da14cebeSEric Cheng ptr = statep->fs_line; 1654da14cebeSEric Cheng break; 1655da14cebeSEric Cheng case FLOWPROP_DEFAULT: 1656da14cebeSEric Cheng print_flowprop(flowname, statep, propname, 1657da14cebeSEric Cheng DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 1658da14cebeSEric Cheng if (statep->fs_status != DLADM_STATUS_OK) 1659da14cebeSEric Cheng goto skip; 1660da14cebeSEric Cheng ptr = statep->fs_line; 1661da14cebeSEric Cheng break; 1662da14cebeSEric Cheng case FLOWPROP_POSSIBLE: 1663da14cebeSEric Cheng print_flowprop(flowname, statep, propname, 1664da14cebeSEric Cheng DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 1665da14cebeSEric Cheng if (statep->fs_status != DLADM_STATUS_OK) 1666da14cebeSEric Cheng goto skip; 1667da14cebeSEric Cheng ptr = statep->fs_line; 1668da14cebeSEric Cheng break; 1669da14cebeSEric Cheng default: 1670da14cebeSEric Cheng die("invalid input"); 1671da14cebeSEric Cheng break; 1672da14cebeSEric Cheng } 16738002d411SSowmini Varadhan (void) strlcpy(buf, ptr, bufsize); 16748002d411SSowmini Varadhan return (B_TRUE); 1675da14cebeSEric Cheng skip: 16768002d411SSowmini Varadhan buf[0] = '\0'; 16778002d411SSowmini Varadhan return ((statep->fs_status == DLADM_STATUS_OK) ? 16788002d411SSowmini Varadhan B_TRUE : B_FALSE); 1679da14cebeSEric Cheng } 1680da14cebeSEric Cheng 1681da14cebeSEric Cheng static int 1682da14cebeSEric Cheng show_one_flowprop(void *arg, const char *propname) 1683da14cebeSEric Cheng { 1684da14cebeSEric Cheng show_flowprop_state_t *statep = arg; 1685da14cebeSEric Cheng flowprop_args_t fs_arg; 1686da14cebeSEric Cheng 1687da14cebeSEric Cheng bzero(&fs_arg, sizeof (fs_arg)); 1688da14cebeSEric Cheng fs_arg.fs_state = statep; 1689da14cebeSEric Cheng fs_arg.fs_propname = (char *)propname; 1690da14cebeSEric Cheng fs_arg.fs_flowname = (char *)statep->fs_flow; 1691da14cebeSEric Cheng 16928002d411SSowmini Varadhan ofmt_print(statep->fs_ofmt, (void *)&fs_arg); 1693da14cebeSEric Cheng 1694da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1695da14cebeSEric Cheng } 1696da14cebeSEric Cheng 1697c3affd82SMichael Lim /*ARGSUSED*/ 1698da14cebeSEric Cheng /* Walker function called by dladm_walk_flow to display flow properties */ 1699da14cebeSEric Cheng static int 1700c3affd82SMichael Lim show_flowprop(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg) 1701da14cebeSEric Cheng { 1702da14cebeSEric Cheng show_flowprop_one_flow(arg, attr->fa_flowname); 1703da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1704da14cebeSEric Cheng } 1705da14cebeSEric Cheng 1706da14cebeSEric Cheng /* 1707da14cebeSEric Cheng * Wrapper of dladm_walk_flow(show_walk_fn,...) to make it 1708da14cebeSEric Cheng * usable to dladm_walk_datalink_id() 1709da14cebeSEric Cheng */ 1710da14cebeSEric Cheng static int 17114ac67f02SAnurag S. Maskey show_flowprop_onelink(dladm_handle_t dh, datalink_id_t linkid, void *arg) 1712da14cebeSEric Cheng { 1713da14cebeSEric Cheng char name[MAXLINKNAMELEN]; 1714da14cebeSEric Cheng 17154ac67f02SAnurag S. Maskey if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, name, 17164ac67f02SAnurag S. Maskey sizeof (name)) != DLADM_STATUS_OK) 1717da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 1718da14cebeSEric Cheng 17194ac67f02SAnurag S. Maskey (void) dladm_walk_flow(show_flowprop, dh, linkid, arg, B_FALSE); 1720da14cebeSEric Cheng 1721da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1722da14cebeSEric Cheng } 1723da14cebeSEric Cheng 1724da14cebeSEric Cheng static void 1725da14cebeSEric Cheng do_show_flowprop(int argc, char **argv) 1726da14cebeSEric Cheng { 1727da14cebeSEric Cheng int option; 1728da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 1729da14cebeSEric Cheng show_flowprop_state_t state; 1730da14cebeSEric Cheng char *fields_str = NULL; 17318002d411SSowmini Varadhan ofmt_handle_t ofmt; 17328002d411SSowmini Varadhan ofmt_status_t oferr; 17338002d411SSowmini Varadhan uint_t ofmtflags = 0; 1734da14cebeSEric Cheng 1735da14cebeSEric Cheng opterr = 0; 1736da14cebeSEric Cheng state.fs_propvals = NULL; 1737da14cebeSEric Cheng state.fs_line = NULL; 17388002d411SSowmini Varadhan state.fs_parsable = B_FALSE; 1739da14cebeSEric Cheng state.fs_persist = B_FALSE; 1740da14cebeSEric Cheng state.fs_header = B_TRUE; 1741da14cebeSEric Cheng state.fs_retstatus = DLADM_STATUS_OK; 1742da14cebeSEric Cheng state.fs_linkid = DATALINK_INVALID_LINKID; 1743da14cebeSEric Cheng state.fs_flow = NULL; 1744da14cebeSEric Cheng 1745da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":p:cPl:o:", 1746da14cebeSEric Cheng prop_longopts, NULL)) != -1) { 1747da14cebeSEric Cheng switch (option) { 1748da14cebeSEric Cheng case 'p': 1749da14cebeSEric Cheng if (dladm_parse_flow_props(optarg, &proplist, B_TRUE) 1750da14cebeSEric Cheng != DLADM_STATUS_OK) 1751da14cebeSEric Cheng die("invalid flow properties specified"); 1752da14cebeSEric Cheng break; 1753da14cebeSEric Cheng case 'c': 17548002d411SSowmini Varadhan state.fs_parsable = B_TRUE; 17558002d411SSowmini Varadhan ofmtflags |= OFMT_PARSABLE; 1756da14cebeSEric Cheng break; 1757da14cebeSEric Cheng case 'P': 1758da14cebeSEric Cheng state.fs_persist = B_TRUE; 1759da14cebeSEric Cheng break; 1760da14cebeSEric Cheng case 'l': 17614ac67f02SAnurag S. Maskey if (dladm_name2info(handle, optarg, &state.fs_linkid, 1762da14cebeSEric Cheng NULL, NULL, NULL) != DLADM_STATUS_OK) 1763da14cebeSEric Cheng die("invalid link '%s'", optarg); 1764da14cebeSEric Cheng break; 1765da14cebeSEric Cheng case 'o': 1766da14cebeSEric Cheng fields_str = optarg; 1767da14cebeSEric Cheng break; 1768da14cebeSEric Cheng default: 1769da14cebeSEric Cheng die_opterr(optopt, option); 1770da14cebeSEric Cheng break; 1771da14cebeSEric Cheng } 1772da14cebeSEric Cheng } 1773da14cebeSEric Cheng 1774da14cebeSEric Cheng if (optind == (argc - 1)) { 1775da000602SGirish Moodalbail if (strlen(argv[optind]) >= MAXFLOWNAMELEN) 1776da14cebeSEric Cheng die("flow name too long"); 1777da14cebeSEric Cheng state.fs_flow = argv[optind]; 1778da14cebeSEric Cheng } else if (optind != argc) { 1779da14cebeSEric Cheng usage(); 1780da14cebeSEric Cheng } 1781da14cebeSEric Cheng state.fs_proplist = proplist; 1782da14cebeSEric Cheng state.fs_status = DLADM_STATUS_OK; 1783da14cebeSEric Cheng 17848002d411SSowmini Varadhan oferr = ofmt_open(fields_str, flowprop_fields, ofmtflags, 0, &ofmt); 17858002d411SSowmini Varadhan flowadm_ofmt_check(oferr, state.fs_parsable, ofmt); 17868002d411SSowmini Varadhan state.fs_ofmt = ofmt; 1787da14cebeSEric Cheng 1788da14cebeSEric Cheng /* Show properties for one flow */ 1789da14cebeSEric Cheng if (state.fs_flow != NULL) { 1790da14cebeSEric Cheng show_flowprop_one_flow(&state, state.fs_flow); 1791da14cebeSEric Cheng 1792da14cebeSEric Cheng /* Show properties for all flows on one link */ 1793da14cebeSEric Cheng } else if (state.fs_linkid != DATALINK_INVALID_LINKID) { 17944ac67f02SAnurag S. Maskey (void) show_flowprop_onelink(handle, state.fs_linkid, &state); 1795da14cebeSEric Cheng 1796da14cebeSEric Cheng /* Show properties for all flows on all links */ 1797da14cebeSEric Cheng } else { 17984ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(show_flowprop_onelink, handle, 17994ac67f02SAnurag S. Maskey &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 1800da14cebeSEric Cheng DLADM_OPT_ACTIVE); 1801da14cebeSEric Cheng } 1802da14cebeSEric Cheng 1803da14cebeSEric Cheng dladm_free_props(proplist); 18048002d411SSowmini Varadhan ofmt_close(ofmt); 1805da14cebeSEric Cheng } 1806da14cebeSEric Cheng 1807da14cebeSEric Cheng static void 1808da14cebeSEric Cheng show_flowprop_one_flow(void *arg, const char *flow) 1809da14cebeSEric Cheng { 1810da14cebeSEric Cheng int i; 1811da14cebeSEric Cheng char *buf; 1812da14cebeSEric Cheng dladm_status_t status; 1813da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 1814da14cebeSEric Cheng show_flowprop_state_t *statep = arg; 1815da14cebeSEric Cheng dladm_flow_attr_t attr; 1816da14cebeSEric Cheng const char *savep; 1817da14cebeSEric Cheng 1818da14cebeSEric Cheng /* 1819da14cebeSEric Cheng * Do not print flow props for invalid flows. 1820da14cebeSEric Cheng */ 18214ac67f02SAnurag S. Maskey if ((status = dladm_flow_info(handle, flow, &attr)) != 18224ac67f02SAnurag S. Maskey DLADM_STATUS_OK) { 1823da14cebeSEric Cheng die("invalid flow: '%s'", flow); 1824da14cebeSEric Cheng } 1825da14cebeSEric Cheng 1826da14cebeSEric Cheng savep = statep->fs_flow; 1827da14cebeSEric Cheng statep->fs_flow = flow; 1828da14cebeSEric Cheng 1829da14cebeSEric Cheng proplist = statep->fs_proplist; 1830da14cebeSEric Cheng 1831da14cebeSEric Cheng buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) 1832da14cebeSEric Cheng * DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 1833da14cebeSEric Cheng if (buf == NULL) 1834da14cebeSEric Cheng die("insufficient memory"); 1835da14cebeSEric Cheng 1836da14cebeSEric Cheng statep->fs_propvals = (char **)(void *)buf; 1837da14cebeSEric Cheng for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 1838da14cebeSEric Cheng statep->fs_propvals[i] = buf + 1839da14cebeSEric Cheng sizeof (char *) * DLADM_MAX_PROP_VALCNT + 1840da14cebeSEric Cheng i * DLADM_PROP_VAL_MAX; 1841da14cebeSEric Cheng } 1842da14cebeSEric Cheng statep->fs_line = buf + 1843da14cebeSEric Cheng (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 1844da14cebeSEric Cheng 1845da14cebeSEric Cheng /* show only specified flow properties */ 1846da14cebeSEric Cheng if (proplist != NULL) { 1847da14cebeSEric Cheng for (i = 0; i < proplist->al_count; i++) { 1848da14cebeSEric Cheng if (show_one_flowprop(statep, 1849da14cebeSEric Cheng proplist->al_info[i].ai_name) != DLADM_STATUS_OK) 1850da14cebeSEric Cheng break; 1851da14cebeSEric Cheng } 1852da14cebeSEric Cheng 1853da14cebeSEric Cheng /* show all flow properties */ 1854da14cebeSEric Cheng } else { 1855da14cebeSEric Cheng status = dladm_walk_flowprop(show_one_flowprop, flow, statep); 1856da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 1857da14cebeSEric Cheng die_dlerr(status, "show-flowprop"); 1858da14cebeSEric Cheng } 1859da14cebeSEric Cheng free(buf); 1860da14cebeSEric Cheng statep->fs_flow = savep; 1861da14cebeSEric Cheng } 1862da14cebeSEric Cheng 1863da14cebeSEric Cheng /* 18648002d411SSowmini Varadhan * default output callback function that, when invoked from dladm_print_output, 18658002d411SSowmini Varadhan * prints string which is offset by of_arg->ofmt_id within buf. 1866da14cebeSEric Cheng */ 18678002d411SSowmini Varadhan static boolean_t 18688002d411SSowmini Varadhan print_default_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 1869da14cebeSEric Cheng { 1870da14cebeSEric Cheng char *value; 1871da14cebeSEric Cheng 18728002d411SSowmini Varadhan value = (char *)of_arg->ofmt_cbarg + of_arg->ofmt_id; 18738002d411SSowmini Varadhan (void) strlcpy(buf, value, bufsize); 18748002d411SSowmini Varadhan return (B_TRUE); 1875da14cebeSEric Cheng } 1876da14cebeSEric Cheng 1877da14cebeSEric Cheng static void 18788002d411SSowmini Varadhan flowadm_ofmt_check(ofmt_status_t oferr, boolean_t parsable, 18798002d411SSowmini Varadhan ofmt_handle_t ofmt) 1880da14cebeSEric Cheng { 18818002d411SSowmini Varadhan char buf[OFMT_BUFSIZE]; 1882da14cebeSEric Cheng 18838002d411SSowmini Varadhan if (oferr == OFMT_SUCCESS) 18848002d411SSowmini Varadhan return; 18858002d411SSowmini Varadhan (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf)); 1886ad091ee1SMichael Lim /* 18878002d411SSowmini Varadhan * All errors are considered fatal in parsable mode. 18888002d411SSowmini Varadhan * NOMEM errors are always fatal, regardless of mode. 18898002d411SSowmini Varadhan * For other errors, we print diagnostics in human-readable 18908002d411SSowmini Varadhan * mode and processs what we can. 1891ad091ee1SMichael Lim */ 18928002d411SSowmini Varadhan if (parsable || oferr == OFMT_ENOFIELDS) { 18938002d411SSowmini Varadhan ofmt_close(ofmt); 18948002d411SSowmini Varadhan die(buf); 1895da14cebeSEric Cheng } else { 18968002d411SSowmini Varadhan warn(buf); 1897da14cebeSEric Cheng } 1898da14cebeSEric Cheng } 1899