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> 52da14cebeSEric Cheng 53da14cebeSEric Cheng #define CMD_TYPE_ANY 0xffffffff 54da14cebeSEric Cheng #define STR_UNDEF_VAL "--" 55da14cebeSEric Cheng 56da14cebeSEric Cheng 57da14cebeSEric Cheng /* 58da14cebeSEric Cheng * data structures and routines for printing output. 59da14cebeSEric Cheng */ 60da14cebeSEric Cheng 61da14cebeSEric Cheng typedef struct print_field_s { 62da14cebeSEric Cheng const char *pf_name; 63da14cebeSEric Cheng const char *pf_header; 64da14cebeSEric Cheng uint_t pf_width; 65da14cebeSEric Cheng union { 66da14cebeSEric Cheng uint_t _pf_index; 67da14cebeSEric Cheng size_t _pf_offset; 68da14cebeSEric Cheng }_pf_un; 69da14cebeSEric Cheng #define pf_index _pf_un._pf_index 70da14cebeSEric Cheng #define pf_offset _pf_un._pf_offset; 71da14cebeSEric Cheng uint_t pf_cmdtype; 72da14cebeSEric Cheng } print_field_t; 73da14cebeSEric Cheng 74da14cebeSEric Cheng typedef struct print_state_s { 75da14cebeSEric Cheng print_field_t **ps_fields; 76da14cebeSEric Cheng uint_t ps_nfields; 77da14cebeSEric Cheng boolean_t ps_lastfield; 78da14cebeSEric Cheng uint_t ps_overflow; 79da14cebeSEric Cheng } print_state_t; 80da14cebeSEric Cheng 81da14cebeSEric Cheng typedef struct show_usage_state_s { 82da14cebeSEric Cheng boolean_t us_plot; 83da14cebeSEric Cheng boolean_t us_parseable; 84da14cebeSEric Cheng boolean_t us_printheader; 85da14cebeSEric Cheng boolean_t us_first; 86ae6aa22aSVenugopal Iyer boolean_t us_showall; 87da14cebeSEric Cheng print_state_t us_print; 88da14cebeSEric Cheng } show_usage_state_t; 89da14cebeSEric Cheng 90da14cebeSEric Cheng typedef char *(*print_callback_t)(print_field_t *, void *); 91da14cebeSEric Cheng static print_field_t **parse_output_fields(char *, print_field_t *, int, 92da14cebeSEric Cheng uint_t, uint_t *); 93da14cebeSEric Cheng 94da14cebeSEric Cheng static void print_header(print_state_t *); 95da14cebeSEric Cheng static void print_field(print_state_t *, print_field_t *, const char *, 96da14cebeSEric Cheng boolean_t); 97da14cebeSEric Cheng 98da14cebeSEric Cheng static void flowadm_print_output(print_state_t *, boolean_t, 99da14cebeSEric Cheng print_callback_t, void *); 100da14cebeSEric Cheng 101da14cebeSEric Cheng /* 102da14cebeSEric Cheng * helper function that, when invoked as flowadm(print_field(pf, buf) 103da14cebeSEric Cheng * prints string which is offset by pf->pf_offset within buf. 104da14cebeSEric Cheng */ 105da14cebeSEric Cheng static char *flowadm_print_field(print_field_t *, void *); 106da14cebeSEric Cheng 107da14cebeSEric Cheng #define MAX_FIELD_LEN 32 108da14cebeSEric Cheng 109ae6aa22aSVenugopal Iyer typedef struct show_flow_state { 110ae6aa22aSVenugopal Iyer boolean_t fs_firstonly; 111ae6aa22aSVenugopal Iyer boolean_t fs_donefirst; 112ae6aa22aSVenugopal Iyer pktsum_t fs_prevstats; 113ae6aa22aSVenugopal Iyer uint32_t fs_flags; 114ae6aa22aSVenugopal Iyer dladm_status_t fs_status; 115ae6aa22aSVenugopal Iyer print_state_t fs_print; 116ae6aa22aSVenugopal Iyer const char *fs_flow; 117ae6aa22aSVenugopal Iyer const char *fs_link; 118ae6aa22aSVenugopal Iyer boolean_t fs_parseable; 119ae6aa22aSVenugopal Iyer boolean_t fs_printheader; 120ae6aa22aSVenugopal Iyer boolean_t fs_persist; 121ae6aa22aSVenugopal Iyer boolean_t fs_stats; 122ae6aa22aSVenugopal Iyer uint64_t fs_mask; 123ae6aa22aSVenugopal Iyer } show_flow_state_t; 124ae6aa22aSVenugopal Iyer 125da14cebeSEric Cheng typedef void cmdfunc_t(int, char **); 126da14cebeSEric Cheng 127da14cebeSEric Cheng static cmdfunc_t do_add_flow, do_remove_flow, do_init_flow, do_show_flow; 128da14cebeSEric Cheng static cmdfunc_t do_show_flowprop, do_set_flowprop, do_reset_flowprop; 129da14cebeSEric Cheng static cmdfunc_t do_show_usage; 130da14cebeSEric Cheng 131da14cebeSEric Cheng static int show_flow(dladm_flow_attr_t *, void *); 1324ac67f02SAnurag S. Maskey static int show_flows_onelink(dladm_handle_t, datalink_id_t, void *); 133da14cebeSEric Cheng 134ae6aa22aSVenugopal Iyer static void flow_stats(const char *, datalink_id_t, uint_t, char *, 135ae6aa22aSVenugopal Iyer show_flow_state_t *); 136da14cebeSEric Cheng static void get_flow_stats(const char *, pktsum_t *); 137da14cebeSEric Cheng static int show_flow_stats(dladm_flow_attr_t *, void *); 1384ac67f02SAnurag S. Maskey static int show_link_flow_stats(dladm_handle_t, datalink_id_t, void *); 139da14cebeSEric Cheng 140da14cebeSEric Cheng static int remove_flow(dladm_flow_attr_t *, void *); 141da14cebeSEric Cheng 142da14cebeSEric Cheng static int show_flowprop(dladm_flow_attr_t *, void *); 143da14cebeSEric Cheng static void show_flowprop_one_flow(void *, const char *); 1444ac67f02SAnurag S. Maskey static int show_flowprop_onelink(dladm_handle_t, datalink_id_t, void *); 145da14cebeSEric Cheng 146da14cebeSEric Cheng static void die(const char *, ...); 147da14cebeSEric Cheng static void die_optdup(int); 148da14cebeSEric Cheng static void die_opterr(int, int); 149da14cebeSEric Cheng static void die_dlerr(dladm_status_t, const char *, ...); 150da14cebeSEric Cheng static void warn(const char *, ...); 151da14cebeSEric Cheng static void warn_dlerr(dladm_status_t, const char *, ...); 152da14cebeSEric Cheng 153da14cebeSEric Cheng typedef struct cmd { 154da14cebeSEric Cheng char *c_name; 155da14cebeSEric Cheng void (*c_fn)(int, char **); 156da14cebeSEric Cheng } cmd_t; 157da14cebeSEric Cheng 158da14cebeSEric Cheng static cmd_t cmds[] = { 159da14cebeSEric Cheng { "add-flow", do_add_flow }, 160da14cebeSEric Cheng { "remove-flow", do_remove_flow }, 161da14cebeSEric Cheng { "show-flowprop", do_show_flowprop }, 162da14cebeSEric Cheng { "set-flowprop", do_set_flowprop }, 163da14cebeSEric Cheng { "reset-flowprop", do_reset_flowprop }, 164da14cebeSEric Cheng { "show-flow", do_show_flow }, 165da14cebeSEric Cheng { "init-flow", do_init_flow }, 166da14cebeSEric Cheng { "show-usage", do_show_usage } 167da14cebeSEric Cheng }; 168da14cebeSEric Cheng 169da14cebeSEric Cheng static const struct option longopts[] = { 170da14cebeSEric Cheng {"link", required_argument, 0, 'l'}, 171da14cebeSEric Cheng {"parseable", no_argument, 0, 'p'}, 172da14cebeSEric Cheng {"statistics", no_argument, 0, 's'}, 173da14cebeSEric Cheng {"interval", required_argument, 0, 'i'}, 174da14cebeSEric Cheng {"temporary", no_argument, 0, 't'}, 175da14cebeSEric Cheng {"root-dir", required_argument, 0, 'R'}, 176da14cebeSEric Cheng { 0, 0, 0, 0 } 177da14cebeSEric Cheng }; 178da14cebeSEric Cheng 179da14cebeSEric Cheng static const struct option prop_longopts[] = { 180da14cebeSEric Cheng {"link", required_argument, 0, 'l'}, 181da14cebeSEric Cheng {"temporary", no_argument, 0, 't'}, 182da14cebeSEric Cheng {"root-dir", required_argument, 0, 'R'}, 183da14cebeSEric Cheng {"prop", required_argument, 0, 'p'}, 184da14cebeSEric Cheng {"attr", required_argument, 0, 'a'}, 185da14cebeSEric Cheng { 0, 0, 0, 0 } 186da14cebeSEric Cheng }; 187da14cebeSEric Cheng 188da14cebeSEric Cheng /* 189da14cebeSEric Cheng * structures for 'flowadm remove-flow' 190da14cebeSEric Cheng */ 191da14cebeSEric Cheng 192da14cebeSEric Cheng typedef struct remove_flow_state { 193da14cebeSEric Cheng boolean_t fs_tempop; 194da14cebeSEric Cheng const char *fs_altroot; 195da14cebeSEric Cheng dladm_status_t fs_status; 196da14cebeSEric Cheng } remove_flow_state_t; 197da14cebeSEric Cheng 198da14cebeSEric Cheng #define PROTO_MAXSTR_LEN 7 199da14cebeSEric Cheng #define PORT_MAXSTR_LEN 6 200da14cebeSEric Cheng #define DSFIELD_MAXSTR_LEN 10 201da14cebeSEric Cheng 202da14cebeSEric Cheng typedef struct flow_fields_buf_s 203da14cebeSEric Cheng { 204da000602SGirish Moodalbail char flow_name[MAXFLOWNAMELEN]; 205da14cebeSEric Cheng char flow_link[MAXLINKNAMELEN]; 206da14cebeSEric Cheng char flow_ipaddr[INET6_ADDRSTRLEN+4]; 207da14cebeSEric Cheng char flow_proto[PROTO_MAXSTR_LEN]; 208da14cebeSEric Cheng char flow_port[PORT_MAXSTR_LEN]; 209da14cebeSEric Cheng char flow_dsfield[DSFIELD_MAXSTR_LEN]; 210da14cebeSEric Cheng } flow_fields_buf_t; 211da14cebeSEric Cheng 212da14cebeSEric Cheng static print_field_t flow_fields[] = { 213da14cebeSEric Cheng /* name, header, field width, index, cmdtype */ 214da14cebeSEric Cheng { "flow", "FLOW", 11, 215da14cebeSEric Cheng offsetof(flow_fields_buf_t, flow_name), CMD_TYPE_ANY}, 216da14cebeSEric Cheng { "link", "LINK", 11, 217da14cebeSEric Cheng offsetof(flow_fields_buf_t, flow_link), CMD_TYPE_ANY}, 218da14cebeSEric Cheng { "ipaddr", "IPADDR", 30, 219da14cebeSEric Cheng offsetof(flow_fields_buf_t, flow_ipaddr), CMD_TYPE_ANY}, 220ad091ee1SMichael Lim { "proto", "PROTO", 6, 221da14cebeSEric Cheng offsetof(flow_fields_buf_t, flow_proto), CMD_TYPE_ANY}, 222da14cebeSEric Cheng { "port", "PORT", 7, 223da14cebeSEric Cheng offsetof(flow_fields_buf_t, flow_port), CMD_TYPE_ANY}, 224ad091ee1SMichael Lim { "dsfld", "DSFLD", 9, 225da14cebeSEric Cheng offsetof(flow_fields_buf_t, flow_dsfield), CMD_TYPE_ANY}} 226da14cebeSEric Cheng ; 227da14cebeSEric Cheng 228da14cebeSEric Cheng #define FLOW_MAX_FIELDS (sizeof (flow_fields) / sizeof (print_field_t)) 229da14cebeSEric Cheng 230da14cebeSEric Cheng /* 231da14cebeSEric Cheng * structures for 'flowadm show-flowprop' 232da14cebeSEric Cheng */ 233da14cebeSEric Cheng typedef enum { 234da14cebeSEric Cheng FLOWPROP_FLOW, 235da14cebeSEric Cheng FLOWPROP_PROPERTY, 236da14cebeSEric Cheng FLOWPROP_VALUE, 237da14cebeSEric Cheng FLOWPROP_DEFAULT, 238da14cebeSEric Cheng FLOWPROP_POSSIBLE 239da14cebeSEric Cheng } flowprop_field_index_t; 240da14cebeSEric Cheng 241da14cebeSEric Cheng static print_field_t flowprop_fields[] = { 242da14cebeSEric Cheng /* name, header, fieldwidth, index, cmdtype */ 243da14cebeSEric Cheng { "flow", "FLOW", 12, FLOWPROP_FLOW, CMD_TYPE_ANY}, 244da14cebeSEric Cheng { "property", "PROPERTY", 15, FLOWPROP_PROPERTY, CMD_TYPE_ANY}, 245da14cebeSEric Cheng { "value", "VALUE", 14, FLOWPROP_VALUE, CMD_TYPE_ANY}, 246da14cebeSEric Cheng { "default", "DEFAULT", 14, FLOWPROP_DEFAULT, CMD_TYPE_ANY}, 247da14cebeSEric Cheng { "possible", "POSSIBLE", 20, FLOWPROP_POSSIBLE, CMD_TYPE_ANY}} 248da14cebeSEric Cheng ; 249da14cebeSEric Cheng #define FLOWPROP_MAX_FIELDS \ 250da14cebeSEric Cheng (sizeof (flowprop_fields) / sizeof (print_field_t)) 251da14cebeSEric Cheng 252da14cebeSEric Cheng #define MAX_PROP_LINE 512 253da14cebeSEric Cheng 254da14cebeSEric Cheng typedef struct show_flowprop_state { 255da14cebeSEric Cheng const char *fs_flow; 256da14cebeSEric Cheng datalink_id_t fs_linkid; 257da14cebeSEric Cheng char *fs_line; 258da14cebeSEric Cheng char **fs_propvals; 259da14cebeSEric Cheng dladm_arg_list_t *fs_proplist; 260da14cebeSEric Cheng boolean_t fs_parseable; 261da14cebeSEric Cheng boolean_t fs_persist; 262da14cebeSEric Cheng boolean_t fs_header; 263da14cebeSEric Cheng dladm_status_t fs_status; 264da14cebeSEric Cheng dladm_status_t fs_retstatus; 265da14cebeSEric Cheng print_state_t fs_print; 266da14cebeSEric Cheng } show_flowprop_state_t; 267da14cebeSEric Cheng 268da14cebeSEric Cheng typedef struct set_flowprop_state { 269da14cebeSEric Cheng const char *fs_name; 270da14cebeSEric Cheng boolean_t fs_reset; 271da14cebeSEric Cheng boolean_t fs_temp; 272da14cebeSEric Cheng dladm_status_t fs_status; 273da14cebeSEric Cheng } set_flowprop_state_t; 274da14cebeSEric Cheng 275da14cebeSEric Cheng typedef struct flowprop_args_s { 276da14cebeSEric Cheng show_flowprop_state_t *fs_state; 277da14cebeSEric Cheng char *fs_propname; 278da14cebeSEric Cheng char *fs_flowname; 279da14cebeSEric Cheng } flowprop_args_t; 280ae6aa22aSVenugopal Iyer /* 281ae6aa22aSVenugopal Iyer * structures for 'flowadm show-flow -s' (print statistics) 282ae6aa22aSVenugopal Iyer */ 283ae6aa22aSVenugopal Iyer typedef enum { 284ae6aa22aSVenugopal Iyer FLOW_S_FLOW, 285ae6aa22aSVenugopal Iyer FLOW_S_IPKTS, 286ae6aa22aSVenugopal Iyer FLOW_S_RBYTES, 287ae6aa22aSVenugopal Iyer FLOW_S_IERRORS, 288ae6aa22aSVenugopal Iyer FLOW_S_OPKTS, 289ae6aa22aSVenugopal Iyer FLOW_S_OBYTES, 290ae6aa22aSVenugopal Iyer FLOW_S_OERRORS 291ae6aa22aSVenugopal Iyer } flow_s_field_index_t; 292ae6aa22aSVenugopal Iyer 293ae6aa22aSVenugopal Iyer static print_field_t flow_s_fields[] = { 294ae6aa22aSVenugopal Iyer /* name, header, field width, index, cmdtype */ 295ae6aa22aSVenugopal Iyer { "flow", "FLOW", 15, FLOW_S_FLOW, CMD_TYPE_ANY}, 296ae6aa22aSVenugopal Iyer { "ipackets", "IPACKETS", 10, FLOW_S_IPKTS, CMD_TYPE_ANY}, 297ae6aa22aSVenugopal Iyer { "rbytes", "RBYTES", 8, FLOW_S_RBYTES, CMD_TYPE_ANY}, 298ae6aa22aSVenugopal Iyer { "ierrors", "IERRORS", 10, FLOW_S_IERRORS, CMD_TYPE_ANY}, 299ae6aa22aSVenugopal Iyer { "opackets", "OPACKETS", 12, FLOW_S_OPKTS, CMD_TYPE_ANY}, 300ae6aa22aSVenugopal Iyer { "obytes", "OBYTES", 12, FLOW_S_OBYTES, CMD_TYPE_ANY}, 301ae6aa22aSVenugopal Iyer { "oerrors", "OERRORS", 8, FLOW_S_OERRORS, CMD_TYPE_ANY}} 302ae6aa22aSVenugopal Iyer ; 303ae6aa22aSVenugopal Iyer #define FLOW_S_MAX_FIELDS \ 304ae6aa22aSVenugopal Iyer (sizeof (flow_s_fields) / sizeof (print_field_t)) 305ae6aa22aSVenugopal Iyer 306ae6aa22aSVenugopal Iyer typedef struct flow_args_s { 307ae6aa22aSVenugopal Iyer char *flow_s_flow; 308ae6aa22aSVenugopal Iyer pktsum_t *flow_s_psum; 309ae6aa22aSVenugopal Iyer } flow_args_t; 310ae6aa22aSVenugopal Iyer static char *print_flow_stats(print_field_t *, void *); 311da14cebeSEric Cheng 312da14cebeSEric Cheng /* 313ae6aa22aSVenugopal Iyer * structures for 'flowadm show-usage' 314da14cebeSEric Cheng */ 315da14cebeSEric Cheng 316da14cebeSEric Cheng typedef struct usage_fields_buf_s { 317da14cebeSEric Cheng char usage_flow[12]; 318da14cebeSEric Cheng char usage_duration[10]; 319da14cebeSEric Cheng char usage_ipackets[9]; 320da14cebeSEric Cheng char usage_rbytes[10]; 321da14cebeSEric Cheng char usage_opackets[9]; 322da14cebeSEric Cheng char usage_obytes[10]; 323da14cebeSEric Cheng char usage_bandwidth[14]; 324da14cebeSEric Cheng } usage_fields_buf_t; 325da14cebeSEric Cheng 326da14cebeSEric Cheng static print_field_t usage_fields[] = { 327da14cebeSEric Cheng /* name, header, field width, offset, cmdtype */ 328da14cebeSEric Cheng { "flow", "FLOW", 12, 329da14cebeSEric Cheng offsetof(usage_fields_buf_t, usage_flow), CMD_TYPE_ANY}, 330da14cebeSEric Cheng { "duration", "DURATION", 10, 331da14cebeSEric Cheng offsetof(usage_fields_buf_t, usage_duration), CMD_TYPE_ANY}, 332da14cebeSEric Cheng { "ipackets", "IPACKETS", 9, 333da14cebeSEric Cheng offsetof(usage_fields_buf_t, usage_ipackets), CMD_TYPE_ANY}, 334da14cebeSEric Cheng { "rbytes", "RBYTES", 10, 335da14cebeSEric Cheng offsetof(usage_fields_buf_t, usage_rbytes), CMD_TYPE_ANY}, 336da14cebeSEric Cheng { "opackets", "OPACKETS", 9, 337da14cebeSEric Cheng offsetof(usage_fields_buf_t, usage_opackets), CMD_TYPE_ANY}, 338da14cebeSEric Cheng { "obytes", "OBYTES", 10, 339da14cebeSEric Cheng offsetof(usage_fields_buf_t, usage_obytes), CMD_TYPE_ANY}, 340da14cebeSEric Cheng { "bandwidth", "BANDWIDTH", 14, 341da14cebeSEric Cheng offsetof(usage_fields_buf_t, usage_bandwidth), CMD_TYPE_ANY}} 342da14cebeSEric Cheng ; 343da14cebeSEric Cheng 344da14cebeSEric Cheng #define USAGE_MAX_FIELDS (sizeof (usage_fields) / sizeof (print_field_t)) 345da14cebeSEric Cheng 346da14cebeSEric Cheng /* 347da14cebeSEric Cheng * structures for 'dladm show-usage link' 348da14cebeSEric Cheng */ 349da14cebeSEric Cheng 350da14cebeSEric Cheng typedef struct usage_l_fields_buf_s { 351da14cebeSEric Cheng char usage_l_flow[12]; 352da14cebeSEric Cheng char usage_l_stime[13]; 353da14cebeSEric Cheng char usage_l_etime[13]; 354da14cebeSEric Cheng char usage_l_rbytes[8]; 355da14cebeSEric Cheng char usage_l_obytes[8]; 356da14cebeSEric Cheng char usage_l_bandwidth[14]; 357da14cebeSEric Cheng } usage_l_fields_buf_t; 358da14cebeSEric Cheng 359da14cebeSEric Cheng static print_field_t usage_l_fields[] = { 360da14cebeSEric Cheng /* name, header, field width, offset, cmdtype */ 361da14cebeSEric Cheng { "flow", "FLOW", 12, 362da14cebeSEric Cheng offsetof(usage_l_fields_buf_t, usage_l_flow), CMD_TYPE_ANY}, 363da14cebeSEric Cheng { "start", "START", 13, 364da14cebeSEric Cheng offsetof(usage_l_fields_buf_t, usage_l_stime), CMD_TYPE_ANY}, 365da14cebeSEric Cheng { "end", "END", 13, 366da14cebeSEric Cheng offsetof(usage_l_fields_buf_t, usage_l_etime), CMD_TYPE_ANY}, 367da14cebeSEric Cheng { "rbytes", "RBYTES", 8, 368da14cebeSEric Cheng offsetof(usage_l_fields_buf_t, usage_l_rbytes), CMD_TYPE_ANY}, 369da14cebeSEric Cheng { "obytes", "OBYTES", 8, 370da14cebeSEric Cheng offsetof(usage_l_fields_buf_t, usage_l_obytes), CMD_TYPE_ANY}, 371da14cebeSEric Cheng { "bandwidth", "BANDWIDTH", 14, 372da14cebeSEric Cheng offsetof(usage_l_fields_buf_t, usage_l_bandwidth), CMD_TYPE_ANY}} 373da14cebeSEric Cheng ; 374da14cebeSEric Cheng 375da14cebeSEric Cheng #define USAGE_L_MAX_FIELDS \ 376da14cebeSEric Cheng (sizeof (usage_l_fields) /sizeof (print_field_t)) 377da14cebeSEric Cheng 378da14cebeSEric Cheng #define PRI_HI 100 379da14cebeSEric Cheng #define PRI_LO 10 380da14cebeSEric Cheng #define PRI_NORM 50 381da14cebeSEric Cheng 382da14cebeSEric Cheng #define FLOWADM_CONF "/etc/dladm/flowadm.conf" 383da14cebeSEric Cheng #define BLANK_LINE(s) ((s[0] == '\0') || (s[0] == '#') || (s[0] == '\n')) 384da14cebeSEric Cheng 385da14cebeSEric Cheng static char *progname; 386da14cebeSEric Cheng 387da14cebeSEric Cheng boolean_t t_arg = B_FALSE; /* changes are persistent */ 388da14cebeSEric Cheng char *altroot = NULL; 389da14cebeSEric Cheng 3904ac67f02SAnurag S. Maskey /* 3914ac67f02SAnurag S. Maskey * Handle to libdladm. Opened in main() before the sub-command 3924ac67f02SAnurag S. Maskey * specific function is called. 3934ac67f02SAnurag S. Maskey */ 3944ac67f02SAnurag S. Maskey static dladm_handle_t handle = NULL; 3954ac67f02SAnurag S. Maskey 396da14cebeSEric Cheng static const char *attr_table[] = 397da14cebeSEric Cheng {"local_ip", "remote_ip", "transport", "local_port", "dsfield"}; 398da14cebeSEric Cheng 399da14cebeSEric Cheng #define NATTR (sizeof (attr_table)/sizeof (char *)) 400da14cebeSEric Cheng 401da14cebeSEric Cheng static void 402da14cebeSEric Cheng usage(void) 403da14cebeSEric Cheng { 404da14cebeSEric Cheng (void) fprintf(stderr, gettext("usage: flowadm <subcommand>" 405da14cebeSEric Cheng " <args>...\n" 4060790b6dcSAnurag S. Maskey " add-flow [-t] -l <link> -a <attr>=<value>[,...]\n" 4070790b6dcSAnurag S. Maskey "\t\t [-p <prop>=<value>,...] <flow>\n" 4080790b6dcSAnurag S. Maskey " remove-flow [-t] {-l <link> | <flow>}\n" 4090790b6dcSAnurag S. Maskey " show-flow [-p] [-s [-i <interval>]] [-l <link>] " 4100790b6dcSAnurag S. Maskey "[<flow>]\n\n" 4110790b6dcSAnurag S. Maskey " set-flowprop [-t] -p <prop>=<value>[,...] <flow>\n" 4120790b6dcSAnurag S. Maskey " reset-flowprop [-t] [-p <prop>,...] <flow>\n" 4130790b6dcSAnurag S. Maskey " show-flowprop [-cP] [-l <link>] [-p <prop>,...] " 4140790b6dcSAnurag S. Maskey "[<flow>]\n\n" 415ae6aa22aSVenugopal Iyer " show-usage [-a] [-d | -F <format>] " 4160790b6dcSAnurag S. Maskey "[-s <DD/MM/YYYY,HH:MM:SS>]\n" 4170790b6dcSAnurag S. Maskey "\t\t [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<flow>]\n")); 4184ac67f02SAnurag S. Maskey 4194ac67f02SAnurag S. Maskey /* close dladm handle if it was opened */ 4204ac67f02SAnurag S. Maskey if (handle != NULL) 4214ac67f02SAnurag S. Maskey dladm_close(handle); 4224ac67f02SAnurag S. Maskey 423da14cebeSEric Cheng exit(1); 424da14cebeSEric Cheng } 425da14cebeSEric Cheng 426da14cebeSEric Cheng int 427da14cebeSEric Cheng main(int argc, char *argv[]) 428da14cebeSEric Cheng { 429da14cebeSEric Cheng int i, arglen, cmdlen; 430da14cebeSEric Cheng cmd_t *cmdp; 4314ac67f02SAnurag S. Maskey dladm_status_t status; 432da14cebeSEric Cheng 433da14cebeSEric Cheng (void) setlocale(LC_ALL, ""); 434da14cebeSEric Cheng #if !defined(TEXT_DOMAIN) 435da14cebeSEric Cheng #define TEXT_DOMAIN "SYS_TEST" 436da14cebeSEric Cheng #endif 437da14cebeSEric Cheng (void) textdomain(TEXT_DOMAIN); 438da14cebeSEric Cheng 439da14cebeSEric Cheng progname = argv[0]; 440da14cebeSEric Cheng 441da14cebeSEric Cheng if (argc < 2) 442da14cebeSEric Cheng usage(); 443da14cebeSEric Cheng 444da14cebeSEric Cheng for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 445da14cebeSEric Cheng cmdp = &cmds[i]; 446da14cebeSEric Cheng arglen = strlen(argv[1]); 447da14cebeSEric Cheng cmdlen = strlen(cmdp->c_name); 448da14cebeSEric Cheng if ((arglen == cmdlen) && (strncmp(argv[1], cmdp->c_name, 449da14cebeSEric Cheng cmdlen) == 0)) { 4504ac67f02SAnurag S. Maskey /* Open the libdladm handle */ 4514ac67f02SAnurag S. Maskey if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) { 4524ac67f02SAnurag S. Maskey die_dlerr(status, 4534ac67f02SAnurag S. Maskey "could not open /dev/dld"); 4544ac67f02SAnurag S. Maskey } 4554ac67f02SAnurag S. Maskey 456da14cebeSEric Cheng cmdp->c_fn(argc - 1, &argv[1]); 4574ac67f02SAnurag S. Maskey 4584ac67f02SAnurag S. Maskey dladm_close(handle); 459ad091ee1SMichael Lim exit(EXIT_SUCCESS); 460da14cebeSEric Cheng } 461da14cebeSEric Cheng } 462da14cebeSEric Cheng 463da14cebeSEric Cheng (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 464da14cebeSEric Cheng progname, argv[1]); 465da14cebeSEric Cheng usage(); 466da14cebeSEric Cheng 467da14cebeSEric Cheng return (0); 468da14cebeSEric Cheng } 469da14cebeSEric Cheng 470da14cebeSEric Cheng static const char * 471da14cebeSEric Cheng match_attr(char *attr) 472da14cebeSEric Cheng { 473da14cebeSEric Cheng int i; 474da14cebeSEric Cheng 475da14cebeSEric Cheng for (i = 0; i < NATTR; i++) { 476da14cebeSEric Cheng if (strlen(attr) == strlen(attr_table[i]) && 477da14cebeSEric Cheng strncmp(attr, attr_table[i], strlen(attr_table[i])) == 0) { 478da14cebeSEric Cheng return (attr); 479da14cebeSEric Cheng } 480da14cebeSEric Cheng } 481da14cebeSEric Cheng return (NULL); 482da14cebeSEric Cheng } 483da14cebeSEric Cheng 484da14cebeSEric Cheng /* ARGSUSED */ 485da14cebeSEric Cheng static void 486da14cebeSEric Cheng do_init_flow(int argc, char *argv[]) 487da14cebeSEric Cheng { 488da14cebeSEric Cheng dladm_status_t status; 489da14cebeSEric Cheng 4904ac67f02SAnurag S. Maskey status = dladm_flow_init(handle); 491da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 492da14cebeSEric Cheng die_dlerr(status, "flows initialization failed"); 493da14cebeSEric Cheng } 494da14cebeSEric Cheng 495da14cebeSEric Cheng /* ARGSUSED */ 496da14cebeSEric Cheng static int 497da14cebeSEric Cheng show_usage_date(dladm_usage_t *usage, void *arg) 498da14cebeSEric Cheng { 499ae6aa22aSVenugopal Iyer show_usage_state_t *state = (show_usage_state_t *)arg; 500da14cebeSEric Cheng time_t stime; 501da14cebeSEric Cheng char timebuf[20]; 502ae6aa22aSVenugopal Iyer dladm_flow_attr_t attr; 503ae6aa22aSVenugopal Iyer dladm_status_t status; 504ae6aa22aSVenugopal Iyer 505ae6aa22aSVenugopal Iyer /* 506ae6aa22aSVenugopal Iyer * Only show usage information for existing flows unless '-a' 507ae6aa22aSVenugopal Iyer * is specified. 508ae6aa22aSVenugopal Iyer */ 509ae6aa22aSVenugopal Iyer if (!state->us_showall && ((status = dladm_flow_info(handle, 510ae6aa22aSVenugopal Iyer usage->du_name, &attr)) != DLADM_STATUS_OK)) { 511ae6aa22aSVenugopal Iyer return (status); 512ae6aa22aSVenugopal Iyer } 513da14cebeSEric Cheng 514da14cebeSEric Cheng stime = usage->du_stime; 515da14cebeSEric Cheng (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y", 516da14cebeSEric Cheng localtime(&stime)); 517da14cebeSEric Cheng (void) printf("%s\n", timebuf); 518da14cebeSEric Cheng 519da14cebeSEric Cheng return (DLADM_STATUS_OK); 520da14cebeSEric Cheng } 521da14cebeSEric Cheng 522da14cebeSEric Cheng static int 523da14cebeSEric Cheng show_usage_time(dladm_usage_t *usage, void *arg) 524da14cebeSEric Cheng { 525da14cebeSEric Cheng show_usage_state_t *state = (show_usage_state_t *)arg; 526da14cebeSEric Cheng char buf[DLADM_STRSIZE]; 527da14cebeSEric Cheng usage_l_fields_buf_t ubuf; 528da14cebeSEric Cheng time_t time; 529da14cebeSEric Cheng double bw; 530ae6aa22aSVenugopal Iyer dladm_flow_attr_t attr; 531ae6aa22aSVenugopal Iyer dladm_status_t status; 532ae6aa22aSVenugopal Iyer 533ae6aa22aSVenugopal Iyer /* 534ae6aa22aSVenugopal Iyer * Only show usage information for existing flows unless '-a' 535ae6aa22aSVenugopal Iyer * is specified. 536ae6aa22aSVenugopal Iyer */ 537ae6aa22aSVenugopal Iyer if (!state->us_showall && ((status = dladm_flow_info(handle, 538ae6aa22aSVenugopal Iyer usage->du_name, &attr)) != DLADM_STATUS_OK)) { 539ae6aa22aSVenugopal Iyer return (status); 540ae6aa22aSVenugopal Iyer } 541da14cebeSEric Cheng 542da14cebeSEric Cheng if (state->us_plot) { 543da14cebeSEric Cheng if (!state->us_printheader) { 544da14cebeSEric Cheng if (state->us_first) { 545da14cebeSEric Cheng (void) printf("# Time"); 546da14cebeSEric Cheng state->us_first = B_FALSE; 547da14cebeSEric Cheng } 548da14cebeSEric Cheng (void) printf(" %s", usage->du_name); 549da14cebeSEric Cheng if (usage->du_last) { 550da14cebeSEric Cheng (void) printf("\n"); 551da14cebeSEric Cheng state->us_first = B_TRUE; 552da14cebeSEric Cheng state->us_printheader = B_TRUE; 553da14cebeSEric Cheng } 554da14cebeSEric Cheng } else { 555da14cebeSEric Cheng if (state->us_first) { 556da14cebeSEric Cheng time = usage->du_etime; 557da14cebeSEric Cheng (void) strftime(buf, sizeof (buf), "%T", 558da14cebeSEric Cheng localtime(&time)); 559da14cebeSEric Cheng state->us_first = B_FALSE; 560da14cebeSEric Cheng (void) printf("%s", buf); 561da14cebeSEric Cheng } 562da14cebeSEric Cheng bw = (double)usage->du_bandwidth/1000; 563da14cebeSEric Cheng (void) printf(" %.2f", bw); 564da14cebeSEric Cheng if (usage->du_last) { 565da14cebeSEric Cheng (void) printf("\n"); 566da14cebeSEric Cheng state->us_first = B_TRUE; 567da14cebeSEric Cheng } 568da14cebeSEric Cheng } 569da14cebeSEric Cheng return (DLADM_STATUS_OK); 570da14cebeSEric Cheng } 571da14cebeSEric Cheng 572da14cebeSEric Cheng bzero(&ubuf, sizeof (ubuf)); 573da14cebeSEric Cheng 574da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_flow, sizeof (ubuf.usage_l_flow), "%s", 575da14cebeSEric Cheng usage->du_name); 576da14cebeSEric Cheng time = usage->du_stime; 577da14cebeSEric Cheng (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 578da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s", 579da14cebeSEric Cheng buf); 580da14cebeSEric Cheng time = usage->du_etime; 581da14cebeSEric Cheng (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 582da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s", 583da14cebeSEric Cheng buf); 584da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes), 585da14cebeSEric Cheng "%llu", usage->du_rbytes); 586da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes), 587da14cebeSEric Cheng "%llu", usage->du_obytes); 588da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth), 589da14cebeSEric Cheng "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 590da14cebeSEric Cheng 591da14cebeSEric Cheng if (!state->us_parseable && !state->us_printheader) { 592da14cebeSEric Cheng print_header(&state->us_print); 593da14cebeSEric Cheng state->us_printheader = B_TRUE; 594da14cebeSEric Cheng } 595da14cebeSEric Cheng 596da14cebeSEric Cheng flowadm_print_output(&state->us_print, state->us_parseable, 597da14cebeSEric Cheng flowadm_print_field, (void *)&ubuf); 598da14cebeSEric Cheng 599da14cebeSEric Cheng return (DLADM_STATUS_OK); 600da14cebeSEric Cheng } 601da14cebeSEric Cheng 602da14cebeSEric Cheng static int 603da14cebeSEric Cheng show_usage_res(dladm_usage_t *usage, void *arg) 604da14cebeSEric Cheng { 605da14cebeSEric Cheng show_usage_state_t *state = (show_usage_state_t *)arg; 606da14cebeSEric Cheng char buf[DLADM_STRSIZE]; 607da14cebeSEric Cheng usage_fields_buf_t ubuf; 608ae6aa22aSVenugopal Iyer dladm_flow_attr_t attr; 609ae6aa22aSVenugopal Iyer dladm_status_t status; 610ae6aa22aSVenugopal Iyer 611ae6aa22aSVenugopal Iyer /* 612ae6aa22aSVenugopal Iyer * Only show usage information for existing flows unless '-a' 613ae6aa22aSVenugopal Iyer * is specified. 614ae6aa22aSVenugopal Iyer */ 615ae6aa22aSVenugopal Iyer if (!state->us_showall && ((status = dladm_flow_info(handle, 616ae6aa22aSVenugopal Iyer usage->du_name, &attr)) != DLADM_STATUS_OK)) { 617ae6aa22aSVenugopal Iyer return (status); 618ae6aa22aSVenugopal Iyer } 619da14cebeSEric Cheng 620da14cebeSEric Cheng bzero(&ubuf, sizeof (ubuf)); 621da14cebeSEric Cheng 622da14cebeSEric Cheng (void) snprintf(ubuf.usage_flow, sizeof (ubuf.usage_flow), "%s", 623da14cebeSEric Cheng usage->du_name); 624da14cebeSEric Cheng (void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration), 625da14cebeSEric Cheng "%llu", usage->du_duration); 626da14cebeSEric Cheng (void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets), 627da14cebeSEric Cheng "%llu", usage->du_ipackets); 628da14cebeSEric Cheng (void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes), 629da14cebeSEric Cheng "%llu", usage->du_rbytes); 630da14cebeSEric Cheng (void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets), 631da14cebeSEric Cheng "%llu", usage->du_opackets); 632da14cebeSEric Cheng (void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes), 633da14cebeSEric Cheng "%llu", usage->du_obytes); 634da14cebeSEric Cheng (void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth), 635da14cebeSEric Cheng "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 636da14cebeSEric Cheng 637da14cebeSEric Cheng if (!state->us_parseable && !state->us_printheader) { 638da14cebeSEric Cheng print_header(&state->us_print); 639da14cebeSEric Cheng state->us_printheader = B_TRUE; 640da14cebeSEric Cheng } 641da14cebeSEric Cheng 642da14cebeSEric Cheng flowadm_print_output(&state->us_print, state->us_parseable, 643da14cebeSEric Cheng flowadm_print_field, (void *)&ubuf); 644da14cebeSEric Cheng 645da14cebeSEric Cheng return (DLADM_STATUS_OK); 646da14cebeSEric Cheng } 647da14cebeSEric Cheng 648da14cebeSEric Cheng static boolean_t 649da14cebeSEric Cheng valid_formatspec(char *formatspec_str) 650da14cebeSEric Cheng { 651da14cebeSEric Cheng if (strcmp(formatspec_str, "gnuplot") == 0) 652da14cebeSEric Cheng return (B_TRUE); 653da14cebeSEric Cheng return (B_FALSE); 654da14cebeSEric Cheng } 655da14cebeSEric Cheng 656da14cebeSEric Cheng /* ARGSUSED */ 657da14cebeSEric Cheng static void 658da14cebeSEric Cheng do_show_usage(int argc, char *argv[]) 659da14cebeSEric Cheng { 660da14cebeSEric Cheng char *file = NULL; 661da14cebeSEric Cheng int opt; 662da14cebeSEric Cheng dladm_status_t status; 663da14cebeSEric Cheng boolean_t d_arg = B_FALSE; 664da14cebeSEric Cheng char *stime = NULL; 665da14cebeSEric Cheng char *etime = NULL; 666da14cebeSEric Cheng char *resource = NULL; 667da14cebeSEric Cheng show_usage_state_t state; 668da14cebeSEric Cheng boolean_t o_arg = B_FALSE; 669da14cebeSEric Cheng boolean_t F_arg = B_FALSE; 670da14cebeSEric Cheng char *fields_str = NULL; 671da14cebeSEric Cheng char *formatspec_str = NULL; 672da14cebeSEric Cheng print_field_t **fields; 673da14cebeSEric Cheng uint_t nfields; 674da14cebeSEric Cheng char *all_fields = 675da14cebeSEric Cheng "flow,duration,ipackets,rbytes,opackets,obytes,bandwidth"; 676da14cebeSEric Cheng char *all_l_fields = 677da14cebeSEric Cheng "flow,start,end,rbytes,obytes,bandwidth"; 678da14cebeSEric Cheng 679da14cebeSEric Cheng bzero(&state, sizeof (show_usage_state_t)); 680da14cebeSEric Cheng state.us_parseable = B_FALSE; 681da14cebeSEric Cheng state.us_printheader = B_FALSE; 682da14cebeSEric Cheng state.us_plot = B_FALSE; 683da14cebeSEric Cheng state.us_first = B_TRUE; 684da14cebeSEric Cheng 685ae6aa22aSVenugopal Iyer while ((opt = getopt(argc, argv, "das:e:o:f:F:")) != -1) { 686da14cebeSEric Cheng switch (opt) { 687da14cebeSEric Cheng case 'd': 688da14cebeSEric Cheng d_arg = B_TRUE; 689da14cebeSEric Cheng break; 690ae6aa22aSVenugopal Iyer case 'a': 691ae6aa22aSVenugopal Iyer state.us_showall = B_TRUE; 692da14cebeSEric Cheng break; 693da14cebeSEric Cheng case 'f': 694da14cebeSEric Cheng file = optarg; 695da14cebeSEric Cheng break; 696da14cebeSEric Cheng case 's': 697da14cebeSEric Cheng stime = optarg; 698da14cebeSEric Cheng break; 699da14cebeSEric Cheng case 'e': 700da14cebeSEric Cheng etime = optarg; 701da14cebeSEric Cheng break; 702da14cebeSEric Cheng case 'o': 703da14cebeSEric Cheng o_arg = B_TRUE; 704da14cebeSEric Cheng fields_str = optarg; 705da14cebeSEric Cheng break; 706da14cebeSEric Cheng case 'F': 707ae6aa22aSVenugopal Iyer state.us_plot = F_arg = B_TRUE; 708da14cebeSEric Cheng formatspec_str = optarg; 709da14cebeSEric Cheng break; 710da14cebeSEric Cheng default: 711da14cebeSEric Cheng die_opterr(optopt, opt); 712da14cebeSEric Cheng } 713da14cebeSEric Cheng } 714da14cebeSEric Cheng 715da14cebeSEric Cheng if (file == NULL) 716da14cebeSEric Cheng die("show-usage requires a file"); 717da14cebeSEric Cheng 718da14cebeSEric Cheng if (optind == (argc-1)) { 719ae6aa22aSVenugopal Iyer dladm_flow_attr_t attr; 720ae6aa22aSVenugopal Iyer 721ae6aa22aSVenugopal Iyer if (!state.us_showall && 722ae6aa22aSVenugopal Iyer dladm_flow_info(handle, resource, &attr) != 723ae6aa22aSVenugopal Iyer DLADM_STATUS_OK) { 724ae6aa22aSVenugopal Iyer die("invalid flow: '%s'", resource); 725ae6aa22aSVenugopal Iyer } 726da14cebeSEric Cheng resource = argv[optind]; 727da14cebeSEric Cheng } 728da14cebeSEric Cheng 729da14cebeSEric Cheng if (resource == NULL && stime == NULL && etime == NULL) { 730da14cebeSEric Cheng if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 731da14cebeSEric Cheng fields_str = all_fields; 732da14cebeSEric Cheng fields = parse_output_fields(fields_str, usage_fields, 733da14cebeSEric Cheng USAGE_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 734da14cebeSEric Cheng } else { 735da14cebeSEric Cheng if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 736da14cebeSEric Cheng fields_str = all_l_fields; 737da14cebeSEric Cheng fields = parse_output_fields(fields_str, usage_l_fields, 738da14cebeSEric Cheng USAGE_L_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 739da14cebeSEric Cheng } 740da14cebeSEric Cheng 741da14cebeSEric Cheng if (fields == NULL) { 742da14cebeSEric Cheng die("invalid fields(s) specified"); 743da14cebeSEric Cheng return; 744da14cebeSEric Cheng } 745da14cebeSEric Cheng state.us_print.ps_fields = fields; 746da14cebeSEric Cheng state.us_print.ps_nfields = nfields; 747da14cebeSEric Cheng 748ae6aa22aSVenugopal Iyer if (F_arg && d_arg) 749ae6aa22aSVenugopal Iyer die("incompatible -d and -F options"); 750da14cebeSEric Cheng 751da14cebeSEric Cheng if (F_arg && valid_formatspec(formatspec_str) == B_FALSE) 752da14cebeSEric Cheng die("Format specifier %s not supported", formatspec_str); 753da14cebeSEric Cheng 754da14cebeSEric Cheng if (d_arg) { 755da14cebeSEric Cheng /* Print log dates */ 756da14cebeSEric Cheng status = dladm_usage_dates(show_usage_date, 757da14cebeSEric Cheng DLADM_LOGTYPE_FLOW, file, resource, &state); 758da14cebeSEric Cheng } else if (resource == NULL && stime == NULL && etime == NULL && 759ae6aa22aSVenugopal Iyer !F_arg) { 760da14cebeSEric Cheng /* Print summary */ 761da14cebeSEric Cheng status = dladm_usage_summary(show_usage_res, 762da14cebeSEric Cheng DLADM_LOGTYPE_FLOW, file, &state); 763da14cebeSEric Cheng } else if (resource != NULL) { 764da14cebeSEric Cheng /* Print log entries for named resource */ 765da14cebeSEric Cheng status = dladm_walk_usage_res(show_usage_time, 766da14cebeSEric Cheng DLADM_LOGTYPE_FLOW, file, resource, stime, etime, &state); 767da14cebeSEric Cheng } else { 768da14cebeSEric Cheng /* Print time and information for each link */ 769da14cebeSEric Cheng status = dladm_walk_usage_time(show_usage_time, 770da14cebeSEric Cheng DLADM_LOGTYPE_FLOW, file, stime, etime, &state); 771da14cebeSEric Cheng } 772da14cebeSEric Cheng 773da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 774da14cebeSEric Cheng die_dlerr(status, "show-usage"); 775da14cebeSEric Cheng } 776da14cebeSEric Cheng 777da14cebeSEric Cheng static void 778da14cebeSEric Cheng do_add_flow(int argc, char *argv[]) 779da14cebeSEric Cheng { 780da000602SGirish Moodalbail char devname[MAXLINKNAMELEN]; 781da14cebeSEric Cheng char *name = NULL; 782da14cebeSEric Cheng uint_t index; 783da14cebeSEric Cheng datalink_id_t linkid; 784da14cebeSEric Cheng 785da14cebeSEric Cheng char option; 786da14cebeSEric Cheng boolean_t l_arg = B_FALSE; 787*63a6526dSMichael Lim char propstr[DLADM_STRSIZE]; 788*63a6526dSMichael Lim char attrstr[DLADM_STRSIZE]; 789da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 790da14cebeSEric Cheng dladm_arg_list_t *attrlist = NULL; 791da14cebeSEric Cheng dladm_status_t status; 792da14cebeSEric Cheng 793*63a6526dSMichael Lim bzero(propstr, DLADM_STRSIZE); 794*63a6526dSMichael Lim bzero(attrstr, DLADM_STRSIZE); 795*63a6526dSMichael Lim 796da14cebeSEric Cheng while ((option = getopt_long(argc, argv, "tR:l:a:p:", 797da14cebeSEric Cheng prop_longopts, NULL)) != -1) { 798da14cebeSEric Cheng switch (option) { 799da14cebeSEric Cheng case 't': 800da14cebeSEric Cheng t_arg = B_TRUE; 801da14cebeSEric Cheng break; 802da14cebeSEric Cheng case 'R': 803da14cebeSEric Cheng altroot = optarg; 804da14cebeSEric Cheng break; 805da14cebeSEric Cheng case 'l': 806da14cebeSEric Cheng if (strlcpy(devname, optarg, 807da000602SGirish Moodalbail MAXLINKNAMELEN) >= MAXLINKNAMELEN) { 808da14cebeSEric Cheng die("link name too long"); 809da14cebeSEric Cheng } 8104ac67f02SAnurag S. Maskey if (dladm_name2info(handle, devname, &linkid, NULL, 811da14cebeSEric Cheng NULL, NULL) != DLADM_STATUS_OK) 812da14cebeSEric Cheng die("invalid link '%s'", devname); 813da14cebeSEric Cheng l_arg = B_TRUE; 814da14cebeSEric Cheng break; 815da14cebeSEric Cheng case 'a': 816*63a6526dSMichael Lim (void) strlcat(attrstr, optarg, DLADM_STRSIZE); 817*63a6526dSMichael Lim if (strlcat(attrstr, ",", DLADM_STRSIZE) >= 818*63a6526dSMichael Lim DLADM_STRSIZE) 819*63a6526dSMichael Lim die("attribute list too long '%s'", attrstr); 820da14cebeSEric Cheng break; 821da14cebeSEric Cheng case 'p': 822*63a6526dSMichael Lim (void) strlcat(propstr, optarg, DLADM_STRSIZE); 823*63a6526dSMichael Lim if (strlcat(propstr, ",", DLADM_STRSIZE) >= 824*63a6526dSMichael Lim DLADM_STRSIZE) 825*63a6526dSMichael Lim die("property list too long '%s'", propstr); 826da14cebeSEric Cheng break; 827da14cebeSEric Cheng default: 828da14cebeSEric Cheng die_opterr(optopt, option); 829da14cebeSEric Cheng } 830da14cebeSEric Cheng } 831da14cebeSEric Cheng if (!l_arg) { 832da14cebeSEric Cheng die("link is required"); 833da14cebeSEric Cheng } 834da14cebeSEric Cheng 835da14cebeSEric Cheng opterr = 0; 836da14cebeSEric Cheng index = optind; 837da14cebeSEric Cheng 838da14cebeSEric Cheng if ((index != (argc - 1)) || match_attr(argv[index]) != NULL) { 839da14cebeSEric Cheng die("flow name is required"); 840da14cebeSEric Cheng } else { 841da14cebeSEric Cheng /* get flow name; required last argument */ 842da000602SGirish Moodalbail if (strlen(argv[index]) >= MAXFLOWNAMELEN) 843da14cebeSEric Cheng die("flow name too long"); 844da14cebeSEric Cheng name = argv[index]; 845da14cebeSEric Cheng } 846da14cebeSEric Cheng 847*63a6526dSMichael Lim if (dladm_parse_flow_attrs(attrstr, &attrlist, B_FALSE) 848*63a6526dSMichael Lim != DLADM_STATUS_OK) 849*63a6526dSMichael Lim die("invalid flow attribute specified"); 850*63a6526dSMichael Lim if (dladm_parse_flow_props(propstr, &proplist, B_FALSE) 851*63a6526dSMichael Lim != DLADM_STATUS_OK) 852*63a6526dSMichael Lim die("invalid flow property specified"); 853*63a6526dSMichael Lim 8544ac67f02SAnurag S. Maskey status = dladm_flow_add(handle, linkid, attrlist, proplist, name, 855da14cebeSEric Cheng t_arg, altroot); 856da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 857da14cebeSEric Cheng die_dlerr(status, "add flow failed"); 858da14cebeSEric Cheng 859da14cebeSEric Cheng dladm_free_attrs(attrlist); 860da14cebeSEric Cheng dladm_free_props(proplist); 861da14cebeSEric Cheng } 862da14cebeSEric Cheng 863da14cebeSEric Cheng static void 864da14cebeSEric Cheng do_remove_flow(int argc, char *argv[]) 865da14cebeSEric Cheng { 866da14cebeSEric Cheng char option; 867da14cebeSEric Cheng char *flowname = NULL; 868da000602SGirish Moodalbail char linkname[MAXLINKNAMELEN]; 869da14cebeSEric Cheng datalink_id_t linkid = DATALINK_ALL_LINKID; 870da14cebeSEric Cheng boolean_t l_arg = B_FALSE; 871da14cebeSEric Cheng remove_flow_state_t state; 872da14cebeSEric Cheng dladm_status_t status; 873da14cebeSEric Cheng 874da14cebeSEric Cheng bzero(&state, sizeof (state)); 875da14cebeSEric Cheng 876da14cebeSEric Cheng opterr = 0; 877da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":tR:l:", 878da14cebeSEric Cheng longopts, NULL)) != -1) { 879da14cebeSEric Cheng switch (option) { 880da14cebeSEric Cheng case 't': 881da14cebeSEric Cheng t_arg = B_TRUE; 882da14cebeSEric Cheng break; 883da14cebeSEric Cheng case 'R': 884da14cebeSEric Cheng altroot = optarg; 885da14cebeSEric Cheng break; 886da14cebeSEric Cheng case 'l': 887da14cebeSEric Cheng if (strlcpy(linkname, optarg, 888da14cebeSEric Cheng MAXLINKNAMELEN) >= MAXLINKNAMELEN) { 889da14cebeSEric Cheng die("link name too long"); 890da14cebeSEric Cheng } 8914ac67f02SAnurag S. Maskey if (dladm_name2info(handle, linkname, &linkid, NULL, 892da14cebeSEric Cheng NULL, NULL) != DLADM_STATUS_OK) { 893da14cebeSEric Cheng die("invalid link '%s'", linkname); 894da14cebeSEric Cheng } 895da14cebeSEric Cheng l_arg = B_TRUE; 896da14cebeSEric Cheng break; 897da14cebeSEric Cheng default: 898da14cebeSEric Cheng die_opterr(optopt, option); 899da14cebeSEric Cheng break; 900da14cebeSEric Cheng } 901da14cebeSEric Cheng } 902da14cebeSEric Cheng 903da14cebeSEric Cheng /* when link not specified get flow name */ 904da14cebeSEric Cheng if (!l_arg) { 905da14cebeSEric Cheng if (optind != (argc-1)) { 906da14cebeSEric Cheng usage(); 907da14cebeSEric Cheng } else { 908da000602SGirish Moodalbail if (strlen(argv[optind]) >= MAXFLOWNAMELEN) 909da14cebeSEric Cheng die("flow name too long"); 910da14cebeSEric Cheng flowname = argv[optind]; 911da14cebeSEric Cheng } 9124ac67f02SAnurag S. Maskey status = dladm_flow_remove(handle, flowname, t_arg, altroot); 913da14cebeSEric Cheng } else { 914da14cebeSEric Cheng /* if link is specified then flow name should not be there */ 915da14cebeSEric Cheng if (optind == argc-1) 916da14cebeSEric Cheng usage(); 917da14cebeSEric Cheng /* walk the link to find flows and remove them */ 918da14cebeSEric Cheng state.fs_tempop = t_arg; 919da14cebeSEric Cheng state.fs_altroot = altroot; 920da14cebeSEric Cheng state.fs_status = DLADM_STATUS_OK; 9214ac67f02SAnurag S. Maskey status = dladm_walk_flow(remove_flow, handle, linkid, &state, 9224ac67f02SAnurag S. Maskey B_FALSE); 923da14cebeSEric Cheng /* 924da14cebeSEric Cheng * check if dladm_walk_flow terminated early and see if the 925da14cebeSEric Cheng * walker function as any status for us 926da14cebeSEric Cheng */ 927da14cebeSEric Cheng if (status == DLADM_STATUS_OK) 928da14cebeSEric Cheng status = state.fs_status; 929da14cebeSEric Cheng } 930da14cebeSEric Cheng 931da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 932da14cebeSEric Cheng die_dlerr(status, "remove flow failed"); 933da14cebeSEric Cheng } 934da14cebeSEric Cheng 935da14cebeSEric Cheng /* 936da14cebeSEric Cheng * Walker function for removing a flow through dladm_walk_flow(); 937da14cebeSEric Cheng */ 938da14cebeSEric Cheng static int 939da14cebeSEric Cheng remove_flow(dladm_flow_attr_t *attr, void *arg) 940da14cebeSEric Cheng { 941da14cebeSEric Cheng remove_flow_state_t *state = (remove_flow_state_t *)arg; 942da14cebeSEric Cheng 9434ac67f02SAnurag S. Maskey state->fs_status = dladm_flow_remove(handle, attr->fa_flowname, 944da14cebeSEric Cheng state->fs_tempop, state->fs_altroot); 945da14cebeSEric Cheng 946da14cebeSEric Cheng if (state->fs_status == DLADM_STATUS_OK) 947da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 948da14cebeSEric Cheng else 949da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 950da14cebeSEric Cheng } 951da14cebeSEric Cheng 952da14cebeSEric Cheng static char * 953da14cebeSEric Cheng flowadm_print_field(print_field_t *pf, void *arg) 954da14cebeSEric Cheng { 955da14cebeSEric Cheng char *value; 956da14cebeSEric Cheng 957da14cebeSEric Cheng value = (char *)arg + pf->pf_offset; 958da14cebeSEric Cheng return (value); 959da14cebeSEric Cheng } 960da14cebeSEric Cheng 961da14cebeSEric Cheng /*ARGSUSED*/ 962da14cebeSEric Cheng static dladm_status_t 963da14cebeSEric Cheng print_flow(show_flow_state_t *state, dladm_flow_attr_t *attr, 964da14cebeSEric Cheng flow_fields_buf_t *fbuf) 965da14cebeSEric Cheng { 966da14cebeSEric Cheng char link[MAXLINKNAMELEN]; 967da14cebeSEric Cheng dladm_status_t status; 968da14cebeSEric Cheng 9694ac67f02SAnurag S. Maskey if ((status = dladm_datalink_id2info(handle, attr->fa_linkid, NULL, 9704ac67f02SAnurag S. Maskey NULL, NULL, link, sizeof (link))) != DLADM_STATUS_OK) { 971da14cebeSEric Cheng return (status); 972da14cebeSEric Cheng } 973da14cebeSEric Cheng 974da14cebeSEric Cheng (void) snprintf(fbuf->flow_name, sizeof (fbuf->flow_name), 975da14cebeSEric Cheng "%s", attr->fa_flowname); 976da14cebeSEric Cheng (void) snprintf(fbuf->flow_link, sizeof (fbuf->flow_link), 977da14cebeSEric Cheng "%s", link); 978da14cebeSEric Cheng 979da14cebeSEric Cheng (void) dladm_flow_attr_ip2str(attr, fbuf->flow_ipaddr, 980da14cebeSEric Cheng sizeof (fbuf->flow_ipaddr)); 981da14cebeSEric Cheng (void) dladm_flow_attr_proto2str(attr, fbuf->flow_proto, 982da14cebeSEric Cheng sizeof (fbuf->flow_proto)); 983da14cebeSEric Cheng (void) dladm_flow_attr_port2str(attr, fbuf->flow_port, 984da14cebeSEric Cheng sizeof (fbuf->flow_port)); 985da14cebeSEric Cheng (void) dladm_flow_attr_dsfield2str(attr, fbuf->flow_dsfield, 986da14cebeSEric Cheng sizeof (fbuf->flow_dsfield)); 987da14cebeSEric Cheng 988da14cebeSEric Cheng return (DLADM_STATUS_OK); 989da14cebeSEric Cheng } 990da14cebeSEric Cheng 991da14cebeSEric Cheng /* 992da14cebeSEric Cheng * Walker function for showing flow attributes through dladm_walk_flow(). 993da14cebeSEric Cheng */ 994da14cebeSEric Cheng static int 995da14cebeSEric Cheng show_flow(dladm_flow_attr_t *attr, void *arg) 996da14cebeSEric Cheng { 997da14cebeSEric Cheng show_flow_state_t *statep = arg; 998da14cebeSEric Cheng dladm_status_t status; 999da14cebeSEric Cheng flow_fields_buf_t fbuf; 1000da14cebeSEric Cheng 1001da14cebeSEric Cheng /* 1002da14cebeSEric Cheng * first get all the flow attributes into fbuf; 1003da14cebeSEric Cheng */ 1004da14cebeSEric Cheng bzero(&fbuf, sizeof (fbuf)); 1005da14cebeSEric Cheng status = print_flow(statep, attr, &fbuf); 1006da14cebeSEric Cheng 1007da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 1008da14cebeSEric Cheng goto done; 1009da14cebeSEric Cheng 1010da14cebeSEric Cheng if (!statep->fs_parseable && !statep->fs_printheader) { 1011da14cebeSEric Cheng print_header(&statep->fs_print); 1012da14cebeSEric Cheng statep->fs_printheader = B_TRUE; 1013da14cebeSEric Cheng } 1014da14cebeSEric Cheng 1015da14cebeSEric Cheng flowadm_print_output(&statep->fs_print, statep->fs_parseable, 1016da14cebeSEric Cheng flowadm_print_field, (void *)&fbuf); 1017da14cebeSEric Cheng 1018da14cebeSEric Cheng done: 1019da14cebeSEric Cheng statep->fs_status = status; 1020da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1021da14cebeSEric Cheng } 1022da14cebeSEric Cheng 1023da14cebeSEric Cheng static void 1024da14cebeSEric Cheng show_one_flow(void *arg, const char *name) 1025da14cebeSEric Cheng { 1026da14cebeSEric Cheng dladm_flow_attr_t attr; 1027da14cebeSEric Cheng 10284ac67f02SAnurag S. Maskey if (dladm_flow_info(handle, name, &attr) != DLADM_STATUS_OK) 1029da14cebeSEric Cheng die("invalid flow: '%s'", name); 1030da14cebeSEric Cheng else 10314ac67f02SAnurag S. Maskey (void) show_flow(&attr, arg); 1032da14cebeSEric Cheng } 1033da14cebeSEric Cheng 1034da14cebeSEric Cheng /* 1035da14cebeSEric Cheng * Wrapper of dladm_walk_flow(show_flow,...) to make it usable to 1036da14cebeSEric Cheng * dladm_walk_datalink_id(). Used for showing flow attributes for 1037da14cebeSEric Cheng * all flows on all links. 1038da14cebeSEric Cheng */ 1039da14cebeSEric Cheng static int 10404ac67f02SAnurag S. Maskey show_flows_onelink(dladm_handle_t dh, datalink_id_t linkid, void *arg) 1041da14cebeSEric Cheng { 1042da14cebeSEric Cheng show_flow_state_t *state = arg; 1043da14cebeSEric Cheng 10444ac67f02SAnurag S. Maskey (void) dladm_walk_flow(show_flow, dh, linkid, arg, state->fs_persist); 1045da14cebeSEric Cheng 1046da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1047da14cebeSEric Cheng } 1048da14cebeSEric Cheng 1049da14cebeSEric Cheng static void 1050da14cebeSEric Cheng get_flow_stats(const char *flowname, pktsum_t *stats) 1051da14cebeSEric Cheng { 1052da14cebeSEric Cheng kstat_ctl_t *kcp; 1053da14cebeSEric Cheng kstat_t *ksp; 1054da14cebeSEric Cheng 1055da14cebeSEric Cheng bzero(stats, sizeof (*stats)); 1056da14cebeSEric Cheng 1057da14cebeSEric Cheng if ((kcp = kstat_open()) == NULL) { 1058da14cebeSEric Cheng warn("kstat open operation failed"); 1059da14cebeSEric Cheng return; 1060da14cebeSEric Cheng } 1061da14cebeSEric Cheng 1062da14cebeSEric Cheng ksp = dladm_kstat_lookup(kcp, NULL, -1, flowname, "flow"); 1063da14cebeSEric Cheng 1064da14cebeSEric Cheng if (ksp != NULL) 1065da14cebeSEric Cheng dladm_get_stats(kcp, ksp, stats); 1066da14cebeSEric Cheng 1067da14cebeSEric Cheng (void) kstat_close(kcp); 1068da14cebeSEric Cheng } 1069da14cebeSEric Cheng 1070ae6aa22aSVenugopal Iyer 1071ae6aa22aSVenugopal Iyer static char * 1072ae6aa22aSVenugopal Iyer print_flow_stats(print_field_t *pf, void *arg) 1073ae6aa22aSVenugopal Iyer { 1074ae6aa22aSVenugopal Iyer flow_args_t *fargs = arg; 1075ae6aa22aSVenugopal Iyer pktsum_t *diff_stats = fargs->flow_s_psum; 1076ae6aa22aSVenugopal Iyer static char buf[DLADM_STRSIZE]; 1077ae6aa22aSVenugopal Iyer 1078ae6aa22aSVenugopal Iyer switch (pf->pf_index) { 1079ae6aa22aSVenugopal Iyer case FLOW_S_FLOW: 1080ae6aa22aSVenugopal Iyer (void) snprintf(buf, sizeof (buf), "%s", fargs->flow_s_flow); 1081ae6aa22aSVenugopal Iyer break; 1082ae6aa22aSVenugopal Iyer case FLOW_S_IPKTS: 1083ae6aa22aSVenugopal Iyer (void) snprintf(buf, sizeof (buf), "%llu", 1084ae6aa22aSVenugopal Iyer diff_stats->ipackets); 1085ae6aa22aSVenugopal Iyer break; 1086ae6aa22aSVenugopal Iyer case FLOW_S_RBYTES: 1087ae6aa22aSVenugopal Iyer (void) snprintf(buf, sizeof (buf), "%llu", 1088ae6aa22aSVenugopal Iyer diff_stats->rbytes); 1089ae6aa22aSVenugopal Iyer break; 1090ae6aa22aSVenugopal Iyer case FLOW_S_IERRORS: 1091ae6aa22aSVenugopal Iyer (void) snprintf(buf, sizeof (buf), "%u", 1092ae6aa22aSVenugopal Iyer diff_stats->ierrors); 1093ae6aa22aSVenugopal Iyer break; 1094ae6aa22aSVenugopal Iyer case FLOW_S_OPKTS: 1095ae6aa22aSVenugopal Iyer (void) snprintf(buf, sizeof (buf), "%llu", 1096ae6aa22aSVenugopal Iyer diff_stats->opackets); 1097ae6aa22aSVenugopal Iyer break; 1098ae6aa22aSVenugopal Iyer case FLOW_S_OBYTES: 1099ae6aa22aSVenugopal Iyer (void) snprintf(buf, sizeof (buf), "%llu", 1100ae6aa22aSVenugopal Iyer diff_stats->obytes); 1101ae6aa22aSVenugopal Iyer break; 1102ae6aa22aSVenugopal Iyer case FLOW_S_OERRORS: 1103ae6aa22aSVenugopal Iyer (void) snprintf(buf, sizeof (buf), "%u", 1104ae6aa22aSVenugopal Iyer diff_stats->oerrors); 1105ae6aa22aSVenugopal Iyer break; 1106ae6aa22aSVenugopal Iyer default: 1107ae6aa22aSVenugopal Iyer die("invalid input"); 1108ae6aa22aSVenugopal Iyer break; 1109ae6aa22aSVenugopal Iyer } 1110ae6aa22aSVenugopal Iyer return (buf); 1111ae6aa22aSVenugopal Iyer } 1112da14cebeSEric Cheng /* ARGSUSED */ 1113da14cebeSEric Cheng static int 1114da14cebeSEric Cheng show_flow_stats(dladm_flow_attr_t *attr, void *arg) 1115da14cebeSEric Cheng { 1116da14cebeSEric Cheng show_flow_state_t *state = (show_flow_state_t *)arg; 1117ae6aa22aSVenugopal Iyer char *name = attr->fa_flowname; 1118da14cebeSEric Cheng pktsum_t stats, diff_stats; 1119ae6aa22aSVenugopal Iyer flow_args_t fargs; 1120da14cebeSEric Cheng 1121da14cebeSEric Cheng if (state->fs_firstonly) { 1122da14cebeSEric Cheng if (state->fs_donefirst) 1123da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 1124da14cebeSEric Cheng state->fs_donefirst = B_TRUE; 1125da14cebeSEric Cheng } else { 1126da14cebeSEric Cheng bzero(&state->fs_prevstats, sizeof (state->fs_prevstats)); 1127da14cebeSEric Cheng } 1128da14cebeSEric Cheng 1129da14cebeSEric Cheng get_flow_stats(name, &stats); 1130da14cebeSEric Cheng dladm_stats_diff(&diff_stats, &stats, &state->fs_prevstats); 1131da14cebeSEric Cheng 1132ae6aa22aSVenugopal Iyer fargs.flow_s_flow = name; 1133ae6aa22aSVenugopal Iyer fargs.flow_s_psum = &diff_stats; 1134ae6aa22aSVenugopal Iyer flowadm_print_output(&state->fs_print, state->fs_parseable, 1135ae6aa22aSVenugopal Iyer print_flow_stats, &fargs); 1136da14cebeSEric Cheng 1137da14cebeSEric Cheng state->fs_prevstats = stats; 1138da14cebeSEric Cheng 1139da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1140da14cebeSEric Cheng } 1141da14cebeSEric Cheng 1142da14cebeSEric Cheng /* 1143da14cebeSEric Cheng * Wrapper of dladm_walk_flow(show_flow,...) to make it usable for 1144da14cebeSEric Cheng * dladm_walk_datalink_id(). Used for showing flow stats for 1145da14cebeSEric Cheng * all flows on all links. 1146da14cebeSEric Cheng */ 1147da14cebeSEric Cheng static int 11484ac67f02SAnurag S. Maskey show_link_flow_stats(dladm_handle_t dh, datalink_id_t linkid, void * arg) 1149da14cebeSEric Cheng { 11504ac67f02SAnurag S. Maskey if (dladm_walk_flow(show_flow_stats, dh, linkid, arg, B_FALSE) 1151da14cebeSEric Cheng == DLADM_STATUS_OK) 1152da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1153da14cebeSEric Cheng else 1154da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 1155da14cebeSEric Cheng } 1156da14cebeSEric Cheng 1157da14cebeSEric Cheng /* ARGSUSED */ 1158da14cebeSEric Cheng static void 1159ae6aa22aSVenugopal Iyer flow_stats(const char *flow, datalink_id_t linkid, uint_t interval, 1160ae6aa22aSVenugopal Iyer char *fields_str, show_flow_state_t *state) 1161da14cebeSEric Cheng { 1162da14cebeSEric Cheng dladm_flow_attr_t attr; 1163ae6aa22aSVenugopal Iyer print_field_t **fields; 1164ae6aa22aSVenugopal Iyer uint_t nfields; 1165ae6aa22aSVenugopal Iyer 1166ae6aa22aSVenugopal Iyer fields = parse_output_fields(fields_str, flow_s_fields, 1167ae6aa22aSVenugopal Iyer FLOW_S_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 1168ae6aa22aSVenugopal Iyer if (fields == NULL) { 1169ae6aa22aSVenugopal Iyer die("invalid field(s) specified"); 1170ae6aa22aSVenugopal Iyer return; 1171ae6aa22aSVenugopal Iyer } 1172ae6aa22aSVenugopal Iyer 1173ae6aa22aSVenugopal Iyer state->fs_print.ps_fields = fields; 1174ae6aa22aSVenugopal Iyer state->fs_print.ps_nfields = nfields; 1175da14cebeSEric Cheng 11764ac67f02SAnurag S. Maskey if (flow != NULL && 11774ac67f02SAnurag S. Maskey dladm_flow_info(handle, flow, &attr) != DLADM_STATUS_OK) 1178da14cebeSEric Cheng die("invalid flow %s", flow); 1179da14cebeSEric Cheng 1180da14cebeSEric Cheng /* 1181da14cebeSEric Cheng * If an interval is specified, continuously show the stats 1182da14cebeSEric Cheng * for only the first flow. 1183da14cebeSEric Cheng */ 1184ae6aa22aSVenugopal Iyer state->fs_firstonly = (interval != 0); 1185da14cebeSEric Cheng 1186ae6aa22aSVenugopal Iyer if (!state->fs_parseable) 1187ae6aa22aSVenugopal Iyer print_header(&state->fs_print); 1188da14cebeSEric Cheng for (;;) { 1189ae6aa22aSVenugopal Iyer state->fs_donefirst = B_FALSE; 1190da14cebeSEric Cheng 1191da14cebeSEric Cheng /* Show stats for named flow */ 1192da14cebeSEric Cheng if (flow != NULL) { 1193ae6aa22aSVenugopal Iyer state->fs_flow = flow; 1194ae6aa22aSVenugopal Iyer (void) show_flow_stats(&attr, state); 1195da14cebeSEric Cheng 1196da14cebeSEric Cheng /* Show all stats on a link */ 1197da14cebeSEric Cheng } else if (linkid != DATALINK_INVALID_LINKID) { 11984ac67f02SAnurag S. Maskey (void) dladm_walk_flow(show_flow_stats, handle, linkid, 1199ae6aa22aSVenugopal Iyer state, B_FALSE); 1200da14cebeSEric Cheng 1201da14cebeSEric Cheng /* Show all stats by datalink */ 1202da14cebeSEric Cheng } else { 1203da14cebeSEric Cheng (void) dladm_walk_datalink_id(show_link_flow_stats, 1204ae6aa22aSVenugopal Iyer handle, state, DATALINK_CLASS_ALL, 12054ac67f02SAnurag S. Maskey DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 1206da14cebeSEric Cheng } 1207da14cebeSEric Cheng 1208da14cebeSEric Cheng if (interval == 0) 1209da14cebeSEric Cheng break; 1210da14cebeSEric Cheng 1211da14cebeSEric Cheng (void) sleep(interval); 1212da14cebeSEric Cheng } 1213da14cebeSEric Cheng } 1214da14cebeSEric Cheng 1215da14cebeSEric Cheng static void 1216da14cebeSEric Cheng do_show_flow(int argc, char *argv[]) 1217da14cebeSEric Cheng { 1218da000602SGirish Moodalbail char flowname[MAXFLOWNAMELEN]; 1219da000602SGirish Moodalbail char linkname[MAXLINKNAMELEN]; 1220da14cebeSEric Cheng datalink_id_t linkid = DATALINK_ALL_LINKID; 1221da14cebeSEric Cheng int option; 1222da14cebeSEric Cheng boolean_t s_arg = B_FALSE; 1223da14cebeSEric Cheng boolean_t S_arg = B_FALSE; 1224da14cebeSEric Cheng boolean_t i_arg = B_FALSE; 1225da14cebeSEric Cheng boolean_t l_arg = B_FALSE; 1226da14cebeSEric Cheng boolean_t o_arg = B_FALSE; 1227da14cebeSEric Cheng uint32_t interval = 0; 1228da14cebeSEric Cheng show_flow_state_t state; 1229da14cebeSEric Cheng char *fields_str = NULL; 1230da14cebeSEric Cheng print_field_t **fields; 1231da14cebeSEric Cheng uint_t nfields; 1232da14cebeSEric Cheng char *all_fields = 1233ad091ee1SMichael Lim "flow,link,ipaddr,proto,port,dsfld"; 1234ae6aa22aSVenugopal Iyer char *allstat_fields = 1235ae6aa22aSVenugopal Iyer "flow,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; 1236da14cebeSEric Cheng 1237da14cebeSEric Cheng bzero(&state, sizeof (state)); 1238da14cebeSEric Cheng 1239da14cebeSEric Cheng opterr = 0; 1240da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":pPsSi:l:o:", 1241da14cebeSEric Cheng longopts, NULL)) != -1) { 1242da14cebeSEric Cheng switch (option) { 1243da14cebeSEric Cheng case 'p': 1244da14cebeSEric Cheng state.fs_parseable = B_TRUE; 1245da14cebeSEric Cheng break; 1246da14cebeSEric Cheng case 'P': 1247da14cebeSEric Cheng state.fs_persist = B_TRUE; 1248da14cebeSEric Cheng break; 1249da14cebeSEric Cheng case 's': 1250da14cebeSEric Cheng if (s_arg) 1251da14cebeSEric Cheng die_optdup(option); 1252da14cebeSEric Cheng 1253da14cebeSEric Cheng s_arg = B_TRUE; 1254da14cebeSEric Cheng break; 1255da14cebeSEric Cheng case 'S': 1256da14cebeSEric Cheng if (S_arg) 1257da14cebeSEric Cheng die_optdup(option); 1258da14cebeSEric Cheng 1259da14cebeSEric Cheng S_arg = B_TRUE; 1260da14cebeSEric Cheng break; 1261da14cebeSEric Cheng case 'o': 1262da14cebeSEric Cheng if (o_arg) 1263da14cebeSEric Cheng die_optdup(option); 1264da14cebeSEric Cheng 1265da14cebeSEric Cheng o_arg = B_TRUE; 1266da14cebeSEric Cheng fields_str = optarg; 1267da14cebeSEric Cheng break; 1268da14cebeSEric Cheng case 'i': 1269da14cebeSEric Cheng if (i_arg) 1270da14cebeSEric Cheng die_optdup(option); 1271da14cebeSEric Cheng 1272da14cebeSEric Cheng i_arg = B_TRUE; 1273da14cebeSEric Cheng 1274*63a6526dSMichael Lim if (!dladm_str2interval(optarg, &interval)) 1275*63a6526dSMichael Lim die("invalid interval value '%s'", optarg); 1276da14cebeSEric Cheng break; 1277da14cebeSEric Cheng case 'l': 1278da14cebeSEric Cheng if (strlcpy(linkname, optarg, MAXLINKNAMELEN) 1279da14cebeSEric Cheng >= MAXLINKNAMELEN) 1280da14cebeSEric Cheng die("link name too long\n"); 12814ac67f02SAnurag S. Maskey if (dladm_name2info(handle, linkname, &linkid, NULL, 1282da14cebeSEric Cheng NULL, NULL) != DLADM_STATUS_OK) 1283da14cebeSEric Cheng die("invalid link '%s'", linkname); 1284da14cebeSEric Cheng l_arg = B_TRUE; 1285da14cebeSEric Cheng break; 1286da14cebeSEric Cheng default: 1287da14cebeSEric Cheng die_opterr(optopt, option); 1288da14cebeSEric Cheng break; 1289da14cebeSEric Cheng } 1290da14cebeSEric Cheng } 1291ad091ee1SMichael Lim 1292da14cebeSEric Cheng if (i_arg && !(s_arg || S_arg)) 1293da14cebeSEric Cheng die("the -i option can be used only with -s or -S"); 1294da14cebeSEric Cheng 1295da14cebeSEric Cheng if (s_arg && S_arg) 1296da14cebeSEric Cheng die("the -s option cannot be used with -S"); 1297da14cebeSEric Cheng 1298da14cebeSEric Cheng /* get flow name (optional last argument */ 1299da14cebeSEric Cheng if (optind == (argc-1)) { 1300da000602SGirish Moodalbail if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN) 1301da000602SGirish Moodalbail >= MAXFLOWNAMELEN) 1302da14cebeSEric Cheng die("flow name too long"); 1303da14cebeSEric Cheng state.fs_flow = flowname; 1304da14cebeSEric Cheng } 1305da14cebeSEric Cheng 1306da14cebeSEric Cheng if (S_arg) { 13074ac67f02SAnurag S. Maskey dladm_continuous(handle, linkid, state.fs_flow, interval, 13084ac67f02SAnurag S. Maskey FLOW_REPORT); 1309da14cebeSEric Cheng return; 1310da14cebeSEric Cheng } 1311da14cebeSEric Cheng 1312ae6aa22aSVenugopal Iyer if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 1313ae6aa22aSVenugopal Iyer if (s_arg) 1314ae6aa22aSVenugopal Iyer fields_str = allstat_fields; 1315ae6aa22aSVenugopal Iyer else 1316da14cebeSEric Cheng fields_str = all_fields; 1317ae6aa22aSVenugopal Iyer } 1318ae6aa22aSVenugopal Iyer 1319ae6aa22aSVenugopal Iyer if (s_arg) { 1320ae6aa22aSVenugopal Iyer flow_stats(state.fs_flow, linkid, interval, fields_str, &state); 1321ae6aa22aSVenugopal Iyer return; 1322ae6aa22aSVenugopal Iyer } 1323da14cebeSEric Cheng 1324da14cebeSEric Cheng fields = parse_output_fields(fields_str, flow_fields, FLOW_MAX_FIELDS, 1325da14cebeSEric Cheng CMD_TYPE_ANY, &nfields); 1326da14cebeSEric Cheng 1327da14cebeSEric Cheng if (fields == NULL) { 1328da14cebeSEric Cheng die("invalid fields(s) specified"); 1329da14cebeSEric Cheng return; 1330da14cebeSEric Cheng } 1331da14cebeSEric Cheng 1332da14cebeSEric Cheng state.fs_print.ps_fields = fields; 1333da14cebeSEric Cheng state.fs_print.ps_nfields = nfields; 1334da14cebeSEric Cheng 1335da14cebeSEric Cheng /* Show attributes of one flow */ 1336da14cebeSEric Cheng if (state.fs_flow != NULL) { 1337da14cebeSEric Cheng show_one_flow(&state, state.fs_flow); 1338da14cebeSEric Cheng 1339da14cebeSEric Cheng /* Show attributes of flows on one link */ 1340da14cebeSEric Cheng } else if (l_arg) { 13414ac67f02SAnurag S. Maskey (void) show_flows_onelink(handle, linkid, &state); 1342da14cebeSEric Cheng 1343da14cebeSEric Cheng /* Show attributes of all flows on all links */ 1344da14cebeSEric Cheng } else { 13454ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(show_flows_onelink, handle, 13464ac67f02SAnurag S. Maskey &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 1347da14cebeSEric Cheng DLADM_OPT_ACTIVE); 1348da14cebeSEric Cheng } 1349da14cebeSEric Cheng } 1350da14cebeSEric Cheng 1351da14cebeSEric Cheng static dladm_status_t 1352da14cebeSEric Cheng set_flowprop_persist(const char *flow, const char *prop_name, char **prop_val, 1353da14cebeSEric Cheng uint_t val_cnt, boolean_t reset) 1354da14cebeSEric Cheng { 1355da14cebeSEric Cheng dladm_status_t status; 1356da14cebeSEric Cheng char *errprop; 1357da14cebeSEric Cheng 13584ac67f02SAnurag S. Maskey status = dladm_set_flowprop(handle, flow, prop_name, prop_val, val_cnt, 1359da14cebeSEric Cheng DLADM_OPT_PERSIST, &errprop); 1360da14cebeSEric Cheng 1361da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 1362da14cebeSEric Cheng warn_dlerr(status, "cannot persistently %s flow " 1363da14cebeSEric Cheng "property '%s' on '%s'", reset? "reset": "set", 1364da14cebeSEric Cheng errprop, flow); 1365da14cebeSEric Cheng } 1366da14cebeSEric Cheng return (status); 1367da14cebeSEric Cheng } 1368da14cebeSEric Cheng 1369da14cebeSEric Cheng static void 1370da14cebeSEric Cheng set_flowprop(int argc, char **argv, boolean_t reset) 1371da14cebeSEric Cheng { 1372da14cebeSEric Cheng int i, option; 1373da14cebeSEric Cheng char errmsg[DLADM_STRSIZE]; 1374da14cebeSEric Cheng const char *flow = NULL; 1375*63a6526dSMichael Lim char propstr[DLADM_STRSIZE]; 1376da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 1377da14cebeSEric Cheng boolean_t temp = B_FALSE; 1378da14cebeSEric Cheng dladm_status_t status = DLADM_STATUS_OK; 1379da14cebeSEric Cheng 1380da14cebeSEric Cheng opterr = 0; 1381*63a6526dSMichael Lim bzero(propstr, DLADM_STRSIZE); 1382*63a6526dSMichael Lim 1383da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":p:R:t", 1384da14cebeSEric Cheng prop_longopts, NULL)) != -1) { 1385da14cebeSEric Cheng switch (option) { 1386da14cebeSEric Cheng case 'p': 1387*63a6526dSMichael Lim (void) strlcat(propstr, optarg, DLADM_STRSIZE); 1388*63a6526dSMichael Lim if (strlcat(propstr, ",", DLADM_STRSIZE) >= 1389*63a6526dSMichael Lim DLADM_STRSIZE) 1390*63a6526dSMichael Lim die("property list too long '%s'", propstr); 1391da14cebeSEric Cheng break; 1392da14cebeSEric Cheng case 't': 1393da14cebeSEric Cheng temp = B_TRUE; 1394da14cebeSEric Cheng break; 1395da14cebeSEric Cheng case 'R': 1396da14cebeSEric Cheng status = dladm_set_rootdir(optarg); 1397da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 1398da14cebeSEric Cheng die_dlerr(status, "invalid directory " 1399da14cebeSEric Cheng "specified"); 1400da14cebeSEric Cheng } 1401da14cebeSEric Cheng break; 1402da14cebeSEric Cheng default: 1403da14cebeSEric Cheng die_opterr(optopt, option); 1404da14cebeSEric Cheng break; 1405da14cebeSEric Cheng } 1406da14cebeSEric Cheng } 1407da14cebeSEric Cheng 1408da14cebeSEric Cheng if (optind == (argc - 1)) { 1409da000602SGirish Moodalbail if (strlen(argv[optind]) >= MAXFLOWNAMELEN) 1410da14cebeSEric Cheng die("flow name too long"); 1411da14cebeSEric Cheng flow = argv[optind]; 1412da14cebeSEric Cheng } else if (optind != argc) { 1413da14cebeSEric Cheng usage(); 1414da14cebeSEric Cheng } 1415da14cebeSEric Cheng if (flow == NULL) 1416da14cebeSEric Cheng die("flow name must be specified"); 1417da14cebeSEric Cheng 1418*63a6526dSMichael Lim if (dladm_parse_flow_props(propstr, &proplist, reset) 1419*63a6526dSMichael Lim != DLADM_STATUS_OK) 1420*63a6526dSMichael Lim die("invalid flow property specified"); 1421*63a6526dSMichael Lim 1422da14cebeSEric Cheng if (proplist == NULL) { 1423da14cebeSEric Cheng char *errprop; 1424da14cebeSEric Cheng 1425da14cebeSEric Cheng if (!reset) 1426da14cebeSEric Cheng die("flow property must be specified"); 1427da14cebeSEric Cheng 14284ac67f02SAnurag S. Maskey status = dladm_set_flowprop(handle, flow, NULL, NULL, 0, 1429da14cebeSEric Cheng DLADM_OPT_ACTIVE, &errprop); 1430da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 1431da14cebeSEric Cheng warn_dlerr(status, "cannot reset flow property '%s' " 1432da14cebeSEric Cheng "on '%s'", errprop, flow); 1433da14cebeSEric Cheng } 1434da14cebeSEric Cheng if (!temp) { 1435da14cebeSEric Cheng dladm_status_t s; 1436da14cebeSEric Cheng 1437da14cebeSEric Cheng s = set_flowprop_persist(flow, NULL, NULL, 0, reset); 1438da14cebeSEric Cheng if (s != DLADM_STATUS_OK) 1439da14cebeSEric Cheng status = s; 1440da14cebeSEric Cheng } 1441da14cebeSEric Cheng goto done; 1442da14cebeSEric Cheng } 1443da14cebeSEric Cheng 1444da14cebeSEric Cheng for (i = 0; i < proplist->al_count; i++) { 1445da14cebeSEric Cheng dladm_arg_info_t *aip = &proplist->al_info[i]; 1446da14cebeSEric Cheng char **val; 1447da14cebeSEric Cheng uint_t count; 1448da14cebeSEric Cheng dladm_status_t s; 1449da14cebeSEric Cheng 1450da14cebeSEric Cheng if (reset) { 1451da14cebeSEric Cheng val = NULL; 1452da14cebeSEric Cheng count = 0; 1453da14cebeSEric Cheng } else { 1454da14cebeSEric Cheng val = aip->ai_val; 1455da14cebeSEric Cheng count = aip->ai_count; 1456da14cebeSEric Cheng if (count == 0) { 1457da14cebeSEric Cheng warn("no value specified for '%s'", 1458da14cebeSEric Cheng aip->ai_name); 1459da14cebeSEric Cheng status = DLADM_STATUS_BADARG; 1460da14cebeSEric Cheng continue; 1461da14cebeSEric Cheng } 1462da14cebeSEric Cheng } 14634ac67f02SAnurag S. Maskey s = dladm_set_flowprop(handle, flow, aip->ai_name, val, count, 1464da14cebeSEric Cheng DLADM_OPT_ACTIVE, NULL); 1465da14cebeSEric Cheng if (s == DLADM_STATUS_OK) { 1466da14cebeSEric Cheng if (!temp) { 1467da14cebeSEric Cheng s = set_flowprop_persist(flow, 1468da14cebeSEric Cheng aip->ai_name, val, count, reset); 1469da14cebeSEric Cheng if (s != DLADM_STATUS_OK) 1470da14cebeSEric Cheng status = s; 1471da14cebeSEric Cheng } 1472da14cebeSEric Cheng continue; 1473da14cebeSEric Cheng } 1474da14cebeSEric Cheng status = s; 1475da14cebeSEric Cheng switch (s) { 1476da14cebeSEric Cheng case DLADM_STATUS_NOTFOUND: 1477da14cebeSEric Cheng warn("invalid flow property '%s'", aip->ai_name); 1478da14cebeSEric Cheng break; 1479da14cebeSEric Cheng case DLADM_STATUS_BADVAL: { 1480da14cebeSEric Cheng int j; 1481da14cebeSEric Cheng char *ptr, *lim; 1482da14cebeSEric Cheng char **propvals = NULL; 1483da14cebeSEric Cheng uint_t valcnt = DLADM_MAX_PROP_VALCNT; 1484da14cebeSEric Cheng 1485da14cebeSEric Cheng ptr = malloc((sizeof (char *) + 1486da14cebeSEric Cheng DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 1487da14cebeSEric Cheng MAX_PROP_LINE); 1488da14cebeSEric Cheng 1489da14cebeSEric Cheng if (ptr == NULL) 1490da14cebeSEric Cheng die("insufficient memory"); 1491da14cebeSEric Cheng propvals = (char **)(void *)ptr; 1492da14cebeSEric Cheng 1493da14cebeSEric Cheng for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 1494da14cebeSEric Cheng propvals[j] = ptr + sizeof (char *) * 1495da14cebeSEric Cheng DLADM_MAX_PROP_VALCNT + 1496da14cebeSEric Cheng j * DLADM_PROP_VAL_MAX; 1497da14cebeSEric Cheng } 14984ac67f02SAnurag S. Maskey s = dladm_get_flowprop(handle, flow, 14994ac67f02SAnurag S. Maskey DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals, 15004ac67f02SAnurag S. Maskey &valcnt); 1501da14cebeSEric Cheng 1502da14cebeSEric Cheng ptr = errmsg; 1503da14cebeSEric Cheng lim = ptr + DLADM_STRSIZE; 1504da14cebeSEric Cheng *ptr = '\0'; 1505da14cebeSEric Cheng for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) { 1506da14cebeSEric Cheng ptr += snprintf(ptr, lim - ptr, "%s,", 1507da14cebeSEric Cheng propvals[j]); 1508da14cebeSEric Cheng if (ptr >= lim) 1509da14cebeSEric Cheng break; 1510da14cebeSEric Cheng } 1511da14cebeSEric Cheng if (ptr > errmsg) { 1512da14cebeSEric Cheng *(ptr - 1) = '\0'; 1513da14cebeSEric Cheng warn("flow property '%s' must be one of: %s", 1514da14cebeSEric Cheng aip->ai_name, errmsg); 1515da14cebeSEric Cheng } else 1516da14cebeSEric Cheng warn("%s is an invalid value for " 1517da14cebeSEric Cheng "flow property %s", *val, aip->ai_name); 1518da14cebeSEric Cheng free(propvals); 1519da14cebeSEric Cheng break; 1520da14cebeSEric Cheng } 1521da14cebeSEric Cheng default: 1522da14cebeSEric Cheng if (reset) { 1523da14cebeSEric Cheng warn_dlerr(status, "cannot reset flow property " 1524da14cebeSEric Cheng "'%s' on '%s'", aip->ai_name, flow); 1525da14cebeSEric Cheng } else { 1526da14cebeSEric Cheng warn_dlerr(status, "cannot set flow property " 1527da14cebeSEric Cheng "'%s' on '%s'", aip->ai_name, flow); 1528da14cebeSEric Cheng } 1529da14cebeSEric Cheng break; 1530da14cebeSEric Cheng } 1531da14cebeSEric Cheng } 1532da14cebeSEric Cheng done: 1533da14cebeSEric Cheng dladm_free_props(proplist); 15344ac67f02SAnurag S. Maskey if (status != DLADM_STATUS_OK) { 15354ac67f02SAnurag S. Maskey dladm_close(handle); 1536ad091ee1SMichael Lim exit(EXIT_FAILURE); 1537da14cebeSEric Cheng } 15384ac67f02SAnurag S. Maskey } 1539da14cebeSEric Cheng 1540da14cebeSEric Cheng static void 1541da14cebeSEric Cheng do_set_flowprop(int argc, char **argv) 1542da14cebeSEric Cheng { 1543da14cebeSEric Cheng set_flowprop(argc, argv, B_FALSE); 1544da14cebeSEric Cheng } 1545da14cebeSEric Cheng 1546da14cebeSEric Cheng static void 1547da14cebeSEric Cheng do_reset_flowprop(int argc, char **argv) 1548da14cebeSEric Cheng { 1549da14cebeSEric Cheng set_flowprop(argc, argv, B_TRUE); 1550da14cebeSEric Cheng } 1551da14cebeSEric Cheng 1552da14cebeSEric Cheng static void 1553da14cebeSEric Cheng warn(const char *format, ...) 1554da14cebeSEric Cheng { 1555da14cebeSEric Cheng va_list alist; 1556da14cebeSEric Cheng 1557da14cebeSEric Cheng format = gettext(format); 1558da14cebeSEric Cheng (void) fprintf(stderr, "%s: warning: ", progname); 1559da14cebeSEric Cheng 1560da14cebeSEric Cheng va_start(alist, format); 1561da14cebeSEric Cheng (void) vfprintf(stderr, format, alist); 1562da14cebeSEric Cheng va_end(alist); 1563da14cebeSEric Cheng 1564da14cebeSEric Cheng (void) putchar('\n'); 1565da14cebeSEric Cheng } 1566da14cebeSEric Cheng 1567da14cebeSEric Cheng /* PRINTFLIKE2 */ 1568da14cebeSEric Cheng static void 1569da14cebeSEric Cheng warn_dlerr(dladm_status_t err, const char *format, ...) 1570da14cebeSEric Cheng { 1571da14cebeSEric Cheng va_list alist; 1572da14cebeSEric Cheng char errmsg[DLADM_STRSIZE]; 1573da14cebeSEric Cheng 1574da14cebeSEric Cheng format = gettext(format); 1575da14cebeSEric Cheng (void) fprintf(stderr, gettext("%s: warning: "), progname); 1576da14cebeSEric Cheng 1577da14cebeSEric Cheng va_start(alist, format); 1578da14cebeSEric Cheng (void) vfprintf(stderr, format, alist); 1579da14cebeSEric Cheng va_end(alist); 1580da14cebeSEric Cheng (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 1581da14cebeSEric Cheng } 1582da14cebeSEric Cheng 1583da14cebeSEric Cheng /* PRINTFLIKE1 */ 1584da14cebeSEric Cheng static void 1585da14cebeSEric Cheng die(const char *format, ...) 1586da14cebeSEric Cheng { 1587da14cebeSEric Cheng va_list alist; 1588da14cebeSEric Cheng 1589da14cebeSEric Cheng format = gettext(format); 1590da14cebeSEric Cheng (void) fprintf(stderr, "%s: ", progname); 1591da14cebeSEric Cheng 1592da14cebeSEric Cheng va_start(alist, format); 1593da14cebeSEric Cheng (void) vfprintf(stderr, format, alist); 1594da14cebeSEric Cheng va_end(alist); 1595da14cebeSEric Cheng 1596da14cebeSEric Cheng (void) putchar('\n'); 15974ac67f02SAnurag S. Maskey 15984ac67f02SAnurag S. Maskey /* close dladm handle if it was opened */ 15994ac67f02SAnurag S. Maskey if (handle != NULL) 16004ac67f02SAnurag S. Maskey dladm_close(handle); 16014ac67f02SAnurag S. Maskey 1602da14cebeSEric Cheng exit(EXIT_FAILURE); 1603da14cebeSEric Cheng } 1604da14cebeSEric Cheng 1605da14cebeSEric Cheng static void 1606da14cebeSEric Cheng die_optdup(int opt) 1607da14cebeSEric Cheng { 1608da14cebeSEric Cheng die("the option -%c cannot be specified more than once", opt); 1609da14cebeSEric Cheng } 1610da14cebeSEric Cheng 1611da14cebeSEric Cheng static void 1612da14cebeSEric Cheng die_opterr(int opt, int opterr) 1613da14cebeSEric Cheng { 1614da14cebeSEric Cheng switch (opterr) { 1615da14cebeSEric Cheng case ':': 1616da14cebeSEric Cheng die("option '-%c' requires a value", opt); 1617da14cebeSEric Cheng break; 1618da14cebeSEric Cheng case '?': 1619da14cebeSEric Cheng default: 1620da14cebeSEric Cheng die("unrecognized option '-%c'", opt); 1621da14cebeSEric Cheng break; 1622da14cebeSEric Cheng } 1623da14cebeSEric Cheng } 1624da14cebeSEric Cheng 1625da14cebeSEric Cheng /* PRINTFLIKE2 */ 1626da14cebeSEric Cheng static void 1627da14cebeSEric Cheng die_dlerr(dladm_status_t err, const char *format, ...) 1628da14cebeSEric Cheng { 1629da14cebeSEric Cheng va_list alist; 1630da14cebeSEric Cheng char errmsg[DLADM_STRSIZE]; 1631da14cebeSEric Cheng 1632da14cebeSEric Cheng format = gettext(format); 1633da14cebeSEric Cheng (void) fprintf(stderr, "%s: ", progname); 1634da14cebeSEric Cheng 1635da14cebeSEric Cheng va_start(alist, format); 1636da14cebeSEric Cheng (void) vfprintf(stderr, format, alist); 1637da14cebeSEric Cheng va_end(alist); 1638da14cebeSEric Cheng (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 1639da14cebeSEric Cheng 16404ac67f02SAnurag S. Maskey /* close dladm handle if it was opened */ 16414ac67f02SAnurag S. Maskey if (handle != NULL) 16424ac67f02SAnurag S. Maskey dladm_close(handle); 16434ac67f02SAnurag S. Maskey 1644da14cebeSEric Cheng exit(EXIT_FAILURE); 1645da14cebeSEric Cheng } 1646da14cebeSEric Cheng 1647da14cebeSEric Cheng static void 1648da14cebeSEric Cheng print_flowprop(const char *flowname, show_flowprop_state_t *statep, 1649da14cebeSEric Cheng const char *propname, dladm_prop_type_t type, 1650da14cebeSEric Cheng const char *format, char **pptr) 1651da14cebeSEric Cheng { 1652da14cebeSEric Cheng int i; 1653da14cebeSEric Cheng char *ptr, *lim; 1654da14cebeSEric Cheng char buf[DLADM_STRSIZE]; 1655da14cebeSEric Cheng char *unknown = "--", *notsup = ""; 1656da14cebeSEric Cheng char **propvals = statep->fs_propvals; 1657da14cebeSEric Cheng uint_t valcnt = DLADM_MAX_PROP_VALCNT; 1658da14cebeSEric Cheng dladm_status_t status; 1659da14cebeSEric Cheng 16604ac67f02SAnurag S. Maskey status = dladm_get_flowprop(handle, flowname, type, propname, propvals, 1661da14cebeSEric Cheng &valcnt); 1662da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 1663da14cebeSEric Cheng if (status == DLADM_STATUS_TEMPONLY) { 1664da14cebeSEric Cheng if (type == DLADM_PROP_VAL_MODIFIABLE && 1665da14cebeSEric Cheng statep->fs_persist) { 1666da14cebeSEric Cheng valcnt = 1; 1667da14cebeSEric Cheng propvals = &unknown; 1668da14cebeSEric Cheng } else { 1669da14cebeSEric Cheng statep->fs_status = status; 1670da14cebeSEric Cheng statep->fs_retstatus = status; 1671da14cebeSEric Cheng return; 1672da14cebeSEric Cheng } 1673da14cebeSEric Cheng } else if (status == DLADM_STATUS_NOTSUP || 1674da14cebeSEric Cheng statep->fs_persist) { 1675da14cebeSEric Cheng valcnt = 1; 1676da14cebeSEric Cheng if (type == DLADM_PROP_VAL_CURRENT) 1677da14cebeSEric Cheng propvals = &unknown; 1678da14cebeSEric Cheng else 1679da14cebeSEric Cheng propvals = ¬sup; 1680da14cebeSEric Cheng } else { 1681da14cebeSEric Cheng if ((statep->fs_proplist != NULL) && 1682da14cebeSEric Cheng statep->fs_status == DLADM_STATUS_OK) { 1683da14cebeSEric Cheng warn("invalid flow property '%s'", propname); 1684da14cebeSEric Cheng } 1685da14cebeSEric Cheng statep->fs_status = status; 1686da14cebeSEric Cheng statep->fs_retstatus = status; 1687da14cebeSEric Cheng return; 1688da14cebeSEric Cheng } 1689da14cebeSEric Cheng } 1690da14cebeSEric Cheng 1691da14cebeSEric Cheng statep->fs_status = DLADM_STATUS_OK; 1692da14cebeSEric Cheng 1693da14cebeSEric Cheng ptr = buf; 1694da14cebeSEric Cheng lim = buf + DLADM_STRSIZE; 1695da14cebeSEric Cheng for (i = 0; i < valcnt; i++) { 1696da14cebeSEric Cheng if (propvals[i][0] == '\0' && !statep->fs_parseable) 1697da14cebeSEric Cheng ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL","); 1698da14cebeSEric Cheng else 1699da14cebeSEric Cheng ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 1700da14cebeSEric Cheng if (ptr >= lim) 1701da14cebeSEric Cheng break; 1702da14cebeSEric Cheng } 1703da14cebeSEric Cheng if (valcnt > 0) 1704da14cebeSEric Cheng buf[strlen(buf) - 1] = '\0'; 1705da14cebeSEric Cheng 1706da14cebeSEric Cheng lim = statep->fs_line + MAX_PROP_LINE; 1707da14cebeSEric Cheng if (statep->fs_parseable) { 1708da14cebeSEric Cheng *pptr += snprintf(*pptr, lim - *pptr, 1709da14cebeSEric Cheng "%s", buf); 1710da14cebeSEric Cheng } else { 1711da14cebeSEric Cheng *pptr += snprintf(*pptr, lim - *pptr, format, buf); 1712da14cebeSEric Cheng } 1713da14cebeSEric Cheng } 1714da14cebeSEric Cheng 1715da14cebeSEric Cheng static char * 1716da14cebeSEric Cheng flowprop_callback(print_field_t *pf, void *fs_arg) 1717da14cebeSEric Cheng { 1718da14cebeSEric Cheng flowprop_args_t *arg = fs_arg; 1719da14cebeSEric Cheng char *propname = arg->fs_propname; 1720da14cebeSEric Cheng show_flowprop_state_t *statep = arg->fs_state; 1721da14cebeSEric Cheng char *ptr = statep->fs_line; 1722da14cebeSEric Cheng char *lim = ptr + MAX_PROP_LINE; 1723da14cebeSEric Cheng char *flowname = arg->fs_flowname; 1724da14cebeSEric Cheng 1725da14cebeSEric Cheng switch (pf->pf_index) { 1726da14cebeSEric Cheng case FLOWPROP_FLOW: 1727da14cebeSEric Cheng (void) snprintf(ptr, lim - ptr, "%s", statep->fs_flow); 1728da14cebeSEric Cheng break; 1729da14cebeSEric Cheng case FLOWPROP_PROPERTY: 1730da14cebeSEric Cheng (void) snprintf(ptr, lim - ptr, "%s", propname); 1731da14cebeSEric Cheng break; 1732da14cebeSEric Cheng case FLOWPROP_VALUE: 1733da14cebeSEric Cheng print_flowprop(flowname, statep, propname, 1734da14cebeSEric Cheng statep->fs_persist ? DLADM_PROP_VAL_PERSISTENT : 1735da14cebeSEric Cheng DLADM_PROP_VAL_CURRENT, "%s", &ptr); 1736da14cebeSEric Cheng /* 1737da14cebeSEric Cheng * If we failed to query the flow property, for example, query 1738da14cebeSEric Cheng * the persistent value of a non-persistable flow property, 1739da14cebeSEric Cheng * simply skip the output. 1740da14cebeSEric Cheng */ 1741da14cebeSEric Cheng if (statep->fs_status != DLADM_STATUS_OK) 1742da14cebeSEric Cheng goto skip; 1743da14cebeSEric Cheng ptr = statep->fs_line; 1744da14cebeSEric Cheng break; 1745da14cebeSEric Cheng case FLOWPROP_DEFAULT: 1746da14cebeSEric Cheng print_flowprop(flowname, statep, propname, 1747da14cebeSEric Cheng DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 1748da14cebeSEric Cheng if (statep->fs_status != DLADM_STATUS_OK) 1749da14cebeSEric Cheng goto skip; 1750da14cebeSEric Cheng ptr = statep->fs_line; 1751da14cebeSEric Cheng break; 1752da14cebeSEric Cheng case FLOWPROP_POSSIBLE: 1753da14cebeSEric Cheng print_flowprop(flowname, statep, propname, 1754da14cebeSEric Cheng DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 1755da14cebeSEric Cheng if (statep->fs_status != DLADM_STATUS_OK) 1756da14cebeSEric Cheng goto skip; 1757da14cebeSEric Cheng ptr = statep->fs_line; 1758da14cebeSEric Cheng break; 1759da14cebeSEric Cheng default: 1760da14cebeSEric Cheng die("invalid input"); 1761da14cebeSEric Cheng break; 1762da14cebeSEric Cheng } 1763da14cebeSEric Cheng return (ptr); 1764da14cebeSEric Cheng skip: 1765da14cebeSEric Cheng if (statep->fs_status != DLADM_STATUS_OK) 1766da14cebeSEric Cheng return (NULL); 1767da14cebeSEric Cheng else 1768da14cebeSEric Cheng return (""); 1769da14cebeSEric Cheng } 1770da14cebeSEric Cheng 1771da14cebeSEric Cheng static int 1772da14cebeSEric Cheng show_one_flowprop(void *arg, const char *propname) 1773da14cebeSEric Cheng { 1774da14cebeSEric Cheng show_flowprop_state_t *statep = arg; 1775da14cebeSEric Cheng flowprop_args_t fs_arg; 1776da14cebeSEric Cheng 1777da14cebeSEric Cheng bzero(&fs_arg, sizeof (fs_arg)); 1778da14cebeSEric Cheng fs_arg.fs_state = statep; 1779da14cebeSEric Cheng fs_arg.fs_propname = (char *)propname; 1780da14cebeSEric Cheng fs_arg.fs_flowname = (char *)statep->fs_flow; 1781da14cebeSEric Cheng 1782da14cebeSEric Cheng if (statep->fs_header) { 1783da14cebeSEric Cheng statep->fs_header = B_FALSE; 1784da14cebeSEric Cheng if (!statep ->fs_parseable) 1785da14cebeSEric Cheng print_header(&statep->fs_print); 1786da14cebeSEric Cheng } 1787da14cebeSEric Cheng flowadm_print_output(&statep->fs_print, statep->fs_parseable, 1788da14cebeSEric Cheng flowprop_callback, (void *)&fs_arg); 1789da14cebeSEric Cheng 1790da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1791da14cebeSEric Cheng } 1792da14cebeSEric Cheng 1793da14cebeSEric Cheng /* Walker function called by dladm_walk_flow to display flow properties */ 1794da14cebeSEric Cheng static int 1795da14cebeSEric Cheng show_flowprop(dladm_flow_attr_t *attr, void *arg) 1796da14cebeSEric Cheng { 1797da14cebeSEric Cheng show_flowprop_one_flow(arg, attr->fa_flowname); 1798da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1799da14cebeSEric Cheng } 1800da14cebeSEric Cheng 1801da14cebeSEric Cheng /* 1802da14cebeSEric Cheng * Wrapper of dladm_walk_flow(show_walk_fn,...) to make it 1803da14cebeSEric Cheng * usable to dladm_walk_datalink_id() 1804da14cebeSEric Cheng */ 1805da14cebeSEric Cheng static int 18064ac67f02SAnurag S. Maskey show_flowprop_onelink(dladm_handle_t dh, datalink_id_t linkid, void *arg) 1807da14cebeSEric Cheng { 1808da14cebeSEric Cheng char name[MAXLINKNAMELEN]; 1809da14cebeSEric Cheng 18104ac67f02SAnurag S. Maskey if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, name, 18114ac67f02SAnurag S. Maskey sizeof (name)) != DLADM_STATUS_OK) 1812da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 1813da14cebeSEric Cheng 18144ac67f02SAnurag S. Maskey (void) dladm_walk_flow(show_flowprop, dh, linkid, arg, B_FALSE); 1815da14cebeSEric Cheng 1816da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1817da14cebeSEric Cheng } 1818da14cebeSEric Cheng 1819da14cebeSEric Cheng static void 1820da14cebeSEric Cheng do_show_flowprop(int argc, char **argv) 1821da14cebeSEric Cheng { 1822da14cebeSEric Cheng int option; 1823ad091ee1SMichael Lim boolean_t o_arg = B_FALSE; 1824da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 1825da14cebeSEric Cheng show_flowprop_state_t state; 1826da14cebeSEric Cheng char *fields_str = NULL; 1827da14cebeSEric Cheng print_field_t **fields; 1828da14cebeSEric Cheng uint_t nfields; 1829da14cebeSEric Cheng char *all_fields = 1830da14cebeSEric Cheng "flow,property,value,default,possible"; 1831da14cebeSEric Cheng 1832da14cebeSEric Cheng fields_str = all_fields; 1833da14cebeSEric Cheng opterr = 0; 1834da14cebeSEric Cheng state.fs_propvals = NULL; 1835da14cebeSEric Cheng state.fs_line = NULL; 1836da14cebeSEric Cheng state.fs_parseable = B_FALSE; 1837da14cebeSEric Cheng state.fs_persist = B_FALSE; 1838da14cebeSEric Cheng state.fs_header = B_TRUE; 1839da14cebeSEric Cheng state.fs_retstatus = DLADM_STATUS_OK; 1840da14cebeSEric Cheng state.fs_linkid = DATALINK_INVALID_LINKID; 1841da14cebeSEric Cheng state.fs_flow = NULL; 1842da14cebeSEric Cheng 1843da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":p:cPl:o:", 1844da14cebeSEric Cheng prop_longopts, NULL)) != -1) { 1845da14cebeSEric Cheng switch (option) { 1846da14cebeSEric Cheng case 'p': 1847da14cebeSEric Cheng if (dladm_parse_flow_props(optarg, &proplist, B_TRUE) 1848da14cebeSEric Cheng != DLADM_STATUS_OK) 1849da14cebeSEric Cheng die("invalid flow properties specified"); 1850da14cebeSEric Cheng break; 1851da14cebeSEric Cheng case 'c': 1852da14cebeSEric Cheng state.fs_parseable = B_TRUE; 1853da14cebeSEric Cheng break; 1854da14cebeSEric Cheng case 'P': 1855da14cebeSEric Cheng state.fs_persist = B_TRUE; 1856da14cebeSEric Cheng break; 1857da14cebeSEric Cheng case 'l': 18584ac67f02SAnurag S. Maskey if (dladm_name2info(handle, optarg, &state.fs_linkid, 1859da14cebeSEric Cheng NULL, NULL, NULL) != DLADM_STATUS_OK) 1860da14cebeSEric Cheng die("invalid link '%s'", optarg); 1861da14cebeSEric Cheng break; 1862da14cebeSEric Cheng case 'o': 1863ad091ee1SMichael Lim o_arg = B_TRUE; 1864da14cebeSEric Cheng if (strcasecmp(optarg, "all") == 0) 1865da14cebeSEric Cheng fields_str = all_fields; 1866da14cebeSEric Cheng else 1867da14cebeSEric Cheng fields_str = optarg; 1868da14cebeSEric Cheng break; 1869da14cebeSEric Cheng default: 1870da14cebeSEric Cheng die_opterr(optopt, option); 1871da14cebeSEric Cheng break; 1872da14cebeSEric Cheng } 1873da14cebeSEric Cheng } 1874da14cebeSEric Cheng 1875ad091ee1SMichael Lim if (state.fs_parseable && !o_arg) 1876ad091ee1SMichael Lim die("-p requires -o"); 1877ad091ee1SMichael Lim 1878ad091ee1SMichael Lim if (state.fs_parseable && strcasecmp(fields_str, "all") == 0) 1879ad091ee1SMichael Lim die("\"-o all\" is invalid with -p"); 1880ad091ee1SMichael Lim 1881da14cebeSEric Cheng if (optind == (argc - 1)) { 1882da000602SGirish Moodalbail if (strlen(argv[optind]) >= MAXFLOWNAMELEN) 1883da14cebeSEric Cheng die("flow name too long"); 1884da14cebeSEric Cheng state.fs_flow = argv[optind]; 1885da14cebeSEric Cheng } else if (optind != argc) { 1886da14cebeSEric Cheng usage(); 1887da14cebeSEric Cheng } 1888da14cebeSEric Cheng bzero(&state.fs_print, sizeof (print_state_t)); 1889da14cebeSEric Cheng state.fs_proplist = proplist; 1890da14cebeSEric Cheng state.fs_status = DLADM_STATUS_OK; 1891da14cebeSEric Cheng 1892da14cebeSEric Cheng fields = parse_output_fields(fields_str, flowprop_fields, 1893da14cebeSEric Cheng FLOWPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 1894da14cebeSEric Cheng 1895da14cebeSEric Cheng if (fields == NULL) { 1896da14cebeSEric Cheng die("invalid field(s) specified"); 1897da14cebeSEric Cheng return; 1898da14cebeSEric Cheng } 1899da14cebeSEric Cheng 1900da14cebeSEric Cheng state.fs_print.ps_fields = fields; 1901da14cebeSEric Cheng state.fs_print.ps_nfields = nfields; 1902da14cebeSEric Cheng 1903da14cebeSEric Cheng /* Show properties for one flow */ 1904da14cebeSEric Cheng if (state.fs_flow != NULL) { 1905da14cebeSEric Cheng show_flowprop_one_flow(&state, state.fs_flow); 1906da14cebeSEric Cheng 1907da14cebeSEric Cheng /* Show properties for all flows on one link */ 1908da14cebeSEric Cheng } else if (state.fs_linkid != DATALINK_INVALID_LINKID) { 19094ac67f02SAnurag S. Maskey (void) show_flowprop_onelink(handle, state.fs_linkid, &state); 1910da14cebeSEric Cheng 1911da14cebeSEric Cheng /* Show properties for all flows on all links */ 1912da14cebeSEric Cheng } else { 19134ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(show_flowprop_onelink, handle, 19144ac67f02SAnurag S. Maskey &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 1915da14cebeSEric Cheng DLADM_OPT_ACTIVE); 1916da14cebeSEric Cheng } 1917da14cebeSEric Cheng 1918da14cebeSEric Cheng dladm_free_props(proplist); 1919da14cebeSEric Cheng } 1920da14cebeSEric Cheng 1921da14cebeSEric Cheng static void 1922da14cebeSEric Cheng show_flowprop_one_flow(void *arg, const char *flow) 1923da14cebeSEric Cheng { 1924da14cebeSEric Cheng int i; 1925da14cebeSEric Cheng char *buf; 1926da14cebeSEric Cheng dladm_status_t status; 1927da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 1928da14cebeSEric Cheng show_flowprop_state_t *statep = arg; 1929da14cebeSEric Cheng dladm_flow_attr_t attr; 1930da14cebeSEric Cheng const char *savep; 1931da14cebeSEric Cheng 1932da14cebeSEric Cheng /* 1933da14cebeSEric Cheng * Do not print flow props for invalid flows. 1934da14cebeSEric Cheng */ 19354ac67f02SAnurag S. Maskey if ((status = dladm_flow_info(handle, flow, &attr)) != 19364ac67f02SAnurag S. Maskey DLADM_STATUS_OK) { 1937da14cebeSEric Cheng die("invalid flow: '%s'", flow); 1938da14cebeSEric Cheng } 1939da14cebeSEric Cheng 1940da14cebeSEric Cheng savep = statep->fs_flow; 1941da14cebeSEric Cheng statep->fs_flow = flow; 1942da14cebeSEric Cheng 1943da14cebeSEric Cheng proplist = statep->fs_proplist; 1944da14cebeSEric Cheng 1945da14cebeSEric Cheng buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) 1946da14cebeSEric Cheng * DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 1947da14cebeSEric Cheng if (buf == NULL) 1948da14cebeSEric Cheng die("insufficient memory"); 1949da14cebeSEric Cheng 1950da14cebeSEric Cheng statep->fs_propvals = (char **)(void *)buf; 1951da14cebeSEric Cheng for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 1952da14cebeSEric Cheng statep->fs_propvals[i] = buf + 1953da14cebeSEric Cheng sizeof (char *) * DLADM_MAX_PROP_VALCNT + 1954da14cebeSEric Cheng i * DLADM_PROP_VAL_MAX; 1955da14cebeSEric Cheng } 1956da14cebeSEric Cheng statep->fs_line = buf + 1957da14cebeSEric Cheng (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 1958da14cebeSEric Cheng 1959da14cebeSEric Cheng /* show only specified flow properties */ 1960da14cebeSEric Cheng if (proplist != NULL) { 1961da14cebeSEric Cheng for (i = 0; i < proplist->al_count; i++) { 1962da14cebeSEric Cheng if (show_one_flowprop(statep, 1963da14cebeSEric Cheng proplist->al_info[i].ai_name) != DLADM_STATUS_OK) 1964da14cebeSEric Cheng break; 1965da14cebeSEric Cheng } 1966da14cebeSEric Cheng 1967da14cebeSEric Cheng /* show all flow properties */ 1968da14cebeSEric Cheng } else { 1969da14cebeSEric Cheng status = dladm_walk_flowprop(show_one_flowprop, flow, statep); 1970da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 1971da14cebeSEric Cheng die_dlerr(status, "show-flowprop"); 1972da14cebeSEric Cheng } 1973da14cebeSEric Cheng free(buf); 1974da14cebeSEric Cheng statep->fs_flow = savep; 1975da14cebeSEric Cheng } 1976da14cebeSEric Cheng 1977da14cebeSEric Cheng typedef struct { 1978da14cebeSEric Cheng char *s_buf; 1979da14cebeSEric Cheng char **s_fields; /* array of pointer to the fields in s_buf */ 1980da14cebeSEric Cheng uint_t s_nfields; /* the number of fields in s_buf */ 1981da14cebeSEric Cheng } split_t; 1982da14cebeSEric Cheng 1983da14cebeSEric Cheng /* 1984da14cebeSEric Cheng * Free the split_t structure pointed to by `sp'. 1985da14cebeSEric Cheng */ 1986da14cebeSEric Cheng static void 1987da14cebeSEric Cheng splitfree(split_t *sp) 1988da14cebeSEric Cheng { 1989da14cebeSEric Cheng free(sp->s_buf); 1990da14cebeSEric Cheng free(sp->s_fields); 1991da14cebeSEric Cheng free(sp); 1992da14cebeSEric Cheng } 1993da14cebeSEric Cheng 1994da14cebeSEric Cheng /* 1995da14cebeSEric Cheng * Split `str' into at most `maxfields' fields, each field at most `maxlen' in 1996da14cebeSEric Cheng * length. Return a pointer to a split_t containing the split fields, or NULL 1997da14cebeSEric Cheng * on failure. 1998da14cebeSEric Cheng */ 1999da14cebeSEric Cheng static split_t * 2000da14cebeSEric Cheng split(const char *str, uint_t maxfields, uint_t maxlen) 2001da14cebeSEric Cheng { 2002da14cebeSEric Cheng char *field, *token, *lasts = NULL; 2003da14cebeSEric Cheng split_t *sp; 2004da14cebeSEric Cheng 2005da14cebeSEric Cheng if (*str == '\0' || maxfields == 0 || maxlen == 0) 2006da14cebeSEric Cheng return (NULL); 2007da14cebeSEric Cheng 2008da14cebeSEric Cheng sp = calloc(sizeof (split_t), 1); 2009da14cebeSEric Cheng if (sp == NULL) 2010da14cebeSEric Cheng return (NULL); 2011da14cebeSEric Cheng 2012da14cebeSEric Cheng sp->s_buf = strdup(str); 2013da14cebeSEric Cheng sp->s_fields = malloc(sizeof (char *) * maxfields); 2014da14cebeSEric Cheng if (sp->s_buf == NULL || sp->s_fields == NULL) 2015da14cebeSEric Cheng goto fail; 2016da14cebeSEric Cheng 2017da14cebeSEric Cheng token = sp->s_buf; 2018da14cebeSEric Cheng while ((field = strtok_r(token, ",", &lasts)) != NULL) { 2019da14cebeSEric Cheng if (sp->s_nfields == maxfields || strlen(field) > maxlen) 2020da14cebeSEric Cheng goto fail; 2021da14cebeSEric Cheng token = NULL; 2022da14cebeSEric Cheng sp->s_fields[sp->s_nfields++] = field; 2023da14cebeSEric Cheng } 2024da14cebeSEric Cheng return (sp); 2025da14cebeSEric Cheng fail: 2026da14cebeSEric Cheng splitfree(sp); 2027da14cebeSEric Cheng return (NULL); 2028da14cebeSEric Cheng } 2029da14cebeSEric Cheng 2030da14cebeSEric Cheng static print_field_t ** 2031da14cebeSEric Cheng parse_output_fields(char *str, print_field_t *template, int max_fields, 2032da14cebeSEric Cheng uint_t cmdtype, uint_t *countp) 2033da14cebeSEric Cheng { 2034da14cebeSEric Cheng split_t *sp; 2035da14cebeSEric Cheng boolean_t good_match = B_FALSE; 2036da14cebeSEric Cheng uint_t i, j; 2037da14cebeSEric Cheng print_field_t **pf = NULL; 2038da14cebeSEric Cheng 2039da14cebeSEric Cheng sp = split(str, max_fields, MAX_FIELD_LEN); 2040da14cebeSEric Cheng 2041da14cebeSEric Cheng if (sp == NULL) 2042da14cebeSEric Cheng return (NULL); 2043da14cebeSEric Cheng 2044da14cebeSEric Cheng pf = malloc(sp->s_nfields * sizeof (print_field_t *)); 2045da14cebeSEric Cheng if (pf == NULL) 2046da14cebeSEric Cheng goto fail; 2047da14cebeSEric Cheng 2048da14cebeSEric Cheng for (i = 0; i < sp->s_nfields; i++) { 2049da14cebeSEric Cheng for (j = 0; j < max_fields; j++) { 2050da14cebeSEric Cheng if (strcasecmp(sp->s_fields[i], 2051da14cebeSEric Cheng template[j].pf_name) == 0) { 2052da14cebeSEric Cheng good_match = template[j]. pf_cmdtype & cmdtype; 2053da14cebeSEric Cheng break; 2054da14cebeSEric Cheng } 2055da14cebeSEric Cheng } 2056da14cebeSEric Cheng if (!good_match) 2057da14cebeSEric Cheng goto fail; 2058da14cebeSEric Cheng 2059da14cebeSEric Cheng good_match = B_FALSE; 2060da14cebeSEric Cheng pf[i] = &template[j]; 2061da14cebeSEric Cheng } 2062da14cebeSEric Cheng *countp = i; 2063da14cebeSEric Cheng splitfree(sp); 2064da14cebeSEric Cheng return (pf); 2065da14cebeSEric Cheng fail: 2066da14cebeSEric Cheng free(pf); 2067da14cebeSEric Cheng splitfree(sp); 2068da14cebeSEric Cheng return (NULL); 2069da14cebeSEric Cheng } 2070da14cebeSEric Cheng 2071da14cebeSEric Cheng static void 2072da14cebeSEric Cheng flowadm_print_output(print_state_t *statep, boolean_t parseable, 2073da14cebeSEric Cheng print_callback_t fn, void *arg) 2074da14cebeSEric Cheng { 2075da14cebeSEric Cheng int i; 2076da14cebeSEric Cheng char *value; 2077da14cebeSEric Cheng print_field_t **pf; 2078da14cebeSEric Cheng 2079da14cebeSEric Cheng pf = statep->ps_fields; 2080da14cebeSEric Cheng for (i = 0; i < statep->ps_nfields; i++) { 2081da14cebeSEric Cheng statep->ps_lastfield = (i + 1 == statep->ps_nfields); 2082da14cebeSEric Cheng value = (*fn)(pf[i], arg); 2083da14cebeSEric Cheng if (value != NULL) 2084da14cebeSEric Cheng print_field(statep, pf[i], value, parseable); 2085da14cebeSEric Cheng } 2086da14cebeSEric Cheng (void) putchar('\n'); 2087da14cebeSEric Cheng } 2088da14cebeSEric Cheng 2089da14cebeSEric Cheng static void 2090da14cebeSEric Cheng print_header(print_state_t *ps) 2091da14cebeSEric Cheng { 2092da14cebeSEric Cheng int i; 2093da14cebeSEric Cheng print_field_t **pf; 2094da14cebeSEric Cheng 2095da14cebeSEric Cheng pf = ps->ps_fields; 2096da14cebeSEric Cheng for (i = 0; i < ps->ps_nfields; i++) { 2097da14cebeSEric Cheng ps->ps_lastfield = (i + 1 == ps->ps_nfields); 2098da14cebeSEric Cheng print_field(ps, pf[i], pf[i]->pf_header, B_FALSE); 2099da14cebeSEric Cheng } 2100da14cebeSEric Cheng (void) putchar('\n'); 2101da14cebeSEric Cheng } 2102da14cebeSEric Cheng 2103da14cebeSEric Cheng static void 2104da14cebeSEric Cheng print_field(print_state_t *statep, print_field_t *pfp, const char *value, 2105da14cebeSEric Cheng boolean_t parseable) 2106da14cebeSEric Cheng { 2107da14cebeSEric Cheng uint_t width = pfp->pf_width; 2108ad091ee1SMichael Lim uint_t valwidth; 2109da14cebeSEric Cheng uint_t compress; 2110da14cebeSEric Cheng 2111ad091ee1SMichael Lim /* 2112ad091ee1SMichael Lim * Parsable fields are separated by ':'. If such a field contains 2113ad091ee1SMichael Lim * a ':' or '\', this character is prefixed by a '\'. 2114ad091ee1SMichael Lim */ 2115da14cebeSEric Cheng if (parseable) { 2116ad091ee1SMichael Lim char c; 2117ad091ee1SMichael Lim 2118ad091ee1SMichael Lim if (statep->ps_nfields == 1) { 2119ad091ee1SMichael Lim (void) printf("%s", value); 2120ad091ee1SMichael Lim return; 2121ad091ee1SMichael Lim } 2122ad091ee1SMichael Lim while ((c = *value++) != '\0') { 2123ad091ee1SMichael Lim if (c == ':' || c == '\\') 2124ad091ee1SMichael Lim (void) putchar('\\'); 2125ad091ee1SMichael Lim (void) putchar(c); 2126ad091ee1SMichael Lim } 2127ad091ee1SMichael Lim if (!statep->ps_lastfield) 2128ad091ee1SMichael Lim (void) putchar(':'); 2129ad091ee1SMichael Lim return; 2130da14cebeSEric Cheng } else { 2131da14cebeSEric Cheng if (value[0] == '\0') 2132da14cebeSEric Cheng value = STR_UNDEF_VAL; 2133da14cebeSEric Cheng if (statep->ps_lastfield) { 2134da14cebeSEric Cheng (void) printf("%s", value); 2135ad091ee1SMichael Lim statep->ps_overflow = 0; 2136da14cebeSEric Cheng return; 2137da14cebeSEric Cheng } 2138da14cebeSEric Cheng 2139ad091ee1SMichael Lim valwidth = strlen(value); 2140da14cebeSEric Cheng if (valwidth > width) { 2141da14cebeSEric Cheng statep->ps_overflow += valwidth - width; 2142da14cebeSEric Cheng } else if (valwidth < width && statep->ps_overflow > 0) { 2143da14cebeSEric Cheng compress = min(statep->ps_overflow, width - valwidth); 2144da14cebeSEric Cheng statep->ps_overflow -= compress; 2145da14cebeSEric Cheng width -= compress; 2146da14cebeSEric Cheng } 2147da14cebeSEric Cheng (void) printf("%-*s", width, value); 2148da14cebeSEric Cheng } 2149da14cebeSEric Cheng 2150da14cebeSEric Cheng if (!statep->ps_lastfield) 2151da14cebeSEric Cheng (void) putchar(' '); 2152da14cebeSEric Cheng } 2153