diff options
author | sowmini <none@none> | 2008-01-24 14:49:21 -0800 |
---|---|---|
committer | sowmini <none@none> | 2008-01-24 14:49:21 -0800 |
commit | e7801d59e8ceda0cde8ebdfdddd7582ee2ea96ef (patch) | |
tree | aa5f6ba96fab8905146ea99d10af75f480c45e9e /usr/src/cmd | |
parent | 575bd8a230f2c20b1878ebb473c30a12f0eb1b2e (diff) | |
download | illumos-gate-e7801d59e8ceda0cde8ebdfdddd7582ee2ea96ef.tar.gz |
PSARC 2007/429 Brussels - enhanced network driver configuration via dladm
6565373 driver ndd parameter behavior does not match the ieee802.3(5) man page.
6598690 need support for 'dladm show-ether' subcommand.
6619126 ndd abuse in network (Layer 2) drivers
6621285 bge_setup_params_kstat is dead code
Diffstat (limited to 'usr/src/cmd')
-rw-r--r-- | usr/src/cmd/dladm/dladm.c | 2680 | ||||
-rw-r--r-- | usr/src/cmd/dladm/dladm.xcl | 48 |
2 files changed, 1981 insertions, 747 deletions
diff --git a/usr/src/cmd/dladm/dladm.c b/usr/src/cmd/dladm/dladm.c index 22cc5c515e..0de78dfd63 100644 --- a/usr/src/cmd/dladm/dladm.c +++ b/usr/src/cmd/dladm/dladm.c @@ -56,8 +56,10 @@ #include <libinetutil.h> #include <bsm/adt.h> #include <bsm/adt_event.h> +#include <stddef.h> #define AGGR_DRV "aggr" +#define STR_UNDEF_VAL "--" #define MAXPORT 256 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) #define MAXLINELEN 1024 @@ -65,6 +67,132 @@ #define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink" #define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)" +#define CMD_TYPE_ANY 0xffffffff +#define WIFI_CMD_SCAN 0x00000001 +#define WIFI_CMD_SHOW 0x00000002 +#define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) + +/* + * data structures and routines for printing output. + * All non-parseable output is assumed to be in a columnar format. + * Parseable output will be printed as <pf_header>="<value>" + * + * Each sub-command is associated with a global array of pointers, + * print_field_t *fields[], where the print_field_t contains information + * about the format in which the output is to be printed. + * + * Sub-commands may be implemented in one of two ways: + * (i) the implementation could get all field values into a character + * buffer, with pf_offset containing the offset (for pf_name) within + * the buffer. The sub-command would make the needed system calls + * to obtain all possible column values and then invoke the + * dladm_print_field() function to print the specific fields + * requested in the command line. See the comments for dladm_print_field + * for further details. + * (ii) Alternatively, each fields[i] entry could store a pf_index value + * that uniquely identifies the column to be printed. The implementation + * of the sub-command would then invoke dladm_print_output() with a + * callback function whose semantics are described below (see comments + * for dladm_print_output()) + * + * Thus, an implementation of a sub-command must provide the following: + * + * static print_field_t sub_command_fields[] = { + * {<name>, <header>,<field width>, <offset_or_index>, cmdtype}, + * : + * {<name>, <header>,<field width>, <offset_or_index>, cmdtype} + * }; + * + * #define SUB_COMMAND_MAX_FIELDS sizeof \ + * (sub_comand_fields) / sizeof (print_field_t)) + * + * print_state_t sub_command_print_state; + * + * The function that parses command line arguments (typically + * do_sub_command()) should then contain an invocation like: + * + * fields = parse_output_fields(fields_str, sub_command_fields, + * SUB_COMMAND_MAX_FIELDS, CMD_TYPE_ANY, &nfields); + * + * and store the resulting fields and nfields value in a print_state_t + * structure tracked for the command. + * + * sub_command_print_state.ps_fields = fields; + * sub_command_print_state.ps_nfields = nfields; + * + * To print the column header for the output, the print_header() + * function must then be invoked by do_sub_command(). + * + * Then if method (i) is used for the sub_command, the do_sub_command() + * function should make the necessary system calls to fill up the buffer + * and then invoke dladm_print_field(). An example of this method is + * the implementation of do_show_link() and show_link(); + * + * If method (ii) is used, do_sub_command should invoke dladm_print_output() + * with a callback function that will be called for each field to be printed. + * The callback function will be passed a pointer to the print_field_t + * for the field, and the pf_index may then be used to identify the + * system call required to find the value to be printed. An example of + * this implementation may be found in the do_show_dev() and print_dev() + * invocation. + */ + +typedef struct print_field_s { + const char *pf_name; /* name of column to be printed */ + const char *pf_header; /* header for this column */ + uint_t pf_width; + union { + uint_t _pf_index; /* private index for sub-command */ + size_t _pf_offset; + }_pf_un; +#define pf_index _pf_un._pf_index +#define pf_offset _pf_un._pf_offset; + uint_t pf_cmdtype; +} print_field_t; + +/* + * The state of the output is tracked in a print_state_t structure. + * Each ps_fields[i] entry points at the global print_field_t array for + * the sub-command, where ps_nfields is the number of requested fields. + */ +typedef struct print_state_s { + print_field_t **ps_fields; + uint_t ps_nfields; + boolean_t ps_lastfield; + uint_t ps_overflow; +} print_state_t; + +typedef char *(*print_callback_t)(print_field_t *, void *); +static print_field_t **parse_output_fields(char *, print_field_t *, int, + uint_t, uint_t *); +/* + * print the header for the output + */ +static void print_header(print_state_t *); +static void print_field(print_state_t *, print_field_t *, const char *, + boolean_t); + +/* + * to print output values, call dladm_print_output with a callback + * function (*func)() that should parse the args and return an + * unformatted character buffer with the value to be printed. + * + * dladm_print_output() prints the character buffer using the formatting + * information provided in the print_field_t for that column. + */ +static void dladm_print_output(print_state_t *, boolean_t, + print_callback_t, void *); + +/* + * helper function that, when invoked as dladm_print_field(pf, buf) + * prints string which is offset by pf->pf_offset within buf + */ +static char *dladm_print_field(print_field_t *, void *); + + +#define MAX_FIELD_LEN 32 + + typedef struct pktsum_s { uint64_t ipackets; uint64_t opackets; @@ -78,21 +206,25 @@ typedef struct show_state { boolean_t ls_firstonly; boolean_t ls_donefirst; pktsum_t ls_prevstats; - boolean_t ls_parseable; uint32_t ls_flags; dladm_status_t ls_status; + print_state_t ls_print; + boolean_t ls_parseable; + boolean_t ls_printheader; } show_state_t; typedef struct show_grp_state { + pktsum_t gs_prevstats[MAXPORT]; + uint32_t gs_flags; + dladm_status_t gs_status; + boolean_t gs_parseable; boolean_t gs_lacp; boolean_t gs_extended; boolean_t gs_stats; boolean_t gs_firstonly; boolean_t gs_donefirst; - pktsum_t gs_prevstats[MAXPORT]; - boolean_t gs_parseable; - uint32_t gs_flags; - dladm_status_t gs_status; + boolean_t gs_printheader; + print_state_t gs_print; } show_grp_state_t; typedef void cmdfunc_t(int, char **); @@ -107,13 +239,14 @@ static cmdfunc_t do_init_linkprop, do_init_secobj; static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan; static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys; static cmdfunc_t do_show_linkmap; +static cmdfunc_t do_show_ether; static void altroot_cmd(char *, int, char **); static int show_linkprop_onelink(datalink_id_t, void *); static void link_stats(datalink_id_t, uint_t); static void aggr_stats(datalink_id_t, show_grp_state_t *, uint_t); -static void dev_stats(const char *dev, uint32_t); +static void dev_stats(const char *dev, uint32_t, char *, show_state_t *); static int get_one_kstat(const char *, const char *, uint8_t, void *, boolean_t); @@ -125,6 +258,16 @@ static void stats_diff(pktsum_t *, pktsum_t *, pktsum_t *); static const char *get_linkstate(const char *, boolean_t, char *); static const char *get_linkduplex(const char *, boolean_t, char *); +static int show_etherprop(datalink_id_t, void *); +static void show_ether_xprop(datalink_id_t, void *); +static boolean_t get_speed_duplex(datalink_id_t, const char *, char *, + char *, boolean_t); +static char *pause_str(int, int); +static boolean_t link_is_ether(const char *, datalink_id_t *); + +#define IS_FDX 0x10 +#define IS_HDX 0x01 + static boolean_t str2int(const char *, int *); static void die(const char *, ...); static void die_optdup(int); @@ -155,6 +298,7 @@ static cmd_t cmds[] = { { "show-linkprop", do_show_linkprop }, { "set-linkprop", do_set_linkprop }, { "reset-linkprop", do_reset_linkprop }, + { "show-ether", do_show_ether }, { "create-secobj", do_create_secobj }, { "delete-secobj", do_delete_secobj }, { "show-secobj", do_show_secobj }, @@ -173,6 +317,7 @@ static cmd_t cmds[] = { static const struct option lopts[] = { {"vlan-id", required_argument, 0, 'v'}, + {"output", required_argument, 0, 'o'}, {"dev", required_argument, 0, 'd'}, {"policy", required_argument, 0, 'P'}, {"lacp-mode", required_argument, 0, 'L'}, @@ -190,6 +335,7 @@ static const struct option show_lopts[] = { {"interval", required_argument, 0, 'i'}, {"parseable", no_argument, 0, 'p'}, {"extended", no_argument, 0, 'x'}, + {"output", required_argument, 0, 'o'}, {"persistent", no_argument, 0, 'P'}, {"lacp", no_argument, 0, 'L'}, { 0, 0, 0, 0 } @@ -197,6 +343,7 @@ static const struct option show_lopts[] = { static const struct option prop_longopts[] = { {"temporary", no_argument, 0, 't' }, + {"output", required_argument, 0, 'o' }, {"root-dir", required_argument, 0, 'R' }, {"prop", required_argument, 0, 'p' }, {"parseable", no_argument, 0, 'c' }, @@ -222,6 +369,418 @@ static const struct option wifi_longopts[] = { {"file", required_argument, 0, 'f' }, { 0, 0, 0, 0 } }; +static const struct option showeth_lopts[] = { + {"parseable", no_argument, 0, 'p' }, + {"extended", no_argument, 0, 'x' }, + {"output", required_argument, 0, 'o' }, + { 0, 0, 0, 0 } +}; + +/* + * structures for 'dladm show-ether' + */ +typedef struct ether_fields_buf_s +{ + char eth_link[15]; + char eth_ptype[8]; + char eth_state[8]; + char eth_autoneg[5]; + char eth_spdx[31]; + char eth_pause[6]; + char eth_rem_fault[16]; +} ether_fields_buf_t; + +static print_field_t ether_fields[] = { +/* name, header, field width, offset, cmdtype */ +{ "link", "LINK", 15, + offsetof(ether_fields_buf_t, eth_link), CMD_TYPE_ANY}, +{ "ptype", "PTYPE", 8, + offsetof(ether_fields_buf_t, eth_ptype), CMD_TYPE_ANY}, +{ "state", "STATE", 8, + offsetof(ether_fields_buf_t, eth_state), CMD_TYPE_ANY}, +{ "auto", "AUTO", 5, + offsetof(ether_fields_buf_t, eth_autoneg), CMD_TYPE_ANY}, +{ "speed-duplex", "SPEED-DUPLEX", 31, + offsetof(ether_fields_buf_t, eth_spdx), CMD_TYPE_ANY}, +{ "pause", "PAUSE", 6, + offsetof(ether_fields_buf_t, eth_pause), CMD_TYPE_ANY}, +{ "rem_fault", "REM_FAULT", 16, + offsetof(ether_fields_buf_t, eth_rem_fault), CMD_TYPE_ANY}} +; +#define ETHER_MAX_FIELDS (sizeof (ether_fields) / sizeof (print_field_t)) + +typedef struct print_ether_state { + const char *es_link; + boolean_t es_parseable; + boolean_t es_header; + boolean_t es_extended; + print_state_t es_print; +} print_ether_state_t; + +/* + * structures for 'dladm show-dev'. + */ +typedef enum { + DEV_LINK, + DEV_STATE, + DEV_SPEED, + DEV_DUPLEX +} dev_field_index_t; + +static print_field_t dev_fields[] = { +/* name, header, field width, index, cmdtype */ +{ "link", "LINK", 15, DEV_LINK, CMD_TYPE_ANY}, +{ "state", "STATE", 6, DEV_STATE, CMD_TYPE_ANY}, +{ "speed", "SPEED", 8, DEV_SPEED, CMD_TYPE_ANY}, +{ "duplex", "DUPLEX", 8, DEV_DUPLEX, CMD_TYPE_ANY}} +; +#define DEV_MAX_FIELDS (sizeof (dev_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-dev -s' (print statistics) + */ +typedef enum { + DEVS_LINK, + DEVS_IPKTS, + DEVS_RBYTES, + DEVS_IERRORS, + DEVS_OPKTS, + DEVS_OBYTES, + DEVS_OERRORS +} devs_field_index_t; + +static print_field_t devs_fields[] = { +/* name, header, field width, index, cmdtype */ +{ "link", "LINK", 15, DEVS_LINK, CMD_TYPE_ANY}, +{ "ipackets", "IPACKETS", 10, DEVS_IPKTS, CMD_TYPE_ANY}, +{ "rbytes", "RBYTES", 8, DEVS_RBYTES, CMD_TYPE_ANY}, +{ "ierrors", "IERRORS", 10, DEVS_IERRORS, CMD_TYPE_ANY}, +{ "opackets", "OPACKETS", 12, DEVS_OPKTS, CMD_TYPE_ANY}, +{ "obytes", "OBYTES", 12, DEVS_OBYTES, CMD_TYPE_ANY}, +{ "oerrors", "OERRORS", 8, DEVS_OERRORS, CMD_TYPE_ANY}} +; +#define DEVS_MAX_FIELDS (sizeof (devs_fields) / sizeof (print_field_t)) +typedef struct dev_args_s { + char *devs_link; + pktsum_t *devs_psum; +} dev_args_t; +static char *print_dev_stats(print_field_t *, void *); +static char *print_dev(print_field_t *, void *); + +/* + * buffer used by print functions for show-{link,phys,vlan} commands. + */ +typedef struct link_fields_buf_s { + char link_name[MAXLINKNAMELEN]; + char link_class[DLADM_STRSIZE]; + char link_mtu[6]; + char link_state[DLADM_STRSIZE]; + char link_over[MAXLINKNAMELEN]; + char link_phys_state[6]; + char link_phys_media[DLADM_STRSIZE]; + char link_phys_speed[DLADM_STRSIZE]; + char link_phys_duplex[DLPI_LINKNAME_MAX]; + char link_phys_device[DLPI_LINKNAME_MAX]; + char link_flags[6]; + char link_vlan_vid[6]; +} link_fields_buf_t; + +/* + * structures for 'dladm show-link' + */ +static print_field_t link_fields[] = { +/* name, header, field width, offset, cmdtype */ +{ "link", "LINK", 11, + offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, +{ "class", "CLASS", 8, + offsetof(link_fields_buf_t, link_class), CMD_TYPE_ANY}, +{ "mtu", "MTU", 6, + offsetof(link_fields_buf_t, link_mtu), CMD_TYPE_ANY}, +{ "state", "STATE", 8, + offsetof(link_fields_buf_t, link_state), CMD_TYPE_ANY}, +{ "over", "OVER", DLPI_LINKNAME_MAX, + offsetof(link_fields_buf_t, link_over), CMD_TYPE_ANY}} +; +#define DEV_LINK_FIELDS (sizeof (link_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-aggr' + */ +typedef struct laggr_fields_buf_s { + char laggr_name[DLPI_LINKNAME_MAX]; + char laggr_policy[9]; + char laggr_addrpolicy[ETHERADDRL * 3 + 3]; + char laggr_lacpactivity[14]; + char laggr_lacptimer[DLADM_STRSIZE]; + char laggr_flags[7]; +} laggr_fields_buf_t; + +typedef struct laggr_args_s { + int laggr_lport; /* -1 indicates the aggr itself */ + const char *laggr_link; + dladm_aggr_grp_attr_t *laggr_ginfop; + dladm_status_t *laggr_status; + pktsum_t *laggr_pktsumtot; /* -s only */ + pktsum_t *laggr_prevstats; /* -s only */ + boolean_t laggr_parseable; +} laggr_args_t; + +static print_field_t laggr_fields[] = { +/* name, header, field width, offset, cmdtype */ +{ "link", "LINK", 15, + offsetof(laggr_fields_buf_t, laggr_name), CMD_TYPE_ANY}, +{ "policy", "POLICY", 8, + offsetof(laggr_fields_buf_t, laggr_policy), CMD_TYPE_ANY}, +{ "addrpolicy", "ADDRPOLICY", ETHERADDRL * 3 + 2, + offsetof(laggr_fields_buf_t, laggr_addrpolicy), CMD_TYPE_ANY}, +{ "lacpactivity", "LACPACTIVITY", 13, + offsetof(laggr_fields_buf_t, laggr_lacpactivity), CMD_TYPE_ANY}, +{ "lacptimer", "LACPTIMER", 11, + offsetof(laggr_fields_buf_t, laggr_lacptimer), CMD_TYPE_ANY}, +{ "flags", "FLAGS", 7, + offsetof(laggr_fields_buf_t, laggr_flags), CMD_TYPE_ANY}} +; +#define LAGGR_MAX_FIELDS (sizeof (laggr_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-aggr -x'. + */ +typedef enum { + AGGR_X_LINK, + AGGR_X_PORT, + AGGR_X_SPEED, + AGGR_X_DUPLEX, + AGGR_X_STATE, + AGGR_X_ADDRESS, + AGGR_X_PORTSTATE +} aggr_x_field_index_t; + +static print_field_t aggr_x_fields[] = { +/* name, header, field width, index, cmdtype */ +{ "link", "LINK", 11, AGGR_X_LINK, CMD_TYPE_ANY}, +{ "port", "PORT", 14, AGGR_X_PORT, CMD_TYPE_ANY}, +{ "speed", "SPEED", 4, AGGR_X_SPEED, CMD_TYPE_ANY}, +{ "duplex", "DUPLEX", 9, AGGR_X_DUPLEX, CMD_TYPE_ANY}, +{ "state", "STATE", 9, AGGR_X_STATE, CMD_TYPE_ANY}, +{ "address", "ADDRESS", 18, AGGR_X_ADDRESS, CMD_TYPE_ANY}, +{ "portstate", "PORTSTATE", 15, AGGR_X_PORTSTATE, CMD_TYPE_ANY}} +; +#define AGGR_X_MAX_FIELDS \ + (sizeof (aggr_x_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-aggr -s'. + */ +typedef enum { + AGGR_S_LINK, + AGGR_S_PORT, + AGGR_S_IPKTS, + AGGR_S_RBYTES, + AGGR_S_OPKTS, + AGGR_S_OBYTES, + AGGR_S_IPKTDIST, + AGGR_S_OPKTDIST +} aggr_s_field_index_t; + +static print_field_t aggr_s_fields[] = { +/* name, header, field width, index, cmdtype */ +{ "link", "LINK", 11, AGGR_S_LINK, + CMD_TYPE_ANY}, +{ "port", "PORT", 9, AGGR_S_PORT, + CMD_TYPE_ANY}, +{ "ipackets", "IPACKETS", 7, AGGR_S_IPKTS, + CMD_TYPE_ANY}, +{ "rbytes", "RBYTES", 7, AGGR_S_RBYTES, + CMD_TYPE_ANY}, +{ "opackets", "OPACKETS", 7, AGGR_S_OPKTS, + CMD_TYPE_ANY}, +{ "obytes", "OBYTES", 7, AGGR_S_OBYTES, + CMD_TYPE_ANY}, +{ "ipktdist", "IPKTDIST", 8, AGGR_S_IPKTDIST, + CMD_TYPE_ANY}, +{ "opktdist", "OPKTDIST", 14, AGGR_S_OPKTDIST, + CMD_TYPE_ANY}} +; +#define AGGR_S_MAX_FIELDS \ + (sizeof (aggr_l_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-dev -L'. + */ +typedef enum { + AGGR_L_LINK, + AGGR_L_PORT, + AGGR_L_AGGREGATABLE, + AGGR_L_SYNC, + AGGR_L_COLL, + AGGR_L_DIST, + AGGR_L_DEFAULTED, + AGGR_L_EXPIRED +} aggr_l_field_index_t; + +static print_field_t aggr_l_fields[] = { +/* name, header, field width, index, cmdtype */ +{ "link", "LINK", 11, AGGR_L_LINK, + CMD_TYPE_ANY}, +{ "port", "PORT", 12, AGGR_L_PORT, + CMD_TYPE_ANY}, +{ "aggregatable", "AGGREGATABLE", 12, AGGR_L_AGGREGATABLE, + CMD_TYPE_ANY}, +{ "sync", "SYNC", 4, AGGR_L_SYNC, + CMD_TYPE_ANY}, +{ "coll", "COLL", 4, AGGR_L_COLL, + CMD_TYPE_ANY}, +{ "dist", "DIST", 4, AGGR_L_DIST, + CMD_TYPE_ANY}, +{ "defaulted", "DEFAULTED", 9, AGGR_L_DEFAULTED, + CMD_TYPE_ANY}, +{ "expired", "EXPIRED", 14, AGGR_L_EXPIRED, + CMD_TYPE_ANY}} +; +#define AGGR_L_MAX_FIELDS \ + (sizeof (aggr_l_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-phys' + */ + +static print_field_t phys_fields[] = { +/* name, header, field width, offset, cmdtype */ +{ "link", "LINK", 12, + offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, +{ "media", "MEDIA", 20, + offsetof(link_fields_buf_t, link_phys_media), CMD_TYPE_ANY}, +{ "state", "STATE", 10, + offsetof(link_fields_buf_t, link_phys_state), CMD_TYPE_ANY}, +{ "speed", "SPEED", 4, + offsetof(link_fields_buf_t, link_phys_speed), CMD_TYPE_ANY}, +{ "duplex", "DUPLEX", 9, + offsetof(link_fields_buf_t, link_phys_duplex), CMD_TYPE_ANY}, +{ "device", "DEVICE", 12, + offsetof(link_fields_buf_t, link_phys_device), CMD_TYPE_ANY}, +{ "flags", "FLAGS", 6, + offsetof(link_fields_buf_t, link_flags), CMD_TYPE_ANY}} +; +#define PHYS_MAX_FIELDS (sizeof (phys_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-vlan' + */ +static print_field_t vlan_fields[] = { +/* name, header, field width, offset, cmdtype */ +{ "link", "LINK", 15, + offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, +{ "vid", "VID", 8, + offsetof(link_fields_buf_t, link_vlan_vid), CMD_TYPE_ANY}, +{ "over", "OVER", 12, + offsetof(link_fields_buf_t, link_over), CMD_TYPE_ANY}, +{ "flags", "FLAGS", 6, + offsetof(link_fields_buf_t, link_flags), CMD_TYPE_ANY}} +; +#define VLAN_MAX_FIELDS (sizeof (vlan_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-wifi' + */ +static print_field_t wifi_fields[] = { +{ "link", "LINK", 10, 0, WIFI_CMD_ALL}, +{ "essid", "ESSID", 19, DLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, +{ "bssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, +{ "ibssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, +{ "mode", "MODE", 6, DLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, +{ "speed", "SPEED", 6, DLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, +{ "auth", "AUTH", 8, DLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW}, +{ "bsstype", "BSSTYPE", 8, DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, +{ "sec", "SEC", 6, DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, +{ "status", "STATUS", 17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW}, +{ "strength", "STRENGTH", 10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} +; + +static char *all_scan_wifi_fields = + "link,essid,bssid,sec,strength,mode,speed,bsstype"; +static char *all_show_wifi_fields = + "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; +static char *def_scan_wifi_fields = + "link,essid,bssid,sec,strength,mode,speed"; +static char *def_show_wifi_fields = + "link,status,essid,sec,strength,mode,speed"; + +#define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-linkprop' + */ +typedef enum { + LINKPROP_LINK, + LINKPROP_PROPERTY, + LINKPROP_VALUE, + LINKPROP_DEFAULT, + LINKPROP_POSSIBLE +} linkprop_field_index_t; + +static print_field_t linkprop_fields[] = { +/* name, header, field width, index, cmdtype */ +{ "link", "LINK", 12, LINKPROP_LINK, CMD_TYPE_ANY}, +{ "property", "PROPERTY", 15, LINKPROP_PROPERTY, CMD_TYPE_ANY}, +{ "value", "VALUE", 14, LINKPROP_VALUE, CMD_TYPE_ANY}, +{ "default", "DEFAULT", 14, LINKPROP_DEFAULT, CMD_TYPE_ANY}, +{ "possible", "POSSIBLE", 20, LINKPROP_POSSIBLE, CMD_TYPE_ANY}} +; +#define LINKPROP_MAX_FIELDS \ + (sizeof (linkprop_fields) / sizeof (print_field_t)) + +#define MAX_PROPS 32 +#define MAX_PROP_LINE 512 + +typedef struct prop_info { + char *pi_name; + char *pi_val[DLADM_MAX_PROP_VALCNT]; + uint_t pi_count; +} prop_info_t; + +typedef struct prop_list { + prop_info_t pl_info[MAX_PROPS]; + uint_t pl_count; + char *pl_buf; +} prop_list_t; + +typedef struct show_linkprop_state { + char ls_link[MAXLINKNAMELEN]; + char *ls_line; + char **ls_propvals; + prop_list_t *ls_proplist; + boolean_t ls_parseable; + boolean_t ls_persist; + boolean_t ls_header; + dladm_status_t ls_status; + dladm_status_t ls_retstatus; + print_state_t ls_print; +} show_linkprop_state_t; + +typedef struct linkprop_args_s { + show_linkprop_state_t *ls_state; + char *ls_propname; + datalink_id_t ls_linkid; +} linkprop_args_t; + +/* + * structures for 'dladm show-secobj' + */ +typedef struct secobj_fields_buf_s { + char ss_obj_name[DLADM_SECOBJ_VAL_MAX]; + char ss_class[20]; + char ss_val[30]; +} secobj_fields_buf_t; +static print_field_t secobj_fields[] = { +/* name, header, field width, offset, cmdtype */ +{ "object", "OBJECT", 20, + offsetof(secobj_fields_buf_t, ss_obj_name), CMD_TYPE_ANY}, +{ "class", "CLASS", 20, + offsetof(secobj_fields_buf_t, ss_class), CMD_TYPE_ANY}, +{ "value", "VALUE", 30, + offsetof(secobj_fields_buf_t, ss_val), CMD_TYPE_ANY}} +; +#define DEV_SOBJ_FIELDS (sizeof (secobj_fields) / sizeof (print_field_t)) static char *progname; static sig_atomic_t signalled; @@ -230,25 +789,28 @@ static void usage(void) { (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ...\n" - "\tshow-link [-pP] [-s [-i <interval>]] [<link>]\n" + "\tshow-link [-pP] [-o <field>,..] [-s [-i <interval>]] " + "[<link>]\n" "\trename-link [-R <root-dir>] <oldlink> <newlink>\n" "\n" "\tdelete-phys <link>\n" - "\tshow-phys [-pP] [<link>]\n" - "\tshow-dev [-p] [-s [-i <interval>]] [<dev>]\n" + "\tshow-phys [-pP] [-o <field>,..] [<link>]\n" + "\tshow-dev [-p] [-o <field>,..] [-s [-i <interval>]] " + "[<dev>]\n" "\n" "\tcreate-aggr [-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n" "\t [-T <time>] [-u <address>] [-l <link>] ... <link>\n" "\tmodify-aggr [-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n" "\t [-T <time>] [-u <address>] <link>\n" "\tdelete-aggr [-t] [-R <root-dir>] <link>\n" - "\tadd-aggr [-t] [-R <root-dir>] [-l <link>] ... <link>\n" + "\tadd-aggr [-t] [-R <root-dir>] [-l <link>] ... <link>\n" "\tremove-aggr [-t] [-R <root-dir>] [-l <link>] ... <link>" - "\n\tshow-aggr [-pPLx][-s [-i <interval>]] [<link>]\n" + "\n\tshow-aggr [-pPLx] [-o <field>,..] [-s [-i <interval>]] " + "[<link>]\n" "\n" "\tcreate-vlan [-ft] [-R <root-dir>] -l <link> -v <vid> [link]" "\n\tdelete-vlan [-t] [-R <root-dir>] <link>\n" - "\tshow-vlan [-pP] [<link>]\n" + "\tshow-vlan [-pP] [-o <field>,..] [<link>]\n" "\n" "\tscan-wifi [-p] [-o <field>,...] [<link>]\n" "\tconnect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...]" @@ -261,12 +823,15 @@ usage(void) "\tset-linkprop [-t] [-R <root-dir>] -p <prop>=<value>[,...]" " <name>\n" "\treset-linkprop [-t] [-R <root-dir>] [-p <prop>,...] <name>\n" - "\tshow-linkprop [-cP][-p <prop>,...] <name>\n" + "\tshow-linkprop [-cP][-o <field>,...][-p <prop>,...] <name>\n" "\n" "\tcreate-secobj [-t] [-R <root-dir>] [-f <file>] -c <class>" " <secobj>\n" "\tdelete-secobj [-t] [-R <root-dir>] <secobj>[,...]\n" - "\tshow-secobj [-pP][<secobj>,...]\n")); + "\tshow-secobj [-pP][-o <field>,...][<secobj>,...]\n" + "\n" + "\tshow-ether [-px][-o <field>,...] <link>\n")); + exit(1); } @@ -890,8 +1455,8 @@ do_create_vlan(int argc, char *argv[]) if ((status = dladm_vlan_create(vlan, linkid, vid, flags)) != DLADM_STATUS_OK) { if (status == DLADM_STATUS_NOTSUP) { - die_dlerr(status, "VLAN over '%s' may require lowered " - "MTU; must use -f (see dladm(1M))\n", link); + die_dlerr(status, "not all links have link up/down " + "detection; must use -f (see dladm(1M))\n"); } else { die_dlerr(status, "create operation failed"); } @@ -1102,40 +1667,21 @@ do_init_phys(int argc, char *argv[]) DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); } -static void -print_link_head(show_state_t *state) -{ - if (state->ls_donefirst) - return; - state->ls_donefirst = B_TRUE; - - if (state->ls_parseable) - return; - - if (state->ls_flags & DLADM_OPT_ACTIVE) { - (void) printf("%-12s%-8s%6s %-9s%s\n", "LINK", "CLASS", "MTU", - "STATE", "OVER"); - } else { - (void) printf("%-12s%-8s%s\n", "LINK", "CLASS", "OVER"); - } -} /* * Print the active topology information. */ static dladm_status_t print_link_topology(show_state_t *state, datalink_id_t linkid, - datalink_class_t class, char **pptr, char *lim) + datalink_class_t class, link_fields_buf_t *lbuf) { - char *fmt; - char over[MAXLINKNAMELEN]; uint32_t flags = state->ls_flags; dladm_status_t status = DLADM_STATUS_OK; - if (state->ls_parseable) - fmt = "OVER=\"%s"; + if (!state->ls_parseable) + (void) sprintf(lbuf->link_over, STR_UNDEF_VAL); else - fmt = "%s"; + (void) sprintf(lbuf->link_over, ""); if (class == DATALINK_CLASS_VLAN) { dladm_vlan_attr_t vinfo; @@ -1144,12 +1690,9 @@ print_link_topology(show_state_t *state, datalink_id_t linkid, if (status != DLADM_STATUS_OK) goto done; status = dladm_datalink_id2info(vinfo.dv_linkid, NULL, NULL, - NULL, over, sizeof (over)); + NULL, lbuf->link_over, sizeof (lbuf->link_over)); if (status != DLADM_STATUS_OK) goto done; - - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, over); } else if (class == DATALINK_CLASS_AGGR) { dladm_aggr_grp_attr_t ginfo; int i; @@ -1164,15 +1707,12 @@ print_link_topology(show_state_t *state, datalink_id_t linkid, } for (i = 0; i < ginfo.lg_nports; i++) { status = dladm_datalink_id2info( - ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, over, - sizeof (over)); + ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, + lbuf->link_over, sizeof (lbuf->link_over)); if (status != DLADM_STATUS_OK) { free(ginfo.lg_ports); goto done; } - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, over); - fmt = " %s"; } free(ginfo.lg_ports); } else if (class == DATALINK_CLASS_VNIC) { @@ -1180,35 +1720,21 @@ print_link_topology(show_state_t *state, datalink_id_t linkid, if ((status = dladm_vnic_info(linkid, &vinfo, flags)) != DLADM_STATUS_OK || (status = dladm_datalink_id2info( - vinfo.va_link_id, NULL, NULL, NULL, over, - sizeof (over))) != DLADM_STATUS_OK) { + vinfo.va_link_id, NULL, NULL, NULL, lbuf->link_over, + sizeof (lbuf->link_over)) != DLADM_STATUS_OK)) { goto done; } - - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, over); - } else { - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, - state->ls_parseable ? "" : "--"); } - if (state->ls_parseable) - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "\"\n"); - else - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "\n"); - done: return (status); } static dladm_status_t -print_link(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim) +print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf) { char link[MAXLINKNAMELEN]; - char buf[DLADM_STRSIZE]; datalink_class_t class; uint_t mtu; - char *fmt; uint32_t flags; dladm_status_t status; @@ -1265,40 +1791,16 @@ link_mtu: } } + (void) snprintf(lbuf->link_name, sizeof (lbuf->link_name), + "%s", link); + (void) dladm_class2str(class, lbuf->link_class); if (state->ls_flags == DLADM_OPT_ACTIVE) { - if (state->ls_parseable) - fmt = "LINK=\"%s\" CLASS=\"%s\" MTU=\"%d\" "; - else - fmt = "%-12s%-8s%6d "; - } else { - if (state->ls_parseable) - fmt = "LINK=\"%s\" CLASS=\"%s\" "; - else - fmt = "%-12s%-8s"; - } - - (void) dladm_class2str(class, buf); - if (state->ls_flags == DLADM_OPT_ACTIVE) { - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, - buf, mtu); - } else { - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, buf); - } - - (void) get_linkstate(link, B_TRUE, buf); - if (state->ls_flags == DLADM_OPT_ACTIVE) { - if (state->ls_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "STATE=\"%s\" ", buf); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-9s", buf); - } + (void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu), + "%d", mtu); + (void) get_linkstate(link, B_TRUE, lbuf->link_state); } - status = print_link_topology(state, linkid, class, pptr, lim); + status = print_link_topology(state, linkid, class, lbuf); if (status != DLADM_STATUS_OK) goto done; @@ -1306,19 +1808,29 @@ done: return (status); } + static int show_link(datalink_id_t linkid, void *arg) { - show_state_t *state = arg; - dladm_status_t status; - char buf[MAXLINELEN]; - char *ptr = buf, *lim = buf + MAXLINELEN; + show_state_t *state = (show_state_t *)arg; + dladm_status_t status; + link_fields_buf_t lbuf; + + /* + * first get all the link attributes into lbuf; + */ + status = print_link(state, linkid, &lbuf); - status = print_link(state, linkid, &ptr, lim); if (status != DLADM_STATUS_OK) goto done; - print_link_head(state); - (void) printf("%s", buf); + + if (!state->ls_parseable && !state->ls_printheader) { + print_header(&state->ls_print); + state->ls_printheader = B_TRUE; + } + + dladm_print_output(&state->ls_print, state->ls_parseable, + dladm_print_field, (void *)&lbuf); done: state->ls_status = status; @@ -1328,9 +1840,9 @@ done: static int show_link_stats(datalink_id_t linkid, void *arg) { - char link[MAXLINKNAMELEN]; + char link[DLPI_LINKNAME_MAX]; datalink_class_t class; - show_state_t *state = arg; + show_state_t *state = (show_state_t *)arg; pktsum_t stats, diff_stats; dladm_phys_attr_t dpa; @@ -1343,7 +1855,7 @@ show_link_stats(datalink_id_t linkid, void *arg) } if (dladm_datalink_id2info(linkid, NULL, &class, NULL, link, - sizeof (link)) != DLADM_STATUS_OK) { + DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { return (DLADM_WALK_CONTINUE); } @@ -1373,233 +1885,270 @@ show_link_stats(datalink_id_t linkid, void *arg) return (DLADM_WALK_CONTINUE); } -static void -print_port_stat(const char *port, pktsum_t *old_stats, pktsum_t *port_stats, - pktsum_t *tot_stats, char **pptr, char *lim) + +static dladm_status_t +print_aggr_info(show_grp_state_t *state, const char *link, + dladm_aggr_grp_attr_t *ginfop) { - pktsum_t diff_stats; + char addr_str[ETHERADDRL * 3]; + laggr_fields_buf_t lbuf; - stats_diff(&diff_stats, port_stats, old_stats); - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-12s%-10s%8llu %8llu %8llu %8llu ", "", port, - diff_stats.ipackets, diff_stats.rbytes, diff_stats.opackets, - diff_stats.obytes); + (void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name), + "%s", link); - if (tot_stats->ipackets == 0) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%8s ", "--"); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%7.1f%% ", - (double)diff_stats.ipackets/ - (double)tot_stats->ipackets * 100); - } + (void) dladm_aggr_policy2str(ginfop->lg_policy, + lbuf.laggr_policy); - if (tot_stats->opackets == 0) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%8s\n", "--"); + if (ginfop->lg_mac_fixed) { + (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); + (void) snprintf(lbuf.laggr_addrpolicy, + sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str); } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%7.1f%%\n", - (double)diff_stats.opackets/ - (double)tot_stats->opackets * 100); + (void) snprintf(lbuf.laggr_addrpolicy, + sizeof (lbuf.laggr_addrpolicy), "auto"); } - *old_stats = *port_stats; -} -static void -print_aggr_head(show_grp_state_t *state) -{ - if (state->gs_donefirst) - return; - state->gs_donefirst = B_TRUE; + (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, + lbuf.laggr_lacpactivity); + (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, + lbuf.laggr_lacptimer); + (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----", + ginfop->lg_force ? 'f' : '-'); - if (state->gs_parseable) - return; - - if (state->gs_lacp) { - (void) printf("%-12s%-12s%-13s%-5s%-5s%-5s%-10s%s\n", "LINK", - "PORT", "AGGREGATABLE", "SYNC", "COLL", "DIST", - "DEFAULTED", "EXPIRED"); - } else if (state->gs_extended) { - (void) printf("%-12s%-14s%6s %-9s%-9s%-18s%s\n", "LINK", - "PORT", "SPEED", "DUPLEX", "STATE", "ADDRESS", "PORTSTATE"); - } else if (!state->gs_stats) { - (void) printf("%-12s%-8s%-24s%-13s%-11s%s\n", "LINK", "POLICY", - "ADDRPOLICY", "LACPACTIVITY", "LACPTIMER", "FLAGS"); + if (!state->gs_parseable && !state->gs_printheader) { + print_header(&state->gs_print); + state->gs_printheader = B_TRUE; } + + dladm_print_output(&state->gs_print, state->gs_parseable, + dladm_print_field, (void *)&lbuf); + + return (DLADM_STATUS_OK); } -static dladm_status_t -print_aggr_info(show_grp_state_t *state, const char *link, - dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim) +static char * +print_xaggr_callback(print_field_t *pf, void *arg) { - char buf[DLADM_STRSIZE]; - char *fmt; - char addr_str[ETHERADDRL * 3]; - char str[ETHERADDRL * 3 + 2]; + const laggr_args_t *l = arg; + int portnum; + static char buf[DLADM_STRSIZE]; + boolean_t is_port = (l->laggr_lport >= 0); + dladm_aggr_port_attr_t *portp; + dladm_phys_attr_t dpa; + dladm_status_t *stat, status; - if (state->gs_parseable) - fmt = "LINK=\"%s\" POLICY=\"%s\" ADDRPOLICY=\"%s%s\" "; - else - fmt = "%-12s%-8s%-6s%-18s"; + stat = l->laggr_status; + *stat = DLADM_STATUS_OK; - if (ginfop->lg_mac_fixed) { - (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); - (void) snprintf(str, ETHERADDRL * 3 + 3, " (%s)", addr_str); - } else { - str[0] = '\0'; + if (is_port) { + portnum = l->laggr_lport; + portp = &(l->laggr_ginfop->lg_ports[portnum]); + if ((status = dladm_datalink_id2info(portp->lp_linkid, + NULL, NULL, NULL, buf, sizeof (buf))) != + DLADM_STATUS_OK) { + goto err; + } + if ((status = dladm_phys_info(portp->lp_linkid, &dpa, + DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { + goto err; + } } - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, - dladm_aggr_policy2str(ginfop->lg_policy, buf), - ginfop->lg_mac_fixed ? "fixed" : "auto", str); + switch (pf->pf_index) { + case AGGR_X_LINK: + (void) snprintf(buf, sizeof (buf), "%s", + (is_port && !l->laggr_parseable ? " " : l->laggr_link)); + break; + case AGGR_X_PORT: + if (is_port) + break; + return (""); + break; - (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, buf); - if (state->gs_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "LACPACTIVITY=\"%s\" ", buf); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%-13s", buf); - } + case AGGR_X_SPEED: + if (is_port) { + (void) snprintf(buf, sizeof (buf), "%uMb", + (uint_t)((get_ifspeed(dpa.dp_dev, + B_FALSE)) / 1000000ull)); + } else { + (void) snprintf(buf, sizeof (buf), "%uMb", + (uint_t)((get_ifspeed(l->laggr_link, + B_TRUE)) / 1000000ull)); + } + break; - (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, buf); - if (state->gs_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "LACPTIMER=\"%s\" FLAGS=\"%c----\"\n", buf, - ginfop->lg_force ? 'f' : '-'); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-11s%c----\n", buf, ginfop->lg_force ? 'f' : '-'); + case AGGR_X_DUPLEX: + if (is_port) + (void) get_linkduplex(dpa.dp_dev, B_FALSE, buf); + else + (void) get_linkduplex(l->laggr_link, B_TRUE, buf); + break; + + case AGGR_X_STATE: + if (is_port) { + (void) dladm_aggr_portstate2str( + portp->lp_state, buf); + } else { + return (STR_UNDEF_VAL); + } + break; + case AGGR_X_ADDRESS: + (void) dladm_aggr_macaddr2str( + (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac), + buf); + break; + + case AGGR_X_PORTSTATE: + (void) snprintf(buf, sizeof (buf), "%s", + (is_port ? dladm_aggr_portstate2str(portp->lp_state, buf): + (l->laggr_parseable ? "" : STR_UNDEF_VAL))); + break; } + return (buf); - return (DLADM_STATUS_OK); +err: + *stat = status; + buf[0] = '\0'; + return (buf); } static dladm_status_t print_aggr_extended(show_grp_state_t *state, const char *link, - dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim) + dladm_aggr_grp_attr_t *ginfop) { - char addr_str[ETHERADDRL * 3]; - char port[MAXLINKNAMELEN]; - dladm_phys_attr_t dpa; - char buf[DLADM_STRSIZE]; - char *fmt; int i; dladm_status_t status; + laggr_args_t largs; - if (state->gs_parseable) - fmt = "LINK=\"%s\" PORT=\"%s\" SPEED=\"%uMb\" DUPLEX=\"%s\" "; - else - fmt = "%-12s%-14s%4uMb %-9s"; + if (!state->gs_parseable && !state->gs_printheader) { + print_header(&state->gs_print); + state->gs_printheader = B_TRUE; + } - (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); + largs.laggr_lport = -1; + largs.laggr_link = link; + largs.laggr_ginfop = ginfop; + largs.laggr_status = &status; + largs.laggr_parseable = state->gs_parseable; - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, - state->gs_parseable ? "" : "--", - (uint_t)((get_ifspeed(link, B_TRUE)) / 1000000ull), - get_linkduplex(link, B_TRUE, buf)); + dladm_print_output(&state->gs_print, state->gs_parseable, + print_xaggr_callback, &largs); - (void) get_linkstate(link, B_TRUE, buf); - if (state->gs_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "STATE=\"%s\" ADDRESS=\"%s\" PORTSTATE=\"%s\"\n", buf, - addr_str, ""); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%-9s%-18s%s\n", - buf, addr_str, "--"); - } + if (status != DLADM_STATUS_OK) + goto done; for (i = 0; i < ginfop->lg_nports; i++) { - dladm_aggr_port_attr_t *portp = &(ginfop->lg_ports[i]); - const char *tmp; - - if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL, - NULL, NULL, port, sizeof (port))) != DLADM_STATUS_OK) { + largs.laggr_lport = i; + dladm_print_output(&state->gs_print, state->gs_parseable, + print_xaggr_callback, &largs); + if (status != DLADM_STATUS_OK) goto done; - } + } - if ((status = dladm_phys_info(portp->lp_linkid, &dpa, - DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { - goto done; - } + status = DLADM_STATUS_OK; +done: + return (status); +} - (void) dladm_aggr_macaddr2str(portp->lp_mac, addr_str); - if (state->gs_parseable) - tmp = link; - else - tmp = ""; +static char * +print_lacp_callback(print_field_t *pf, void *arg) +{ + const laggr_args_t *l = arg; + int portnum; + static char buf[DLADM_STRSIZE]; + boolean_t is_port = (l->laggr_lport >= 0); + dladm_aggr_port_attr_t *portp; + dladm_status_t *stat, status; + aggr_lacp_state_t *lstate; - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, tmp, port, - (uint_t)((get_ifspeed(dpa.dp_dev, B_FALSE)) / 1000000ull), - get_linkduplex(dpa.dp_dev, B_FALSE, buf)); + if (!is_port) { + return (NULL); /* cannot happen! */ + } - (void) get_linkstate(dpa.dp_dev, B_FALSE, buf); - if (state->gs_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "STATE=\"%s\" ADDRESS=\"%s\" ", buf, addr_str); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-9s%-18s", buf, addr_str); - } + stat = l->laggr_status; - (void) dladm_aggr_portstate2str( - ginfop->lg_ports[i].lp_state, buf); - if (state->gs_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "PORTSTATE=\"%s\"\n", buf); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%s\n", buf); - } + portnum = l->laggr_lport; + portp = &(l->laggr_ginfop->lg_ports[portnum]); + if ((status = dladm_datalink_id2info(portp->lp_linkid, + NULL, NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) { + goto err; } + lstate = &(portp->lp_lacp_state); - status = DLADM_STATUS_OK; -done: - return (status); + switch (pf->pf_index) { + case AGGR_L_LINK: + (void) snprintf(buf, sizeof (buf), "%s", + (portnum > 0 ? "" : l->laggr_link)); + break; + + case AGGR_L_PORT: + break; + + case AGGR_L_AGGREGATABLE: + (void) snprintf(buf, sizeof (buf), "%s", + (lstate->bit.aggregation ? "yes" : "no")); + break; + + case AGGR_L_SYNC: + (void) snprintf(buf, sizeof (buf), "%s", + (lstate->bit.sync ? "yes" : "no")); + break; + + case AGGR_L_COLL: + (void) snprintf(buf, sizeof (buf), "%s", + (lstate->bit.collecting ? "yes" : "no")); + break; + + case AGGR_L_DIST: + (void) snprintf(buf, sizeof (buf), "%s", + (lstate->bit.distributing ? "yes" : "no")); + break; + + case AGGR_L_DEFAULTED: + (void) snprintf(buf, sizeof (buf), "%s", + (lstate->bit.defaulted ? "yes" : "no")); + break; + + case AGGR_L_EXPIRED: + (void) snprintf(buf, sizeof (buf), "%s", + (lstate->bit.expired ? "yes" : "no")); + break; + } + + *stat = DLADM_STATUS_OK; + return (buf); + +err: + *stat = status; + buf[0] = '\0'; + return (buf); } static dladm_status_t print_aggr_lacp(show_grp_state_t *state, const char *link, - dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim) + dladm_aggr_grp_attr_t *ginfop) { - char port[MAXLINKNAMELEN]; - char *fmt; - const char *dlink = link; int i; dladm_status_t status; + laggr_args_t largs; - if (state->gs_parseable) { - fmt = "LINK=\"%s\" PORT=\"%s\" AGGREGATABLE=\"%s\" SYNC=\"%s\" " - "COLL=\"%s\" DIST=\"%s\" DEFAULTED=\"%s\" EXPITED=\"%s\"\n"; - } else { - fmt = "%-12s%-12s%-13s%-5s%-5s%-5s%-10s%s\n"; + if (!state->gs_parseable && !state->gs_printheader) { + print_header(&state->gs_print); + state->gs_printheader = B_TRUE; } - for (i = 0; i < ginfop->lg_nports; i++) { - aggr_lacp_state_t *lstate; + largs.laggr_link = link; + largs.laggr_ginfop = ginfop; + largs.laggr_status = &status; - status = dladm_datalink_id2info(ginfop->lg_ports[i].lp_linkid, - NULL, NULL, NULL, port, sizeof (port)); + for (i = 0; i < ginfop->lg_nports; i++) { + largs.laggr_lport = i; + dladm_print_output(&state->gs_print, state->gs_parseable, + print_lacp_callback, &largs); if (status != DLADM_STATUS_OK) goto done; - - /* - * Only display link for the first port. - */ - if ((i > 0) && !(state->gs_parseable)) - dlink = ""; - lstate = &(ginfop->lg_ports[i].lp_lacp_state); - - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, dlink, port, - lstate->bit.aggregation ? "yes" : "no", - lstate->bit.sync ? "yes" : "no", - lstate->bit.collecting ? "yes" : "no", - lstate->bit.distributing ? "yes" : "no", - lstate->bit.defaulted ? "yes" : "no", - lstate->bit.expired ? "yes" : "no"); } status = DLADM_STATUS_OK; @@ -1607,24 +2156,127 @@ done: return (status); } +static char * +print_aggr_stats_callback(print_field_t *pf, void *arg) +{ + const laggr_args_t *l = arg; + int portnum; + static char buf[DLADM_STRSIZE]; + boolean_t is_port = (l->laggr_lport >= 0); + dladm_aggr_port_attr_t *portp; + dladm_phys_attr_t dpa; + dladm_status_t *stat, status; + pktsum_t port_stat, diff_stats; + + stat = l->laggr_status; + *stat = DLADM_STATUS_OK; + + if (is_port) { + portnum = l->laggr_lport; + portp = &(l->laggr_ginfop->lg_ports[portnum]); + if ((status = dladm_phys_info(portp->lp_linkid, &dpa, + DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { + goto err; + } + + get_mac_stats(dpa.dp_dev, &port_stat); + + if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL, + NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) { + goto err; + } + + stats_diff(&diff_stats, &port_stat, l->laggr_prevstats); + } + + switch (pf->pf_index) { + case AGGR_S_LINK: + (void) snprintf(buf, sizeof (buf), "%s", + (is_port ? "" : l->laggr_link)); + break; + case AGGR_S_PORT: + if (is_port) + break; + return (STR_UNDEF_VAL); + break; + + case AGGR_S_IPKTS: + if (is_port) { + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats.ipackets); + } else { + (void) snprintf(buf, sizeof (buf), "%llu", + l->laggr_pktsumtot->ipackets); + } + break; + + case AGGR_S_RBYTES: + if (is_port) { + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats.rbytes); + } else { + (void) snprintf(buf, sizeof (buf), "%llu", + l->laggr_pktsumtot->rbytes); + } + break; + + case AGGR_S_OPKTS: + if (is_port) { + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats.opackets); + } else { + (void) snprintf(buf, sizeof (buf), "%llu", + l->laggr_pktsumtot->opackets); + } + break; + case AGGR_S_OBYTES: + if (is_port) { + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats.obytes); + } else { + (void) snprintf(buf, sizeof (buf), "%llu", + l->laggr_pktsumtot->obytes); + + } + break; + + case AGGR_S_IPKTDIST: + if (is_port) { + (void) snprintf(buf, sizeof (buf), "%-6.1f", + (double)diff_stats.opackets/ + (double)l->laggr_pktsumtot->ipackets * 100); + } else { + return (STR_UNDEF_VAL); + } + break; + case AGGR_S_OPKTDIST: + if (is_port) { + (void) snprintf(buf, sizeof (buf), "%-6.1f", + (double)diff_stats.opackets/ + (double)l->laggr_pktsumtot->opackets * 100); + } else { + (void) sprintf(buf, STR_UNDEF_VAL); + } + break; + } + return (buf); + +err: + *stat = status; + buf[0] = '\0'; + return (buf); +} + static dladm_status_t print_aggr_stats(show_grp_state_t *state, const char *link, - dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim) + dladm_aggr_grp_attr_t *ginfop) { - char port[MAXLINKNAMELEN]; dladm_phys_attr_t dpa; dladm_aggr_port_attr_t *portp; pktsum_t pktsumtot, port_stat; dladm_status_t status; int i; - - if (state->gs_firstonly) { - if (state->gs_donefirst) - return (DLADM_WALK_CONTINUE); - state->gs_donefirst = B_TRUE; - } else { - bzero(&state->gs_prevstats, sizeof (state->gs_prevstats)); - } + laggr_args_t largs; /* sum the ports statistics */ bzero(&pktsumtot, sizeof (pktsumtot)); @@ -1641,28 +2293,30 @@ print_aggr_stats(show_grp_state_t *state, const char *link, stats_total(&pktsumtot, &port_stat, &state->gs_prevstats[i]); } - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-12s%-10s%8llu %8llu %8llu %8llu %8s %8s\n", link, "--", - pktsumtot.ipackets, pktsumtot.rbytes, pktsumtot.opackets, - pktsumtot.obytes, "--", "--"); + if (!state->gs_parseable && !state->gs_printheader) { + print_header(&state->gs_print); + state->gs_printheader = B_TRUE; + } - for (i = 0; i < ginfop->lg_nports; i++) { - portp = &(ginfop->lg_ports[i]); + largs.laggr_lport = -1; + largs.laggr_link = link; + largs.laggr_ginfop = ginfop; + largs.laggr_status = &status; + largs.laggr_pktsumtot = &pktsumtot; - if ((status = dladm_phys_info(portp->lp_linkid, &dpa, - DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { - goto done; - } + dladm_print_output(&state->gs_print, state->gs_parseable, + print_aggr_stats_callback, &largs); - get_mac_stats(dpa.dp_dev, &port_stat); + if (status != DLADM_STATUS_OK) + goto done; - if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL, - NULL, NULL, port, sizeof (port))) != DLADM_STATUS_OK) { + for (i = 0; i < ginfop->lg_nports; i++) { + largs.laggr_lport = i; + largs.laggr_prevstats = &state->gs_prevstats[i]; + dladm_print_output(&state->gs_print, state->gs_parseable, + print_aggr_stats_callback, &largs); + if (status != DLADM_STATUS_OK) goto done; - } - - print_port_stat(port, &state->gs_prevstats[i], &port_stat, - &pktsumtot, pptr, lim); } status = DLADM_STATUS_OK; @@ -1671,8 +2325,7 @@ done: } static dladm_status_t -print_aggr(show_grp_state_t *state, datalink_id_t linkid, char **pptr, - char *lim) +print_aggr(show_grp_state_t *state, datalink_id_t linkid) { char link[MAXLINKNAMELEN]; dladm_aggr_grp_attr_t ginfo; @@ -1680,7 +2333,7 @@ print_aggr(show_grp_state_t *state, datalink_id_t linkid, char **pptr, dladm_status_t status; if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link, - sizeof (link))) != DLADM_STATUS_OK) { + MAXLINKNAMELEN)) != DLADM_STATUS_OK) { return (status); } @@ -1692,13 +2345,14 @@ print_aggr(show_grp_state_t *state, datalink_id_t linkid, char **pptr, return (status); if (state->gs_lacp) - status = print_aggr_lacp(state, link, &ginfo, pptr, lim); + status = print_aggr_lacp(state, link, &ginfo); else if (state->gs_extended) - status = print_aggr_extended(state, link, &ginfo, pptr, lim); + status = print_aggr_extended(state, link, &ginfo); else if (state->gs_stats) - status = print_aggr_stats(state, link, &ginfo, pptr, lim); - else - status = print_aggr_info(state, link, &ginfo, pptr, lim); + status = print_aggr_stats(state, link, &ginfo); + else { + status = print_aggr_info(state, link, &ginfo); + } done: free(ginfo.lg_ports); @@ -1710,83 +2364,107 @@ show_aggr(datalink_id_t linkid, void *arg) { show_grp_state_t *state = arg; dladm_status_t status; - char buf[MAXLINELEN]; - char *ptr = buf, *lim = buf + MAXLINELEN; - status = print_aggr(state, linkid, &ptr, lim); + status = print_aggr(state, linkid); if (status != DLADM_STATUS_OK) goto done; - print_aggr_head(state); - (void) printf("%s", buf); done: state->gs_status = status; return (DLADM_WALK_CONTINUE); } -static int -kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) +static char * +print_dev(print_field_t *pf, void *arg) { - kstat_named_t *knp; - - if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) - return (-1); - - if (knp->data_type != type) - return (-1); + const char *dev = arg; + static char buf[DLADM_STRSIZE]; - switch (type) { - case KSTAT_DATA_UINT64: - *(uint64_t *)buf = knp->value.ui64; + switch (pf->pf_index) { + case DEV_LINK: + (void) snprintf(buf, sizeof (buf), "%s", dev); + break; + case DEV_STATE: + (void) get_linkstate(dev, B_FALSE, buf); + break; + case DEV_SPEED: + (void) snprintf(buf, sizeof (buf), "%uMb", + (unsigned int)(get_ifspeed(dev, B_FALSE) / 1000000ull)); break; - case KSTAT_DATA_UINT32: - *(uint32_t *)buf = knp->value.ui32; + case DEV_DUPLEX: + (void) get_linkduplex(dev, B_FALSE, buf); break; default: - return (-1); + die("invalid index '%d'", pf->pf_index); + break; } - - return (0); + return (buf); } static int show_dev(const char *dev, void *arg) { show_state_t *state = arg; - char buf[DLADM_STRSIZE]; - char *fmt; - - if (state->ls_parseable) - fmt = "DEV=\"%s\" STATE=\"%s\" SPEED=\"%u\" "; - else - fmt = "%-12s%-10s%4uMb "; - if (!state->ls_donefirst) { - if (!state->ls_parseable) { - (void) printf("%-12s%-10s%6s %s\n", "DEV", "STATE", - "SPEED", "DUPLEX"); - } - state->ls_donefirst = B_TRUE; + if (!state->ls_parseable && !state->ls_printheader) { + print_header(&state->ls_print); + state->ls_printheader = B_TRUE; } - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - (void) printf(fmt, dev, get_linkstate(dev, B_FALSE, buf), - (uint_t)(get_ifspeed(dev, B_FALSE) / 1000000ull)); - - (void) get_linkduplex(dev, B_FALSE, buf); - if (state->ls_parseable) - (void) printf("DUPLEX=\"%s\"\n", buf); - else - (void) printf("%s\n", buf); + dladm_print_output(&state->ls_print, state->ls_parseable, + print_dev, (void *)dev); return (DLADM_WALK_CONTINUE); } +static char * +print_dev_stats(print_field_t *pf, void *arg) +{ + dev_args_t *dargs = arg; + pktsum_t *diff_stats = dargs->devs_psum; + static char buf[DLADM_STRSIZE]; + + switch (pf->pf_index) { + case DEVS_LINK: + (void) snprintf(buf, sizeof (buf), "%s", dargs->devs_link); + break; + case DEVS_IPKTS: + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats->ipackets); + break; + case DEVS_RBYTES: + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats->rbytes); + break; + case DEVS_IERRORS: + (void) snprintf(buf, sizeof (buf), "%u", + diff_stats->ierrors); + break; + case DEVS_OPKTS: + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats->opackets); + break; + case DEVS_OBYTES: + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats->obytes); + break; + case DEVS_OERRORS: + (void) snprintf(buf, sizeof (buf), "%u", + diff_stats->oerrors); + break; + default: + die("invalid input"); + break; + } + return (buf); +} + static int show_dev_stats(const char *dev, void *arg) { show_state_t *state = arg; pktsum_t stats, diff_stats; + dev_args_t dargs; if (state->ls_firstonly) { if (state->ls_donefirst) @@ -1799,13 +2477,10 @@ show_dev_stats(const char *dev, void *arg) get_mac_stats(dev, &stats); stats_diff(&diff_stats, &stats, &state->ls_prevstats); - (void) printf("%-12s", dev); - (void) printf("%-10llu", diff_stats.ipackets); - (void) printf("%-12llu", diff_stats.rbytes); - (void) printf("%-8u", diff_stats.ierrors); - (void) printf("%-10llu", diff_stats.opackets); - (void) printf("%-12llu", diff_stats.obytes); - (void) printf("%-8u\n", diff_stats.oerrors); + dargs.devs_link = (char *)dev; + dargs.devs_psum = &diff_stats; + dladm_print_output(&state->ls_print, state->ls_parseable, + print_dev_stats, &dargs); state->ls_prevstats = stats; return (DLADM_WALK_CONTINUE); @@ -1823,9 +2498,17 @@ do_show_link(int argc, char *argv[]) int interval = 0; show_state_t state; dladm_status_t status; + boolean_t o_arg = B_FALSE; + char *fields_str = NULL; + print_field_t **fields; + uint_t nfields; + char *all_active_fields = "link,class,mtu,state,over"; + char *all_inactive_fields = "link,class,over"; + + bzero(&state, sizeof (state)); opterr = 0; - while ((option = getopt_long(argc, argv, ":pPsi:", + while ((option = getopt_long(argc, argv, ":pPsi:o:", show_lopts, NULL)) != -1) { switch (option) { case 'p': @@ -1846,6 +2529,10 @@ do_show_link(int argc, char *argv[]) flags = DLADM_OPT_PERSIST; break; + case 'o': + o_arg = B_TRUE; + fields_str = optarg; + break; case 'i': if (i_arg) die_optdup(option); @@ -1892,6 +2579,26 @@ do_show_link(int argc, char *argv[]) state.ls_parseable = p_arg; state.ls_flags = flags; state.ls_donefirst = B_FALSE; + + if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { + if (state.ls_flags & DLADM_OPT_ACTIVE) + fields_str = all_active_fields; + else + fields_str = all_inactive_fields; + } + + + fields = parse_output_fields(fields_str, link_fields, DEV_LINK_FIELDS, + CMD_TYPE_ANY, &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + return; + } + + state.ls_print.ps_fields = fields; + state.ls_print.ps_nfields = nfields; + if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(show_link, &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); @@ -1919,9 +2626,25 @@ do_show_aggr(int argc, char *argv[]) int interval = 0; int key; dladm_status_t status; + boolean_t o_arg = B_FALSE; + char *fields_str = NULL; + print_field_t **fields; + uint_t nfields; + char *all_fields = + "link,policy,addrpolicy,lacpactivity,lacptimer,flags"; + char *all_lacp_fields = + "link,port,aggregatable,sync,coll,dist,defaulted,expired"; + char *all_stats_fields = + "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist"; + char *all_extended_fields = + "link,port,speed,duplex,state,address,portstate"; + print_field_t *pf; + int pfmax; + + bzero(&state, sizeof (state)); opterr = 0; - while ((option = getopt_long(argc, argv, ":LpPxsi:", + while ((option = getopt_long(argc, argv, ":LpPxsi:o:", show_lopts, NULL)) != -1) { switch (option) { case 'L': @@ -1954,6 +2677,10 @@ do_show_aggr(int argc, char *argv[]) s_arg = B_TRUE; break; + case 'o': + o_arg = B_TRUE; + fields_str = optarg; + break; case 'i': if (i_arg) die_optdup(option); @@ -2006,6 +2733,41 @@ do_show_aggr(int argc, char *argv[]) state.gs_parseable = p_arg; state.gs_extended = x_arg; + if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { + if (state.gs_lacp) + fields_str = all_lacp_fields; + else if (state.gs_stats) + fields_str = all_stats_fields; + else if (state.gs_extended) + fields_str = all_extended_fields; + else + fields_str = all_fields; + } + + if (state.gs_lacp) { + pf = aggr_l_fields; + pfmax = AGGR_L_MAX_FIELDS; + } else if (state.gs_stats) { + pf = aggr_s_fields; + pfmax = AGGR_S_MAX_FIELDS; + } else if (state.gs_extended) { + pf = aggr_x_fields; + pfmax = AGGR_X_MAX_FIELDS; + } else { + pf = laggr_fields; + pfmax = LAGGR_MAX_FIELDS; + } + fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY, + &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + return; + } + + state.gs_print.ps_fields = fields; + state.gs_print.ps_nfields = nfields; + if (s_arg) { aggr_stats(linkid, &state, interval); return; @@ -2030,13 +2792,23 @@ do_show_dev(int argc, char *argv[]) char *dev = NULL; boolean_t s_arg = B_FALSE; boolean_t i_arg = B_FALSE; + boolean_t o_arg = B_FALSE; boolean_t p_arg = B_FALSE; datalink_id_t linkid; int interval = 0; show_state_t state; + char *fields_str = NULL; + print_field_t **fields; + uint_t nfields; + char *all_fields = "link,state,speed,duplex"; + static char *allstat_fields = + "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; + + bzero(&state, sizeof (state)); + fields_str = all_fields; opterr = 0; - while ((option = getopt_long(argc, argv, ":psi:", + while ((option = getopt_long(argc, argv, ":psi:o:", show_lopts, NULL)) != -1) { switch (option) { case 'p': @@ -2051,6 +2823,10 @@ do_show_dev(int argc, char *argv[]) s_arg = B_TRUE; break; + case 'o': + o_arg = B_TRUE; + fields_str = optarg; + break; case 'i': if (i_arg) die_optdup(option); @@ -2068,6 +2844,16 @@ do_show_dev(int argc, char *argv[]) if (i_arg && !s_arg) die("the option -i can be used only with -s"); + if (o_arg && strcasecmp(fields_str, "all") == 0) { + if (!s_arg) + fields_str = all_fields; + else + fields_str = allstat_fields; + } + + if (!o_arg && s_arg) + fields_str = allstat_fields; + if (s_arg && p_arg) die("the option -s cannot be used with -p"); @@ -2089,52 +2875,45 @@ do_show_dev(int argc, char *argv[]) usage(); } + state.ls_parseable = p_arg; + state.ls_donefirst = B_FALSE; + if (s_arg) { - dev_stats(dev, interval); + dev_stats(dev, interval, fields_str, &state); return; } - state.ls_donefirst = B_FALSE; - state.ls_parseable = p_arg; - if (dev == NULL) { - (void) dladm_mac_walk(show_dev, &state); - } else { - (void) show_dev(dev, &state); - } -} + fields = parse_output_fields(fields_str, dev_fields, DEV_MAX_FIELDS, + CMD_TYPE_ANY, &nfields); -static void -print_phys_head(show_state_t *state) -{ - if (state->ls_donefirst) + if (fields == NULL) { + die("invalid field(s) specified"); return; - state->ls_donefirst = B_TRUE; + } - if (state->ls_parseable) - return; + state.ls_print.ps_fields = fields; + state.ls_print.ps_nfields = nfields; - if (state->ls_flags == DLADM_OPT_ACTIVE) { - (void) printf("%-12s%-20s%-10s%6s %-9s%s\n", "LINK", - "MEDIA", "STATE", "SPEED", "DUPLEX", "DEVICE"); + if (dev == NULL) { + (void) dladm_mac_walk(show_dev, &state); } else { - (void) printf("%-12s%-12s%-20s%s\n", "LINK", "DEVICE", - "MEDIA", "FLAGS"); + (void) show_dev(dev, &state); } } + static dladm_status_t -print_phys(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim) +print_phys(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *pattr) { char link[MAXLINKNAMELEN]; dladm_phys_attr_t dpa; - char buf[DLADM_STRSIZE]; uint32_t flags; datalink_class_t class; uint32_t media; dladm_status_t status; if ((status = dladm_datalink_id2info(linkid, &flags, &class, &media, - link, sizeof (link))) != DLADM_STATUS_OK) { + link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { goto done; } @@ -2152,58 +2931,39 @@ print_phys(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim) if (status != DLADM_STATUS_OK) goto done; + (void) snprintf(pattr->link_phys_device, + sizeof (pattr->link_phys_device), "%s", dpa.dp_dev); + (void) dladm_media2str(media, pattr->link_phys_media); if (state->ls_flags == DLADM_OPT_ACTIVE) { - char name[MAXLINKNAMELEN]; boolean_t islink; if (!dpa.dp_novanity) { - (void) strlcpy(name, link, sizeof (name)); + (void) strlcpy(pattr->link_name, link, + sizeof (pattr->link_name)); islink = B_TRUE; } else { /* * This is a physical link that does not have * vanity naming support. */ - (void) strlcpy(name, dpa.dp_dev, sizeof (name)); + (void) strlcpy(pattr->link_name, dpa.dp_dev, + sizeof (pattr->link_name)); islink = B_FALSE; } - if (state->ls_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "LINK=\"%s\" MEDIA=\"%s\" ", link, - dladm_media2str(media, buf)); - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "STATE=\"%s\" SPEED=\"%uMb\" ", - get_linkstate(name, islink, buf), - (uint_t)((get_ifspeed(name, islink)) / 1000000ull)); - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "DUPLEX=\"%s\" DEVICE=\"%s\"\n", - get_linkduplex(name, islink, buf), dpa.dp_dev); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-12s%-20s", link, - dladm_media2str(media, buf)); - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-10s%4uMb ", - get_linkstate(name, islink, buf), - (uint_t)((get_ifspeed(name, islink)) / 1000000ull)); - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-9s%s\n", get_linkduplex(name, islink, buf), - dpa.dp_dev); - } + (void) get_linkstate(pattr->link_name, islink, + pattr->link_phys_state); + (void) snprintf(pattr->link_phys_speed, + sizeof (pattr->link_phys_speed), "%u", + (uint_t)((get_ifspeed(pattr->link_name, + islink)) / 1000000ull)); + (void) get_linkduplex(pattr->link_name, islink, + pattr->link_phys_duplex); } else { - if (state->ls_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "LINK=\"%s\" DEVICE=\"%s\" MEDIA=\"%s\" " - "FLAGS=\"%c----\"\n", link, dpa.dp_dev, - dladm_media2str(media, buf), - flags & DLADM_OPT_ACTIVE ? '-' : 'r'); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-12s%-12s%-20s%c----\n", link, - dpa.dp_dev, dladm_media2str(media, buf), - flags & DLADM_OPT_ACTIVE ? '-' : 'r'); - } + (void) snprintf(pattr->link_name, sizeof (pattr->link_name), + "%s", link); + (void) snprintf(pattr->link_flags, sizeof (pattr->link_flags), + "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r'); } done: @@ -2215,48 +2975,38 @@ show_phys(datalink_id_t linkid, void *arg) { show_state_t *state = arg; dladm_status_t status; - char buf[MAXLINELEN]; - char *ptr = buf, *lim = buf + MAXLINELEN; + link_fields_buf_t pattr; - status = print_phys(state, linkid, &ptr, lim); + status = print_phys(state, linkid, &pattr); if (status != DLADM_STATUS_OK) goto done; - print_phys_head(state); - (void) printf("%s", buf); + + if (!state->ls_parseable && !state->ls_printheader) { + print_header(&state->ls_print); + state->ls_printheader = B_TRUE; + } + + dladm_print_output(&state->ls_print, state->ls_parseable, + dladm_print_field, (void *)&pattr); done: state->ls_status = status; return (DLADM_WALK_CONTINUE); } -static void -print_vlan_head(show_state_t *state) -{ - if (state->ls_donefirst) - return; - state->ls_donefirst = B_TRUE; - - if (state->ls_parseable) - return; - - (void) printf("%-12s%5s %-12s%s\n", "LINK", "VID", "OVER", "FLAGS"); -} /* * Print the active topology information. */ static dladm_status_t -print_vlan(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim) +print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l) { - char link[MAXLINKNAMELEN]; - char over[MAXLINKNAMELEN]; - char *fmt; dladm_vlan_attr_t vinfo; uint32_t flags; dladm_status_t status; - if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link, - sizeof (link))) != DLADM_STATUS_OK) { + if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, + l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) { goto done; } @@ -2267,19 +3017,15 @@ print_vlan(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim) if ((status = dladm_vlan_info(linkid, &vinfo, state->ls_flags)) != DLADM_STATUS_OK || (status = dladm_datalink_id2info( - vinfo.dv_linkid, NULL, NULL, NULL, over, sizeof (over))) != - DLADM_STATUS_OK) { + vinfo.dv_linkid, NULL, NULL, NULL, l->link_over, + sizeof (l->link_over))) != DLADM_STATUS_OK) { goto done; } - if (state->ls_parseable) - fmt = "LINK=\"%s\" VID=\"%d\" OVER=\"%s\" FLAGS=\"%c%c---\"\n"; - else - fmt = "%-12s%5d %-12s%c%c---\n"; - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, - vinfo.dv_vid, over, vinfo.dv_force ? 'f' : '-', - vinfo.dv_implicit ? 'i' : '-'); + (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d", + vinfo.dv_vid); + (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c%c---", + vinfo.dv_force ? 'f' : '-', vinfo.dv_implicit ? 'i' : '-'); done: return (status); @@ -2290,14 +3036,19 @@ show_vlan(datalink_id_t linkid, void *arg) { show_state_t *state = arg; dladm_status_t status; - char buf[MAXLINELEN]; - char *ptr = buf, *lim = buf + MAXLINELEN; + link_fields_buf_t lbuf; - status = print_vlan(state, linkid, &ptr, lim); + status = print_vlan(state, linkid, &lbuf); if (status != DLADM_STATUS_OK) goto done; - print_vlan_head(state); - (void) printf("%s", buf); + + if (!state->ls_parseable && !state->ls_printheader) { + print_header(&state->ls_print); + state->ls_printheader = B_TRUE; + } + + dladm_print_output(&state->ls_print, state->ls_parseable, + dladm_print_field, (void *)&lbuf); done: state->ls_status = status; @@ -2310,12 +3061,21 @@ do_show_phys(int argc, char *argv[]) int option; uint32_t flags = DLADM_OPT_ACTIVE; boolean_t p_arg = B_FALSE; + boolean_t o_arg = B_FALSE; datalink_id_t linkid = DATALINK_ALL_LINKID; show_state_t state; dladm_status_t status; + char *fields_str = NULL; + print_field_t **fields; + uint_t nfields; + char *all_active_fields = + "link,media,state,speed,duplex,device"; + char *all_inactive_fields = + "link,device,media,flags"; + bzero(&state, sizeof (state)); opterr = 0; - while ((option = getopt_long(argc, argv, ":pP", + while ((option = getopt_long(argc, argv, ":pPo:", show_lopts, NULL)) != -1) { switch (option) { case 'p': @@ -2330,6 +3090,10 @@ do_show_phys(int argc, char *argv[]) flags = DLADM_OPT_PERSIST; break; + case 'o': + o_arg = B_TRUE; + fields_str = optarg; + break; default: die_opterr(optopt, option); break; @@ -2350,6 +3114,24 @@ do_show_phys(int argc, char *argv[]) state.ls_flags = flags; state.ls_donefirst = B_FALSE; + if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { + if (state.ls_flags & DLADM_OPT_ACTIVE) + fields_str = all_active_fields; + else + fields_str = all_inactive_fields; + } + + fields = parse_output_fields(fields_str, phys_fields, + PHYS_MAX_FIELDS, CMD_TYPE_ANY, &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + return; + } + + state.ls_print.ps_fields = fields; + state.ls_print.ps_nfields = nfields; + if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(show_phys, &state, DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags); @@ -2371,9 +3153,16 @@ do_show_vlan(int argc, char *argv[]) datalink_id_t linkid = DATALINK_ALL_LINKID; show_state_t state; dladm_status_t status; + boolean_t o_arg = B_FALSE; + char *fields_str = NULL; + print_field_t **fields; + uint_t nfields; + char *all_fields = "link,vid,over,flags"; + + bzero(&state, sizeof (state)); opterr = 0; - while ((option = getopt_long(argc, argv, ":pP", + while ((option = getopt_long(argc, argv, ":pPo:", show_lopts, NULL)) != -1) { switch (option) { case 'p': @@ -2388,6 +3177,10 @@ do_show_vlan(int argc, char *argv[]) flags = DLADM_OPT_PERSIST; break; + case 'o': + o_arg = B_TRUE; + fields_str = optarg; + break; default: die_opterr(optopt, option); break; @@ -2408,6 +3201,19 @@ do_show_vlan(int argc, char *argv[]) state.ls_flags = flags; state.ls_donefirst = B_FALSE; + if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) + fields_str = all_fields; + + fields = parse_output_fields(fields_str, vlan_fields, VLAN_MAX_FIELDS, + CMD_TYPE_ANY, &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + return; + } + state.ls_print.ps_fields = fields; + state.ls_print.ps_nfields = nfields; + if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(show_vlan, &state, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags); @@ -2464,11 +3270,6 @@ aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) state->gs_firstonly = (interval != 0); for (;;) { - - (void) printf("%-12s%-10s%8s %8s %8s %8s %-9s%s\n", - "LINK", "PORT", "IPACKETS", "RBYTES", "OPACKETS", - "OBYTES", "IPKTDIST", "OPKTDIST"); - state->gs_donefirst = B_FALSE; if (linkid == DATALINK_ALL_LINKID) (void) dladm_walk_datalink_id(show_aggr, state, @@ -2485,29 +3286,40 @@ aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) } static void -dev_stats(const char *dev, uint32_t interval) +dev_stats(const char *dev, uint32_t interval, char *fields_str, + show_state_t *state) { - show_state_t state; + print_field_t **fields; + uint_t nfields; + + fields = parse_output_fields(fields_str, devs_fields, DEVS_MAX_FIELDS, + CMD_TYPE_ANY, &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + return; + } + + state->ls_print.ps_fields = fields; + state->ls_print.ps_nfields = nfields; - bzero(&state, sizeof (state)); /* * If an interval is specified, continuously show the stats * only for the first MAC port. */ - state.ls_firstonly = (interval != 0); + state->ls_firstonly = (interval != 0); for (;;) { - (void) printf("%-12s%-10s%-12s%-8s%-10s%-12s%-8s\n", - "DEV", "IPACKETS", "RBYTES", "IERRORS", "OPACKETS", - "OBYTES", "OERRORS"); + if (!state->ls_parseable) + print_header(&state->ls_print); + state->ls_donefirst = B_FALSE; - state.ls_donefirst = B_FALSE; if (dev == NULL) - (void) dladm_mac_walk(show_dev_stats, &state); + (void) dladm_mac_walk(show_dev_stats, state); else - (void) show_dev_stats(dev, &state); + (void) show_dev_stats(dev, state); if (interval == 0) break; @@ -2515,8 +3327,8 @@ dev_stats(const char *dev, uint32_t interval) (void) sleep(interval); } - if (dev != NULL && state.ls_status != DLADM_STATUS_OK) - die_dlerr(state.ls_status, "cannot show device '%s'", dev); + if (dev != NULL && state->ls_status != DLADM_STATUS_OK) + die_dlerr(state->ls_status, "cannot show device '%s'", dev); } /* accumulate stats (s1 += (s2 - s3)) */ @@ -2566,27 +3378,27 @@ get_stats(char *module, int instance, const char *name, pktsum_t *stats) if (kstat_read(kcp, ksp, NULL) == -1) goto bail; - if (kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, + if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, &stats->ipackets) < 0) goto bail; - if (kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, + if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, &stats->opackets) < 0) goto bail; - if (kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, + if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, &stats->rbytes) < 0) goto bail; - if (kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, + if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, &stats->obytes) < 0) goto bail; - if (kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, + if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, &stats->ierrors) < 0) goto bail; - if (kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, + if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, &stats->oerrors) < 0) goto bail; @@ -2641,7 +3453,7 @@ query_kstat(char *module, int instance, const char *name, const char *stat, goto bail; } - if (kstat_value(ksp, stat, type, val) < 0) + if (dladm_kstat_value(ksp, stat, type, val) < 0) goto bail; (void) kstat_close(kcp); @@ -2707,43 +3519,6 @@ get_linkduplex(const char *name, boolean_t islink, char *buf) return (dladm_linkduplex2str(linkduplex, buf)); } -#define WIFI_CMD_SCAN 0x00000001 -#define WIFI_CMD_SHOW 0x00000002 -#define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) -typedef struct wifi_field { - const char *wf_name; - const char *wf_header; - uint_t wf_width; - uint_t wf_mask; - uint_t wf_cmdtype; -} wifi_field_t; - -static wifi_field_t wifi_fields[] = { -{ "link", "LINK", 10, 0, WIFI_CMD_ALL}, -{ "essid", "ESSID", 19, DLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, -{ "bssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, -{ "ibssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, -{ "mode", "MODE", 6, DLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, -{ "speed", "SPEED", 6, DLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, -{ "auth", "AUTH", 8, DLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW}, -{ "bsstype", "BSSTYPE", 8, DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, -{ "sec", "SEC", 6, DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, -{ "status", "STATUS", 17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW}, -{ "strength", "STRENGTH", 10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} -; - -static char *all_scan_wifi_fields = - "link,essid,bssid,sec,strength,mode,speed,bsstype"; -static char *all_show_wifi_fields = - "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; -static char *def_scan_wifi_fields = - "link,essid,bssid,sec,strength,mode,speed"; -static char *def_show_wifi_fields = - "link,status,essid,sec,strength,mode,speed"; - -#define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (wifi_field_t)) -#define WIFI_MAX_FIELD_LEN 32 - typedef struct { char *s_buf; char **s_fields; /* array of pointer to the fields in s_buf */ @@ -2798,13 +3573,9 @@ fail: } static int -parse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp, +parse_wifi_fields(char *str, print_field_t ***fields, uint_t *countp, uint_t cmdtype) { - uint_t i, j; - wifi_field_t **wf = NULL; - split_t *sp; - boolean_t good_match = B_FALSE; if (cmdtype == WIFI_CMD_SCAN) { if (str == NULL) @@ -2819,21 +3590,35 @@ parse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp, } else { return (-1); } + *fields = parse_output_fields(str, wifi_fields, WIFI_MAX_FIELDS, + cmdtype, countp); + if (*fields != NULL) + return (0); + return (-1); +} +static print_field_t ** +parse_output_fields(char *str, print_field_t *template, int max_fields, + uint_t cmdtype, uint_t *countp) +{ + split_t *sp; + boolean_t good_match = B_FALSE; + uint_t i, j; + print_field_t **pf = NULL; + + sp = split(str, max_fields, MAX_FIELD_LEN); - sp = split(str, WIFI_MAX_FIELDS, WIFI_MAX_FIELD_LEN); if (sp == NULL) - return (-1); + return (NULL); - wf = malloc(sp->s_nfields * sizeof (wifi_field_t *)); - if (wf == NULL) + pf = malloc(sp->s_nfields * sizeof (print_field_t *)); + if (pf == NULL) goto fail; for (i = 0; i < sp->s_nfields; i++) { - for (j = 0; j < WIFI_MAX_FIELDS; j++) { + for (j = 0; j < max_fields; j++) { if (strcasecmp(sp->s_fields[i], - wifi_fields[j].wf_name) == 0) { - good_match = wifi_fields[j]. - wf_cmdtype & cmdtype; + template[j].pf_name) == 0) { + good_match = template[j]. pf_cmdtype & cmdtype; break; } } @@ -2841,142 +3626,127 @@ parse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp, goto fail; good_match = B_FALSE; - wf[i] = &wifi_fields[j]; + pf[i] = &template[j]; } *countp = i; - *fields = wf; splitfree(sp); - return (0); + return (pf); fail: - free(wf); + free(pf); splitfree(sp); - return (-1); + return (NULL); } typedef struct print_wifi_state { char *ws_link; boolean_t ws_parseable; boolean_t ws_header; - wifi_field_t **ws_fields; - uint_t ws_nfields; - boolean_t ws_lastfield; - uint_t ws_overflow; + print_state_t ws_print_state; } print_wifi_state_t; -static void -print_wifi_head(print_wifi_state_t *statep) -{ - int i; - wifi_field_t *wfp; +typedef struct wlan_scan_args_s { + print_wifi_state_t *ws_state; + void *ws_attr; +} wlan_scan_args_t; - for (i = 0; i < statep->ws_nfields; i++) { - wfp = statep->ws_fields[i]; - if (i + 1 < statep->ws_nfields) - (void) printf("%-*s ", wfp->wf_width, wfp->wf_header); - else - (void) printf("%s", wfp->wf_header); - } - (void) printf("\n"); -} static void -print_wifi_field(print_wifi_state_t *statep, wifi_field_t *wfp, - const char *value) +print_field(print_state_t *statep, print_field_t *pfp, const char *value, + boolean_t parseable) { - uint_t width = wfp->wf_width; + uint_t width = pfp->pf_width; uint_t valwidth = strlen(value); uint_t compress; - if (statep->ws_parseable) { - (void) printf("%s=\"%s\"", wfp->wf_header, value); + if (parseable) { + (void) printf("%s=\"%s\"", pfp->pf_header, value); } else { if (value[0] == '\0') - value = "--"; - if (statep->ws_lastfield) { + value = STR_UNDEF_VAL; + if (statep->ps_lastfield) { (void) printf("%s", value); return; } if (valwidth > width) { - statep->ws_overflow += valwidth - width; - } else if (valwidth < width && statep->ws_overflow > 0) { - compress = min(statep->ws_overflow, width - valwidth); - statep->ws_overflow -= compress; + statep->ps_overflow += valwidth - width; + } else if (valwidth < width && statep->ps_overflow > 0) { + compress = min(statep->ps_overflow, width - valwidth); + statep->ps_overflow -= compress; width -= compress; } (void) printf("%-*s", width, value); } - if (!statep->ws_lastfield) + if (!statep->ps_lastfield) (void) putchar(' '); } -static void -print_wlan_attr(print_wifi_state_t *statep, wifi_field_t *wfp, - dladm_wlan_attr_t *attrp) +static char * +print_wlan_attr(print_field_t *wfp, void *warg) { - char buf[DLADM_STRSIZE]; - const char *str = ""; + static char buf[DLADM_STRSIZE]; + wlan_scan_args_t *w = warg; + print_wifi_state_t *statep = w->ws_state; + dladm_wlan_attr_t *attrp = w->ws_attr; - if (wfp->wf_mask == 0) { - print_wifi_field(statep, wfp, statep->ws_link); - return; + if (wfp->pf_index == 0) { + return ((char *)statep->ws_link); } - if ((wfp->wf_mask & attrp->wa_valid) == 0) { - print_wifi_field(statep, wfp, ""); - return; + if ((wfp->pf_index & attrp->wa_valid) == 0) { + return (""); } - switch (wfp->wf_mask) { + switch (wfp->pf_index) { case DLADM_WLAN_ATTR_ESSID: - str = dladm_wlan_essid2str(&attrp->wa_essid, buf); + (void) dladm_wlan_essid2str(&attrp->wa_essid, buf); break; case DLADM_WLAN_ATTR_BSSID: - str = dladm_wlan_bssid2str(&attrp->wa_bssid, buf); + (void) dladm_wlan_bssid2str(&attrp->wa_bssid, buf); break; case DLADM_WLAN_ATTR_SECMODE: - str = dladm_wlan_secmode2str(&attrp->wa_secmode, buf); + (void) dladm_wlan_secmode2str(&attrp->wa_secmode, buf); break; case DLADM_WLAN_ATTR_STRENGTH: - str = dladm_wlan_strength2str(&attrp->wa_strength, buf); + (void) dladm_wlan_strength2str(&attrp->wa_strength, buf); break; case DLADM_WLAN_ATTR_MODE: - str = dladm_wlan_mode2str(&attrp->wa_mode, buf); + (void) dladm_wlan_mode2str(&attrp->wa_mode, buf); break; case DLADM_WLAN_ATTR_SPEED: - str = dladm_wlan_speed2str(&attrp->wa_speed, buf); + (void) dladm_wlan_speed2str(&attrp->wa_speed, buf); (void) strlcat(buf, "Mb", sizeof (buf)); break; case DLADM_WLAN_ATTR_AUTH: - str = dladm_wlan_auth2str(&attrp->wa_auth, buf); + (void) dladm_wlan_auth2str(&attrp->wa_auth, buf); break; case DLADM_WLAN_ATTR_BSSTYPE: - str = dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf); + (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf); break; } - print_wifi_field(statep, wfp, str); + return (buf); } static boolean_t print_scan_results(void *arg, dladm_wlan_attr_t *attrp) { print_wifi_state_t *statep = arg; - int i; + wlan_scan_args_t warg; if (statep->ws_header) { statep->ws_header = B_FALSE; if (!statep->ws_parseable) - print_wifi_head(statep); + print_header(&statep->ws_print_state); } - statep->ws_overflow = 0; - for (i = 0; i < statep->ws_nfields; i++) { - statep->ws_lastfield = (i + 1 == statep->ws_nfields); - print_wlan_attr(statep, statep->ws_fields[i], attrp); - } - (void) putchar('\n'); + statep->ws_print_state.ps_overflow = 0; + bzero(&warg, sizeof (warg)); + warg.ws_state = statep; + warg.ws_attr = attrp; + dladm_print_output(&statep->ws_print_state, statep->ws_parseable, + print_wlan_attr, &warg); return (B_TRUE); } @@ -2987,8 +3757,8 @@ scan_wifi(datalink_id_t linkid, void *arg) dladm_status_t status; char link[MAXLINKNAMELEN]; - if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, - sizeof (link)) != DLADM_STATUS_OK) { + if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, + sizeof (link))) != DLADM_STATUS_OK) { return (DLADM_WALK_CONTINUE); } @@ -3000,33 +3770,40 @@ scan_wifi(datalink_id_t linkid, void *arg) return (DLADM_WALK_CONTINUE); } -static void -print_link_attr(print_wifi_state_t *statep, wifi_field_t *wfp, - dladm_wlan_linkattr_t *attrp) +static char * +print_link_attr(print_field_t *wfp, void *warg) { - char buf[DLADM_STRSIZE]; - const char *str = ""; - - if (strcmp(wfp->wf_name, "status") == 0) { - if ((wfp->wf_mask & attrp->la_valid) != 0) - str = dladm_wlan_linkstatus2str(&attrp->la_status, buf); - print_wifi_field(statep, wfp, str); - return; + static char buf[DLADM_STRSIZE]; + char *ptr; + wlan_scan_args_t *w = warg, w1; + print_wifi_state_t *statep = w->ws_state; + dladm_wlan_linkattr_t *attrp = w->ws_attr; + + if (strcmp(wfp->pf_name, "status") == 0) { + if ((wfp->pf_index & attrp->la_valid) != 0) + (void) dladm_wlan_linkstatus2str( + &attrp->la_status, buf); + return (buf); } - print_wlan_attr(statep, wfp, &attrp->la_wlan_attr); + statep->ws_print_state.ps_overflow = 0; + bzero(&w1, sizeof (w1)); + w1.ws_state = statep; + w1.ws_attr = &attrp->la_wlan_attr; + ptr = print_wlan_attr(wfp, &w1); + return (ptr); } static int show_wifi(datalink_id_t linkid, void *arg) { - int i; print_wifi_state_t *statep = arg; dladm_wlan_linkattr_t attr; dladm_status_t status; char link[MAXLINKNAMELEN]; + wlan_scan_args_t warg; - if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, - sizeof (link)) != DLADM_STATUS_OK) { + if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, + sizeof (link))) != DLADM_STATUS_OK) { return (DLADM_WALK_CONTINUE); } @@ -3039,15 +3816,15 @@ show_wifi(datalink_id_t linkid, void *arg) if (statep->ws_header) { statep->ws_header = B_FALSE; if (!statep->ws_parseable) - print_wifi_head(statep); + print_header(&statep->ws_print_state); } - statep->ws_overflow = 0; - for (i = 0; i < statep->ws_nfields; i++) { - statep->ws_lastfield = (i + 1 == statep->ws_nfields); - print_link_attr(statep, statep->ws_fields[i], &attr); - } - (void) putchar('\n'); + statep->ws_print_state.ps_overflow = 0; + bzero(&warg, sizeof (warg)); + warg.ws_state = statep; + warg.ws_attr = &attr; + dladm_print_output(&statep->ws_print_state, statep->ws_parseable, + print_link_attr, &warg); return (DLADM_WALK_CONTINUE); } @@ -3056,7 +3833,7 @@ do_display_wifi(int argc, char **argv, int cmd) { int option; char *fields_str = NULL; - wifi_field_t **fields; + print_field_t **fields; int (*callback)(datalink_id_t, void *); uint_t nfields; print_wifi_state_t state; @@ -3102,8 +3879,9 @@ do_display_wifi(int argc, char **argv, int cmd) if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) die("invalid field(s) specified"); - state.ws_fields = fields; - state.ws_nfields = nfields; + bzero(&state.ws_print_state, sizeof (state.ws_print_state)); + state.ws_print_state.ps_fields = fields; + state.ws_print_state.ps_nfields = nfields; if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(callback, &state, @@ -3423,32 +4201,6 @@ do_disconnect_wifi(int argc, char **argv) die_dlerr(status, "cannot disconnect"); } -#define MAX_PROPS 32 -#define MAX_PROP_LINE 512 - -typedef struct prop_info { - char *pi_name; - char *pi_val[DLADM_MAX_PROP_VALCNT]; - uint_t pi_count; -} prop_info_t; - -typedef struct prop_list { - prop_info_t pl_info[MAX_PROPS]; - uint_t pl_count; - char *pl_buf; -} prop_list_t; - -typedef struct show_linkprop_state { - char ls_link[MAXLINKNAMELEN]; - char *ls_line; - char **ls_propvals; - prop_list_t *ls_proplist; - uint32_t ls_parseable : 1, - ls_persist : 1, - ls_header : 1, - ls_pad_bits : 29; - dladm_status_t ls_status; -} show_linkprop_state_t; static void free_props(prop_list_t *list) @@ -3476,6 +4228,19 @@ parse_props(char *str, prop_list_t **listp, boolean_t novalues) if (buf == NULL) goto fail; + /* + * buf is a string of form [<propname>=<value>][,<propname>=<value>]+ + * where each <value> string itself could be a comma-separated array. + * The loop below will count the number of propname assignments + * in pl_count; for each property, there is a pip entry with + * pi_name == <propname>, pi_count == # of elements in <value> array. + * pi_val[] contains the actual values. + * + * This could really be a combination of calls to + * strtok (token delimiter is ",") and strchr (chr '=') + * with appropriate null/string-bound-checks. + */ + curr = buf; len = strlen(buf); pip = NULL; @@ -3523,15 +4288,8 @@ fail: } static void -print_linkprop_head(void) -{ - (void) printf("%-12s %-15s %-14s %-14s %-20s \n", - "LINK", "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE"); -} - -static void print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, - const char *propname, dladm_prop_type_t type, const char *typename, + const char *propname, dladm_prop_type_t type, const char *format, char **pptr) { int i; @@ -3551,6 +4309,7 @@ print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, propvals = &unknown; } else { statep->ls_status = status; + statep->ls_retstatus = status; return; } } else if (status == DLADM_STATUS_NOTSUP || @@ -3561,21 +4320,25 @@ print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, else propvals = ¬sup; } else { - statep->ls_status = status; - if (statep->ls_proplist) { + if (statep->ls_proplist && + statep->ls_status == DLADM_STATUS_OK) { warn_dlerr(status, "cannot get link property '%s' for %s", propname, statep->ls_link); } + statep->ls_status = status; + statep->ls_retstatus = status; return; } } + statep->ls_status = DLADM_STATUS_OK; + ptr = buf; lim = buf + DLADM_STRSIZE; for (i = 0; i < valcnt; i++) { if (propvals[i][0] == '\0' && !statep->ls_parseable) - ptr += snprintf(ptr, lim - ptr, "--,"); + ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL","); else ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); if (ptr >= lim) @@ -3587,58 +4350,87 @@ print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, lim = statep->ls_line + MAX_PROP_LINE; if (statep->ls_parseable) { *pptr += snprintf(*pptr, lim - *pptr, - "%s=\"%s\" ", typename, buf); + "%s", buf); } else { *pptr += snprintf(*pptr, lim - *pptr, format, buf); } } -static int -show_linkprop(datalink_id_t linkid, const char *propname, void *arg) +static char * +linkprop_callback(print_field_t *pf, void *ls_arg) { - show_linkprop_state_t *statep = arg; + linkprop_args_t *arg = ls_arg; + char *propname = arg->ls_propname; + show_linkprop_state_t *statep = arg->ls_state; char *ptr = statep->ls_line; char *lim = ptr + MAX_PROP_LINE; + datalink_id_t linkid = arg->ls_linkid; - if (statep->ls_parseable) - ptr += snprintf(ptr, lim - ptr, "LINK=\"%s\" ", - statep->ls_link); - else - ptr += snprintf(ptr, lim - ptr, "%-12s ", statep->ls_link); - - if (statep->ls_parseable) - ptr += snprintf(ptr, lim - ptr, "PROPERTY=\"%s\" ", propname); - else - ptr += snprintf(ptr, lim - ptr, "%-15s ", propname); - - print_linkprop(linkid, statep, propname, - statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : - DLADM_PROP_VAL_CURRENT, "VALUE", "%-14s ", &ptr); - - /* - * If we failed to query the link property, for example, query - * the persistent value of a non-persistable link property, simply - * skip the output. - */ + switch (pf->pf_index) { + case LINKPROP_LINK: + (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); + break; + case LINKPROP_PROPERTY: + (void) snprintf(ptr, lim - ptr, "%s", propname); + break; + case LINKPROP_VALUE: + print_linkprop(linkid, statep, propname, + statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : + DLADM_PROP_VAL_CURRENT, "%s", &ptr); + /* + * If we failed to query the link property, for example, query + * the persistent value of a non-persistable link property, + * simply skip the output. + */ + if (statep->ls_status != DLADM_STATUS_OK) + goto skip; + ptr = statep->ls_line; + break; + case LINKPROP_DEFAULT: + print_linkprop(linkid, statep, propname, + DLADM_PROP_VAL_DEFAULT, "%s", &ptr); + if (statep->ls_status != DLADM_STATUS_OK) + goto skip; + ptr = statep->ls_line; + break; + case LINKPROP_POSSIBLE: + print_linkprop(linkid, statep, propname, + DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); + if (statep->ls_status != DLADM_STATUS_OK) + goto skip; + ptr = statep->ls_line; + break; + default: + die("invalid input"); + break; + } + return (ptr); +skip: if (statep->ls_status != DLADM_STATUS_OK) - return (DLADM_WALK_CONTINUE); + return (NULL); + else + return (""); +} - print_linkprop(linkid, statep, propname, DLADM_PROP_VAL_DEFAULT, - "DEFAULT", "%-14s ", &ptr); - if (statep->ls_status != DLADM_STATUS_OK) - return (DLADM_WALK_CONTINUE); +static int +show_linkprop(datalink_id_t linkid, const char *propname, void *arg) +{ + show_linkprop_state_t *statep = arg; + linkprop_args_t ls_arg; - print_linkprop(linkid, statep, propname, DLADM_PROP_VAL_MODIFIABLE, - "POSSIBLE", "%-20s ", &ptr); - if (statep->ls_status != DLADM_STATUS_OK) - return (DLADM_WALK_CONTINUE); + bzero(&ls_arg, sizeof (ls_arg)); + ls_arg.ls_state = statep; + ls_arg.ls_propname = (char *)propname; + ls_arg.ls_linkid = linkid; if (statep->ls_header) { statep->ls_header = B_FALSE; if (!statep->ls_parseable) - print_linkprop_head(); + print_header(&statep->ls_print); } - (void) printf("%s\n", statep->ls_line); + dladm_print_output(&statep->ls_print, statep->ls_parseable, + linkprop_callback, (void *)&ls_arg); + return (DLADM_WALK_CONTINUE); } @@ -3651,6 +4443,13 @@ do_show_linkprop(int argc, char **argv) show_linkprop_state_t state; uint32_t flags = DLADM_OPT_ACTIVE; dladm_status_t status; + char *fields_str = NULL; + print_field_t **fields; + uint_t nfields; + char *all_fields = + "link,property,value,default,possible"; + + fields_str = all_fields; opterr = 0; state.ls_propvals = NULL; @@ -3658,7 +4457,8 @@ do_show_linkprop(int argc, char **argv) state.ls_parseable = B_FALSE; state.ls_persist = B_FALSE; state.ls_header = B_TRUE; - while ((option = getopt_long(argc, argv, ":p:cP", + state.ls_retstatus = DLADM_STATUS_OK; + while ((option = getopt_long(argc, argv, ":p:cPo:", prop_longopts, NULL)) != -1) { switch (option) { case 'p': @@ -3672,6 +4472,12 @@ do_show_linkprop(int argc, char **argv) state.ls_persist = B_TRUE; flags = DLADM_OPT_PERSIST; break; + case 'o': + if (strcasecmp(optarg, "all") == 0) + fields_str = all_fields; + else + fields_str = optarg; + break; default: die_opterr(optopt, option); break; @@ -3687,9 +4493,20 @@ do_show_linkprop(int argc, char **argv) usage(); } + bzero(&state.ls_print, sizeof (print_state_t)); state.ls_proplist = proplist; state.ls_status = DLADM_STATUS_OK; + fields = parse_output_fields(fields_str, linkprop_fields, + LINKPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + return; + } + + state.ls_print.ps_fields = fields; + state.ls_print.ps_nfields = nfields; if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(show_linkprop_onelink, &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); @@ -3698,13 +4515,8 @@ do_show_linkprop(int argc, char **argv) } free_props(proplist); - if (state.ls_status != DLADM_STATUS_OK) { - if (optind == (argc - 1)) { - warn_dlerr(state.ls_status, - "show-linkprop failed for %s", argv[optind]); - } + if (state.ls_retstatus != DLADM_STATUS_OK) exit(EXIT_FAILURE); - } } static int @@ -3839,8 +4651,9 @@ set_linkprop(int argc, char **argv, boolean_t reset) die_dlerr(status, "link %s is not valid", argv[optind]); if (proplist == NULL) { - if ((status = dladm_set_linkprop(linkid, NULL, NULL, 0, - DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { + status = dladm_set_linkprop(linkid, NULL, NULL, 0, + DLADM_OPT_ACTIVE); + if (status != DLADM_STATUS_OK) { warn_dlerr(status, "cannot reset link property " "on '%s'", argv[optind]); } @@ -4347,18 +5160,10 @@ do_delete_secobj(int argc, char **argv) typedef struct show_secobj_state { boolean_t ss_persist; boolean_t ss_parseable; - boolean_t ss_debug; boolean_t ss_header; + print_state_t ss_print; } show_secobj_state_t; -static void -print_secobj_head(show_secobj_state_t *statep) -{ - (void) printf("%-20s %-20s ", "OBJECT", "CLASS"); - if (statep->ss_debug) - (void) printf("%-30s", "VALUE"); - (void) putchar('\n'); -} static boolean_t show_secobj(void *arg, const char *obj_name) @@ -4370,6 +5175,7 @@ show_secobj(void *arg, const char *obj_name) dladm_secobj_class_t class; show_secobj_state_t *statep = arg; dladm_status_t status; + secobj_fields_buf_t sbuf; if (statep->ss_persist) flags |= DLADM_OPT_PERSIST; @@ -4381,29 +5187,23 @@ show_secobj(void *arg, const char *obj_name) if (statep->ss_header) { statep->ss_header = B_FALSE; if (!statep->ss_parseable) - print_secobj_head(statep); - } - - if (statep->ss_parseable) { - (void) printf("OBJECT=\"%s\" CLASS=\"%s\" ", obj_name, - dladm_secobjclass2str(class, buf)); - } else { - (void) printf("%-20s %-20s ", obj_name, - dladm_secobjclass2str(class, buf)); + print_header(&statep->ss_print); } - if (statep->ss_debug) { + (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), + obj_name); + (void) dladm_secobjclass2str(class, buf); + (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf); + if (getuid() == 0) { char val[DLADM_SECOBJ_VAL_MAX * 2]; uint_t len = sizeof (val); - if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) { - if (statep->ss_parseable) - (void) printf("VALUE=\"0x%s\"", val); - else - (void) printf("0x%-30s", val); - } + if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) + (void) snprintf(sbuf.ss_val, + sizeof (sbuf.ss_val), "%s", val); } - (void) putchar('\n'); + dladm_print_output(&statep->ss_print, statep->ss_parseable, + dladm_print_field, (void *)&sbuf); return (B_TRUE); } @@ -4416,13 +5216,20 @@ do_show_secobj(int argc, char **argv) uint_t i; split_t *sp; uint_t flags; + char *fields_str = NULL; + print_field_t **fields; + uint_t nfields; + char *def_fields = "object,class"; + char *all_fields = "object,class,value"; opterr = 0; + bzero(&state, sizeof (state)); + state.ss_parseable = B_FALSE; + fields_str = def_fields; state.ss_persist = B_FALSE; state.ss_parseable = B_FALSE; - state.ss_debug = B_FALSE; state.ss_header = B_TRUE; - while ((option = getopt_long(argc, argv, ":pPd", + while ((option = getopt_long(argc, argv, ":pPo:", wifi_longopts, NULL)) != -1) { switch (option) { case 'p': @@ -4431,10 +5238,11 @@ do_show_secobj(int argc, char **argv) case 'P': state.ss_persist = B_TRUE; break; - case 'd': - if (getuid() != 0) - die("insufficient privileges"); - state.ss_debug = B_TRUE; + case 'o': + if (strcasecmp(optarg, "all") == 0) + fields_str = all_fields; + else + fields_str = optarg; break; default: die_opterr(optopt, option); @@ -4442,6 +5250,17 @@ do_show_secobj(int argc, char **argv) } } + fields = parse_output_fields(fields_str, secobj_fields, + DEV_SOBJ_FIELDS, CMD_TYPE_ANY, &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + return; + } + state.ss_print.ps_fields = fields; + state.ss_print.ps_nfields = nfields; + + flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; if (optind == (argc - 1)) { sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); if (sp == NULL) { @@ -4457,7 +5276,6 @@ do_show_secobj(int argc, char **argv) } else if (optind != argc) usage(); - flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; status = dladm_walk_secobj(&state, show_secobj, flags); if (status != DLADM_STATUS_OK) die_dlerr(status, "show-secobj"); @@ -4485,6 +5303,153 @@ do_init_linkprop(int argc, char **argv) /* ARGSUSED */ static void +do_show_ether(int argc, char **argv) +{ + int option; + datalink_id_t linkid; + print_ether_state_t state; + print_field_t **fields; + char *fields_str; + uint_t nfields; + char *all_fields = + "link,ptype,state,auto,speed-duplex,pause,rem_fault"; + char *default_fields = + "link,ptype,state,auto,speed-duplex,pause"; + + fields_str = default_fields; + bzero(&state, sizeof (state)); + state.es_link = NULL; + state.es_parseable = B_FALSE; + + while ((option = getopt_long(argc, argv, "o:px", + showeth_lopts, NULL)) != -1) { + switch (option) { + case 'x': + state.es_extended = B_TRUE; + break; + case 'p': + state.es_parseable = B_TRUE; + break; + case 'o': + if (strcasecmp(optarg, "all") == 0) + fields_str = all_fields; + else + fields_str = optarg; + break; + default: + die_opterr(optopt, option); + break; + } + } + + if (optind == (argc - 1)) + state.es_link = argv[optind]; + + fields = parse_output_fields(fields_str, ether_fields, + ETHER_MAX_FIELDS, CMD_TYPE_ANY, &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + exit(EXIT_FAILURE); + } + state.es_print.ps_fields = fields; + state.es_print.ps_nfields = nfields; + + if (state.es_link == NULL) { + (void) dladm_walk_datalink_id(show_etherprop, &state, + DATALINK_CLASS_PHYS, DL_ETHER, + DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); + } else { + if (!link_is_ether(state.es_link, &linkid)) { + die("invalid link specified"); + } + (void) show_etherprop(linkid, &state); + } + + exit(DLADM_STATUS_OK); + +} + +static char * +dladm_print_field(print_field_t *pf, void *arg) +{ + char *value; + + value = (char *)arg + pf->pf_offset; + return (value); +} + +static int +show_etherprop(datalink_id_t linkid, void *arg) +{ + print_ether_state_t *statep = arg; + char buf[DLADM_STRSIZE]; + int speed; + uint64_t s; + uint32_t autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf; + ether_fields_buf_t ebuf; + char speed_unit = 'M'; + + if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, + ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) { + return (DLADM_WALK_CONTINUE); + } + + if (!statep->es_header && !statep->es_parseable) { + print_header(&statep->es_print); + statep->es_header = B_TRUE; + } + (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), + "%s", "current"); + + (void) dladm_get_single_mac_stat(linkid, "link_autoneg", + KSTAT_DATA_UINT32, &autoneg); + (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), + "%s", (autoneg ? "yes" : "no")); + + (void) dladm_get_single_mac_stat(linkid, "link_pause", + KSTAT_DATA_UINT32, &pause); + (void) dladm_get_single_mac_stat(linkid, "link_asmpause", + KSTAT_DATA_UINT32, &asmpause); + (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), + "%s", pause_str(pause, asmpause)); + + (void) dladm_get_single_mac_stat(linkid, "ifspeed", + KSTAT_DATA_UINT64, &s); + speed = (int)(s/1000000ull); + + if (speed >= 1000) { + speed = speed/1000; + speed_unit = 'G'; + } + (void) get_linkduplex(ebuf.eth_link, B_FALSE, buf); + (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%d%c-%c", + speed, speed_unit, buf[0]); + + (void) get_linkstate(ebuf.eth_link, B_FALSE, buf); + (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), + "%s", buf); + + (void) dladm_get_single_mac_stat(linkid, "adv_rem_fault", + KSTAT_DATA_UINT32, &adv_rf); + (void) dladm_get_single_mac_stat(linkid, "cap_rem_fault", + KSTAT_DATA_UINT32, &cap_rf); + (void) dladm_get_single_mac_stat(linkid, "lp_rem_fault", + KSTAT_DATA_UINT32, &lp_rf); + (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), + "%s", (adv_rf == 0 && lp_rf == 0 ? "none" : "fault")); + + dladm_print_output(&statep->es_print, statep->es_parseable, + dladm_print_field, &ebuf); + + if (statep->es_extended) + show_ether_xprop(linkid, arg); + + return (DLADM_WALK_CONTINUE); +} + +/* ARGSUSED */ +static void do_init_secobj(int argc, char **argv) { dladm_status_t status; @@ -4657,3 +5622,224 @@ die_opterr(int opt, int opterr) break; } } + +static void +show_ether_xprop(datalink_id_t linkid, void *arg) +{ + print_ether_state_t *statep = arg; + char buf[DLADM_STRSIZE]; + uint32_t autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf; + boolean_t add_comma, r1; + ether_fields_buf_t ebuf; + + /* capable */ + bzero(&ebuf, sizeof (ebuf)); + (void) snprintf(ebuf.eth_link, sizeof (ebuf.eth_link), ""); + + (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), + "%s", "capable"); + (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), + STR_UNDEF_VAL); + + (void) dladm_get_single_mac_stat(linkid, "cap_autoneg", + KSTAT_DATA_UINT32, &autoneg); + (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), + "%s", (autoneg ? "yes" : "no")); + + add_comma = B_FALSE; + bzero(buf, sizeof (buf)); + r1 = get_speed_duplex(linkid, "cap_1000", buf, "1G", B_FALSE); + if (r1) + add_comma = B_TRUE; + r1 = get_speed_duplex(linkid, "cap_100", buf, "100M", add_comma); + if (r1) + add_comma = B_TRUE; + r1 = get_speed_duplex(linkid, "cap_10", buf, "10M", add_comma); + add_comma = B_FALSE; + (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); + + (void) dladm_get_single_mac_stat(linkid, "cap_pause", + KSTAT_DATA_UINT32, &pause); + (void) dladm_get_single_mac_stat(linkid, "cap_asmpause", + KSTAT_DATA_UINT32, &asmpause); + (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), + "%s", pause_str(pause, asmpause)); + + (void) dladm_get_single_mac_stat(linkid, "adv_rem_fault", + KSTAT_DATA_UINT32, &adv_rf); + (void) dladm_get_single_mac_stat(linkid, "cap_rem_fault", + KSTAT_DATA_UINT32, &cap_rf); + (void) dladm_get_single_mac_stat(linkid, "lp_rem_fault", + KSTAT_DATA_UINT32, &lp_rf); + + (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), + "%s", (cap_rf ? "yes" : "no")); + + dladm_print_output(&statep->es_print, statep->es_parseable, + dladm_print_field, &ebuf); + + /* advertised */ + bzero(&ebuf, sizeof (ebuf)); + (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), + "%s", "adv"); + (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), + STR_UNDEF_VAL); + + (void) dladm_get_single_mac_stat(linkid, "adv_cap_autoneg", + KSTAT_DATA_UINT32, &autoneg); + (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), + "%s", (autoneg ? "yes" : "no")); + + add_comma = B_FALSE; + bzero(buf, sizeof (buf)); + r1 = get_speed_duplex(linkid, "adv_cap_1000", buf, "1G", add_comma); + if (r1) + add_comma = B_TRUE; + r1 = get_speed_duplex(linkid, "adv_cap_100", buf, "100M", add_comma); + if (r1) + add_comma = B_TRUE; + r1 = get_speed_duplex(linkid, "adv_cap_10", buf, "10M", add_comma); + add_comma = B_FALSE; + (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); + + (void) dladm_get_single_mac_stat(linkid, "adv_cap_pause", + KSTAT_DATA_UINT32, &pause); + (void) dladm_get_single_mac_stat(linkid, "adv_cap_asmpause", + KSTAT_DATA_UINT32, &asmpause); + (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), + "%s", pause_str(pause, asmpause)); + + (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), + "%s", (adv_rf ? "fault" : "none")); + + dladm_print_output(&statep->es_print, statep->es_parseable, + dladm_print_field, &ebuf); + + /* peeradv */ + bzero(&ebuf, sizeof (ebuf)); + (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), + "%s", "peeradv"); + (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), + STR_UNDEF_VAL); + + (void) dladm_get_single_mac_stat(linkid, "lp_cap_autoneg", + KSTAT_DATA_UINT32, &autoneg); + (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), + "%s", (autoneg ? "yes" : "no")); + + add_comma = B_FALSE; + bzero(buf, sizeof (buf)); + r1 = get_speed_duplex(linkid, "lp_cap_1000", buf, "1G", add_comma); + if (r1) + add_comma = B_TRUE; + r1 = get_speed_duplex(linkid, "lp_cap_100", buf, "100M", add_comma); + if (r1) + add_comma = B_TRUE; + r1 = get_speed_duplex(linkid, "lp_cap_10", buf, "10M", add_comma); + (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); + + (void) dladm_get_single_mac_stat(linkid, "lp_cap_pause", + KSTAT_DATA_UINT32, &pause); + (void) dladm_get_single_mac_stat(linkid, "lp_cap_asmpause", + KSTAT_DATA_UINT32, &asmpause); + (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), + "%s", pause_str(pause, asmpause)); + + (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), + "%s", (lp_rf ? "fault" : "none")); + + dladm_print_output(&statep->es_print, statep->es_parseable, + dladm_print_field, &ebuf); +} + +static boolean_t +get_speed_duplex(datalink_id_t linkid, const char *mii_prop_prefix, + char *spbuf, char *sp, boolean_t add_comma) +{ + int speed, duplex = 0; + boolean_t ret = B_FALSE; + char mii_prop[DLADM_STRSIZE]; + + (void) snprintf(mii_prop, DLADM_STRSIZE, "%sfdx", mii_prop_prefix); + (void) dladm_get_single_mac_stat(linkid, mii_prop, KSTAT_DATA_UINT32, + &speed); + if (speed) { + ret = B_TRUE; + duplex |= IS_FDX; + } + (void) snprintf(mii_prop, DLADM_STRSIZE, "%shdx", mii_prop_prefix); + (void) dladm_get_single_mac_stat(linkid, mii_prop, + KSTAT_DATA_UINT32, &speed); + if (speed) { + ret = B_TRUE; + duplex |= IS_HDX; + } + if (ret) { + if (add_comma) + (void) strncat(spbuf, ",", DLADM_STRSIZE); + (void) strncat(spbuf, sp, DLADM_STRSIZE); + if ((duplex & (IS_FDX|IS_HDX)) == (IS_FDX|IS_HDX)) + (void) strncat(spbuf, "-fh", DLADM_STRSIZE); + else if (duplex & IS_FDX) + (void) strncat(spbuf, "-f", DLADM_STRSIZE); + else if (duplex & IS_HDX) + (void) strncat(spbuf, "-h", DLADM_STRSIZE); + } + return (ret); +} + +static void +dladm_print_output(print_state_t *statep, boolean_t parseable, + print_callback_t fn, void *arg) +{ + int i; + char *value; + print_field_t **pf; + + pf = statep->ps_fields; + for (i = 0; i < statep->ps_nfields; i++) { + statep->ps_lastfield = (i + 1 == statep->ps_nfields); + value = (*fn)(pf[i], arg); + if (value != NULL) + print_field(statep, pf[i], value, parseable); + } + (void) putchar('\n'); +} + +static void +print_header(print_state_t *ps) +{ + int i; + print_field_t **pf; + + pf = ps->ps_fields; + for (i = 0; i < ps->ps_nfields; i++) { + ps->ps_lastfield = (i + 1 == ps->ps_nfields); + print_field(ps, pf[i], pf[i]->pf_header, B_FALSE); + } + (void) putchar('\n'); +} + +static char * +pause_str(int pause, int asmpause) +{ + if (pause == 1) + return ("bi"); + if (asmpause == 1) + return ("tx"); + return ("none"); +} + +static boolean_t +link_is_ether(const char *link, datalink_id_t *linkid) +{ + uint32_t media; + datalink_class_t class; + + if (dladm_name2info(link, linkid, NULL, &class, &media) == + DLADM_STATUS_OK) { + if (class == DATALINK_CLASS_PHYS && media == DL_ETHER) + return (B_TRUE); + } + return (B_FALSE); +} diff --git a/usr/src/cmd/dladm/dladm.xcl b/usr/src/cmd/dladm/dladm.xcl index c48e5d4bbb..b849b22f79 100644 --- a/usr/src/cmd/dladm/dladm.xcl +++ b/usr/src/cmd/dladm/dladm.xcl @@ -83,24 +83,30 @@ msgid ":p:cP" msgid ":pPd" msgid ":psi:" msgid "?" +msgid "100M" msgid "ADT_dladm_create_secobj" msgid "ADT_dladm_delete_secobj" msgid "AUTH" +msgid "AUTO" msgid "BSSID/IBSSID" msgid "BSSTYPE" msgid "CLASS" msgid "DEFAULT" +msgid "DUPLEX" msgid "ESSID" msgid "LINK" msgid "MODE" msgid "Mb" msgid "OBJECT" msgid "OBJECT=\"%s\" CLASS=\"%s\" " +msgid "PAUSE" msgid "POSSIBLE" msgid "PROPERTY" msgid "PROPERTY=\"%s\" " +msgid "REM_FAULT" msgid "SEC" msgid "SPEED" +msgid "SPEED-DUPLEX" msgid "STATUS" msgid "STRENGTH" msgid "VALUE" @@ -116,6 +122,12 @@ msgid "\t\t%-10llu" msgid "\t\tipackets rbytes ierrors " msgid "\tipackets rbytes opackets obytes " msgid "active" +msgid "adv_cap_10" +msgid "adv_cap_100" +msgid "adv_cap_1000" +msgid "adv_cap_asmpause" +msgid "adv_cap_autoneg" +msgid "adv_cap_pause" msgid "add-aggr" msgid "adt_alloc_event (%s): %s" msgid "adt_start_session: %s" @@ -125,13 +137,20 @@ msgid "all" msgid "all-links" msgid "attached" msgid "auth" +msgid "auto" msgid "bssid" msgid "bsstype" +msgid "cap_pause" +msgid "cap_10" +msgid "cap_1000" +msgid "cap_autoneg" +msgid "capable" msgid "connect-wifi" msgid "create-aggr" msgid "create-ibss" msgid "create-secobj" msgid "create-vlan" +msgid "current" msgid "delete-aggr" msgid "delete-phys" msgid "delete-secobj" @@ -141,7 +160,9 @@ msgid "dev" msgid "disconnect-wifi" msgid "down" msgid "down-aggr" +msgid "duplex" msgid "essid" +msgid "fault" msgid "file" msgid "forever" msgid "full" @@ -152,19 +173,41 @@ msgid "ifspeed" msgid "init-linkprop" msgid "init-secobj" msgid "interval" +msgid "invalid input" msgid "ipackets64" msgid "key" msgid "lacp" msgid "lacp-mode" msgid "lacp-timer" msgid "link" +msgid "link,class,mtu,state,over" +msgid "link,device,media,flags" msgid "link,essid,bssid,sec,strength,mode,speed" msgid "link,essid,bssid,sec,strength,mode,speed,auth,bsstype" +msgid "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors" +msgid "link,media,state,speed,duplex,device" +msgid "link,property,value,default,possible" +msgid "link,policy,addrpolicy,lacpactivity,lacptimer,flags" +msigd "link,port,aggregatable,sync,coll,dist,defaulted,expired" +msgid "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist" +msgid "link,port,speed,duplex,state,address,portstate" +msgid "link,state,speed,duplex" +msgid "link,vid,over,flags" msgid "link,status,essid,sec,strength,mode,speed" msgid "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype" +msgid "link_asmpause" +msgid "link_autoneg" msgid "link_duplex" +msgid "link_pause" msgid "link_state" msgid "long" +msgid "lp_cap_10" +msgid "lp_cap_100" +msgid "lp_cap_1000" +msgid "lp_cap_autoneg" +msgid "lp_cap_asmpause" +msgid "lp_cap_pause" +msgid "lp_rem_fault" msgid "mac" msgid "mode" msgid "modify-aggr" @@ -177,11 +220,14 @@ msgid "opackets64" msgid "output" msgid "parseable" msgid "passive" +msgid "pause" +msgid "peeradv" msgid "persistent" msgid "policy" msgid "prop" msgid "r" msgid "rbytes64" +msgid "rem_fault" msgid "remove-aggr" msgid "rename-link" msgid "reset-linkprop" @@ -198,8 +244,10 @@ msgid "show-phys" msgid "show-secobj" msgid "show-wifi" msgid "show-vlan" +msgid "show-ether" msgid "solaris.network.link.security" msgid "speed" +msgid "speed-duplex" msgid "standby" msgid "statistics" msgid "status" |