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 /* 22*0dc2366fSVenugopal Iyer * Copyright 2010 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 <strings.h> 35da14cebeSEric Cheng #include <getopt.h> 36da14cebeSEric Cheng #include <unistd.h> 37da14cebeSEric Cheng #include <priv.h> 38da14cebeSEric Cheng #include <netdb.h> 39da14cebeSEric Cheng #include <libintl.h> 40da14cebeSEric Cheng #include <libdlflow.h> 41da14cebeSEric Cheng #include <libdllink.h> 42da14cebeSEric Cheng #include <libdlstat.h> 43da14cebeSEric Cheng #include <sys/types.h> 44da14cebeSEric Cheng #include <sys/socket.h> 45da14cebeSEric Cheng #include <netinet/in.h> 46da14cebeSEric Cheng #include <arpa/inet.h> 47da14cebeSEric Cheng #include <sys/ethernet.h> 48da14cebeSEric Cheng #include <inet/ip.h> 49da14cebeSEric Cheng #include <inet/ip6.h> 50da14cebeSEric Cheng #include <stddef.h> 518002d411SSowmini Varadhan #include <ofmt.h> 52da14cebeSEric Cheng 53ae6aa22aSVenugopal Iyer typedef struct show_flow_state { 54ae6aa22aSVenugopal Iyer dladm_status_t fs_status; 558002d411SSowmini Varadhan ofmt_handle_t fs_ofmt; 56ae6aa22aSVenugopal Iyer const char *fs_flow; 578002d411SSowmini Varadhan boolean_t fs_parsable; 58ae6aa22aSVenugopal Iyer boolean_t fs_persist; 59ae6aa22aSVenugopal Iyer } show_flow_state_t; 60ae6aa22aSVenugopal Iyer 61da14cebeSEric Cheng typedef void cmdfunc_t(int, char **); 62da14cebeSEric Cheng 63da14cebeSEric Cheng static cmdfunc_t do_add_flow, do_remove_flow, do_init_flow, do_show_flow; 64da14cebeSEric Cheng static cmdfunc_t do_show_flowprop, do_set_flowprop, do_reset_flowprop; 65da14cebeSEric Cheng 66c3affd82SMichael Lim static int show_flow(dladm_handle_t, dladm_flow_attr_t *, void *); 674ac67f02SAnurag S. Maskey static int show_flows_onelink(dladm_handle_t, datalink_id_t, void *); 68da14cebeSEric Cheng 69c3affd82SMichael Lim static int remove_flow(dladm_handle_t, dladm_flow_attr_t *, void *); 70da14cebeSEric Cheng 71c3affd82SMichael Lim static int show_flowprop(dladm_handle_t, dladm_flow_attr_t *, void *); 72da14cebeSEric Cheng static void show_flowprop_one_flow(void *, const char *); 734ac67f02SAnurag S. Maskey static int show_flowprop_onelink(dladm_handle_t, datalink_id_t, void *); 74da14cebeSEric Cheng 75da14cebeSEric Cheng static void die(const char *, ...); 76da14cebeSEric Cheng static void die_optdup(int); 77da14cebeSEric Cheng static void die_opterr(int, int); 78da14cebeSEric Cheng static void die_dlerr(dladm_status_t, const char *, ...); 79da14cebeSEric Cheng static void warn(const char *, ...); 80da14cebeSEric Cheng static void warn_dlerr(dladm_status_t, const char *, ...); 81da14cebeSEric Cheng 828002d411SSowmini Varadhan /* callback functions for printing output */ 83*0dc2366fSVenugopal Iyer static ofmt_cb_t print_flowprop_cb, print_default_cb; 848002d411SSowmini Varadhan static void flowadm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t); 858002d411SSowmini Varadhan 86da14cebeSEric Cheng typedef struct cmd { 87da14cebeSEric Cheng char *c_name; 88da14cebeSEric Cheng void (*c_fn)(int, char **); 89da14cebeSEric Cheng } cmd_t; 90da14cebeSEric Cheng 91da14cebeSEric Cheng static cmd_t cmds[] = { 92da14cebeSEric Cheng { "add-flow", do_add_flow }, 93da14cebeSEric Cheng { "remove-flow", do_remove_flow }, 94da14cebeSEric Cheng { "show-flowprop", do_show_flowprop }, 95da14cebeSEric Cheng { "set-flowprop", do_set_flowprop }, 96da14cebeSEric Cheng { "reset-flowprop", do_reset_flowprop }, 97da14cebeSEric Cheng { "show-flow", do_show_flow }, 98da14cebeSEric Cheng { "init-flow", do_init_flow }, 99da14cebeSEric Cheng }; 100da14cebeSEric Cheng 101da14cebeSEric Cheng static const struct option longopts[] = { 102da14cebeSEric Cheng {"link", required_argument, 0, 'l'}, 1038002d411SSowmini Varadhan {"parsable", no_argument, 0, 'p'}, 104da14cebeSEric Cheng {"parseable", no_argument, 0, 'p'}, 105da14cebeSEric Cheng {"temporary", no_argument, 0, 't'}, 106da14cebeSEric Cheng {"root-dir", required_argument, 0, 'R'}, 107da14cebeSEric Cheng { 0, 0, 0, 0 } 108da14cebeSEric Cheng }; 109da14cebeSEric Cheng 110da14cebeSEric Cheng static const struct option prop_longopts[] = { 111da14cebeSEric Cheng {"link", required_argument, 0, 'l'}, 112da14cebeSEric Cheng {"temporary", no_argument, 0, 't'}, 113da14cebeSEric Cheng {"root-dir", required_argument, 0, 'R'}, 114da14cebeSEric Cheng {"prop", required_argument, 0, 'p'}, 115da14cebeSEric Cheng {"attr", required_argument, 0, 'a'}, 116da14cebeSEric Cheng { 0, 0, 0, 0 } 117da14cebeSEric Cheng }; 118da14cebeSEric Cheng 119da14cebeSEric Cheng /* 120da14cebeSEric Cheng * structures for 'flowadm remove-flow' 121da14cebeSEric Cheng */ 122da14cebeSEric Cheng typedef struct remove_flow_state { 123da14cebeSEric Cheng boolean_t fs_tempop; 124da14cebeSEric Cheng const char *fs_altroot; 125da14cebeSEric Cheng dladm_status_t fs_status; 126da14cebeSEric Cheng } remove_flow_state_t; 127da14cebeSEric Cheng 128da14cebeSEric Cheng #define PROTO_MAXSTR_LEN 7 129da14cebeSEric Cheng #define PORT_MAXSTR_LEN 6 130da14cebeSEric Cheng #define DSFIELD_MAXSTR_LEN 10 1318002d411SSowmini Varadhan #define NULL_OFMT {NULL, 0, 0, NULL} 132da14cebeSEric Cheng 133da14cebeSEric Cheng typedef struct flow_fields_buf_s 134da14cebeSEric Cheng { 135da000602SGirish Moodalbail char flow_name[MAXFLOWNAMELEN]; 136da14cebeSEric Cheng char flow_link[MAXLINKNAMELEN]; 137da14cebeSEric Cheng char flow_ipaddr[INET6_ADDRSTRLEN+4]; 138da14cebeSEric Cheng char flow_proto[PROTO_MAXSTR_LEN]; 13925ec3e3dSEric Cheng char flow_lport[PORT_MAXSTR_LEN]; 14025ec3e3dSEric Cheng char flow_rport[PORT_MAXSTR_LEN]; 141da14cebeSEric Cheng char flow_dsfield[DSFIELD_MAXSTR_LEN]; 142da14cebeSEric Cheng } flow_fields_buf_t; 143da14cebeSEric Cheng 1448002d411SSowmini Varadhan static ofmt_field_t flow_fields[] = { 1458002d411SSowmini Varadhan /* name, field width, index */ 1468002d411SSowmini Varadhan { "FLOW", 12, 1478002d411SSowmini Varadhan offsetof(flow_fields_buf_t, flow_name), print_default_cb}, 1488002d411SSowmini Varadhan { "LINK", 12, 1498002d411SSowmini Varadhan offsetof(flow_fields_buf_t, flow_link), print_default_cb}, 15025ec3e3dSEric Cheng { "IPADDR", 25, 1518002d411SSowmini Varadhan offsetof(flow_fields_buf_t, flow_ipaddr), print_default_cb}, 1528002d411SSowmini Varadhan { "PROTO", 7, 1538002d411SSowmini Varadhan offsetof(flow_fields_buf_t, flow_proto), print_default_cb}, 15425ec3e3dSEric Cheng { "LPORT", 8, 15525ec3e3dSEric Cheng offsetof(flow_fields_buf_t, flow_lport), print_default_cb}, 15625ec3e3dSEric Cheng { "RPORT", 8, 15725ec3e3dSEric Cheng offsetof(flow_fields_buf_t, flow_rport), print_default_cb}, 1588002d411SSowmini Varadhan { "DSFLD", 10, 1598002d411SSowmini Varadhan offsetof(flow_fields_buf_t, flow_dsfield), print_default_cb}, 1608002d411SSowmini Varadhan NULL_OFMT} 161da14cebeSEric Cheng ; 162da14cebeSEric Cheng 163da14cebeSEric Cheng /* 164da14cebeSEric Cheng * structures for 'flowadm show-flowprop' 165da14cebeSEric Cheng */ 166da14cebeSEric Cheng typedef enum { 167da14cebeSEric Cheng FLOWPROP_FLOW, 168da14cebeSEric Cheng FLOWPROP_PROPERTY, 169da14cebeSEric Cheng FLOWPROP_VALUE, 170da14cebeSEric Cheng FLOWPROP_DEFAULT, 171da14cebeSEric Cheng FLOWPROP_POSSIBLE 172da14cebeSEric Cheng } flowprop_field_index_t; 173da14cebeSEric Cheng 1748002d411SSowmini Varadhan static ofmt_field_t flowprop_fields[] = { 1758002d411SSowmini Varadhan /* name, fieldwidth, index, callback */ 1768002d411SSowmini Varadhan { "FLOW", 13, FLOWPROP_FLOW, print_flowprop_cb}, 1778002d411SSowmini Varadhan { "PROPERTY", 16, FLOWPROP_PROPERTY, print_flowprop_cb}, 1788002d411SSowmini Varadhan { "VALUE", 15, FLOWPROP_VALUE, print_flowprop_cb}, 1798002d411SSowmini Varadhan { "DEFAULT", 15, FLOWPROP_DEFAULT, print_flowprop_cb}, 1808002d411SSowmini Varadhan { "POSSIBLE", 21, FLOWPROP_POSSIBLE, print_flowprop_cb}, 1818002d411SSowmini Varadhan NULL_OFMT} 182da14cebeSEric Cheng ; 183da14cebeSEric Cheng 184da14cebeSEric Cheng #define MAX_PROP_LINE 512 185da14cebeSEric Cheng 186da14cebeSEric Cheng typedef struct show_flowprop_state { 187da14cebeSEric Cheng const char *fs_flow; 188da14cebeSEric Cheng datalink_id_t fs_linkid; 189da14cebeSEric Cheng char *fs_line; 190da14cebeSEric Cheng char **fs_propvals; 191da14cebeSEric Cheng dladm_arg_list_t *fs_proplist; 1928002d411SSowmini Varadhan boolean_t fs_parsable; 193da14cebeSEric Cheng boolean_t fs_persist; 194da14cebeSEric Cheng boolean_t fs_header; 195da14cebeSEric Cheng dladm_status_t fs_status; 196da14cebeSEric Cheng dladm_status_t fs_retstatus; 1978002d411SSowmini Varadhan ofmt_handle_t fs_ofmt; 198da14cebeSEric Cheng } show_flowprop_state_t; 199da14cebeSEric Cheng 200da14cebeSEric Cheng typedef struct set_flowprop_state { 201da14cebeSEric Cheng const char *fs_name; 202da14cebeSEric Cheng boolean_t fs_reset; 203da14cebeSEric Cheng boolean_t fs_temp; 204da14cebeSEric Cheng dladm_status_t fs_status; 205da14cebeSEric Cheng } set_flowprop_state_t; 206da14cebeSEric Cheng 207da14cebeSEric Cheng typedef struct flowprop_args_s { 208da14cebeSEric Cheng show_flowprop_state_t *fs_state; 209da14cebeSEric Cheng char *fs_propname; 210da14cebeSEric Cheng char *fs_flowname; 211da14cebeSEric Cheng } flowprop_args_t; 212da14cebeSEric Cheng 213da14cebeSEric Cheng static char *progname; 214da14cebeSEric Cheng 215da14cebeSEric Cheng boolean_t t_arg = B_FALSE; /* changes are persistent */ 216da14cebeSEric Cheng char *altroot = NULL; 217da14cebeSEric Cheng 2184ac67f02SAnurag S. Maskey /* 2194ac67f02SAnurag S. Maskey * Handle to libdladm. Opened in main() before the sub-command 2204ac67f02SAnurag S. Maskey * specific function is called. 2214ac67f02SAnurag S. Maskey */ 2224ac67f02SAnurag S. Maskey static dladm_handle_t handle = NULL; 2234ac67f02SAnurag S. Maskey 224da14cebeSEric Cheng static const char *attr_table[] = 22525ec3e3dSEric Cheng {"local_ip", "remote_ip", "transport", "local_port", "remote_port", 22625ec3e3dSEric Cheng "dsfield"}; 227da14cebeSEric Cheng 228da14cebeSEric Cheng #define NATTR (sizeof (attr_table)/sizeof (char *)) 229da14cebeSEric Cheng 230da14cebeSEric Cheng static void 231da14cebeSEric Cheng usage(void) 232da14cebeSEric Cheng { 233da14cebeSEric Cheng (void) fprintf(stderr, gettext("usage: flowadm <subcommand>" 234da14cebeSEric Cheng " <args>...\n" 2350790b6dcSAnurag S. Maskey " add-flow [-t] -l <link> -a <attr>=<value>[,...]\n" 2360790b6dcSAnurag S. Maskey "\t\t [-p <prop>=<value>,...] <flow>\n" 2370790b6dcSAnurag S. Maskey " remove-flow [-t] {-l <link> | <flow>}\n" 238*0dc2366fSVenugopal Iyer " show-flow [-p] [-l <link>] " 2390790b6dcSAnurag S. Maskey "[<flow>]\n\n" 2400790b6dcSAnurag S. Maskey " set-flowprop [-t] -p <prop>=<value>[,...] <flow>\n" 2410790b6dcSAnurag S. Maskey " reset-flowprop [-t] [-p <prop>,...] <flow>\n" 2420790b6dcSAnurag S. Maskey " show-flowprop [-cP] [-l <link>] [-p <prop>,...] " 243*0dc2366fSVenugopal Iyer "[<flow>]\n")); 2444ac67f02SAnurag S. Maskey 2454ac67f02SAnurag S. Maskey /* close dladm handle if it was opened */ 2464ac67f02SAnurag S. Maskey if (handle != NULL) 2474ac67f02SAnurag S. Maskey dladm_close(handle); 2484ac67f02SAnurag S. Maskey 249da14cebeSEric Cheng exit(1); 250da14cebeSEric Cheng } 251da14cebeSEric Cheng 252da14cebeSEric Cheng int 253da14cebeSEric Cheng main(int argc, char *argv[]) 254da14cebeSEric Cheng { 255da14cebeSEric Cheng int i, arglen, cmdlen; 256da14cebeSEric Cheng cmd_t *cmdp; 2574ac67f02SAnurag S. Maskey dladm_status_t status; 258da14cebeSEric Cheng 259da14cebeSEric Cheng (void) setlocale(LC_ALL, ""); 260da14cebeSEric Cheng #if !defined(TEXT_DOMAIN) 261da14cebeSEric Cheng #define TEXT_DOMAIN "SYS_TEST" 262da14cebeSEric Cheng #endif 263da14cebeSEric Cheng (void) textdomain(TEXT_DOMAIN); 264da14cebeSEric Cheng 265da14cebeSEric Cheng progname = argv[0]; 266da14cebeSEric Cheng 267da14cebeSEric Cheng if (argc < 2) 268da14cebeSEric Cheng usage(); 269da14cebeSEric Cheng 270da14cebeSEric Cheng for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 271da14cebeSEric Cheng cmdp = &cmds[i]; 272da14cebeSEric Cheng arglen = strlen(argv[1]); 273da14cebeSEric Cheng cmdlen = strlen(cmdp->c_name); 274da14cebeSEric Cheng if ((arglen == cmdlen) && (strncmp(argv[1], cmdp->c_name, 275da14cebeSEric Cheng cmdlen) == 0)) { 2764ac67f02SAnurag S. Maskey /* Open the libdladm handle */ 2774ac67f02SAnurag S. Maskey if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) { 2784ac67f02SAnurag S. Maskey die_dlerr(status, 2794ac67f02SAnurag S. Maskey "could not open /dev/dld"); 2804ac67f02SAnurag S. Maskey } 2814ac67f02SAnurag S. Maskey 282da14cebeSEric Cheng cmdp->c_fn(argc - 1, &argv[1]); 2834ac67f02SAnurag S. Maskey 2844ac67f02SAnurag S. Maskey dladm_close(handle); 285ad091ee1SMichael Lim exit(EXIT_SUCCESS); 286da14cebeSEric Cheng } 287da14cebeSEric Cheng } 288da14cebeSEric Cheng 289da14cebeSEric Cheng (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 290da14cebeSEric Cheng progname, argv[1]); 291da14cebeSEric Cheng usage(); 292da14cebeSEric Cheng 293da14cebeSEric Cheng return (0); 294da14cebeSEric Cheng } 295da14cebeSEric Cheng 296da14cebeSEric Cheng static const char * 297da14cebeSEric Cheng match_attr(char *attr) 298da14cebeSEric Cheng { 299da14cebeSEric Cheng int i; 300da14cebeSEric Cheng 301da14cebeSEric Cheng for (i = 0; i < NATTR; i++) { 302da14cebeSEric Cheng if (strlen(attr) == strlen(attr_table[i]) && 303da14cebeSEric Cheng strncmp(attr, attr_table[i], strlen(attr_table[i])) == 0) { 304da14cebeSEric Cheng return (attr); 305da14cebeSEric Cheng } 306da14cebeSEric Cheng } 307da14cebeSEric Cheng return (NULL); 308da14cebeSEric Cheng } 309da14cebeSEric Cheng 310da14cebeSEric Cheng /* ARGSUSED */ 311da14cebeSEric Cheng static void 312da14cebeSEric Cheng do_init_flow(int argc, char *argv[]) 313da14cebeSEric Cheng { 314da14cebeSEric Cheng dladm_status_t status; 315da14cebeSEric Cheng 3164ac67f02SAnurag S. Maskey status = dladm_flow_init(handle); 317da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 318da14cebeSEric Cheng die_dlerr(status, "flows initialization failed"); 319da14cebeSEric Cheng } 320da14cebeSEric Cheng 321da14cebeSEric Cheng static void 322da14cebeSEric Cheng do_add_flow(int argc, char *argv[]) 323da14cebeSEric Cheng { 324da000602SGirish Moodalbail char devname[MAXLINKNAMELEN]; 325da14cebeSEric Cheng char *name = NULL; 326da14cebeSEric Cheng uint_t index; 327da14cebeSEric Cheng datalink_id_t linkid; 328da14cebeSEric Cheng 329da14cebeSEric Cheng char option; 330da14cebeSEric Cheng boolean_t l_arg = B_FALSE; 33163a6526dSMichael Lim char propstr[DLADM_STRSIZE]; 33263a6526dSMichael Lim char attrstr[DLADM_STRSIZE]; 333da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 334da14cebeSEric Cheng dladm_arg_list_t *attrlist = NULL; 335da14cebeSEric Cheng dladm_status_t status; 336da14cebeSEric Cheng 33763a6526dSMichael Lim bzero(propstr, DLADM_STRSIZE); 33863a6526dSMichael Lim bzero(attrstr, DLADM_STRSIZE); 33963a6526dSMichael Lim 340da14cebeSEric Cheng while ((option = getopt_long(argc, argv, "tR:l:a:p:", 341da14cebeSEric Cheng prop_longopts, NULL)) != -1) { 342da14cebeSEric Cheng switch (option) { 343da14cebeSEric Cheng case 't': 344da14cebeSEric Cheng t_arg = B_TRUE; 345da14cebeSEric Cheng break; 346da14cebeSEric Cheng case 'R': 347da14cebeSEric Cheng altroot = optarg; 348da14cebeSEric Cheng break; 349da14cebeSEric Cheng case 'l': 350da14cebeSEric Cheng if (strlcpy(devname, optarg, 351da000602SGirish Moodalbail MAXLINKNAMELEN) >= MAXLINKNAMELEN) { 352da14cebeSEric Cheng die("link name too long"); 353da14cebeSEric Cheng } 3544ac67f02SAnurag S. Maskey if (dladm_name2info(handle, devname, &linkid, NULL, 355da14cebeSEric Cheng NULL, NULL) != DLADM_STATUS_OK) 356da14cebeSEric Cheng die("invalid link '%s'", devname); 357da14cebeSEric Cheng l_arg = B_TRUE; 358da14cebeSEric Cheng break; 359da14cebeSEric Cheng case 'a': 36063a6526dSMichael Lim (void) strlcat(attrstr, optarg, DLADM_STRSIZE); 36163a6526dSMichael Lim if (strlcat(attrstr, ",", DLADM_STRSIZE) >= 36263a6526dSMichael Lim DLADM_STRSIZE) 36363a6526dSMichael Lim die("attribute list too long '%s'", attrstr); 364da14cebeSEric Cheng break; 365da14cebeSEric Cheng case 'p': 36663a6526dSMichael Lim (void) strlcat(propstr, optarg, DLADM_STRSIZE); 36763a6526dSMichael Lim if (strlcat(propstr, ",", DLADM_STRSIZE) >= 36863a6526dSMichael Lim DLADM_STRSIZE) 36963a6526dSMichael Lim die("property list too long '%s'", propstr); 370da14cebeSEric Cheng break; 371da14cebeSEric Cheng default: 372da14cebeSEric Cheng die_opterr(optopt, option); 373da14cebeSEric Cheng } 374da14cebeSEric Cheng } 375da14cebeSEric Cheng if (!l_arg) { 376da14cebeSEric Cheng die("link is required"); 377da14cebeSEric Cheng } 378da14cebeSEric Cheng 379da14cebeSEric Cheng opterr = 0; 380da14cebeSEric Cheng index = optind; 381da14cebeSEric Cheng 382da14cebeSEric Cheng if ((index != (argc - 1)) || match_attr(argv[index]) != NULL) { 383da14cebeSEric Cheng die("flow name is required"); 384da14cebeSEric Cheng } else { 385da14cebeSEric Cheng /* get flow name; required last argument */ 386da000602SGirish Moodalbail if (strlen(argv[index]) >= MAXFLOWNAMELEN) 387da14cebeSEric Cheng die("flow name too long"); 388da14cebeSEric Cheng name = argv[index]; 389da14cebeSEric Cheng } 390da14cebeSEric Cheng 39163a6526dSMichael Lim if (dladm_parse_flow_attrs(attrstr, &attrlist, B_FALSE) 39263a6526dSMichael Lim != DLADM_STATUS_OK) 39363a6526dSMichael Lim die("invalid flow attribute specified"); 39463a6526dSMichael Lim if (dladm_parse_flow_props(propstr, &proplist, B_FALSE) 39563a6526dSMichael Lim != DLADM_STATUS_OK) 39663a6526dSMichael Lim die("invalid flow property specified"); 39763a6526dSMichael Lim 3984ac67f02SAnurag S. Maskey status = dladm_flow_add(handle, linkid, attrlist, proplist, name, 399da14cebeSEric Cheng t_arg, altroot); 400da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 401da14cebeSEric Cheng die_dlerr(status, "add flow failed"); 402da14cebeSEric Cheng 403da14cebeSEric Cheng dladm_free_attrs(attrlist); 404da14cebeSEric Cheng dladm_free_props(proplist); 405da14cebeSEric Cheng } 406da14cebeSEric Cheng 407da14cebeSEric Cheng static void 408da14cebeSEric Cheng do_remove_flow(int argc, char *argv[]) 409da14cebeSEric Cheng { 410da14cebeSEric Cheng char option; 411da14cebeSEric Cheng char *flowname = NULL; 412da000602SGirish Moodalbail char linkname[MAXLINKNAMELEN]; 413da14cebeSEric Cheng datalink_id_t linkid = DATALINK_ALL_LINKID; 414da14cebeSEric Cheng boolean_t l_arg = B_FALSE; 415da14cebeSEric Cheng remove_flow_state_t state; 416da14cebeSEric Cheng dladm_status_t status; 417da14cebeSEric Cheng 418da14cebeSEric Cheng bzero(&state, sizeof (state)); 419da14cebeSEric Cheng 420da14cebeSEric Cheng opterr = 0; 421da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":tR:l:", 422da14cebeSEric Cheng longopts, NULL)) != -1) { 423da14cebeSEric Cheng switch (option) { 424da14cebeSEric Cheng case 't': 425da14cebeSEric Cheng t_arg = B_TRUE; 426da14cebeSEric Cheng break; 427da14cebeSEric Cheng case 'R': 428da14cebeSEric Cheng altroot = optarg; 429da14cebeSEric Cheng break; 430da14cebeSEric Cheng case 'l': 431da14cebeSEric Cheng if (strlcpy(linkname, optarg, 432da14cebeSEric Cheng MAXLINKNAMELEN) >= MAXLINKNAMELEN) { 433da14cebeSEric Cheng die("link name too long"); 434da14cebeSEric Cheng } 4354ac67f02SAnurag S. Maskey if (dladm_name2info(handle, linkname, &linkid, NULL, 436da14cebeSEric Cheng NULL, NULL) != DLADM_STATUS_OK) { 437da14cebeSEric Cheng die("invalid link '%s'", linkname); 438da14cebeSEric Cheng } 439da14cebeSEric Cheng l_arg = B_TRUE; 440da14cebeSEric Cheng break; 441da14cebeSEric Cheng default: 442da14cebeSEric Cheng die_opterr(optopt, option); 443da14cebeSEric Cheng break; 444da14cebeSEric Cheng } 445da14cebeSEric Cheng } 446da14cebeSEric Cheng 447da14cebeSEric Cheng /* when link not specified get flow name */ 448da14cebeSEric Cheng if (!l_arg) { 449da14cebeSEric Cheng if (optind != (argc-1)) { 450da14cebeSEric Cheng usage(); 451da14cebeSEric Cheng } else { 452da000602SGirish Moodalbail if (strlen(argv[optind]) >= MAXFLOWNAMELEN) 453da14cebeSEric Cheng die("flow name too long"); 454da14cebeSEric Cheng flowname = argv[optind]; 455da14cebeSEric Cheng } 4564ac67f02SAnurag S. Maskey status = dladm_flow_remove(handle, flowname, t_arg, altroot); 457da14cebeSEric Cheng } else { 458da14cebeSEric Cheng /* if link is specified then flow name should not be there */ 459da14cebeSEric Cheng if (optind == argc-1) 460da14cebeSEric Cheng usage(); 461da14cebeSEric Cheng /* walk the link to find flows and remove them */ 462da14cebeSEric Cheng state.fs_tempop = t_arg; 463da14cebeSEric Cheng state.fs_altroot = altroot; 464da14cebeSEric Cheng state.fs_status = DLADM_STATUS_OK; 4654ac67f02SAnurag S. Maskey status = dladm_walk_flow(remove_flow, handle, linkid, &state, 4664ac67f02SAnurag S. Maskey B_FALSE); 467da14cebeSEric Cheng /* 468da14cebeSEric Cheng * check if dladm_walk_flow terminated early and see if the 469da14cebeSEric Cheng * walker function as any status for us 470da14cebeSEric Cheng */ 471da14cebeSEric Cheng if (status == DLADM_STATUS_OK) 472da14cebeSEric Cheng status = state.fs_status; 473da14cebeSEric Cheng } 474da14cebeSEric Cheng 475da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 476da14cebeSEric Cheng die_dlerr(status, "remove flow failed"); 477da14cebeSEric Cheng } 478da14cebeSEric Cheng 479da14cebeSEric Cheng /* 480da14cebeSEric Cheng * Walker function for removing a flow through dladm_walk_flow(); 481da14cebeSEric Cheng */ 482c3affd82SMichael Lim /*ARGSUSED*/ 483da14cebeSEric Cheng static int 484c3affd82SMichael Lim remove_flow(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg) 485da14cebeSEric Cheng { 486da14cebeSEric Cheng remove_flow_state_t *state = (remove_flow_state_t *)arg; 487da14cebeSEric Cheng 4884ac67f02SAnurag S. Maskey state->fs_status = dladm_flow_remove(handle, attr->fa_flowname, 489da14cebeSEric Cheng state->fs_tempop, state->fs_altroot); 490da14cebeSEric Cheng 491da14cebeSEric Cheng if (state->fs_status == DLADM_STATUS_OK) 492da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 493da14cebeSEric Cheng else 494da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 495da14cebeSEric Cheng } 496da14cebeSEric Cheng 497da14cebeSEric Cheng /*ARGSUSED*/ 498da14cebeSEric Cheng static dladm_status_t 499da14cebeSEric Cheng print_flow(show_flow_state_t *state, dladm_flow_attr_t *attr, 500da14cebeSEric Cheng flow_fields_buf_t *fbuf) 501da14cebeSEric Cheng { 502da14cebeSEric Cheng char link[MAXLINKNAMELEN]; 503da14cebeSEric Cheng dladm_status_t status; 504da14cebeSEric Cheng 5054ac67f02SAnurag S. Maskey if ((status = dladm_datalink_id2info(handle, attr->fa_linkid, NULL, 5064ac67f02SAnurag S. Maskey NULL, NULL, link, sizeof (link))) != DLADM_STATUS_OK) { 507da14cebeSEric Cheng return (status); 508da14cebeSEric Cheng } 509da14cebeSEric Cheng 510da14cebeSEric Cheng (void) snprintf(fbuf->flow_name, sizeof (fbuf->flow_name), 511da14cebeSEric Cheng "%s", attr->fa_flowname); 512da14cebeSEric Cheng (void) snprintf(fbuf->flow_link, sizeof (fbuf->flow_link), 513da14cebeSEric Cheng "%s", link); 514da14cebeSEric Cheng 515da14cebeSEric Cheng (void) dladm_flow_attr_ip2str(attr, fbuf->flow_ipaddr, 516da14cebeSEric Cheng sizeof (fbuf->flow_ipaddr)); 517da14cebeSEric Cheng (void) dladm_flow_attr_proto2str(attr, fbuf->flow_proto, 518da14cebeSEric Cheng sizeof (fbuf->flow_proto)); 51925ec3e3dSEric Cheng if ((attr->fa_flow_desc.fd_mask & FLOW_ULP_PORT_LOCAL) != 0) { 52025ec3e3dSEric Cheng (void) dladm_flow_attr_port2str(attr, fbuf->flow_lport, 52125ec3e3dSEric Cheng sizeof (fbuf->flow_lport)); 52225ec3e3dSEric Cheng } 52325ec3e3dSEric Cheng if ((attr->fa_flow_desc.fd_mask & FLOW_ULP_PORT_REMOTE) != 0) { 52425ec3e3dSEric Cheng (void) dladm_flow_attr_port2str(attr, fbuf->flow_rport, 52525ec3e3dSEric Cheng sizeof (fbuf->flow_rport)); 52625ec3e3dSEric Cheng } 527da14cebeSEric Cheng (void) dladm_flow_attr_dsfield2str(attr, fbuf->flow_dsfield, 528da14cebeSEric Cheng sizeof (fbuf->flow_dsfield)); 529da14cebeSEric Cheng 530da14cebeSEric Cheng return (DLADM_STATUS_OK); 531da14cebeSEric Cheng } 532da14cebeSEric Cheng 533da14cebeSEric Cheng /* 534da14cebeSEric Cheng * Walker function for showing flow attributes through dladm_walk_flow(). 535da14cebeSEric Cheng */ 536c3affd82SMichael Lim /*ARGSUSED*/ 537da14cebeSEric Cheng static int 538c3affd82SMichael Lim show_flow(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg) 539da14cebeSEric Cheng { 540da14cebeSEric Cheng show_flow_state_t *statep = arg; 541da14cebeSEric Cheng dladm_status_t status; 542da14cebeSEric Cheng flow_fields_buf_t fbuf; 543da14cebeSEric Cheng 544da14cebeSEric Cheng /* 545da14cebeSEric Cheng * first get all the flow attributes into fbuf; 546da14cebeSEric Cheng */ 547da14cebeSEric Cheng bzero(&fbuf, sizeof (fbuf)); 548da14cebeSEric Cheng status = print_flow(statep, attr, &fbuf); 549da14cebeSEric Cheng 550da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 551da14cebeSEric Cheng goto done; 552da14cebeSEric Cheng 5538002d411SSowmini Varadhan ofmt_print(statep->fs_ofmt, (void *)&fbuf); 554da14cebeSEric Cheng 555da14cebeSEric Cheng done: 556da14cebeSEric Cheng statep->fs_status = status; 557da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 558da14cebeSEric Cheng } 559da14cebeSEric Cheng 560da14cebeSEric Cheng static void 561da14cebeSEric Cheng show_one_flow(void *arg, const char *name) 562da14cebeSEric Cheng { 563da14cebeSEric Cheng dladm_flow_attr_t attr; 564da14cebeSEric Cheng 5654ac67f02SAnurag S. Maskey if (dladm_flow_info(handle, name, &attr) != DLADM_STATUS_OK) 566da14cebeSEric Cheng die("invalid flow: '%s'", name); 567da14cebeSEric Cheng else 568c3affd82SMichael Lim (void) show_flow(handle, &attr, arg); 569da14cebeSEric Cheng } 570da14cebeSEric Cheng 571da14cebeSEric Cheng /* 572da14cebeSEric Cheng * Wrapper of dladm_walk_flow(show_flow,...) to make it usable to 573da14cebeSEric Cheng * dladm_walk_datalink_id(). Used for showing flow attributes for 574da14cebeSEric Cheng * all flows on all links. 575da14cebeSEric Cheng */ 576da14cebeSEric Cheng static int 5774ac67f02SAnurag S. Maskey show_flows_onelink(dladm_handle_t dh, datalink_id_t linkid, void *arg) 578da14cebeSEric Cheng { 579da14cebeSEric Cheng show_flow_state_t *state = arg; 580da14cebeSEric Cheng 5814ac67f02SAnurag S. Maskey (void) dladm_walk_flow(show_flow, dh, linkid, arg, state->fs_persist); 582da14cebeSEric Cheng 583da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 584da14cebeSEric Cheng } 585da14cebeSEric Cheng 586da14cebeSEric Cheng static void 587da14cebeSEric Cheng do_show_flow(int argc, char *argv[]) 588da14cebeSEric Cheng { 589da000602SGirish Moodalbail char flowname[MAXFLOWNAMELEN]; 590da000602SGirish Moodalbail char linkname[MAXLINKNAMELEN]; 591da14cebeSEric Cheng datalink_id_t linkid = DATALINK_ALL_LINKID; 592da14cebeSEric Cheng int option; 593da14cebeSEric Cheng boolean_t l_arg = B_FALSE; 594da14cebeSEric Cheng boolean_t o_arg = B_FALSE; 595da14cebeSEric Cheng show_flow_state_t state; 596da14cebeSEric Cheng char *fields_str = NULL; 5978002d411SSowmini Varadhan ofmt_handle_t ofmt; 5988002d411SSowmini Varadhan ofmt_status_t oferr; 5998002d411SSowmini Varadhan uint_t ofmtflags = 0; 600da14cebeSEric Cheng 601da14cebeSEric Cheng bzero(&state, sizeof (state)); 602da14cebeSEric Cheng 603da14cebeSEric Cheng opterr = 0; 604*0dc2366fSVenugopal Iyer while ((option = getopt_long(argc, argv, ":pPl:o:", 605da14cebeSEric Cheng longopts, NULL)) != -1) { 606da14cebeSEric Cheng switch (option) { 607da14cebeSEric Cheng case 'p': 6088002d411SSowmini Varadhan state.fs_parsable = B_TRUE; 6098002d411SSowmini Varadhan ofmtflags |= OFMT_PARSABLE; 610da14cebeSEric Cheng break; 611da14cebeSEric Cheng case 'P': 612da14cebeSEric Cheng state.fs_persist = B_TRUE; 613da14cebeSEric Cheng break; 614da14cebeSEric Cheng case 'o': 615da14cebeSEric Cheng if (o_arg) 616da14cebeSEric Cheng die_optdup(option); 617da14cebeSEric Cheng 618da14cebeSEric Cheng o_arg = B_TRUE; 619da14cebeSEric Cheng fields_str = optarg; 620da14cebeSEric Cheng break; 621da14cebeSEric Cheng case 'l': 622da14cebeSEric Cheng if (strlcpy(linkname, optarg, MAXLINKNAMELEN) 623da14cebeSEric Cheng >= MAXLINKNAMELEN) 624da14cebeSEric Cheng die("link name too long\n"); 6254ac67f02SAnurag S. Maskey if (dladm_name2info(handle, linkname, &linkid, NULL, 626da14cebeSEric Cheng NULL, NULL) != DLADM_STATUS_OK) 627da14cebeSEric Cheng die("invalid link '%s'", linkname); 628da14cebeSEric Cheng l_arg = B_TRUE; 629da14cebeSEric Cheng break; 630da14cebeSEric Cheng default: 631da14cebeSEric Cheng die_opterr(optopt, option); 632da14cebeSEric Cheng break; 633da14cebeSEric Cheng } 634da14cebeSEric Cheng } 635da14cebeSEric Cheng 636da14cebeSEric Cheng /* get flow name (optional last argument */ 637da14cebeSEric Cheng if (optind == (argc-1)) { 638da000602SGirish Moodalbail if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN) 639da000602SGirish Moodalbail >= MAXFLOWNAMELEN) 640da14cebeSEric Cheng die("flow name too long"); 641da14cebeSEric Cheng state.fs_flow = flowname; 642da14cebeSEric Cheng } 643da14cebeSEric Cheng 6448002d411SSowmini Varadhan oferr = ofmt_open(fields_str, flow_fields, ofmtflags, 0, &ofmt); 6458002d411SSowmini Varadhan flowadm_ofmt_check(oferr, state.fs_parsable, ofmt); 6468002d411SSowmini Varadhan state.fs_ofmt = ofmt; 647da14cebeSEric Cheng 648da14cebeSEric Cheng /* Show attributes of one flow */ 649da14cebeSEric Cheng if (state.fs_flow != NULL) { 650da14cebeSEric Cheng show_one_flow(&state, state.fs_flow); 651da14cebeSEric Cheng 652da14cebeSEric Cheng /* Show attributes of flows on one link */ 653da14cebeSEric Cheng } else if (l_arg) { 6544ac67f02SAnurag S. Maskey (void) show_flows_onelink(handle, linkid, &state); 655da14cebeSEric Cheng 656da14cebeSEric Cheng /* Show attributes of all flows on all links */ 657da14cebeSEric Cheng } else { 6584ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(show_flows_onelink, handle, 6594ac67f02SAnurag S. Maskey &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 660da14cebeSEric Cheng DLADM_OPT_ACTIVE); 661da14cebeSEric Cheng } 6628002d411SSowmini Varadhan ofmt_close(ofmt); 663da14cebeSEric Cheng } 664da14cebeSEric Cheng 665da14cebeSEric Cheng static dladm_status_t 666da14cebeSEric Cheng set_flowprop_persist(const char *flow, const char *prop_name, char **prop_val, 667da14cebeSEric Cheng uint_t val_cnt, boolean_t reset) 668da14cebeSEric Cheng { 669da14cebeSEric Cheng dladm_status_t status; 670da14cebeSEric Cheng char *errprop; 671da14cebeSEric Cheng 6724ac67f02SAnurag S. Maskey status = dladm_set_flowprop(handle, flow, prop_name, prop_val, val_cnt, 673da14cebeSEric Cheng DLADM_OPT_PERSIST, &errprop); 674da14cebeSEric Cheng 675da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 676da14cebeSEric Cheng warn_dlerr(status, "cannot persistently %s flow " 677da14cebeSEric Cheng "property '%s' on '%s'", reset? "reset": "set", 678da14cebeSEric Cheng errprop, flow); 679da14cebeSEric Cheng } 680da14cebeSEric Cheng return (status); 681da14cebeSEric Cheng } 682da14cebeSEric Cheng 683da14cebeSEric Cheng static void 684da14cebeSEric Cheng set_flowprop(int argc, char **argv, boolean_t reset) 685da14cebeSEric Cheng { 686da14cebeSEric Cheng int i, option; 687da14cebeSEric Cheng char errmsg[DLADM_STRSIZE]; 688da14cebeSEric Cheng const char *flow = NULL; 68963a6526dSMichael Lim char propstr[DLADM_STRSIZE]; 690da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 691da14cebeSEric Cheng boolean_t temp = B_FALSE; 692da14cebeSEric Cheng dladm_status_t status = DLADM_STATUS_OK; 693da14cebeSEric Cheng 694da14cebeSEric Cheng opterr = 0; 69563a6526dSMichael Lim bzero(propstr, DLADM_STRSIZE); 69663a6526dSMichael Lim 697da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":p:R:t", 698da14cebeSEric Cheng prop_longopts, NULL)) != -1) { 699da14cebeSEric Cheng switch (option) { 700da14cebeSEric Cheng case 'p': 70163a6526dSMichael Lim (void) strlcat(propstr, optarg, DLADM_STRSIZE); 70263a6526dSMichael Lim if (strlcat(propstr, ",", DLADM_STRSIZE) >= 70363a6526dSMichael Lim DLADM_STRSIZE) 70463a6526dSMichael Lim die("property list too long '%s'", propstr); 705da14cebeSEric Cheng break; 706da14cebeSEric Cheng case 't': 707da14cebeSEric Cheng temp = B_TRUE; 708da14cebeSEric Cheng break; 709da14cebeSEric Cheng case 'R': 710da14cebeSEric Cheng status = dladm_set_rootdir(optarg); 711da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 712da14cebeSEric Cheng die_dlerr(status, "invalid directory " 713da14cebeSEric Cheng "specified"); 714da14cebeSEric Cheng } 715da14cebeSEric Cheng break; 716da14cebeSEric Cheng default: 717da14cebeSEric Cheng die_opterr(optopt, option); 718da14cebeSEric Cheng break; 719da14cebeSEric Cheng } 720da14cebeSEric Cheng } 721da14cebeSEric Cheng 722da14cebeSEric Cheng if (optind == (argc - 1)) { 723da000602SGirish Moodalbail if (strlen(argv[optind]) >= MAXFLOWNAMELEN) 724da14cebeSEric Cheng die("flow name too long"); 725da14cebeSEric Cheng flow = argv[optind]; 726da14cebeSEric Cheng } else if (optind != argc) { 727da14cebeSEric Cheng usage(); 728da14cebeSEric Cheng } 729da14cebeSEric Cheng if (flow == NULL) 730da14cebeSEric Cheng die("flow name must be specified"); 731da14cebeSEric Cheng 73263a6526dSMichael Lim if (dladm_parse_flow_props(propstr, &proplist, reset) 73363a6526dSMichael Lim != DLADM_STATUS_OK) 73463a6526dSMichael Lim die("invalid flow property specified"); 73563a6526dSMichael Lim 736da14cebeSEric Cheng if (proplist == NULL) { 737da14cebeSEric Cheng char *errprop; 738da14cebeSEric Cheng 739da14cebeSEric Cheng if (!reset) 740da14cebeSEric Cheng die("flow property must be specified"); 741da14cebeSEric Cheng 7424ac67f02SAnurag S. Maskey status = dladm_set_flowprop(handle, flow, NULL, NULL, 0, 743da14cebeSEric Cheng DLADM_OPT_ACTIVE, &errprop); 744da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 745da14cebeSEric Cheng warn_dlerr(status, "cannot reset flow property '%s' " 746da14cebeSEric Cheng "on '%s'", errprop, flow); 747da14cebeSEric Cheng } 748da14cebeSEric Cheng if (!temp) { 749da14cebeSEric Cheng dladm_status_t s; 750da14cebeSEric Cheng 751da14cebeSEric Cheng s = set_flowprop_persist(flow, NULL, NULL, 0, reset); 752da14cebeSEric Cheng if (s != DLADM_STATUS_OK) 753da14cebeSEric Cheng status = s; 754da14cebeSEric Cheng } 755da14cebeSEric Cheng goto done; 756da14cebeSEric Cheng } 757da14cebeSEric Cheng 758da14cebeSEric Cheng for (i = 0; i < proplist->al_count; i++) { 759da14cebeSEric Cheng dladm_arg_info_t *aip = &proplist->al_info[i]; 760da14cebeSEric Cheng char **val; 761da14cebeSEric Cheng uint_t count; 762da14cebeSEric Cheng dladm_status_t s; 763da14cebeSEric Cheng 764da14cebeSEric Cheng if (reset) { 765da14cebeSEric Cheng val = NULL; 766da14cebeSEric Cheng count = 0; 767da14cebeSEric Cheng } else { 768da14cebeSEric Cheng val = aip->ai_val; 769da14cebeSEric Cheng count = aip->ai_count; 770da14cebeSEric Cheng if (count == 0) { 771da14cebeSEric Cheng warn("no value specified for '%s'", 772da14cebeSEric Cheng aip->ai_name); 773da14cebeSEric Cheng status = DLADM_STATUS_BADARG; 774da14cebeSEric Cheng continue; 775da14cebeSEric Cheng } 776da14cebeSEric Cheng } 7774ac67f02SAnurag S. Maskey s = dladm_set_flowprop(handle, flow, aip->ai_name, val, count, 778da14cebeSEric Cheng DLADM_OPT_ACTIVE, NULL); 779da14cebeSEric Cheng if (s == DLADM_STATUS_OK) { 780da14cebeSEric Cheng if (!temp) { 781da14cebeSEric Cheng s = set_flowprop_persist(flow, 782da14cebeSEric Cheng aip->ai_name, val, count, reset); 783da14cebeSEric Cheng if (s != DLADM_STATUS_OK) 784da14cebeSEric Cheng status = s; 785da14cebeSEric Cheng } 786da14cebeSEric Cheng continue; 787da14cebeSEric Cheng } 788da14cebeSEric Cheng status = s; 789da14cebeSEric Cheng switch (s) { 790da14cebeSEric Cheng case DLADM_STATUS_NOTFOUND: 791da14cebeSEric Cheng warn("invalid flow property '%s'", aip->ai_name); 792da14cebeSEric Cheng break; 793da14cebeSEric Cheng case DLADM_STATUS_BADVAL: { 794da14cebeSEric Cheng int j; 795da14cebeSEric Cheng char *ptr, *lim; 796da14cebeSEric Cheng char **propvals = NULL; 797da14cebeSEric Cheng uint_t valcnt = DLADM_MAX_PROP_VALCNT; 798da14cebeSEric Cheng 799da14cebeSEric Cheng ptr = malloc((sizeof (char *) + 800da14cebeSEric Cheng DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 801da14cebeSEric Cheng MAX_PROP_LINE); 802da14cebeSEric Cheng 803da14cebeSEric Cheng if (ptr == NULL) 804da14cebeSEric Cheng die("insufficient memory"); 805da14cebeSEric Cheng propvals = (char **)(void *)ptr; 806da14cebeSEric Cheng 807da14cebeSEric Cheng for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 808da14cebeSEric Cheng propvals[j] = ptr + sizeof (char *) * 809da14cebeSEric Cheng DLADM_MAX_PROP_VALCNT + 810da14cebeSEric Cheng j * DLADM_PROP_VAL_MAX; 811da14cebeSEric Cheng } 8124ac67f02SAnurag S. Maskey s = dladm_get_flowprop(handle, flow, 8134ac67f02SAnurag S. Maskey DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals, 8144ac67f02SAnurag S. Maskey &valcnt); 815da14cebeSEric Cheng 816da14cebeSEric Cheng ptr = errmsg; 817da14cebeSEric Cheng lim = ptr + DLADM_STRSIZE; 818da14cebeSEric Cheng *ptr = '\0'; 819da14cebeSEric Cheng for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) { 820da14cebeSEric Cheng ptr += snprintf(ptr, lim - ptr, "%s,", 821da14cebeSEric Cheng propvals[j]); 822da14cebeSEric Cheng if (ptr >= lim) 823da14cebeSEric Cheng break; 824da14cebeSEric Cheng } 825da14cebeSEric Cheng if (ptr > errmsg) { 826da14cebeSEric Cheng *(ptr - 1) = '\0'; 827da14cebeSEric Cheng warn("flow property '%s' must be one of: %s", 828da14cebeSEric Cheng aip->ai_name, errmsg); 829da14cebeSEric Cheng } else 830da14cebeSEric Cheng warn("%s is an invalid value for " 831da14cebeSEric Cheng "flow property %s", *val, aip->ai_name); 832da14cebeSEric Cheng free(propvals); 833da14cebeSEric Cheng break; 834da14cebeSEric Cheng } 835da14cebeSEric Cheng default: 836da14cebeSEric Cheng if (reset) { 837da14cebeSEric Cheng warn_dlerr(status, "cannot reset flow property " 838da14cebeSEric Cheng "'%s' on '%s'", aip->ai_name, flow); 839da14cebeSEric Cheng } else { 840da14cebeSEric Cheng warn_dlerr(status, "cannot set flow property " 841da14cebeSEric Cheng "'%s' on '%s'", aip->ai_name, flow); 842da14cebeSEric Cheng } 843da14cebeSEric Cheng break; 844da14cebeSEric Cheng } 845da14cebeSEric Cheng } 846da14cebeSEric Cheng done: 847da14cebeSEric Cheng dladm_free_props(proplist); 8484ac67f02SAnurag S. Maskey if (status != DLADM_STATUS_OK) { 8494ac67f02SAnurag S. Maskey dladm_close(handle); 850ad091ee1SMichael Lim exit(EXIT_FAILURE); 851da14cebeSEric Cheng } 8524ac67f02SAnurag S. Maskey } 853da14cebeSEric Cheng 854da14cebeSEric Cheng static void 855da14cebeSEric Cheng do_set_flowprop(int argc, char **argv) 856da14cebeSEric Cheng { 857da14cebeSEric Cheng set_flowprop(argc, argv, B_FALSE); 858da14cebeSEric Cheng } 859da14cebeSEric Cheng 860da14cebeSEric Cheng static void 861da14cebeSEric Cheng do_reset_flowprop(int argc, char **argv) 862da14cebeSEric Cheng { 863da14cebeSEric Cheng set_flowprop(argc, argv, B_TRUE); 864da14cebeSEric Cheng } 865da14cebeSEric Cheng 866da14cebeSEric Cheng static void 867da14cebeSEric Cheng warn(const char *format, ...) 868da14cebeSEric Cheng { 869da14cebeSEric Cheng va_list alist; 870da14cebeSEric Cheng 871da14cebeSEric Cheng format = gettext(format); 872da14cebeSEric Cheng (void) fprintf(stderr, "%s: warning: ", progname); 873da14cebeSEric Cheng 874da14cebeSEric Cheng va_start(alist, format); 875da14cebeSEric Cheng (void) vfprintf(stderr, format, alist); 876da14cebeSEric Cheng va_end(alist); 877da14cebeSEric Cheng 878*0dc2366fSVenugopal Iyer (void) putc('\n', stderr); 879da14cebeSEric Cheng } 880da14cebeSEric Cheng 881da14cebeSEric Cheng /* PRINTFLIKE2 */ 882da14cebeSEric Cheng static void 883da14cebeSEric Cheng warn_dlerr(dladm_status_t err, const char *format, ...) 884da14cebeSEric Cheng { 885da14cebeSEric Cheng va_list alist; 886da14cebeSEric Cheng char errmsg[DLADM_STRSIZE]; 887da14cebeSEric Cheng 888da14cebeSEric Cheng format = gettext(format); 889da14cebeSEric Cheng (void) fprintf(stderr, gettext("%s: warning: "), progname); 890da14cebeSEric Cheng 891da14cebeSEric Cheng va_start(alist, format); 892da14cebeSEric Cheng (void) vfprintf(stderr, format, alist); 893da14cebeSEric Cheng va_end(alist); 894da14cebeSEric Cheng (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 895da14cebeSEric Cheng } 896da14cebeSEric Cheng 897da14cebeSEric Cheng /* PRINTFLIKE1 */ 898da14cebeSEric Cheng static void 899da14cebeSEric Cheng die(const char *format, ...) 900da14cebeSEric Cheng { 901da14cebeSEric Cheng va_list alist; 902da14cebeSEric Cheng 903da14cebeSEric Cheng format = gettext(format); 904da14cebeSEric Cheng (void) fprintf(stderr, "%s: ", progname); 905da14cebeSEric Cheng 906da14cebeSEric Cheng va_start(alist, format); 907da14cebeSEric Cheng (void) vfprintf(stderr, format, alist); 908da14cebeSEric Cheng va_end(alist); 909da14cebeSEric Cheng 910*0dc2366fSVenugopal Iyer (void) putc('\n', stderr); 9114ac67f02SAnurag S. Maskey 9124ac67f02SAnurag S. Maskey /* close dladm handle if it was opened */ 9134ac67f02SAnurag S. Maskey if (handle != NULL) 9144ac67f02SAnurag S. Maskey dladm_close(handle); 9154ac67f02SAnurag S. Maskey 916da14cebeSEric Cheng exit(EXIT_FAILURE); 917da14cebeSEric Cheng } 918da14cebeSEric Cheng 919da14cebeSEric Cheng static void 920da14cebeSEric Cheng die_optdup(int opt) 921da14cebeSEric Cheng { 922da14cebeSEric Cheng die("the option -%c cannot be specified more than once", opt); 923da14cebeSEric Cheng } 924da14cebeSEric Cheng 925da14cebeSEric Cheng static void 926da14cebeSEric Cheng die_opterr(int opt, int opterr) 927da14cebeSEric Cheng { 928da14cebeSEric Cheng switch (opterr) { 929da14cebeSEric Cheng case ':': 930da14cebeSEric Cheng die("option '-%c' requires a value", opt); 931da14cebeSEric Cheng break; 932da14cebeSEric Cheng case '?': 933da14cebeSEric Cheng default: 934da14cebeSEric Cheng die("unrecognized option '-%c'", opt); 935da14cebeSEric Cheng break; 936da14cebeSEric Cheng } 937da14cebeSEric Cheng } 938da14cebeSEric Cheng 939da14cebeSEric Cheng /* PRINTFLIKE2 */ 940da14cebeSEric Cheng static void 941da14cebeSEric Cheng die_dlerr(dladm_status_t err, const char *format, ...) 942da14cebeSEric Cheng { 943da14cebeSEric Cheng va_list alist; 944da14cebeSEric Cheng char errmsg[DLADM_STRSIZE]; 945da14cebeSEric Cheng 946da14cebeSEric Cheng format = gettext(format); 947da14cebeSEric Cheng (void) fprintf(stderr, "%s: ", progname); 948da14cebeSEric Cheng 949da14cebeSEric Cheng va_start(alist, format); 950da14cebeSEric Cheng (void) vfprintf(stderr, format, alist); 951da14cebeSEric Cheng va_end(alist); 952da14cebeSEric Cheng (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 953da14cebeSEric Cheng 9544ac67f02SAnurag S. Maskey /* close dladm handle if it was opened */ 9554ac67f02SAnurag S. Maskey if (handle != NULL) 9564ac67f02SAnurag S. Maskey dladm_close(handle); 9574ac67f02SAnurag S. Maskey 958da14cebeSEric Cheng exit(EXIT_FAILURE); 959da14cebeSEric Cheng } 960da14cebeSEric Cheng 961da14cebeSEric Cheng static void 962da14cebeSEric Cheng print_flowprop(const char *flowname, show_flowprop_state_t *statep, 963da14cebeSEric Cheng const char *propname, dladm_prop_type_t type, 964da14cebeSEric Cheng const char *format, char **pptr) 965da14cebeSEric Cheng { 966da14cebeSEric Cheng int i; 967da14cebeSEric Cheng char *ptr, *lim; 968da14cebeSEric Cheng char buf[DLADM_STRSIZE]; 969da14cebeSEric Cheng char *unknown = "--", *notsup = ""; 970da14cebeSEric Cheng char **propvals = statep->fs_propvals; 971da14cebeSEric Cheng uint_t valcnt = DLADM_MAX_PROP_VALCNT; 972da14cebeSEric Cheng dladm_status_t status; 973da14cebeSEric Cheng 9744ac67f02SAnurag S. Maskey status = dladm_get_flowprop(handle, flowname, type, propname, propvals, 975da14cebeSEric Cheng &valcnt); 976da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 977da14cebeSEric Cheng if (status == DLADM_STATUS_TEMPONLY) { 978da14cebeSEric Cheng if (type == DLADM_PROP_VAL_MODIFIABLE && 979da14cebeSEric Cheng statep->fs_persist) { 980da14cebeSEric Cheng valcnt = 1; 981da14cebeSEric Cheng propvals = &unknown; 982da14cebeSEric Cheng } else { 983da14cebeSEric Cheng statep->fs_status = status; 984da14cebeSEric Cheng statep->fs_retstatus = status; 985da14cebeSEric Cheng return; 986da14cebeSEric Cheng } 987da14cebeSEric Cheng } else if (status == DLADM_STATUS_NOTSUP || 988da14cebeSEric Cheng statep->fs_persist) { 989da14cebeSEric Cheng valcnt = 1; 990da14cebeSEric Cheng if (type == DLADM_PROP_VAL_CURRENT) 991da14cebeSEric Cheng propvals = &unknown; 992da14cebeSEric Cheng else 993da14cebeSEric Cheng propvals = ¬sup; 994da14cebeSEric Cheng } else { 995da14cebeSEric Cheng if ((statep->fs_proplist != NULL) && 996da14cebeSEric Cheng statep->fs_status == DLADM_STATUS_OK) { 997da14cebeSEric Cheng warn("invalid flow property '%s'", propname); 998da14cebeSEric Cheng } 999da14cebeSEric Cheng statep->fs_status = status; 1000da14cebeSEric Cheng statep->fs_retstatus = status; 1001da14cebeSEric Cheng return; 1002da14cebeSEric Cheng } 1003da14cebeSEric Cheng } 1004da14cebeSEric Cheng 1005da14cebeSEric Cheng statep->fs_status = DLADM_STATUS_OK; 1006da14cebeSEric Cheng 1007da14cebeSEric Cheng ptr = buf; 1008da14cebeSEric Cheng lim = buf + DLADM_STRSIZE; 1009da14cebeSEric Cheng for (i = 0; i < valcnt; i++) { 10108002d411SSowmini Varadhan if (propvals[i][0] == '\0' && !statep->fs_parsable) 10118002d411SSowmini Varadhan ptr += snprintf(ptr, lim - ptr, "--,"); 1012da14cebeSEric Cheng else 1013da14cebeSEric Cheng ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 1014da14cebeSEric Cheng if (ptr >= lim) 1015da14cebeSEric Cheng break; 1016da14cebeSEric Cheng } 1017da14cebeSEric Cheng if (valcnt > 0) 1018da14cebeSEric Cheng buf[strlen(buf) - 1] = '\0'; 1019da14cebeSEric Cheng 1020da14cebeSEric Cheng lim = statep->fs_line + MAX_PROP_LINE; 10218002d411SSowmini Varadhan if (statep->fs_parsable) { 1022da14cebeSEric Cheng *pptr += snprintf(*pptr, lim - *pptr, 1023da14cebeSEric Cheng "%s", buf); 1024da14cebeSEric Cheng } else { 1025da14cebeSEric Cheng *pptr += snprintf(*pptr, lim - *pptr, format, buf); 1026da14cebeSEric Cheng } 1027da14cebeSEric Cheng } 1028da14cebeSEric Cheng 10298002d411SSowmini Varadhan static boolean_t 10308002d411SSowmini Varadhan print_flowprop_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 1031da14cebeSEric Cheng { 10328002d411SSowmini Varadhan flowprop_args_t *arg = of_arg->ofmt_cbarg; 1033da14cebeSEric Cheng char *propname = arg->fs_propname; 1034da14cebeSEric Cheng show_flowprop_state_t *statep = arg->fs_state; 1035da14cebeSEric Cheng char *ptr = statep->fs_line; 1036da14cebeSEric Cheng char *lim = ptr + MAX_PROP_LINE; 1037da14cebeSEric Cheng char *flowname = arg->fs_flowname; 1038da14cebeSEric Cheng 10398002d411SSowmini Varadhan switch (of_arg->ofmt_id) { 1040da14cebeSEric Cheng case FLOWPROP_FLOW: 1041da14cebeSEric Cheng (void) snprintf(ptr, lim - ptr, "%s", statep->fs_flow); 1042da14cebeSEric Cheng break; 1043da14cebeSEric Cheng case FLOWPROP_PROPERTY: 1044da14cebeSEric Cheng (void) snprintf(ptr, lim - ptr, "%s", propname); 1045da14cebeSEric Cheng break; 1046da14cebeSEric Cheng case FLOWPROP_VALUE: 1047da14cebeSEric Cheng print_flowprop(flowname, statep, propname, 1048da14cebeSEric Cheng statep->fs_persist ? DLADM_PROP_VAL_PERSISTENT : 1049da14cebeSEric Cheng DLADM_PROP_VAL_CURRENT, "%s", &ptr); 1050da14cebeSEric Cheng /* 1051da14cebeSEric Cheng * If we failed to query the flow property, for example, query 1052da14cebeSEric Cheng * the persistent value of a non-persistable flow property, 1053da14cebeSEric Cheng * simply skip the output. 1054da14cebeSEric Cheng */ 1055da14cebeSEric Cheng if (statep->fs_status != DLADM_STATUS_OK) 1056da14cebeSEric Cheng goto skip; 1057da14cebeSEric Cheng ptr = statep->fs_line; 1058da14cebeSEric Cheng break; 1059da14cebeSEric Cheng case FLOWPROP_DEFAULT: 1060da14cebeSEric Cheng print_flowprop(flowname, statep, propname, 1061da14cebeSEric Cheng DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 1062da14cebeSEric Cheng if (statep->fs_status != DLADM_STATUS_OK) 1063da14cebeSEric Cheng goto skip; 1064da14cebeSEric Cheng ptr = statep->fs_line; 1065da14cebeSEric Cheng break; 1066da14cebeSEric Cheng case FLOWPROP_POSSIBLE: 1067da14cebeSEric Cheng print_flowprop(flowname, statep, propname, 1068da14cebeSEric Cheng DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 1069da14cebeSEric Cheng if (statep->fs_status != DLADM_STATUS_OK) 1070da14cebeSEric Cheng goto skip; 1071da14cebeSEric Cheng ptr = statep->fs_line; 1072da14cebeSEric Cheng break; 1073da14cebeSEric Cheng default: 1074da14cebeSEric Cheng die("invalid input"); 1075da14cebeSEric Cheng break; 1076da14cebeSEric Cheng } 10778002d411SSowmini Varadhan (void) strlcpy(buf, ptr, bufsize); 10788002d411SSowmini Varadhan return (B_TRUE); 1079da14cebeSEric Cheng skip: 10808002d411SSowmini Varadhan buf[0] = '\0'; 10818002d411SSowmini Varadhan return ((statep->fs_status == DLADM_STATUS_OK) ? 10828002d411SSowmini Varadhan B_TRUE : B_FALSE); 1083da14cebeSEric Cheng } 1084da14cebeSEric Cheng 1085da14cebeSEric Cheng static int 1086da14cebeSEric Cheng show_one_flowprop(void *arg, const char *propname) 1087da14cebeSEric Cheng { 1088da14cebeSEric Cheng show_flowprop_state_t *statep = arg; 1089da14cebeSEric Cheng flowprop_args_t fs_arg; 1090da14cebeSEric Cheng 1091da14cebeSEric Cheng bzero(&fs_arg, sizeof (fs_arg)); 1092da14cebeSEric Cheng fs_arg.fs_state = statep; 1093da14cebeSEric Cheng fs_arg.fs_propname = (char *)propname; 1094da14cebeSEric Cheng fs_arg.fs_flowname = (char *)statep->fs_flow; 1095da14cebeSEric Cheng 10968002d411SSowmini Varadhan ofmt_print(statep->fs_ofmt, (void *)&fs_arg); 1097da14cebeSEric Cheng 1098da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1099da14cebeSEric Cheng } 1100da14cebeSEric Cheng 1101c3affd82SMichael Lim /*ARGSUSED*/ 1102da14cebeSEric Cheng /* Walker function called by dladm_walk_flow to display flow properties */ 1103da14cebeSEric Cheng static int 1104c3affd82SMichael Lim show_flowprop(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg) 1105da14cebeSEric Cheng { 1106da14cebeSEric Cheng show_flowprop_one_flow(arg, attr->fa_flowname); 1107da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1108da14cebeSEric Cheng } 1109da14cebeSEric Cheng 1110da14cebeSEric Cheng /* 1111da14cebeSEric Cheng * Wrapper of dladm_walk_flow(show_walk_fn,...) to make it 1112da14cebeSEric Cheng * usable to dladm_walk_datalink_id() 1113da14cebeSEric Cheng */ 1114da14cebeSEric Cheng static int 11154ac67f02SAnurag S. Maskey show_flowprop_onelink(dladm_handle_t dh, datalink_id_t linkid, void *arg) 1116da14cebeSEric Cheng { 1117da14cebeSEric Cheng char name[MAXLINKNAMELEN]; 1118da14cebeSEric Cheng 11194ac67f02SAnurag S. Maskey if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, name, 11204ac67f02SAnurag S. Maskey sizeof (name)) != DLADM_STATUS_OK) 1121da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 1122da14cebeSEric Cheng 11234ac67f02SAnurag S. Maskey (void) dladm_walk_flow(show_flowprop, dh, linkid, arg, B_FALSE); 1124da14cebeSEric Cheng 1125da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 1126da14cebeSEric Cheng } 1127da14cebeSEric Cheng 1128da14cebeSEric Cheng static void 1129da14cebeSEric Cheng do_show_flowprop(int argc, char **argv) 1130da14cebeSEric Cheng { 1131da14cebeSEric Cheng int option; 1132da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 1133da14cebeSEric Cheng show_flowprop_state_t state; 1134da14cebeSEric Cheng char *fields_str = NULL; 11358002d411SSowmini Varadhan ofmt_handle_t ofmt; 11368002d411SSowmini Varadhan ofmt_status_t oferr; 11378002d411SSowmini Varadhan uint_t ofmtflags = 0; 1138da14cebeSEric Cheng 1139da14cebeSEric Cheng opterr = 0; 1140da14cebeSEric Cheng state.fs_propvals = NULL; 1141da14cebeSEric Cheng state.fs_line = NULL; 11428002d411SSowmini Varadhan state.fs_parsable = B_FALSE; 1143da14cebeSEric Cheng state.fs_persist = B_FALSE; 1144da14cebeSEric Cheng state.fs_header = B_TRUE; 1145da14cebeSEric Cheng state.fs_retstatus = DLADM_STATUS_OK; 1146da14cebeSEric Cheng state.fs_linkid = DATALINK_INVALID_LINKID; 1147da14cebeSEric Cheng state.fs_flow = NULL; 1148da14cebeSEric Cheng 1149da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":p:cPl:o:", 1150da14cebeSEric Cheng prop_longopts, NULL)) != -1) { 1151da14cebeSEric Cheng switch (option) { 1152da14cebeSEric Cheng case 'p': 1153da14cebeSEric Cheng if (dladm_parse_flow_props(optarg, &proplist, B_TRUE) 1154da14cebeSEric Cheng != DLADM_STATUS_OK) 1155da14cebeSEric Cheng die("invalid flow properties specified"); 1156da14cebeSEric Cheng break; 1157da14cebeSEric Cheng case 'c': 11588002d411SSowmini Varadhan state.fs_parsable = B_TRUE; 11598002d411SSowmini Varadhan ofmtflags |= OFMT_PARSABLE; 1160da14cebeSEric Cheng break; 1161da14cebeSEric Cheng case 'P': 1162da14cebeSEric Cheng state.fs_persist = B_TRUE; 1163da14cebeSEric Cheng break; 1164da14cebeSEric Cheng case 'l': 11654ac67f02SAnurag S. Maskey if (dladm_name2info(handle, optarg, &state.fs_linkid, 1166da14cebeSEric Cheng NULL, NULL, NULL) != DLADM_STATUS_OK) 1167da14cebeSEric Cheng die("invalid link '%s'", optarg); 1168da14cebeSEric Cheng break; 1169da14cebeSEric Cheng case 'o': 1170da14cebeSEric Cheng fields_str = optarg; 1171da14cebeSEric Cheng break; 1172da14cebeSEric Cheng default: 1173da14cebeSEric Cheng die_opterr(optopt, option); 1174da14cebeSEric Cheng break; 1175da14cebeSEric Cheng } 1176da14cebeSEric Cheng } 1177da14cebeSEric Cheng 1178da14cebeSEric Cheng if (optind == (argc - 1)) { 1179da000602SGirish Moodalbail if (strlen(argv[optind]) >= MAXFLOWNAMELEN) 1180da14cebeSEric Cheng die("flow name too long"); 1181da14cebeSEric Cheng state.fs_flow = argv[optind]; 1182da14cebeSEric Cheng } else if (optind != argc) { 1183da14cebeSEric Cheng usage(); 1184da14cebeSEric Cheng } 1185da14cebeSEric Cheng state.fs_proplist = proplist; 1186da14cebeSEric Cheng state.fs_status = DLADM_STATUS_OK; 1187da14cebeSEric Cheng 11888002d411SSowmini Varadhan oferr = ofmt_open(fields_str, flowprop_fields, ofmtflags, 0, &ofmt); 11898002d411SSowmini Varadhan flowadm_ofmt_check(oferr, state.fs_parsable, ofmt); 11908002d411SSowmini Varadhan state.fs_ofmt = ofmt; 1191da14cebeSEric Cheng 1192da14cebeSEric Cheng /* Show properties for one flow */ 1193da14cebeSEric Cheng if (state.fs_flow != NULL) { 1194da14cebeSEric Cheng show_flowprop_one_flow(&state, state.fs_flow); 1195da14cebeSEric Cheng 1196da14cebeSEric Cheng /* Show properties for all flows on one link */ 1197da14cebeSEric Cheng } else if (state.fs_linkid != DATALINK_INVALID_LINKID) { 11984ac67f02SAnurag S. Maskey (void) show_flowprop_onelink(handle, state.fs_linkid, &state); 1199da14cebeSEric Cheng 1200da14cebeSEric Cheng /* Show properties for all flows on all links */ 1201da14cebeSEric Cheng } else { 12024ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(show_flowprop_onelink, handle, 12034ac67f02SAnurag S. Maskey &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 1204da14cebeSEric Cheng DLADM_OPT_ACTIVE); 1205da14cebeSEric Cheng } 1206da14cebeSEric Cheng 1207da14cebeSEric Cheng dladm_free_props(proplist); 12088002d411SSowmini Varadhan ofmt_close(ofmt); 1209da14cebeSEric Cheng } 1210da14cebeSEric Cheng 1211da14cebeSEric Cheng static void 1212da14cebeSEric Cheng show_flowprop_one_flow(void *arg, const char *flow) 1213da14cebeSEric Cheng { 1214da14cebeSEric Cheng int i; 1215da14cebeSEric Cheng char *buf; 1216da14cebeSEric Cheng dladm_status_t status; 1217da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 1218da14cebeSEric Cheng show_flowprop_state_t *statep = arg; 1219da14cebeSEric Cheng dladm_flow_attr_t attr; 1220da14cebeSEric Cheng const char *savep; 1221da14cebeSEric Cheng 1222da14cebeSEric Cheng /* 1223da14cebeSEric Cheng * Do not print flow props for invalid flows. 1224da14cebeSEric Cheng */ 12254ac67f02SAnurag S. Maskey if ((status = dladm_flow_info(handle, flow, &attr)) != 12264ac67f02SAnurag S. Maskey DLADM_STATUS_OK) { 1227da14cebeSEric Cheng die("invalid flow: '%s'", flow); 1228da14cebeSEric Cheng } 1229da14cebeSEric Cheng 1230da14cebeSEric Cheng savep = statep->fs_flow; 1231da14cebeSEric Cheng statep->fs_flow = flow; 1232da14cebeSEric Cheng 1233da14cebeSEric Cheng proplist = statep->fs_proplist; 1234da14cebeSEric Cheng 1235da14cebeSEric Cheng buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) 1236da14cebeSEric Cheng * DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 1237da14cebeSEric Cheng if (buf == NULL) 1238da14cebeSEric Cheng die("insufficient memory"); 1239da14cebeSEric Cheng 1240da14cebeSEric Cheng statep->fs_propvals = (char **)(void *)buf; 1241da14cebeSEric Cheng for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 1242da14cebeSEric Cheng statep->fs_propvals[i] = buf + 1243da14cebeSEric Cheng sizeof (char *) * DLADM_MAX_PROP_VALCNT + 1244da14cebeSEric Cheng i * DLADM_PROP_VAL_MAX; 1245da14cebeSEric Cheng } 1246da14cebeSEric Cheng statep->fs_line = buf + 1247da14cebeSEric Cheng (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 1248da14cebeSEric Cheng 1249da14cebeSEric Cheng /* show only specified flow properties */ 1250da14cebeSEric Cheng if (proplist != NULL) { 1251da14cebeSEric Cheng for (i = 0; i < proplist->al_count; i++) { 1252da14cebeSEric Cheng if (show_one_flowprop(statep, 1253da14cebeSEric Cheng proplist->al_info[i].ai_name) != DLADM_STATUS_OK) 1254da14cebeSEric Cheng break; 1255da14cebeSEric Cheng } 1256da14cebeSEric Cheng 1257da14cebeSEric Cheng /* show all flow properties */ 1258da14cebeSEric Cheng } else { 1259da14cebeSEric Cheng status = dladm_walk_flowprop(show_one_flowprop, flow, statep); 1260da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 1261da14cebeSEric Cheng die_dlerr(status, "show-flowprop"); 1262da14cebeSEric Cheng } 1263da14cebeSEric Cheng free(buf); 1264da14cebeSEric Cheng statep->fs_flow = savep; 1265da14cebeSEric Cheng } 1266da14cebeSEric Cheng 1267da14cebeSEric Cheng /* 12688002d411SSowmini Varadhan * default output callback function that, when invoked from dladm_print_output, 12698002d411SSowmini Varadhan * prints string which is offset by of_arg->ofmt_id within buf. 1270da14cebeSEric Cheng */ 12718002d411SSowmini Varadhan static boolean_t 12728002d411SSowmini Varadhan print_default_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) 1273da14cebeSEric Cheng { 1274da14cebeSEric Cheng char *value; 1275da14cebeSEric Cheng 12768002d411SSowmini Varadhan value = (char *)of_arg->ofmt_cbarg + of_arg->ofmt_id; 12778002d411SSowmini Varadhan (void) strlcpy(buf, value, bufsize); 12788002d411SSowmini Varadhan return (B_TRUE); 1279da14cebeSEric Cheng } 1280da14cebeSEric Cheng 1281da14cebeSEric Cheng static void 12828002d411SSowmini Varadhan flowadm_ofmt_check(ofmt_status_t oferr, boolean_t parsable, 12838002d411SSowmini Varadhan ofmt_handle_t ofmt) 1284da14cebeSEric Cheng { 12858002d411SSowmini Varadhan char buf[OFMT_BUFSIZE]; 1286da14cebeSEric Cheng 12878002d411SSowmini Varadhan if (oferr == OFMT_SUCCESS) 12888002d411SSowmini Varadhan return; 12898002d411SSowmini Varadhan (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf)); 1290ad091ee1SMichael Lim /* 12918002d411SSowmini Varadhan * All errors are considered fatal in parsable mode. 12928002d411SSowmini Varadhan * NOMEM errors are always fatal, regardless of mode. 12938002d411SSowmini Varadhan * For other errors, we print diagnostics in human-readable 12948002d411SSowmini Varadhan * mode and processs what we can. 1295ad091ee1SMichael Lim */ 12968002d411SSowmini Varadhan if (parsable || oferr == OFMT_ENOFIELDS) { 12978002d411SSowmini Varadhan ofmt_close(ofmt); 12988002d411SSowmini Varadhan die(buf); 1299da14cebeSEric Cheng } else { 13008002d411SSowmini Varadhan warn(buf); 1301da14cebeSEric Cheng } 1302da14cebeSEric Cheng } 1303