1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <ctype.h> 28 #include <locale.h> 29 #include <signal.h> 30 #include <stdarg.h> 31 #include <stdlib.h> 32 #include <fcntl.h> 33 #include <string.h> 34 #include <stropts.h> 35 #include <sys/stat.h> 36 #include <errno.h> 37 #include <kstat.h> 38 #include <strings.h> 39 #include <getopt.h> 40 #include <unistd.h> 41 #include <priv.h> 42 #include <termios.h> 43 #include <pwd.h> 44 #include <auth_attr.h> 45 #include <auth_list.h> 46 #include <libintl.h> 47 #include <libdevinfo.h> 48 #include <libdlpi.h> 49 #include <libdladm.h> 50 #include <libdllink.h> 51 #include <libdlstat.h> 52 #include <libdlaggr.h> 53 #include <libdlwlan.h> 54 #include <libdlvlan.h> 55 #include <libdlvnic.h> 56 #include <libinetutil.h> 57 #include <bsm/adt.h> 58 #include <bsm/adt_event.h> 59 #include <libdlvnic.h> 60 #include <sys/types.h> 61 #include <sys/socket.h> 62 #include <sys/processor.h> 63 #include <netinet/in.h> 64 #include <arpa/inet.h> 65 #include <net/if_types.h> 66 #include <stddef.h> 67 68 #define STR_UNDEF_VAL "--" 69 #define MAXPORT 256 70 #define MAXVNIC 256 71 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) 72 #define MAXLINELEN 1024 73 #define SMF_UPGRADE_FILE "/var/svc/profile/upgrade" 74 #define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink" 75 #define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)" 76 77 #define CMD_TYPE_ANY 0xffffffff 78 #define WIFI_CMD_SCAN 0x00000001 79 #define WIFI_CMD_SHOW 0x00000002 80 #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 81 82 /* 83 * Data structures and routines for printing output. 84 * All non-parseable output is assumed to be in a columnar format. 85 * Multiple fields in parsable output are separated by ':'; single 86 * field output is printed as-is. 87 * 88 * Each sub-command is associated with a global array of pointers, 89 * print_field_t *fields[], where the print_field_t contains information 90 * about the format in which the output is to be printed. 91 * 92 * Sub-commands may be implemented in one of two ways: 93 * (i) the implementation could get all field values into a character 94 * buffer, with pf_offset containing the offset (for pf_name) within 95 * the buffer. The sub-command would make the needed system calls 96 * to obtain all possible column values and then invoke the 97 * dladm_print_field() function to print the specific fields 98 * requested in the command line. See the comments for dladm_print_field 99 * for further details. 100 * (ii) Alternatively, each fields[i] entry could store a pf_index value 101 * that uniquely identifies the column to be printed. The implementation 102 * of the sub-command would then invoke dladm_print_output() with a 103 * callback function whose semantics are described below (see comments 104 * for dladm_print_output()) 105 * 106 * Thus, an implementation of a sub-command must provide the following: 107 * 108 * static print_field_t sub_command_fields[] = { 109 * {<name>, <header>,<field width>, <offset_or_index>, cmdtype}, 110 * : 111 * {<name>, <header>,<field width>, <offset_or_index>, cmdtype} 112 * }; 113 * 114 * #define SUB_COMMAND_MAX_FIELDS sizeof \ 115 * (sub_comand_fields) / sizeof (print_field_t)) 116 * 117 * print_state_t sub_command_print_state; 118 * 119 * The function that parses command line arguments (typically 120 * do_sub_command()) should then contain an invocation like: 121 * 122 * fields = parse_output_fields(fields_str, sub_command_fields, 123 * SUB_COMMAND_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 124 * 125 * and store the resulting fields and nfields value in a print_state_t 126 * structure tracked for the command. 127 * 128 * sub_command_print_state.ps_fields = fields; 129 * sub_command_print_state.ps_nfields = nfields; 130 * 131 * To print the column header for the output, the print_header() 132 * function must then be invoked by do_sub_command(). 133 * 134 * Then if method (i) is used for the sub_command, the do_sub_command() 135 * function should make the necessary system calls to fill up the buffer 136 * and then invoke dladm_print_field(). An example of this method is 137 * the implementation of do_show_link() and show_link(); 138 * 139 * If method (ii) is used, do_sub_command should invoke dladm_print_output() 140 * with a callback function that will be called for each field to be printed. 141 * The callback function will be passed a pointer to the print_field_t 142 * for the field, and the pf_index may then be used to identify the 143 * system call required to find the value to be printed. 144 */ 145 146 typedef struct print_field_s { 147 const char *pf_name; /* name of column to be printed */ 148 const char *pf_header; /* header for this column */ 149 uint_t pf_width; 150 union { 151 uint_t _pf_index; /* private index for sub-command */ 152 size_t _pf_offset; 153 }_pf_un; 154 #define pf_index _pf_un._pf_index 155 #define pf_offset _pf_un._pf_offset; 156 uint_t pf_cmdtype; 157 } print_field_t; 158 159 /* 160 * The state of the output is tracked in a print_state_t structure. 161 * Each ps_fields[i] entry points at the global print_field_t array for 162 * the sub-command, where ps_nfields is the number of requested fields. 163 */ 164 typedef struct print_state_s { 165 print_field_t **ps_fields; 166 uint_t ps_nfields; 167 boolean_t ps_lastfield; 168 uint_t ps_overflow; 169 } print_state_t; 170 171 typedef char *(*print_callback_t)(print_field_t *, void *); 172 static print_field_t **parse_output_fields(char *, print_field_t *, int, 173 uint_t, uint_t *); 174 /* 175 * print the header for the output 176 */ 177 static void print_header(print_state_t *); 178 static void print_field(print_state_t *, print_field_t *, const char *, 179 boolean_t); 180 181 /* 182 * to print output values, call dladm_print_output with a callback 183 * function (*func)() that should parse the args and return an 184 * unformatted character buffer with the value to be printed. 185 * 186 * dladm_print_output() prints the character buffer using the formatting 187 * information provided in the print_field_t for that column. 188 */ 189 static void dladm_print_output(print_state_t *, boolean_t, 190 print_callback_t, void *); 191 192 /* 193 * helper function that, when invoked as dladm_print_field(pf, buf) 194 * prints string which is offset by pf->pf_offset within buf 195 */ 196 static char *dladm_print_field(print_field_t *, void *); 197 198 199 #define MAX_FIELD_LEN 32 200 201 202 typedef struct show_state { 203 boolean_t ls_firstonly; 204 boolean_t ls_donefirst; 205 pktsum_t ls_prevstats; 206 uint32_t ls_flags; 207 dladm_status_t ls_status; 208 print_state_t ls_print; 209 boolean_t ls_parseable; 210 boolean_t ls_printheader; 211 boolean_t ls_mac; 212 boolean_t ls_hwgrp; 213 } show_state_t; 214 215 typedef struct show_grp_state { 216 pktsum_t gs_prevstats[MAXPORT]; 217 uint32_t gs_flags; 218 dladm_status_t gs_status; 219 boolean_t gs_parseable; 220 boolean_t gs_lacp; 221 boolean_t gs_extended; 222 boolean_t gs_stats; 223 boolean_t gs_firstonly; 224 boolean_t gs_donefirst; 225 boolean_t gs_printheader; 226 print_state_t gs_print; 227 } show_grp_state_t; 228 229 typedef struct show_vnic_state { 230 datalink_id_t vs_vnic_id; 231 datalink_id_t vs_link_id; 232 char vs_vnic[MAXLINKNAMELEN]; 233 char vs_link[MAXLINKNAMELEN]; 234 boolean_t vs_parseable; 235 boolean_t vs_printheader; 236 boolean_t vs_found; 237 boolean_t vs_firstonly; 238 boolean_t vs_donefirst; 239 boolean_t vs_stats; 240 boolean_t vs_printstats; 241 pktsum_t vs_totalstats; 242 pktsum_t vs_prevstats[MAXVNIC]; 243 boolean_t vs_etherstub; 244 dladm_status_t vs_status; 245 uint32_t vs_flags; 246 print_state_t vs_print; 247 } show_vnic_state_t; 248 249 typedef struct show_usage_state_s { 250 boolean_t us_plot; 251 boolean_t us_parseable; 252 boolean_t us_printheader; 253 boolean_t us_first; 254 print_state_t us_print; 255 } show_usage_state_t; 256 257 typedef void cmdfunc_t(int, char **, const char *); 258 259 static cmdfunc_t do_show_link, do_show_wifi, do_show_phys; 260 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 261 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr; 262 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 263 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 264 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 265 static cmdfunc_t do_init_linkprop, do_init_secobj; 266 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan; 267 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys; 268 static cmdfunc_t do_show_linkmap; 269 static cmdfunc_t do_show_ether; 270 static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic; 271 static cmdfunc_t do_up_vnic; 272 static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub; 273 static cmdfunc_t do_show_usage; 274 275 static void do_up_vnic_common(int, char **, const char *, boolean_t); 276 277 static void altroot_cmd(char *, int, char **); 278 static int show_linkprop_onelink(datalink_id_t, void *); 279 280 static void link_stats(datalink_id_t, uint_t, char *, show_state_t *); 281 static void aggr_stats(datalink_id_t, show_grp_state_t *, uint_t); 282 static void vnic_stats(show_vnic_state_t *, uint32_t); 283 284 static int get_one_kstat(const char *, const char *, uint8_t, 285 void *, boolean_t); 286 static void get_mac_stats(const char *, pktsum_t *); 287 static void get_link_stats(const char *, pktsum_t *); 288 static uint64_t get_ifspeed(const char *, boolean_t); 289 static const char *get_linkstate(const char *, boolean_t, char *); 290 static const char *get_linkduplex(const char *, boolean_t, char *); 291 292 static int show_etherprop(datalink_id_t, void *); 293 static void show_ether_xprop(datalink_id_t, void *); 294 static boolean_t get_speed_duplex(datalink_id_t, const char *, char *, 295 char *, boolean_t); 296 static char *pause_str(int, int); 297 static boolean_t link_is_ether(const char *, datalink_id_t *); 298 299 #define IS_FDX 0x10 300 #define IS_HDX 0x01 301 302 static boolean_t str2int(const char *, int *); 303 static void die(const char *, ...); 304 static void die_optdup(int); 305 static void die_opterr(int, int, const char *); 306 static void die_dlerr(dladm_status_t, const char *, ...); 307 static void warn(const char *, ...); 308 static void warn_dlerr(dladm_status_t, const char *, ...); 309 310 typedef struct cmd { 311 char *c_name; 312 cmdfunc_t *c_fn; 313 const char *c_usage; 314 } cmd_t; 315 316 static cmd_t cmds[] = { 317 { "show-link", do_show_link, 318 "\tshow-link\t[-pP] [-o <field>,..] [-s [-i <interval>]] [<link>]"}, 319 { "rename-link", do_rename_link, 320 "\trename-link\t[-R <root-dir>] <oldlink> <newlink>\n" }, 321 { "create-aggr", do_create_aggr, 322 "\tcreate-aggr\t[-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n" 323 "\t\t\t[-T <time>] [-u <address>] [-l <link>] ... <link>" }, 324 { "delete-aggr", do_delete_aggr, 325 "\tdelete-aggr\t[-t] [-R <root-dir>] <link>" }, 326 { "add-aggr", do_add_aggr, 327 "\tadd-aggr\t[-t] [-R <root-dir>] [-l <link>] ... <link>" }, 328 { "remove-aggr", do_remove_aggr, 329 "\tremove-aggr\t[-t] [-R <root-dir>] [-l <link>] ... <link>"}, 330 { "modify-aggr", do_modify_aggr, 331 "\tmodify-aggr\t[-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n" 332 "\t\t\t[-T <time>] [-u <address>] <link>" }, 333 { "show-aggr", do_show_aggr, 334 "\tshow-aggr\t[-pPLx] [-o <field>,..] [-s [-i <interval>]] " 335 "[<link>]\n" }, 336 { "up-aggr", do_up_aggr, NULL }, 337 { "scan-wifi", do_scan_wifi, 338 "\tscan-wifi\t[-p] [-o <field>,...] [<link>]" }, 339 { "connect-wifi", do_connect_wifi, 340 "\tconnect-wifi\t[-e <essid>] [-i <bssid>] [-k <key>,...] " 341 "[-s wep|wpa]\n" 342 "\t\t\t[-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n" 343 "\t\t\t[-T <time>] [<link>]" }, 344 { "disconnect-wifi", do_disconnect_wifi, 345 "\tdisconnect-wifi\t[-a] [<link>]" }, 346 { "show-wifi", do_show_wifi, 347 "\tshow-wifi\t[-p] [-o <field>,...] [<link>]\n" }, 348 { "show-linkprop", do_show_linkprop, 349 "\tshow-linkprop\t[-cP] [-o <field>,...] [-p <prop>,...] <name>"}, 350 { "set-linkprop", do_set_linkprop, 351 "\tset-linkprop\t[-t] [-R <root-dir>] -p <prop>=<value>[,...] " 352 "<name>" }, 353 { "reset-linkprop", do_reset_linkprop, 354 "\treset-linkprop\t[-t] [-R <root-dir>] [-p <prop>,...] <name>\n" }, 355 { "show-ether", do_show_ether, 356 "\tshow-ether\t[-px][-o <field>,...] <link>\n" }, 357 { "create-secobj", do_create_secobj, 358 "\tcreate-secobj\t[-t] [-R <root-dir>] [-f <file>] -c <class> " 359 "<secobj>" }, 360 { "delete-secobj", do_delete_secobj, 361 "\tdelete-secobj\t[-t] [-R <root-dir>] <secobj>[,...]" }, 362 { "show-secobj", do_show_secobj, 363 "\tshow-secobj\t[-pP] [-o <field>,...] [<secobj>,...]\n" }, 364 { "init-linkprop", do_init_linkprop, NULL }, 365 { "init-secobj", do_init_secobj, NULL }, 366 { "create-vlan", do_create_vlan, 367 "\tcreate-vlan\t[-ft] [-R <root-dir>] -l <link> -v <vid> [link]" }, 368 { "delete-vlan", do_delete_vlan, 369 "\tdelete-vlan\t[-t] [-R <root-dir>] <link>" }, 370 { "show-vlan", do_show_vlan, 371 "\tshow-vlan\t[-pP] [-o <field>,..] [<link>]\n" }, 372 { "up-vlan", do_up_vlan, NULL }, 373 { "delete-phys", do_delete_phys, 374 "\tdelete-phys\t<link>" }, 375 { "show-phys", do_show_phys, 376 "\tshow-phys\t[-pP] [-o <field>,..] [-H] [<link>]" }, 377 { "init-phys", do_init_phys, NULL }, 378 { "show-linkmap", do_show_linkmap, NULL }, 379 { "create-vnic", do_create_vnic, 380 "\tcreate-vnic [-t] [-R <root-dir>] -l <link> [-m <value> |" 381 " auto |\n" 382 "\t {factory [-n <slot-identifier>]} |\n" 383 "\t {random [-r <prefix>]}] [-v vlan-tag [-f]]\n" 384 "\t -p <prop>=<value>[,...] [-H]" 385 " <vnic-link>\n" }, 386 { "delete-vnic", do_delete_vnic, 387 "\tdelete-vnic [-t] [-R <root-dir>] <vnic-link>\n" }, 388 { "show-vnic", do_show_vnic, 389 "\tshow-vnic [-pP] [-l <link>] [-s [-i <interval>]]" }, 390 { "up-vnic", do_up_vnic, NULL }, 391 { "create-etherstub", do_create_etherstub, 392 "\tcreate-etherstub [-t] [-R <root-dir>] <link>\n" }, 393 { "delete-etherstub", do_delete_etherstub, 394 "\tdelete-etherstub [-t] [-R <root-dir>] <link>\n" }, 395 { "show-etherstub", do_show_etherstub, 396 "\tshow-etherstub [-t] [-R <root-dir>] [<link>]\n" }, 397 { "show-usage", do_show_usage, 398 "\tshow-usage [-d|-p -F <format>] [-f <filename>]\n" 399 "\t [-s <time>] [-e <time>] <link>\n" } 400 }; 401 402 static const struct option lopts[] = { 403 {"vlan-id", required_argument, 0, 'v'}, 404 {"output", required_argument, 0, 'o'}, 405 {"dev", required_argument, 0, 'd'}, 406 {"policy", required_argument, 0, 'P'}, 407 {"lacp-mode", required_argument, 0, 'L'}, 408 {"lacp-timer", required_argument, 0, 'T'}, 409 {"unicast", required_argument, 0, 'u'}, 410 {"temporary", no_argument, 0, 't'}, 411 {"root-dir", required_argument, 0, 'R'}, 412 {"link", required_argument, 0, 'l'}, 413 {"forcible", no_argument, 0, 'f'}, 414 {"bw-limit", required_argument, 0, 'b'}, 415 {"mac-address", required_argument, 0, 'm'}, 416 {"slot", required_argument, 0, 'n'}, 417 { 0, 0, 0, 0 } 418 }; 419 420 static const struct option show_lopts[] = { 421 {"statistics", no_argument, 0, 's'}, 422 {"continuous", no_argument, 0, 'S'}, 423 {"interval", required_argument, 0, 'i'}, 424 {"parseable", no_argument, 0, 'p'}, 425 {"extended", no_argument, 0, 'x'}, 426 {"output", required_argument, 0, 'o'}, 427 {"persistent", no_argument, 0, 'P'}, 428 {"lacp", no_argument, 0, 'L'}, 429 { 0, 0, 0, 0 } 430 }; 431 432 static const struct option prop_longopts[] = { 433 {"temporary", no_argument, 0, 't' }, 434 {"output", required_argument, 0, 'o' }, 435 {"root-dir", required_argument, 0, 'R' }, 436 {"prop", required_argument, 0, 'p' }, 437 {"parseable", no_argument, 0, 'c' }, 438 {"persistent", no_argument, 0, 'P' }, 439 { 0, 0, 0, 0 } 440 }; 441 442 static const struct option wifi_longopts[] = { 443 {"parseable", no_argument, 0, 'p' }, 444 {"output", required_argument, 0, 'o' }, 445 {"essid", required_argument, 0, 'e' }, 446 {"bsstype", required_argument, 0, 'b' }, 447 {"mode", required_argument, 0, 'm' }, 448 {"key", required_argument, 0, 'k' }, 449 {"sec", required_argument, 0, 's' }, 450 {"auth", required_argument, 0, 'a' }, 451 {"create-ibss", required_argument, 0, 'c' }, 452 {"timeout", required_argument, 0, 'T' }, 453 {"all-links", no_argument, 0, 'a' }, 454 {"temporary", no_argument, 0, 't' }, 455 {"root-dir", required_argument, 0, 'R' }, 456 {"persistent", no_argument, 0, 'P' }, 457 {"file", required_argument, 0, 'f' }, 458 { 0, 0, 0, 0 } 459 }; 460 static const struct option showeth_lopts[] = { 461 {"parseable", no_argument, 0, 'p' }, 462 {"extended", no_argument, 0, 'x' }, 463 {"output", required_argument, 0, 'o' }, 464 { 0, 0, 0, 0 } 465 }; 466 467 static const struct option vnic_lopts[] = { 468 {"temporary", no_argument, 0, 't' }, 469 {"root-dir", required_argument, 0, 'R' }, 470 {"dev", required_argument, 0, 'd' }, 471 {"mac-address", required_argument, 0, 'm' }, 472 {"cpus", required_argument, 0, 'c' }, 473 {"bw-limit", required_argument, 0, 'b' }, 474 {"slot", required_argument, 0, 'n' }, 475 {"mac-prefix", required_argument, 0, 'r' }, 476 { 0, 0, 0, 0 } 477 }; 478 479 static const struct option etherstub_lopts[] = { 480 {"temporary", no_argument, 0, 't' }, 481 {"root-dir", required_argument, 0, 'R' }, 482 { 0, 0, 0, 0 } 483 }; 484 485 /* 486 * structures for 'dladm show-ether' 487 */ 488 typedef struct ether_fields_buf_s 489 { 490 char eth_link[15]; 491 char eth_ptype[8]; 492 char eth_state[8]; 493 char eth_autoneg[5]; 494 char eth_spdx[31]; 495 char eth_pause[6]; 496 char eth_rem_fault[16]; 497 } ether_fields_buf_t; 498 499 static print_field_t ether_fields[] = { 500 /* name, header, field width, offset, cmdtype */ 501 { "link", "LINK", 15, 502 offsetof(ether_fields_buf_t, eth_link), CMD_TYPE_ANY}, 503 { "ptype", "PTYPE", 8, 504 offsetof(ether_fields_buf_t, eth_ptype), CMD_TYPE_ANY}, 505 { "state", "STATE", 8, 506 offsetof(ether_fields_buf_t, eth_state), CMD_TYPE_ANY}, 507 { "auto", "AUTO", 5, 508 offsetof(ether_fields_buf_t, eth_autoneg), CMD_TYPE_ANY}, 509 { "speed-duplex", "SPEED-DUPLEX", 31, 510 offsetof(ether_fields_buf_t, eth_spdx), CMD_TYPE_ANY}, 511 { "pause", "PAUSE", 6, 512 offsetof(ether_fields_buf_t, eth_pause), CMD_TYPE_ANY}, 513 { "rem_fault", "REM_FAULT", 16, 514 offsetof(ether_fields_buf_t, eth_rem_fault), CMD_TYPE_ANY}} 515 ; 516 #define ETHER_MAX_FIELDS (sizeof (ether_fields) / sizeof (print_field_t)) 517 518 typedef struct print_ether_state { 519 const char *es_link; 520 boolean_t es_parseable; 521 boolean_t es_header; 522 boolean_t es_extended; 523 print_state_t es_print; 524 } print_ether_state_t; 525 526 /* 527 * structures for 'dladm show-link -s' (print statistics) 528 */ 529 typedef enum { 530 DEVS_LINK, 531 DEVS_IPKTS, 532 DEVS_RBYTES, 533 DEVS_IERRORS, 534 DEVS_OPKTS, 535 DEVS_OBYTES, 536 DEVS_OERRORS 537 } devs_field_index_t; 538 539 static print_field_t devs_fields[] = { 540 /* name, header, field width, index, cmdtype */ 541 { "link", "LINK", 15, DEVS_LINK, CMD_TYPE_ANY}, 542 { "ipackets", "IPACKETS", 10, DEVS_IPKTS, CMD_TYPE_ANY}, 543 { "rbytes", "RBYTES", 8, DEVS_RBYTES, CMD_TYPE_ANY}, 544 { "ierrors", "IERRORS", 10, DEVS_IERRORS, CMD_TYPE_ANY}, 545 { "opackets", "OPACKETS", 12, DEVS_OPKTS, CMD_TYPE_ANY}, 546 { "obytes", "OBYTES", 12, DEVS_OBYTES, CMD_TYPE_ANY}, 547 { "oerrors", "OERRORS", 8, DEVS_OERRORS, CMD_TYPE_ANY}} 548 ; 549 #define DEVS_MAX_FIELDS (sizeof (devs_fields) / sizeof (print_field_t)) 550 551 /* 552 * buffer used by print functions for show-{link,phys,vlan} commands. 553 */ 554 typedef struct link_fields_buf_s { 555 char link_name[MAXLINKNAMELEN]; 556 char link_class[DLADM_STRSIZE]; 557 char link_mtu[11]; 558 char link_state[DLADM_STRSIZE]; 559 char link_over[MAXLINKNAMELEN]; 560 char link_phys_state[DLADM_STRSIZE]; 561 char link_phys_media[DLADM_STRSIZE]; 562 char link_phys_speed[DLADM_STRSIZE]; 563 char link_phys_duplex[DLPI_LINKNAME_MAX]; 564 char link_phys_device[DLPI_LINKNAME_MAX]; 565 char link_flags[6]; 566 char link_vlan_vid[6]; 567 } link_fields_buf_t; 568 569 /* 570 * structures for 'dladm show-link' 571 */ 572 static print_field_t link_fields[] = { 573 /* name, header, field width, offset, cmdtype */ 574 { "link", "LINK", 11, 575 offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, 576 { "class", "CLASS", 8, 577 offsetof(link_fields_buf_t, link_class), CMD_TYPE_ANY}, 578 { "mtu", "MTU", 6, 579 offsetof(link_fields_buf_t, link_mtu), CMD_TYPE_ANY}, 580 { "state", "STATE", 8, 581 offsetof(link_fields_buf_t, link_state), CMD_TYPE_ANY}, 582 { "over", "OVER", DLPI_LINKNAME_MAX, 583 offsetof(link_fields_buf_t, link_over), CMD_TYPE_ANY}} 584 ; 585 #define DEV_LINK_FIELDS (sizeof (link_fields) / sizeof (print_field_t)) 586 587 /* 588 * structures for 'dladm show-aggr' 589 */ 590 typedef struct laggr_fields_buf_s { 591 char laggr_name[DLPI_LINKNAME_MAX]; 592 char laggr_policy[9]; 593 char laggr_addrpolicy[ETHERADDRL * 3 + 3]; 594 char laggr_lacpactivity[14]; 595 char laggr_lacptimer[DLADM_STRSIZE]; 596 char laggr_flags[7]; 597 } laggr_fields_buf_t; 598 599 typedef struct laggr_args_s { 600 int laggr_lport; /* -1 indicates the aggr itself */ 601 const char *laggr_link; 602 dladm_aggr_grp_attr_t *laggr_ginfop; 603 dladm_status_t *laggr_status; 604 pktsum_t *laggr_pktsumtot; /* -s only */ 605 pktsum_t *laggr_prevstats; /* -s only */ 606 boolean_t laggr_parseable; 607 } laggr_args_t; 608 609 static print_field_t laggr_fields[] = { 610 /* name, header, field width, offset, cmdtype */ 611 { "link", "LINK", 15, 612 offsetof(laggr_fields_buf_t, laggr_name), CMD_TYPE_ANY}, 613 { "policy", "POLICY", 8, 614 offsetof(laggr_fields_buf_t, laggr_policy), CMD_TYPE_ANY}, 615 { "addrpolicy", "ADDRPOLICY", ETHERADDRL * 3 + 2, 616 offsetof(laggr_fields_buf_t, laggr_addrpolicy), CMD_TYPE_ANY}, 617 { "lacpactivity", "LACPACTIVITY", 13, 618 offsetof(laggr_fields_buf_t, laggr_lacpactivity), CMD_TYPE_ANY}, 619 { "lacptimer", "LACPTIMER", 11, 620 offsetof(laggr_fields_buf_t, laggr_lacptimer), CMD_TYPE_ANY}, 621 { "flags", "FLAGS", 7, 622 offsetof(laggr_fields_buf_t, laggr_flags), CMD_TYPE_ANY}} 623 ; 624 #define LAGGR_MAX_FIELDS (sizeof (laggr_fields) / sizeof (print_field_t)) 625 626 /* 627 * structures for 'dladm show-aggr -x'. 628 */ 629 typedef enum { 630 AGGR_X_LINK, 631 AGGR_X_PORT, 632 AGGR_X_SPEED, 633 AGGR_X_DUPLEX, 634 AGGR_X_STATE, 635 AGGR_X_ADDRESS, 636 AGGR_X_PORTSTATE 637 } aggr_x_field_index_t; 638 639 static print_field_t aggr_x_fields[] = { 640 /* name, header, field width, index, cmdtype */ 641 { "link", "LINK", 11, AGGR_X_LINK, CMD_TYPE_ANY}, 642 { "port", "PORT", 14, AGGR_X_PORT, CMD_TYPE_ANY}, 643 { "speed", "SPEED", 4, AGGR_X_SPEED, CMD_TYPE_ANY}, 644 { "duplex", "DUPLEX", 9, AGGR_X_DUPLEX, CMD_TYPE_ANY}, 645 { "state", "STATE", 9, AGGR_X_STATE, CMD_TYPE_ANY}, 646 { "address", "ADDRESS", 18, AGGR_X_ADDRESS, CMD_TYPE_ANY}, 647 { "portstate", "PORTSTATE", 15, AGGR_X_PORTSTATE, CMD_TYPE_ANY}} 648 ; 649 #define AGGR_X_MAX_FIELDS \ 650 (sizeof (aggr_x_fields) / sizeof (print_field_t)) 651 652 /* 653 * structures for 'dladm show-aggr -s'. 654 */ 655 typedef enum { 656 AGGR_S_LINK, 657 AGGR_S_PORT, 658 AGGR_S_IPKTS, 659 AGGR_S_RBYTES, 660 AGGR_S_OPKTS, 661 AGGR_S_OBYTES, 662 AGGR_S_IPKTDIST, 663 AGGR_S_OPKTDIST 664 } aggr_s_field_index_t; 665 666 static print_field_t aggr_s_fields[] = { 667 /* name, header, field width, index, cmdtype */ 668 { "link", "LINK", 11, AGGR_S_LINK, 669 CMD_TYPE_ANY}, 670 { "port", "PORT", 9, AGGR_S_PORT, 671 CMD_TYPE_ANY}, 672 { "ipackets", "IPACKETS", 7, AGGR_S_IPKTS, 673 CMD_TYPE_ANY}, 674 { "rbytes", "RBYTES", 7, AGGR_S_RBYTES, 675 CMD_TYPE_ANY}, 676 { "opackets", "OPACKETS", 7, AGGR_S_OPKTS, 677 CMD_TYPE_ANY}, 678 { "obytes", "OBYTES", 7, AGGR_S_OBYTES, 679 CMD_TYPE_ANY}, 680 { "ipktdist", "IPKTDIST", 8, AGGR_S_IPKTDIST, 681 CMD_TYPE_ANY}, 682 { "opktdist", "OPKTDIST", 14, AGGR_S_OPKTDIST, 683 CMD_TYPE_ANY}} 684 ; 685 #define AGGR_S_MAX_FIELDS \ 686 (sizeof (aggr_s_fields) / sizeof (print_field_t)) 687 688 /* 689 * structures for 'dladm show-aggr -L'. 690 */ 691 typedef enum { 692 AGGR_L_LINK, 693 AGGR_L_PORT, 694 AGGR_L_AGGREGATABLE, 695 AGGR_L_SYNC, 696 AGGR_L_COLL, 697 AGGR_L_DIST, 698 AGGR_L_DEFAULTED, 699 AGGR_L_EXPIRED 700 } aggr_l_field_index_t; 701 702 static print_field_t aggr_l_fields[] = { 703 /* name, header, field width, index, cmdtype */ 704 { "link", "LINK", 11, AGGR_L_LINK, 705 CMD_TYPE_ANY}, 706 { "port", "PORT", 12, AGGR_L_PORT, 707 CMD_TYPE_ANY}, 708 { "aggregatable", "AGGREGATABLE", 12, AGGR_L_AGGREGATABLE, 709 CMD_TYPE_ANY}, 710 { "sync", "SYNC", 4, AGGR_L_SYNC, 711 CMD_TYPE_ANY}, 712 { "coll", "COLL", 4, AGGR_L_COLL, 713 CMD_TYPE_ANY}, 714 { "dist", "DIST", 4, AGGR_L_DIST, 715 CMD_TYPE_ANY}, 716 { "defaulted", "DEFAULTED", 9, AGGR_L_DEFAULTED, 717 CMD_TYPE_ANY}, 718 { "expired", "EXPIRED", 14, AGGR_L_EXPIRED, 719 CMD_TYPE_ANY}} 720 ; 721 #define AGGR_L_MAX_FIELDS \ 722 (sizeof (aggr_l_fields) / sizeof (print_field_t)) 723 724 /* 725 * structures for 'dladm show-phys' 726 */ 727 728 static print_field_t phys_fields[] = { 729 /* name, header, field width, offset, cmdtype */ 730 { "link", "LINK", 12, 731 offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, 732 { "media", "MEDIA", 20, 733 offsetof(link_fields_buf_t, link_phys_media), CMD_TYPE_ANY}, 734 { "state", "STATE", 10, 735 offsetof(link_fields_buf_t, link_phys_state), CMD_TYPE_ANY}, 736 { "speed", "SPEED", 6, 737 offsetof(link_fields_buf_t, link_phys_speed), CMD_TYPE_ANY}, 738 { "duplex", "DUPLEX", 9, 739 offsetof(link_fields_buf_t, link_phys_duplex), CMD_TYPE_ANY}, 740 { "device", "DEVICE", 12, 741 offsetof(link_fields_buf_t, link_phys_device), CMD_TYPE_ANY}, 742 { "flags", "FLAGS", 6, 743 offsetof(link_fields_buf_t, link_flags), CMD_TYPE_ANY}} 744 ; 745 #define PHYS_MAX_FIELDS (sizeof (phys_fields) / sizeof (print_field_t)) 746 747 /* 748 * structures for 'dladm show-phys -m' 749 */ 750 751 typedef enum { 752 PHYS_M_LINK, 753 PHYS_M_SLOT, 754 PHYS_M_ADDRESS, 755 PHYS_M_INUSE, 756 PHYS_M_CLIENT 757 } phys_m_field_index_t; 758 759 static print_field_t phys_m_fields[] = { 760 /* name, header, field width, offset, cmdtype */ 761 { "link", "LINK", 12, PHYS_M_LINK, CMD_TYPE_ANY}, 762 { "slot", "SLOT", 8, PHYS_M_SLOT, CMD_TYPE_ANY}, 763 { "address", "ADDRESS", 18, PHYS_M_ADDRESS, CMD_TYPE_ANY}, 764 { "inuse", "INUSE", 4, PHYS_M_INUSE, CMD_TYPE_ANY}, 765 { "client", "CLIENT", 12, PHYS_M_CLIENT, CMD_TYPE_ANY}} 766 ; 767 #define PHYS_M_MAX_FIELDS (sizeof (phys_m_fields) / sizeof (print_field_t)) 768 769 /* 770 * structures for 'dladm show-phys -H' 771 */ 772 773 typedef enum { 774 PHYS_H_LINK, 775 PHYS_H_GROUP, 776 PHYS_H_GRPTYPE, 777 PHYS_H_RINGS, 778 PHYS_H_CLIENTS 779 } phys_h_field_index_t; 780 781 static print_field_t phys_h_fields[] = { 782 /* name, header, field width, offset, cmdtype */ 783 { "link", "LINK", 12, PHYS_H_LINK, CMD_TYPE_ANY}, 784 { "group", "GROUP", 8, PHYS_H_GROUP, CMD_TYPE_ANY}, 785 { "grouptype", "TYPE", 6, PHYS_H_GRPTYPE, CMD_TYPE_ANY}, 786 { "rings", "NUM-RINGS", 16, PHYS_H_RINGS, CMD_TYPE_ANY}, 787 { "clients", "CLIENTS", 20, PHYS_H_CLIENTS, CMD_TYPE_ANY}} 788 ; 789 #define PHYS_H_MAX_FIELDS (sizeof (phys_h_fields) / sizeof (print_field_t)) 790 791 /* 792 * structures for 'dladm show-vlan' 793 */ 794 static print_field_t vlan_fields[] = { 795 /* name, header, field width, offset, cmdtype */ 796 { "link", "LINK", 15, 797 offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, 798 { "vid", "VID", 8, 799 offsetof(link_fields_buf_t, link_vlan_vid), CMD_TYPE_ANY}, 800 { "over", "OVER", 12, 801 offsetof(link_fields_buf_t, link_over), CMD_TYPE_ANY}, 802 { "flags", "FLAGS", 6, 803 offsetof(link_fields_buf_t, link_flags), CMD_TYPE_ANY}} 804 ; 805 #define VLAN_MAX_FIELDS (sizeof (vlan_fields) / sizeof (print_field_t)) 806 807 808 /* 809 * structures for 'dladm show-wifi' 810 */ 811 static print_field_t wifi_fields[] = { 812 { "link", "LINK", 10, 0, WIFI_CMD_ALL}, 813 { "essid", "ESSID", 19, DLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, 814 { "bssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 815 { "ibssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 816 { "mode", "MODE", 6, DLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, 817 { "speed", "SPEED", 6, DLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, 818 { "auth", "AUTH", 8, DLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW}, 819 { "bsstype", "BSSTYPE", 8, DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, 820 { "sec", "SEC", 6, DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, 821 { "status", "STATUS", 17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW}, 822 { "strength", "STRENGTH", 10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} 823 ; 824 825 static char *all_scan_wifi_fields = 826 "link,essid,bssid,sec,strength,mode,speed,bsstype"; 827 static char *all_show_wifi_fields = 828 "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 829 static char *def_scan_wifi_fields = 830 "link,essid,bssid,sec,strength,mode,speed"; 831 static char *def_show_wifi_fields = 832 "link,status,essid,sec,strength,mode,speed"; 833 834 #define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (print_field_t)) 835 836 /* 837 * structures for 'dladm show-linkprop' 838 */ 839 typedef enum { 840 LINKPROP_LINK, 841 LINKPROP_PROPERTY, 842 LINKPROP_PERM, 843 LINKPROP_VALUE, 844 LINKPROP_DEFAULT, 845 LINKPROP_POSSIBLE 846 } linkprop_field_index_t; 847 848 static print_field_t linkprop_fields[] = { 849 /* name, header, field width, index, cmdtype */ 850 { "link", "LINK", 12, LINKPROP_LINK, CMD_TYPE_ANY}, 851 { "property", "PROPERTY", 15, LINKPROP_PROPERTY, CMD_TYPE_ANY}, 852 { "perm", "PERM", 4, LINKPROP_PERM, CMD_TYPE_ANY}, 853 { "value", "VALUE", 14, LINKPROP_VALUE, CMD_TYPE_ANY}, 854 { "default", "DEFAULT", 14, LINKPROP_DEFAULT, CMD_TYPE_ANY}, 855 { "possible", "POSSIBLE", 20, LINKPROP_POSSIBLE, CMD_TYPE_ANY}} 856 ; 857 #define LINKPROP_MAX_FIELDS \ 858 (sizeof (linkprop_fields) / sizeof (print_field_t)) 859 860 #define MAX_PROP_LINE 512 861 862 typedef struct show_linkprop_state { 863 char ls_link[MAXLINKNAMELEN]; 864 char *ls_line; 865 char **ls_propvals; 866 dladm_arg_list_t *ls_proplist; 867 boolean_t ls_parseable; 868 boolean_t ls_persist; 869 boolean_t ls_header; 870 dladm_status_t ls_status; 871 dladm_status_t ls_retstatus; 872 print_state_t ls_print; 873 } show_linkprop_state_t; 874 875 typedef struct set_linkprop_state { 876 const char *ls_name; 877 boolean_t ls_reset; 878 boolean_t ls_temp; 879 dladm_status_t ls_status; 880 } set_linkprop_state_t; 881 882 typedef struct linkprop_args_s { 883 show_linkprop_state_t *ls_state; 884 char *ls_propname; 885 datalink_id_t ls_linkid; 886 } linkprop_args_t; 887 888 /* 889 * structures for 'dladm show-secobj' 890 */ 891 typedef struct secobj_fields_buf_s { 892 char ss_obj_name[DLADM_SECOBJ_VAL_MAX]; 893 char ss_class[20]; 894 char ss_val[30]; 895 } secobj_fields_buf_t; 896 static print_field_t secobj_fields[] = { 897 /* name, header, field width, offset, cmdtype */ 898 { "object", "OBJECT", 20, 899 offsetof(secobj_fields_buf_t, ss_obj_name), CMD_TYPE_ANY}, 900 { "class", "CLASS", 20, 901 offsetof(secobj_fields_buf_t, ss_class), CMD_TYPE_ANY}, 902 { "value", "VALUE", 30, 903 offsetof(secobj_fields_buf_t, ss_val), CMD_TYPE_ANY}} 904 ; 905 #define DEV_SOBJ_FIELDS (sizeof (secobj_fields) / sizeof (print_field_t)) 906 907 /* 908 * structures for 'dladm show-vnic' 909 */ 910 typedef struct vnic_fields_buf_s 911 { 912 char vnic_link[DLPI_LINKNAME_MAX]; 913 char vnic_over[DLPI_LINKNAME_MAX]; 914 char vnic_speed[6]; 915 char vnic_macaddr[19]; 916 char vnic_macaddrtype[19]; 917 char vnic_vid[6]; 918 } vnic_fields_buf_t; 919 920 static print_field_t vnic_fields[] = { 921 /* name, header, field width, offset, cmdtype */ 922 { "link", "LINK", 12, 923 offsetof(vnic_fields_buf_t, vnic_link), CMD_TYPE_ANY}, 924 { "over", "OVER", 12, 925 offsetof(vnic_fields_buf_t, vnic_over), CMD_TYPE_ANY}, 926 { "speed", "SPEED", 6, 927 offsetof(vnic_fields_buf_t, vnic_speed), CMD_TYPE_ANY}, 928 { "macaddr", "MACADDRESS", 20, 929 offsetof(vnic_fields_buf_t, vnic_macaddr), CMD_TYPE_ANY}, 930 { "macaddrtype", "MACADDRTYPE", 19, 931 offsetof(vnic_fields_buf_t, vnic_macaddrtype), CMD_TYPE_ANY}, 932 { "vid", "VID", 6, 933 offsetof(vnic_fields_buf_t, vnic_vid), CMD_TYPE_ANY}} 934 ; 935 #define VNIC_MAX_FIELDS (sizeof (vnic_fields) / sizeof (print_field_t)) 936 937 /* 938 * structures for 'dladm show-usage' 939 */ 940 941 typedef struct usage_fields_buf_s { 942 char usage_link[12]; 943 char usage_duration[10]; 944 char usage_ipackets[9]; 945 char usage_rbytes[10]; 946 char usage_opackets[9]; 947 char usage_obytes[10]; 948 char usage_bandwidth[14]; 949 } usage_fields_buf_t; 950 951 static print_field_t usage_fields[] = { 952 /* name, header, field width, offset, cmdtype */ 953 { "link", "LINK", 12, 954 offsetof(usage_fields_buf_t, usage_link), CMD_TYPE_ANY}, 955 { "duration", "DURATION", 10, 956 offsetof(usage_fields_buf_t, usage_duration), CMD_TYPE_ANY}, 957 { "ipackets", "IPACKETS", 9, 958 offsetof(usage_fields_buf_t, usage_ipackets), CMD_TYPE_ANY}, 959 { "rbytes", "RBYTES", 10, 960 offsetof(usage_fields_buf_t, usage_rbytes), CMD_TYPE_ANY}, 961 { "opackets", "OPACKETS", 9, 962 offsetof(usage_fields_buf_t, usage_opackets), CMD_TYPE_ANY}, 963 { "obytes", "OBYTES", 10, 964 offsetof(usage_fields_buf_t, usage_obytes), CMD_TYPE_ANY}, 965 { "bandwidth", "BANDWIDTH", 14, 966 offsetof(usage_fields_buf_t, usage_bandwidth), CMD_TYPE_ANY}} 967 ; 968 969 #define USAGE_MAX_FIELDS (sizeof (usage_fields) / sizeof (print_field_t)) 970 971 /* 972 * structures for 'dladm show-usage link' 973 */ 974 975 typedef struct usage_l_fields_buf_s { 976 char usage_l_link[12]; 977 char usage_l_stime[13]; 978 char usage_l_etime[13]; 979 char usage_l_rbytes[8]; 980 char usage_l_obytes[8]; 981 char usage_l_bandwidth[14]; 982 } usage_l_fields_buf_t; 983 984 static print_field_t usage_l_fields[] = { 985 /* name, header, field width, offset, cmdtype */ 986 { "link", "LINK", 12, 987 offsetof(usage_l_fields_buf_t, usage_l_link), CMD_TYPE_ANY}, 988 { "start", "START", 13, 989 offsetof(usage_l_fields_buf_t, usage_l_stime), CMD_TYPE_ANY}, 990 { "end", "END", 13, 991 offsetof(usage_l_fields_buf_t, usage_l_etime), CMD_TYPE_ANY}, 992 { "rbytes", "RBYTES", 8, 993 offsetof(usage_l_fields_buf_t, usage_l_rbytes), CMD_TYPE_ANY}, 994 { "obytes", "OBYTES", 8, 995 offsetof(usage_l_fields_buf_t, usage_l_obytes), CMD_TYPE_ANY}, 996 { "bandwidth", "BANDWIDTH", 14, 997 offsetof(usage_l_fields_buf_t, usage_l_bandwidth), CMD_TYPE_ANY}} 998 ; 999 1000 #define USAGE_L_MAX_FIELDS \ 1001 (sizeof (usage_l_fields) /sizeof (print_field_t)) 1002 1003 static char *progname; 1004 static sig_atomic_t signalled; 1005 1006 #define DLADM_ETHERSTUB_NAME "etherstub" 1007 #define DLADM_IS_ETHERSTUB(id) (id == DATALINK_INVALID_LINKID) 1008 1009 static void 1010 usage(void) 1011 { 1012 int i; 1013 cmd_t *cmdp; 1014 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ..." 1015 "\n")); 1016 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 1017 cmdp = &cmds[i]; 1018 if (cmdp->c_usage != NULL) 1019 (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage)); 1020 } 1021 exit(1); 1022 } 1023 1024 int 1025 main(int argc, char *argv[]) 1026 { 1027 int i; 1028 cmd_t *cmdp; 1029 1030 (void) setlocale(LC_ALL, ""); 1031 #if !defined(TEXT_DOMAIN) 1032 #define TEXT_DOMAIN "SYS_TEST" 1033 #endif 1034 (void) textdomain(TEXT_DOMAIN); 1035 1036 progname = argv[0]; 1037 1038 if (argc < 2) 1039 usage(); 1040 1041 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 1042 cmdp = &cmds[i]; 1043 if (strcmp(argv[1], cmdp->c_name) == 0) { 1044 cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage); 1045 exit(0); 1046 } 1047 } 1048 1049 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 1050 progname, argv[1]); 1051 usage(); 1052 1053 return (0); 1054 } 1055 1056 /*ARGSUSED*/ 1057 static int 1058 show_usage_date(dladm_usage_t *usage, void *arg) 1059 { 1060 1061 time_t stime; 1062 char timebuf[20]; 1063 1064 stime = usage->du_stime; 1065 (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y", 1066 localtime(&stime)); 1067 (void) printf("%s\n", timebuf); 1068 1069 return (DLADM_STATUS_OK); 1070 } 1071 1072 static int 1073 show_usage_time(dladm_usage_t *usage, void *arg) 1074 { 1075 show_usage_state_t *state = (show_usage_state_t *)arg; 1076 char buf[DLADM_STRSIZE]; 1077 usage_l_fields_buf_t ubuf; 1078 time_t time; 1079 double bw; 1080 1081 if (state->us_plot) { 1082 if (!state->us_printheader) { 1083 if (state->us_first) { 1084 (void) printf("# Time"); 1085 state->us_first = B_FALSE; 1086 } 1087 (void) printf(" %s", usage->du_name); 1088 if (usage->du_last) { 1089 (void) printf("\n"); 1090 state->us_first = B_TRUE; 1091 state->us_printheader = B_TRUE; 1092 } 1093 } else { 1094 if (state->us_first) { 1095 time = usage->du_etime; 1096 (void) strftime(buf, sizeof (buf), "%T", 1097 localtime(&time)); 1098 state->us_first = B_FALSE; 1099 (void) printf("%s", buf); 1100 } 1101 bw = (double)usage->du_bandwidth/1000; 1102 (void) printf(" %.2f", bw); 1103 if (usage->du_last) { 1104 (void) printf("\n"); 1105 state->us_first = B_TRUE; 1106 } 1107 } 1108 return (DLADM_STATUS_OK); 1109 } 1110 1111 bzero(&ubuf, sizeof (ubuf)); 1112 1113 (void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s", 1114 usage->du_name); 1115 time = usage->du_stime; 1116 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1117 (void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s", 1118 buf); 1119 time = usage->du_etime; 1120 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1121 (void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s", 1122 buf); 1123 (void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes), 1124 "%llu", usage->du_rbytes); 1125 (void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes), 1126 "%llu", usage->du_obytes); 1127 (void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth), 1128 "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1129 1130 if (!state->us_parseable && !state->us_printheader) { 1131 print_header(&state->us_print); 1132 state->us_printheader = B_TRUE; 1133 } 1134 1135 dladm_print_output(&state->us_print, state->us_parseable, 1136 dladm_print_field, (void *)&ubuf); 1137 1138 return (DLADM_STATUS_OK); 1139 } 1140 1141 static int 1142 show_usage_res(dladm_usage_t *usage, void *arg) 1143 { 1144 show_usage_state_t *state = (show_usage_state_t *)arg; 1145 char buf[DLADM_STRSIZE]; 1146 usage_fields_buf_t ubuf; 1147 1148 bzero(&ubuf, sizeof (ubuf)); 1149 1150 (void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s", 1151 usage->du_name); 1152 (void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration), 1153 "%llu", usage->du_duration); 1154 (void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets), 1155 "%llu", usage->du_ipackets); 1156 (void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes), 1157 "%llu", usage->du_rbytes); 1158 (void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets), 1159 "%llu", usage->du_opackets); 1160 (void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes), 1161 "%llu", usage->du_obytes); 1162 (void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth), 1163 "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1164 1165 if (!state->us_parseable && !state->us_printheader) { 1166 print_header(&state->us_print); 1167 state->us_printheader = B_TRUE; 1168 } 1169 1170 dladm_print_output(&state->us_print, state->us_parseable, 1171 dladm_print_field, (void *)&ubuf); 1172 1173 return (DLADM_STATUS_OK); 1174 } 1175 1176 static boolean_t 1177 valid_formatspec(char *formatspec_str) 1178 { 1179 if (strcmp(formatspec_str, "gnuplot") == 0) 1180 return (B_TRUE); 1181 return (B_FALSE); 1182 1183 } 1184 1185 /*ARGSUSED*/ 1186 static void 1187 do_show_usage(int argc, char *argv[], const char *use) 1188 { 1189 char *file = NULL; 1190 int opt; 1191 dladm_status_t status; 1192 boolean_t d_arg = B_FALSE; 1193 boolean_t p_arg = B_FALSE; 1194 char *stime = NULL; 1195 char *etime = NULL; 1196 char *resource = NULL; 1197 show_usage_state_t state; 1198 boolean_t o_arg = B_FALSE; 1199 boolean_t F_arg = B_FALSE; 1200 char *fields_str = NULL; 1201 char *formatspec_str = NULL; 1202 print_field_t **fields; 1203 uint_t nfields; 1204 char *all_fields = 1205 "link,duration,ipackets,rbytes,opackets,obytes,bandwidth"; 1206 char *all_l_fields = 1207 "link,start,end,rbytes,obytes,bandwidth"; 1208 1209 bzero(&state, sizeof (show_usage_state_t)); 1210 state.us_parseable = B_FALSE; 1211 state.us_printheader = B_FALSE; 1212 state.us_plot = B_FALSE; 1213 state.us_first = B_TRUE; 1214 1215 while ((opt = getopt(argc, argv, "dps:e:o:f:F:")) != -1) { 1216 switch (opt) { 1217 case 'd': 1218 d_arg = B_TRUE; 1219 break; 1220 case 'p': 1221 state.us_plot = p_arg = B_TRUE; 1222 break; 1223 case 'f': 1224 file = optarg; 1225 break; 1226 case 's': 1227 stime = optarg; 1228 break; 1229 case 'e': 1230 etime = optarg; 1231 break; 1232 case 'o': 1233 o_arg = B_TRUE; 1234 fields_str = optarg; 1235 break; 1236 case 'F': 1237 F_arg = B_TRUE; 1238 formatspec_str = optarg; 1239 break; 1240 default: 1241 die_opterr(optopt, opt, use); 1242 break; 1243 } 1244 } 1245 1246 if (file == NULL) 1247 die("show-usage requires a file"); 1248 1249 if (optind == (argc-1)) { 1250 resource = argv[optind]; 1251 } 1252 1253 if (resource == NULL && stime == NULL && etime == NULL) { 1254 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 1255 fields_str = all_fields; 1256 fields = parse_output_fields(fields_str, usage_fields, 1257 USAGE_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 1258 } else { 1259 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 1260 fields_str = all_l_fields; 1261 fields = parse_output_fields(fields_str, usage_l_fields, 1262 USAGE_L_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 1263 } 1264 1265 if (fields == NULL) { 1266 die("invalid fields(s) specified"); 1267 return; 1268 } 1269 state.us_print.ps_fields = fields; 1270 state.us_print.ps_nfields = nfields; 1271 1272 if (p_arg && d_arg) 1273 die("plot and date options are incompatible"); 1274 1275 if (p_arg && !F_arg) 1276 die("specify format speicifier: -F <format>"); 1277 1278 if (F_arg && valid_formatspec(formatspec_str) == B_FALSE) 1279 die("Format specifier %s not supported", formatspec_str); 1280 1281 if (d_arg) { 1282 /* Print log dates */ 1283 status = dladm_usage_dates(show_usage_date, 1284 DLADM_LOGTYPE_LINK, file, resource, &state); 1285 } else if (resource == NULL && stime == NULL && etime == NULL && 1286 !p_arg) { 1287 /* Print summary */ 1288 status = dladm_usage_summary(show_usage_res, 1289 DLADM_LOGTYPE_LINK, file, &state); 1290 } else if (resource != NULL) { 1291 /* Print log entries for named resource */ 1292 status = dladm_walk_usage_res(show_usage_time, 1293 DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state); 1294 } else { 1295 /* Print time and information for each link */ 1296 status = dladm_walk_usage_time(show_usage_time, 1297 DLADM_LOGTYPE_LINK, file, stime, etime, &state); 1298 } 1299 1300 if (status != DLADM_STATUS_OK) 1301 die_dlerr(status, "show-usage"); 1302 } 1303 1304 static void 1305 do_create_aggr(int argc, char *argv[], const char *use) 1306 { 1307 char option; 1308 int key = 0; 1309 uint32_t policy = AGGR_POLICY_L4; 1310 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 1311 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 1312 dladm_aggr_port_attr_db_t port[MAXPORT]; 1313 uint_t n, ndev, nlink; 1314 uint8_t mac_addr[ETHERADDRL]; 1315 boolean_t mac_addr_fixed = B_FALSE; 1316 boolean_t P_arg = B_FALSE; 1317 boolean_t l_arg = B_FALSE; 1318 boolean_t u_arg = B_FALSE; 1319 boolean_t T_arg = B_FALSE; 1320 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1321 char *altroot = NULL; 1322 char name[MAXLINKNAMELEN]; 1323 char *devs[MAXPORT]; 1324 char *links[MAXPORT]; 1325 dladm_status_t status; 1326 dladm_status_t pstatus; 1327 dladm_arg_list_t *proplist = NULL; 1328 int i; 1329 datalink_id_t linkid; 1330 1331 ndev = nlink = opterr = 0; 1332 while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:", 1333 lopts, NULL)) != -1) { 1334 switch (option) { 1335 case 'd': 1336 if (ndev + nlink >= MAXPORT) 1337 die("too many ports specified"); 1338 1339 devs[ndev++] = optarg; 1340 break; 1341 case 'P': 1342 if (P_arg) 1343 die_optdup(option); 1344 1345 P_arg = B_TRUE; 1346 if (!dladm_aggr_str2policy(optarg, &policy)) 1347 die("invalid policy '%s'", optarg); 1348 break; 1349 case 'u': 1350 if (u_arg) 1351 die_optdup(option); 1352 1353 u_arg = B_TRUE; 1354 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 1355 mac_addr)) 1356 die("invalid MAC address '%s'", optarg); 1357 break; 1358 case 'l': 1359 if (isdigit(optarg[strlen(optarg) - 1])) { 1360 1361 /* 1362 * Ended with digit, possibly a link name. 1363 */ 1364 if (ndev + nlink >= MAXPORT) 1365 die("too many ports specified"); 1366 1367 links[nlink++] = optarg; 1368 break; 1369 } 1370 /* FALLTHROUGH */ 1371 case 'L': 1372 if (l_arg) 1373 die_optdup(option); 1374 1375 l_arg = B_TRUE; 1376 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 1377 die("invalid LACP mode '%s'", optarg); 1378 break; 1379 case 'T': 1380 if (T_arg) 1381 die_optdup(option); 1382 1383 T_arg = B_TRUE; 1384 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 1385 die("invalid LACP timer value '%s'", optarg); 1386 break; 1387 case 't': 1388 flags &= ~DLADM_OPT_PERSIST; 1389 break; 1390 case 'f': 1391 flags |= DLADM_OPT_FORCE; 1392 break; 1393 case 'R': 1394 altroot = optarg; 1395 break; 1396 case 'p': 1397 if (dladm_parse_link_props(optarg, &proplist, B_FALSE) 1398 != DLADM_STATUS_OK) 1399 die("invalid aggregation property"); 1400 break; 1401 default: 1402 die_opterr(optopt, option, use); 1403 break; 1404 } 1405 } 1406 1407 if (ndev + nlink == 0) 1408 usage(); 1409 1410 /* get key value or the aggregation name (required last argument) */ 1411 if (optind != (argc-1)) 1412 usage(); 1413 1414 if (!str2int(argv[optind], &key)) { 1415 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= 1416 MAXLINKNAMELEN) { 1417 die("link name too long '%s'", argv[optind]); 1418 } 1419 1420 if (!dladm_valid_linkname(name)) 1421 die("invalid link name '%s'", argv[optind]); 1422 } else { 1423 (void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key); 1424 } 1425 1426 if (altroot != NULL) 1427 altroot_cmd(altroot, argc, argv); 1428 1429 for (n = 0; n < ndev; n++) { 1430 if (dladm_dev2linkid(devs[n], &port[n].lp_linkid) != 1431 DLADM_STATUS_OK) { 1432 die("invalid dev name '%s'", devs[n]); 1433 } 1434 } 1435 1436 for (n = 0; n < nlink; n++) { 1437 if (dladm_name2info(links[n], &port[ndev + n].lp_linkid, 1438 NULL, NULL, NULL) != DLADM_STATUS_OK) { 1439 die("invalid link name '%s'", links[n]); 1440 } 1441 } 1442 1443 status = dladm_aggr_create(name, key, ndev + nlink, port, policy, 1444 mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, 1445 lacp_timer, flags); 1446 if (status != DLADM_STATUS_OK) 1447 goto done; 1448 1449 if (proplist == NULL) 1450 return; 1451 1452 status = dladm_name2info(name, &linkid, NULL, NULL, NULL); 1453 if (status != DLADM_STATUS_OK) 1454 goto done; 1455 1456 for (i = 0; i < proplist->al_count; i++) { 1457 dladm_arg_info_t *aip = &proplist->al_info[i]; 1458 1459 pstatus = dladm_set_linkprop(linkid, aip->ai_name, 1460 aip->ai_val, aip->ai_count, flags); 1461 1462 if (pstatus != DLADM_STATUS_OK) { 1463 die_dlerr(pstatus, 1464 "aggr creation succeeded but " 1465 "could not set property '%s'", aip->ai_name); 1466 } 1467 } 1468 done: 1469 dladm_free_props(proplist); 1470 if (status != DLADM_STATUS_OK) { 1471 if (status == DLADM_STATUS_NONOTIF) { 1472 die_dlerr(status, "not all links have link up/down " 1473 "detection; must use -f (see dladm(1M))\n"); 1474 } else { 1475 die_dlerr(status, "create operation failed"); 1476 } 1477 } 1478 } 1479 1480 /* 1481 * arg is either the key or the aggr name. Validate it and convert it to 1482 * the linkid if altroot is NULL. 1483 */ 1484 static dladm_status_t 1485 i_dladm_aggr_get_linkid(const char *altroot, const char *arg, 1486 datalink_id_t *linkidp, uint32_t flags) 1487 { 1488 int key = 0; 1489 char *aggr = NULL; 1490 dladm_status_t status; 1491 1492 if (!str2int(arg, &key)) 1493 aggr = (char *)arg; 1494 1495 if (aggr == NULL && key == 0) 1496 return (DLADM_STATUS_LINKINVAL); 1497 1498 if (altroot != NULL) 1499 return (DLADM_STATUS_OK); 1500 1501 if (aggr != NULL) { 1502 status = dladm_name2info(aggr, linkidp, NULL, NULL, NULL); 1503 } else { 1504 status = dladm_key2linkid(key, linkidp, flags); 1505 } 1506 1507 return (status); 1508 } 1509 1510 static void 1511 do_delete_aggr(int argc, char *argv[], const char *use) 1512 { 1513 char option; 1514 char *altroot = NULL; 1515 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1516 dladm_status_t status; 1517 datalink_id_t linkid; 1518 1519 opterr = 0; 1520 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 1521 switch (option) { 1522 case 't': 1523 flags &= ~DLADM_OPT_PERSIST; 1524 break; 1525 case 'R': 1526 altroot = optarg; 1527 break; 1528 default: 1529 die_opterr(optopt, option, use); 1530 break; 1531 } 1532 } 1533 1534 /* get key value or the aggregation name (required last argument) */ 1535 if (optind != (argc-1)) 1536 usage(); 1537 1538 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1539 if (status != DLADM_STATUS_OK) 1540 goto done; 1541 1542 if (altroot != NULL) 1543 altroot_cmd(altroot, argc, argv); 1544 1545 status = dladm_aggr_delete(linkid, flags); 1546 done: 1547 if (status != DLADM_STATUS_OK) 1548 die_dlerr(status, "delete operation failed"); 1549 } 1550 1551 static void 1552 do_add_aggr(int argc, char *argv[], const char *use) 1553 { 1554 char option; 1555 uint_t n, ndev, nlink; 1556 char *altroot = NULL; 1557 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1558 datalink_id_t linkid; 1559 dladm_status_t status; 1560 dladm_aggr_port_attr_db_t port[MAXPORT]; 1561 char *devs[MAXPORT]; 1562 char *links[MAXPORT]; 1563 1564 ndev = nlink = opterr = 0; 1565 while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts, 1566 NULL)) != -1) { 1567 switch (option) { 1568 case 'd': 1569 if (ndev + nlink >= MAXPORT) 1570 die("too many ports specified"); 1571 1572 devs[ndev++] = optarg; 1573 break; 1574 case 'l': 1575 if (ndev + nlink >= MAXPORT) 1576 die("too many ports specified"); 1577 1578 links[nlink++] = optarg; 1579 break; 1580 case 't': 1581 flags &= ~DLADM_OPT_PERSIST; 1582 break; 1583 case 'f': 1584 flags |= DLADM_OPT_FORCE; 1585 break; 1586 case 'R': 1587 altroot = optarg; 1588 break; 1589 default: 1590 die_opterr(optopt, option, use); 1591 break; 1592 } 1593 } 1594 1595 if (ndev + nlink == 0) 1596 usage(); 1597 1598 /* get key value or the aggregation name (required last argument) */ 1599 if (optind != (argc-1)) 1600 usage(); 1601 1602 if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, 1603 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) != 1604 DLADM_STATUS_OK) { 1605 goto done; 1606 } 1607 1608 if (altroot != NULL) 1609 altroot_cmd(altroot, argc, argv); 1610 1611 for (n = 0; n < ndev; n++) { 1612 if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) != 1613 DLADM_STATUS_OK) { 1614 die("invalid <dev> '%s'", devs[n]); 1615 } 1616 } 1617 1618 for (n = 0; n < nlink; n++) { 1619 if (dladm_name2info(links[n], &port[n + ndev].lp_linkid, 1620 NULL, NULL, NULL) != DLADM_STATUS_OK) { 1621 die("invalid <link> '%s'", links[n]); 1622 } 1623 } 1624 1625 status = dladm_aggr_add(linkid, ndev + nlink, port, flags); 1626 done: 1627 if (status != DLADM_STATUS_OK) { 1628 /* 1629 * checking DLADM_STATUS_NOTSUP is a temporary workaround 1630 * and should be removed once 6399681 is fixed. 1631 */ 1632 if (status == DLADM_STATUS_NOTSUP) { 1633 (void) fprintf(stderr, 1634 gettext("%s: add operation failed: %s\n"), 1635 progname, 1636 gettext("link capabilities don't match")); 1637 exit(ENOTSUP); 1638 } else if (status == DLADM_STATUS_NONOTIF) { 1639 die_dlerr(status, "not all links have link up/down " 1640 "detection; must use -f (see dladm(1M))\n"); 1641 } else { 1642 die_dlerr(status, "add operation failed"); 1643 } 1644 } 1645 } 1646 1647 static void 1648 do_remove_aggr(int argc, char *argv[], const char *use) 1649 { 1650 char option; 1651 dladm_aggr_port_attr_db_t port[MAXPORT]; 1652 uint_t n, ndev, nlink; 1653 char *devs[MAXPORT]; 1654 char *links[MAXPORT]; 1655 char *altroot = NULL; 1656 uint32_t flags; 1657 datalink_id_t linkid; 1658 dladm_status_t status; 1659 1660 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1661 ndev = nlink = opterr = 0; 1662 while ((option = getopt_long(argc, argv, ":d:l:R:t", 1663 lopts, NULL)) != -1) { 1664 switch (option) { 1665 case 'd': 1666 if (ndev + nlink >= MAXPORT) 1667 die("too many ports specified"); 1668 1669 devs[ndev++] = optarg; 1670 break; 1671 case 'l': 1672 if (ndev + nlink >= MAXPORT) 1673 die("too many ports specified"); 1674 1675 links[nlink++] = optarg; 1676 break; 1677 case 't': 1678 flags &= ~DLADM_OPT_PERSIST; 1679 break; 1680 case 'R': 1681 altroot = optarg; 1682 break; 1683 default: 1684 die_opterr(optopt, option, use); 1685 break; 1686 } 1687 } 1688 1689 if (ndev + nlink == 0) 1690 usage(); 1691 1692 /* get key value or the aggregation name (required last argument) */ 1693 if (optind != (argc-1)) 1694 usage(); 1695 1696 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1697 if (status != DLADM_STATUS_OK) 1698 goto done; 1699 1700 if (altroot != NULL) 1701 altroot_cmd(altroot, argc, argv); 1702 1703 for (n = 0; n < ndev; n++) { 1704 if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) != 1705 DLADM_STATUS_OK) { 1706 die("invalid <dev> '%s'", devs[n]); 1707 } 1708 } 1709 1710 for (n = 0; n < nlink; n++) { 1711 if (dladm_name2info(links[n], &port[n + ndev].lp_linkid, 1712 NULL, NULL, NULL) != DLADM_STATUS_OK) { 1713 die("invalid <link> '%s'", links[n]); 1714 } 1715 } 1716 1717 status = dladm_aggr_remove(linkid, ndev + nlink, port, flags); 1718 done: 1719 if (status != DLADM_STATUS_OK) 1720 die_dlerr(status, "remove operation failed"); 1721 } 1722 1723 static void 1724 do_modify_aggr(int argc, char *argv[], const char *use) 1725 { 1726 char option; 1727 uint32_t policy = AGGR_POLICY_L4; 1728 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 1729 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 1730 uint8_t mac_addr[ETHERADDRL]; 1731 boolean_t mac_addr_fixed = B_FALSE; 1732 uint8_t modify_mask = 0; 1733 char *altroot = NULL; 1734 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1735 datalink_id_t linkid; 1736 dladm_status_t status; 1737 1738 opterr = 0; 1739 while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts, 1740 NULL)) != -1) { 1741 switch (option) { 1742 case 'P': 1743 if (modify_mask & DLADM_AGGR_MODIFY_POLICY) 1744 die_optdup(option); 1745 1746 modify_mask |= DLADM_AGGR_MODIFY_POLICY; 1747 1748 if (!dladm_aggr_str2policy(optarg, &policy)) 1749 die("invalid policy '%s'", optarg); 1750 break; 1751 case 'u': 1752 if (modify_mask & DLADM_AGGR_MODIFY_MAC) 1753 die_optdup(option); 1754 1755 modify_mask |= DLADM_AGGR_MODIFY_MAC; 1756 1757 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 1758 mac_addr)) 1759 die("invalid MAC address '%s'", optarg); 1760 break; 1761 case 'l': 1762 case 'L': 1763 if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE) 1764 die_optdup(option); 1765 1766 modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE; 1767 1768 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 1769 die("invalid LACP mode '%s'", optarg); 1770 break; 1771 case 'T': 1772 if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER) 1773 die_optdup(option); 1774 1775 modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER; 1776 1777 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 1778 die("invalid LACP timer value '%s'", optarg); 1779 break; 1780 case 't': 1781 flags &= ~DLADM_OPT_PERSIST; 1782 break; 1783 case 'R': 1784 altroot = optarg; 1785 break; 1786 default: 1787 die_opterr(optopt, option, use); 1788 break; 1789 } 1790 } 1791 1792 if (modify_mask == 0) 1793 die("at least one of the -PulT options must be specified"); 1794 1795 /* get key value or the aggregation name (required last argument) */ 1796 if (optind != (argc-1)) 1797 usage(); 1798 1799 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1800 if (status != DLADM_STATUS_OK) 1801 goto done; 1802 1803 if (altroot != NULL) 1804 altroot_cmd(altroot, argc, argv); 1805 1806 status = dladm_aggr_modify(linkid, modify_mask, policy, mac_addr_fixed, 1807 (const uchar_t *)mac_addr, lacp_mode, lacp_timer, flags); 1808 1809 done: 1810 if (status != DLADM_STATUS_OK) 1811 die_dlerr(status, "modify operation failed"); 1812 } 1813 1814 /*ARGSUSED*/ 1815 static void 1816 do_up_aggr(int argc, char *argv[], const char *use) 1817 { 1818 datalink_id_t linkid = DATALINK_ALL_LINKID; 1819 dladm_status_t status; 1820 1821 /* 1822 * get the key or the name of the aggregation (optional last argument) 1823 */ 1824 if (argc == 2) { 1825 if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid, 1826 DLADM_OPT_PERSIST)) != DLADM_STATUS_OK) { 1827 goto done; 1828 } 1829 } else if (argc > 2) { 1830 usage(); 1831 } 1832 1833 status = dladm_aggr_up(linkid); 1834 done: 1835 if (status != DLADM_STATUS_OK) { 1836 if (argc == 2) { 1837 die_dlerr(status, 1838 "could not bring up aggregation '%s'", argv[1]); 1839 } else { 1840 die_dlerr(status, "could not bring aggregations up"); 1841 } 1842 } 1843 } 1844 1845 static void 1846 do_create_vlan(int argc, char *argv[], const char *use) 1847 { 1848 char *link = NULL; 1849 char drv[DLPI_LINKNAME_MAX]; 1850 uint_t ppa; 1851 datalink_id_t linkid; 1852 datalink_id_t dev_linkid; 1853 int vid = 0; 1854 char option; 1855 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 1856 char *altroot = NULL; 1857 char vlan[MAXLINKNAMELEN]; 1858 dladm_arg_list_t *proplist = NULL; 1859 dladm_status_t status; 1860 1861 opterr = 0; 1862 while ((option = getopt_long(argc, argv, ":tfR:l:v:p:", 1863 lopts, NULL)) != -1) { 1864 switch (option) { 1865 case 'v': 1866 if (vid != 0) 1867 die_optdup(option); 1868 1869 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 1870 die("invalid VLAN identifier '%s'", optarg); 1871 1872 break; 1873 case 'l': 1874 if (link != NULL) 1875 die_optdup(option); 1876 1877 link = optarg; 1878 break; 1879 case 't': 1880 flags &= ~DLADM_OPT_PERSIST; 1881 break; 1882 case 'R': 1883 altroot = optarg; 1884 break; 1885 case 'p': 1886 if (dladm_parse_link_props(optarg, &proplist, B_FALSE) 1887 != DLADM_STATUS_OK) { 1888 die("invalid vlan property"); 1889 } 1890 break; 1891 case 'f': 1892 flags |= DLADM_OPT_FORCE; 1893 break; 1894 default: 1895 die_opterr(optopt, option, use); 1896 break; 1897 } 1898 } 1899 1900 /* get vlan name if there is any */ 1901 if ((vid == 0) || (link == NULL) || (argc - optind > 1)) 1902 usage(); 1903 1904 if (optind == (argc - 1)) { 1905 if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >= 1906 MAXLINKNAMELEN) { 1907 die("vlan name too long '%s'", argv[optind]); 1908 } 1909 } else { 1910 if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) || 1911 (ppa >= 1000) || 1912 (dlpi_makelink(vlan, drv, vid * 1000 + ppa) != 1913 DLPI_SUCCESS)) { 1914 die("invalid link name '%s'", link); 1915 } 1916 } 1917 1918 if (altroot != NULL) 1919 altroot_cmd(altroot, argc, argv); 1920 1921 if (dladm_name2info(link, &dev_linkid, NULL, NULL, NULL) != 1922 DLADM_STATUS_OK) { 1923 die("invalid link name '%s'", link); 1924 } 1925 1926 if ((status = dladm_vlan_create(vlan, dev_linkid, vid, proplist, flags, 1927 &linkid)) != DLADM_STATUS_OK) { 1928 die_dlerr(status, "create operation over %s failed", link); 1929 } 1930 } 1931 1932 static void 1933 do_delete_vlan(int argc, char *argv[], const char *use) 1934 { 1935 char option; 1936 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 1937 char *altroot = NULL; 1938 datalink_id_t linkid; 1939 dladm_status_t status; 1940 1941 opterr = 0; 1942 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 1943 switch (option) { 1944 case 't': 1945 flags &= ~DLADM_OPT_PERSIST; 1946 break; 1947 case 'R': 1948 altroot = optarg; 1949 break; 1950 default: 1951 die_opterr(optopt, option, use); 1952 break; 1953 } 1954 } 1955 1956 /* get VLAN link name (required last argument) */ 1957 if (optind != (argc - 1)) 1958 usage(); 1959 1960 if (altroot != NULL) 1961 altroot_cmd(altroot, argc, argv); 1962 1963 status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL); 1964 if (status != DLADM_STATUS_OK) 1965 goto done; 1966 1967 status = dladm_vlan_delete(linkid, flags); 1968 done: 1969 if (status != DLADM_STATUS_OK) 1970 die_dlerr(status, "delete operation failed"); 1971 } 1972 1973 /*ARGSUSED*/ 1974 static void 1975 do_up_vlan(int argc, char *argv[], const char *use) 1976 { 1977 do_up_vnic_common(argc, argv, use, B_TRUE); 1978 } 1979 1980 static void 1981 do_rename_link(int argc, char *argv[], const char *use) 1982 { 1983 char option; 1984 char *link1, *link2; 1985 char *altroot = NULL; 1986 dladm_status_t status; 1987 1988 opterr = 0; 1989 while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) { 1990 switch (option) { 1991 case 'R': 1992 altroot = optarg; 1993 break; 1994 default: 1995 die_opterr(optopt, option, use); 1996 break; 1997 } 1998 } 1999 2000 /* get link1 and link2 name (required the last 2 arguments) */ 2001 if (optind != (argc - 2)) 2002 usage(); 2003 2004 if (altroot != NULL) 2005 altroot_cmd(altroot, argc, argv); 2006 2007 link1 = argv[optind++]; 2008 link2 = argv[optind]; 2009 if ((status = dladm_rename_link(link1, link2)) != DLADM_STATUS_OK) 2010 die_dlerr(status, "rename operation failed"); 2011 } 2012 2013 /*ARGSUSED*/ 2014 static void 2015 do_delete_phys(int argc, char *argv[], const char *use) 2016 { 2017 datalink_id_t linkid = DATALINK_ALL_LINKID; 2018 dladm_status_t status; 2019 2020 /* get link name (required the last argument) */ 2021 if (argc > 2) 2022 usage(); 2023 2024 if (argc == 2) { 2025 status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL); 2026 if (status != DLADM_STATUS_OK) 2027 die_dlerr(status, "cannot delete '%s'", argv[1]); 2028 } 2029 2030 if ((status = dladm_phys_delete(linkid)) != DLADM_STATUS_OK) { 2031 if (argc == 2) 2032 die_dlerr(status, "cannot delete '%s'", argv[1]); 2033 else 2034 die_dlerr(status, "delete operation failed"); 2035 } 2036 } 2037 2038 /*ARGSUSED*/ 2039 static int 2040 i_dladm_walk_linkmap(datalink_id_t linkid, void *arg) 2041 { 2042 char name[MAXLINKNAMELEN]; 2043 char mediabuf[DLADM_STRSIZE]; 2044 char classbuf[DLADM_STRSIZE]; 2045 datalink_class_t class; 2046 uint32_t media; 2047 uint32_t flags; 2048 2049 if (dladm_datalink_id2info(linkid, &flags, &class, &media, name, 2050 MAXLINKNAMELEN) == DLADM_STATUS_OK) { 2051 (void) dladm_class2str(class, classbuf); 2052 (void) dladm_media2str(media, mediabuf); 2053 (void) printf("%-12s%8d %-12s%-20s %6d\n", name, 2054 linkid, classbuf, mediabuf, flags); 2055 } 2056 return (DLADM_WALK_CONTINUE); 2057 } 2058 2059 /*ARGSUSED*/ 2060 static void 2061 do_show_linkmap(int argc, char *argv[], const char *use) 2062 { 2063 if (argc != 1) 2064 die("invalid arguments"); 2065 2066 (void) printf("%-12s%8s %-12s%-20s %6s\n", "NAME", "LINKID", 2067 "CLASS", "MEDIA", "FLAGS"); 2068 (void) dladm_walk_datalink_id(i_dladm_walk_linkmap, NULL, 2069 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 2070 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2071 } 2072 2073 /* 2074 * Delete inactive physical links. 2075 */ 2076 /*ARGSUSED*/ 2077 static int 2078 purge_phys(datalink_id_t linkid, void *arg) 2079 { 2080 datalink_class_t class; 2081 uint32_t flags; 2082 2083 if (dladm_datalink_id2info(linkid, &flags, &class, NULL, 2084 NULL, 0) != DLADM_STATUS_OK) { 2085 return (DLADM_WALK_CONTINUE); 2086 } 2087 2088 if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE)) 2089 (void) dladm_phys_delete(linkid); 2090 2091 return (DLADM_WALK_CONTINUE); 2092 } 2093 2094 /*ARGSUSED*/ 2095 static void 2096 do_init_phys(int argc, char *argv[], const char *use) 2097 { 2098 di_node_t devtree; 2099 2100 if (argc > 1) 2101 usage(); 2102 2103 /* 2104 * Force all the devices to attach, therefore all the network physical 2105 * devices can be known to the dlmgmtd daemon. 2106 */ 2107 if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL) 2108 di_fini(devtree); 2109 2110 (void) dladm_walk_datalink_id(purge_phys, NULL, 2111 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 2112 } 2113 2114 2115 /* 2116 * Print the active topology information. 2117 */ 2118 static dladm_status_t 2119 print_link_topology(show_state_t *state, datalink_id_t linkid, 2120 datalink_class_t class, link_fields_buf_t *lbuf) 2121 { 2122 uint32_t flags = state->ls_flags; 2123 dladm_status_t status = DLADM_STATUS_OK; 2124 char tmpbuf[MAXLINKNAMELEN]; 2125 2126 if (!state->ls_parseable) 2127 (void) sprintf(lbuf->link_over, STR_UNDEF_VAL); 2128 else 2129 (void) sprintf(lbuf->link_over, ""); 2130 2131 if (class == DATALINK_CLASS_VLAN) { 2132 dladm_vlan_attr_t vinfo; 2133 2134 status = dladm_vlan_info(linkid, &vinfo, flags); 2135 if (status != DLADM_STATUS_OK) 2136 goto done; 2137 status = dladm_datalink_id2info(vinfo.dv_linkid, NULL, NULL, 2138 NULL, lbuf->link_over, sizeof (lbuf->link_over)); 2139 if (status != DLADM_STATUS_OK) 2140 goto done; 2141 } else if (class == DATALINK_CLASS_AGGR) { 2142 dladm_aggr_grp_attr_t ginfo; 2143 int i; 2144 2145 (void) sprintf(lbuf->link_over, ""); 2146 2147 status = dladm_aggr_info(linkid, &ginfo, flags); 2148 if (status != DLADM_STATUS_OK) 2149 goto done; 2150 2151 if (ginfo.lg_nports == 0) { 2152 status = DLADM_STATUS_BADVAL; 2153 goto done; 2154 } 2155 for (i = 0; i < ginfo.lg_nports; i++) { 2156 status = dladm_datalink_id2info( 2157 ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, 2158 tmpbuf, sizeof (tmpbuf)); 2159 if (status != DLADM_STATUS_OK) { 2160 free(ginfo.lg_ports); 2161 goto done; 2162 } 2163 (void) strlcat(lbuf->link_over, tmpbuf, 2164 sizeof (lbuf->link_over)); 2165 if (i != (ginfo.lg_nports - 1)) { 2166 (void) strlcat(lbuf->link_over, " ", 2167 sizeof (lbuf->link_over)); 2168 } 2169 } 2170 free(ginfo.lg_ports); 2171 } else if (class == DATALINK_CLASS_VNIC) { 2172 dladm_vnic_attr_t vinfo; 2173 2174 if ((status = dladm_vnic_info(linkid, &vinfo, flags)) != 2175 DLADM_STATUS_OK || (status = dladm_datalink_id2info( 2176 vinfo.va_link_id, NULL, NULL, NULL, lbuf->link_over, 2177 sizeof (lbuf->link_over)) != DLADM_STATUS_OK)) { 2178 goto done; 2179 } 2180 } 2181 done: 2182 return (status); 2183 } 2184 2185 static dladm_status_t 2186 print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf) 2187 { 2188 char link[MAXLINKNAMELEN]; 2189 datalink_class_t class; 2190 uint_t mtu; 2191 uint32_t flags; 2192 dladm_status_t status; 2193 2194 if ((status = dladm_datalink_id2info(linkid, &flags, &class, NULL, 2195 link, sizeof (link))) != DLADM_STATUS_OK) { 2196 goto done; 2197 } 2198 2199 if (!(state->ls_flags & flags)) { 2200 status = DLADM_STATUS_NOTFOUND; 2201 goto done; 2202 } 2203 2204 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2205 dladm_attr_t dlattr; 2206 2207 if (class == DATALINK_CLASS_PHYS) { 2208 dladm_phys_attr_t dpa; 2209 dlpi_handle_t dh; 2210 dlpi_info_t dlinfo; 2211 2212 if ((status = dladm_phys_info(linkid, &dpa, 2213 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2214 goto done; 2215 } 2216 2217 if (!dpa.dp_novanity) 2218 goto link_mtu; 2219 2220 /* 2221 * This is a physical link that does not have 2222 * vanity naming support. 2223 */ 2224 if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) != 2225 DLPI_SUCCESS) { 2226 status = DLADM_STATUS_NOTFOUND; 2227 goto done; 2228 } 2229 2230 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 2231 dlpi_close(dh); 2232 status = DLADM_STATUS_BADARG; 2233 goto done; 2234 } 2235 2236 dlpi_close(dh); 2237 mtu = dlinfo.di_max_sdu; 2238 } else { 2239 link_mtu: 2240 status = dladm_info(linkid, &dlattr); 2241 if (status != DLADM_STATUS_OK) 2242 goto done; 2243 mtu = dlattr.da_max_sdu; 2244 } 2245 } 2246 2247 (void) snprintf(lbuf->link_name, sizeof (lbuf->link_name), 2248 "%s", link); 2249 (void) dladm_class2str(class, lbuf->link_class); 2250 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2251 (void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu), 2252 "%u", mtu); 2253 (void) get_linkstate(link, B_TRUE, lbuf->link_state); 2254 } 2255 2256 status = print_link_topology(state, linkid, class, lbuf); 2257 if (status != DLADM_STATUS_OK) 2258 goto done; 2259 2260 done: 2261 return (status); 2262 } 2263 2264 static int 2265 show_link(datalink_id_t linkid, void *arg) 2266 { 2267 show_state_t *state = (show_state_t *)arg; 2268 dladm_status_t status; 2269 link_fields_buf_t lbuf; 2270 2271 /* 2272 * first get all the link attributes into lbuf; 2273 */ 2274 bzero(&lbuf, sizeof (link_fields_buf_t)); 2275 status = print_link(state, linkid, &lbuf); 2276 2277 if (status != DLADM_STATUS_OK) 2278 goto done; 2279 2280 if (!state->ls_parseable && !state->ls_printheader) { 2281 print_header(&state->ls_print); 2282 state->ls_printheader = B_TRUE; 2283 } 2284 2285 dladm_print_output(&state->ls_print, state->ls_parseable, 2286 dladm_print_field, (void *)&lbuf); 2287 2288 done: 2289 state->ls_status = status; 2290 return (DLADM_WALK_CONTINUE); 2291 } 2292 2293 static int 2294 show_link_stats(datalink_id_t linkid, void *arg) 2295 { 2296 char link[DLPI_LINKNAME_MAX]; 2297 datalink_class_t class; 2298 show_state_t *state = (show_state_t *)arg; 2299 pktsum_t stats, diff_stats; 2300 dladm_phys_attr_t dpa; 2301 2302 if (state->ls_firstonly) { 2303 if (state->ls_donefirst) 2304 return (DLADM_WALK_CONTINUE); 2305 state->ls_donefirst = B_TRUE; 2306 } else { 2307 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 2308 } 2309 2310 if (dladm_datalink_id2info(linkid, NULL, &class, NULL, link, 2311 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2312 return (DLADM_WALK_CONTINUE); 2313 } 2314 2315 if (class == DATALINK_CLASS_PHYS) { 2316 if (dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE) != 2317 DLADM_STATUS_OK) { 2318 return (DLADM_WALK_CONTINUE); 2319 } 2320 if (dpa.dp_novanity) 2321 get_mac_stats(dpa.dp_dev, &stats); 2322 else 2323 get_link_stats(link, &stats); 2324 } else { 2325 get_link_stats(link, &stats); 2326 } 2327 dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats); 2328 2329 (void) printf("%-12s", link); 2330 (void) printf("%-10llu", diff_stats.ipackets); 2331 (void) printf("%-12llu", diff_stats.rbytes); 2332 (void) printf("%-8llu", diff_stats.ierrors); 2333 (void) printf("%-10llu", diff_stats.opackets); 2334 (void) printf("%-12llu", diff_stats.obytes); 2335 (void) printf("%-8llu\n", diff_stats.oerrors); 2336 2337 state->ls_prevstats = stats; 2338 return (DLADM_WALK_CONTINUE); 2339 } 2340 2341 2342 static dladm_status_t 2343 print_aggr_info(show_grp_state_t *state, const char *link, 2344 dladm_aggr_grp_attr_t *ginfop) 2345 { 2346 char addr_str[ETHERADDRL * 3]; 2347 laggr_fields_buf_t lbuf; 2348 2349 (void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name), 2350 "%s", link); 2351 2352 (void) dladm_aggr_policy2str(ginfop->lg_policy, 2353 lbuf.laggr_policy); 2354 2355 if (ginfop->lg_mac_fixed) { 2356 (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); 2357 (void) snprintf(lbuf.laggr_addrpolicy, 2358 sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str); 2359 } else { 2360 (void) snprintf(lbuf.laggr_addrpolicy, 2361 sizeof (lbuf.laggr_addrpolicy), "auto"); 2362 } 2363 2364 2365 (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, 2366 lbuf.laggr_lacpactivity); 2367 (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, 2368 lbuf.laggr_lacptimer); 2369 (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----", 2370 ginfop->lg_force ? 'f' : '-'); 2371 2372 if (!state->gs_parseable && !state->gs_printheader) { 2373 print_header(&state->gs_print); 2374 state->gs_printheader = B_TRUE; 2375 } 2376 2377 dladm_print_output(&state->gs_print, state->gs_parseable, 2378 dladm_print_field, (void *)&lbuf); 2379 2380 return (DLADM_STATUS_OK); 2381 } 2382 2383 static char * 2384 print_xaggr_callback(print_field_t *pf, void *arg) 2385 { 2386 const laggr_args_t *l = arg; 2387 int portnum; 2388 static char buf[DLADM_STRSIZE]; 2389 boolean_t is_port = (l->laggr_lport >= 0); 2390 dladm_aggr_port_attr_t *portp; 2391 dladm_phys_attr_t dpa; 2392 dladm_status_t *stat, status; 2393 2394 stat = l->laggr_status; 2395 *stat = DLADM_STATUS_OK; 2396 2397 if (is_port) { 2398 portnum = l->laggr_lport; 2399 portp = &(l->laggr_ginfop->lg_ports[portnum]); 2400 if ((status = dladm_datalink_id2info(portp->lp_linkid, 2401 NULL, NULL, NULL, buf, sizeof (buf))) != 2402 DLADM_STATUS_OK) { 2403 goto err; 2404 } 2405 if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 2406 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2407 goto err; 2408 } 2409 } 2410 2411 switch (pf->pf_index) { 2412 case AGGR_X_LINK: 2413 (void) snprintf(buf, sizeof (buf), "%s", 2414 (is_port && !l->laggr_parseable ? " " : l->laggr_link)); 2415 break; 2416 case AGGR_X_PORT: 2417 if (is_port) 2418 break; 2419 return (""); 2420 break; 2421 2422 case AGGR_X_SPEED: 2423 if (is_port) { 2424 (void) snprintf(buf, sizeof (buf), "%uMb", 2425 (uint_t)((get_ifspeed(dpa.dp_dev, 2426 B_FALSE)) / 1000000ull)); 2427 } else { 2428 (void) snprintf(buf, sizeof (buf), "%uMb", 2429 (uint_t)((get_ifspeed(l->laggr_link, 2430 B_TRUE)) / 1000000ull)); 2431 } 2432 break; 2433 2434 case AGGR_X_DUPLEX: 2435 if (is_port) 2436 (void) get_linkduplex(dpa.dp_dev, B_FALSE, buf); 2437 else 2438 (void) get_linkduplex(l->laggr_link, B_TRUE, buf); 2439 break; 2440 2441 case AGGR_X_STATE: 2442 if (is_port) 2443 (void) get_linkstate(dpa.dp_dev, B_FALSE, buf); 2444 else 2445 (void) get_linkstate(l->laggr_link, B_TRUE, buf); 2446 break; 2447 case AGGR_X_ADDRESS: 2448 (void) dladm_aggr_macaddr2str( 2449 (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac), 2450 buf); 2451 break; 2452 case AGGR_X_PORTSTATE: 2453 if (is_port) 2454 (void) dladm_aggr_portstate2str( 2455 portp->lp_state, buf); 2456 else 2457 return (""); 2458 break; 2459 } 2460 return (buf); 2461 2462 err: 2463 *stat = status; 2464 buf[0] = '\0'; 2465 return (buf); 2466 } 2467 2468 static dladm_status_t 2469 print_aggr_extended(show_grp_state_t *state, const char *link, 2470 dladm_aggr_grp_attr_t *ginfop) 2471 { 2472 int i; 2473 dladm_status_t status; 2474 laggr_args_t largs; 2475 2476 if (!state->gs_parseable && !state->gs_printheader) { 2477 print_header(&state->gs_print); 2478 state->gs_printheader = B_TRUE; 2479 } 2480 2481 largs.laggr_lport = -1; 2482 largs.laggr_link = link; 2483 largs.laggr_ginfop = ginfop; 2484 largs.laggr_status = &status; 2485 largs.laggr_parseable = state->gs_parseable; 2486 2487 dladm_print_output(&state->gs_print, state->gs_parseable, 2488 print_xaggr_callback, &largs); 2489 2490 if (status != DLADM_STATUS_OK) 2491 goto done; 2492 2493 for (i = 0; i < ginfop->lg_nports; i++) { 2494 largs.laggr_lport = i; 2495 dladm_print_output(&state->gs_print, state->gs_parseable, 2496 print_xaggr_callback, &largs); 2497 if (status != DLADM_STATUS_OK) 2498 goto done; 2499 } 2500 2501 status = DLADM_STATUS_OK; 2502 done: 2503 return (status); 2504 } 2505 2506 2507 static char * 2508 print_lacp_callback(print_field_t *pf, void *arg) 2509 { 2510 const laggr_args_t *l = arg; 2511 int portnum; 2512 static char buf[DLADM_STRSIZE]; 2513 boolean_t is_port = (l->laggr_lport >= 0); 2514 dladm_aggr_port_attr_t *portp; 2515 dladm_status_t *stat, status; 2516 aggr_lacp_state_t *lstate; 2517 2518 if (!is_port) { 2519 return (NULL); /* cannot happen! */ 2520 } 2521 2522 stat = l->laggr_status; 2523 2524 portnum = l->laggr_lport; 2525 portp = &(l->laggr_ginfop->lg_ports[portnum]); 2526 if ((status = dladm_datalink_id2info(portp->lp_linkid, 2527 NULL, NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) { 2528 goto err; 2529 } 2530 lstate = &(portp->lp_lacp_state); 2531 2532 switch (pf->pf_index) { 2533 case AGGR_L_LINK: 2534 (void) snprintf(buf, sizeof (buf), "%s", 2535 (portnum > 0 ? "" : l->laggr_link)); 2536 break; 2537 2538 case AGGR_L_PORT: 2539 break; 2540 2541 case AGGR_L_AGGREGATABLE: 2542 (void) snprintf(buf, sizeof (buf), "%s", 2543 (lstate->bit.aggregation ? "yes" : "no")); 2544 break; 2545 2546 case AGGR_L_SYNC: 2547 (void) snprintf(buf, sizeof (buf), "%s", 2548 (lstate->bit.sync ? "yes" : "no")); 2549 break; 2550 2551 case AGGR_L_COLL: 2552 (void) snprintf(buf, sizeof (buf), "%s", 2553 (lstate->bit.collecting ? "yes" : "no")); 2554 break; 2555 2556 case AGGR_L_DIST: 2557 (void) snprintf(buf, sizeof (buf), "%s", 2558 (lstate->bit.distributing ? "yes" : "no")); 2559 break; 2560 2561 case AGGR_L_DEFAULTED: 2562 (void) snprintf(buf, sizeof (buf), "%s", 2563 (lstate->bit.defaulted ? "yes" : "no")); 2564 break; 2565 2566 case AGGR_L_EXPIRED: 2567 (void) snprintf(buf, sizeof (buf), "%s", 2568 (lstate->bit.expired ? "yes" : "no")); 2569 break; 2570 } 2571 2572 *stat = DLADM_STATUS_OK; 2573 return (buf); 2574 2575 err: 2576 *stat = status; 2577 buf[0] = '\0'; 2578 return (buf); 2579 } 2580 2581 static dladm_status_t 2582 print_aggr_lacp(show_grp_state_t *state, const char *link, 2583 dladm_aggr_grp_attr_t *ginfop) 2584 { 2585 int i; 2586 dladm_status_t status; 2587 laggr_args_t largs; 2588 2589 if (!state->gs_parseable && !state->gs_printheader) { 2590 print_header(&state->gs_print); 2591 state->gs_printheader = B_TRUE; 2592 } 2593 2594 largs.laggr_link = link; 2595 largs.laggr_ginfop = ginfop; 2596 largs.laggr_status = &status; 2597 2598 for (i = 0; i < ginfop->lg_nports; i++) { 2599 largs.laggr_lport = i; 2600 dladm_print_output(&state->gs_print, state->gs_parseable, 2601 print_lacp_callback, &largs); 2602 if (status != DLADM_STATUS_OK) 2603 goto done; 2604 } 2605 2606 status = DLADM_STATUS_OK; 2607 done: 2608 return (status); 2609 } 2610 2611 static char * 2612 print_aggr_stats_callback(print_field_t *pf, void *arg) 2613 { 2614 const laggr_args_t *l = arg; 2615 int portnum; 2616 static char buf[DLADM_STRSIZE]; 2617 boolean_t is_port = (l->laggr_lport >= 0); 2618 dladm_aggr_port_attr_t *portp; 2619 dladm_phys_attr_t dpa; 2620 dladm_status_t *stat, status; 2621 pktsum_t port_stat, diff_stats; 2622 2623 stat = l->laggr_status; 2624 *stat = DLADM_STATUS_OK; 2625 2626 if (is_port) { 2627 portnum = l->laggr_lport; 2628 portp = &(l->laggr_ginfop->lg_ports[portnum]); 2629 if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 2630 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2631 goto err; 2632 } 2633 2634 get_mac_stats(dpa.dp_dev, &port_stat); 2635 2636 if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL, 2637 NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) { 2638 goto err; 2639 } 2640 2641 dladm_stats_diff(&diff_stats, &port_stat, l->laggr_prevstats); 2642 } 2643 2644 switch (pf->pf_index) { 2645 case AGGR_S_LINK: 2646 (void) snprintf(buf, sizeof (buf), "%s", 2647 (is_port ? "" : l->laggr_link)); 2648 break; 2649 case AGGR_S_PORT: 2650 if (is_port) 2651 break; 2652 return (""); 2653 break; 2654 2655 case AGGR_S_IPKTS: 2656 if (is_port) { 2657 (void) snprintf(buf, sizeof (buf), "%llu", 2658 diff_stats.ipackets); 2659 } else { 2660 (void) snprintf(buf, sizeof (buf), "%llu", 2661 l->laggr_pktsumtot->ipackets); 2662 } 2663 break; 2664 2665 case AGGR_S_RBYTES: 2666 if (is_port) { 2667 (void) snprintf(buf, sizeof (buf), "%llu", 2668 diff_stats.rbytes); 2669 } else { 2670 (void) snprintf(buf, sizeof (buf), "%llu", 2671 l->laggr_pktsumtot->rbytes); 2672 } 2673 break; 2674 2675 case AGGR_S_OPKTS: 2676 if (is_port) { 2677 (void) snprintf(buf, sizeof (buf), "%llu", 2678 diff_stats.opackets); 2679 } else { 2680 (void) snprintf(buf, sizeof (buf), "%llu", 2681 l->laggr_pktsumtot->opackets); 2682 } 2683 break; 2684 case AGGR_S_OBYTES: 2685 if (is_port) { 2686 (void) snprintf(buf, sizeof (buf), "%llu", 2687 diff_stats.obytes); 2688 } else { 2689 (void) snprintf(buf, sizeof (buf), "%llu", 2690 l->laggr_pktsumtot->obytes); 2691 2692 } 2693 break; 2694 2695 case AGGR_S_IPKTDIST: 2696 if (is_port) { 2697 (void) snprintf(buf, sizeof (buf), "%-6.1f", 2698 (double)diff_stats.opackets/ 2699 (double)l->laggr_pktsumtot->ipackets * 100); 2700 } else { 2701 return (""); 2702 } 2703 break; 2704 case AGGR_S_OPKTDIST: 2705 if (is_port) { 2706 (void) snprintf(buf, sizeof (buf), "%-6.1f", 2707 (double)diff_stats.opackets/ 2708 (double)l->laggr_pktsumtot->opackets * 100); 2709 } else { 2710 return (""); 2711 } 2712 break; 2713 } 2714 return (buf); 2715 2716 err: 2717 *stat = status; 2718 buf[0] = '\0'; 2719 return (buf); 2720 } 2721 2722 static dladm_status_t 2723 print_aggr_stats(show_grp_state_t *state, const char *link, 2724 dladm_aggr_grp_attr_t *ginfop) 2725 { 2726 dladm_phys_attr_t dpa; 2727 dladm_aggr_port_attr_t *portp; 2728 pktsum_t pktsumtot, port_stat; 2729 dladm_status_t status; 2730 int i; 2731 laggr_args_t largs; 2732 2733 /* sum the ports statistics */ 2734 bzero(&pktsumtot, sizeof (pktsumtot)); 2735 2736 for (i = 0; i < ginfop->lg_nports; i++) { 2737 2738 portp = &(ginfop->lg_ports[i]); 2739 if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 2740 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2741 goto done; 2742 } 2743 2744 get_mac_stats(dpa.dp_dev, &port_stat); 2745 dladm_stats_total(&pktsumtot, &port_stat, 2746 &state->gs_prevstats[i]); 2747 } 2748 2749 if (!state->gs_parseable && !state->gs_printheader) { 2750 print_header(&state->gs_print); 2751 state->gs_printheader = B_TRUE; 2752 } 2753 2754 largs.laggr_lport = -1; 2755 largs.laggr_link = link; 2756 largs.laggr_ginfop = ginfop; 2757 largs.laggr_status = &status; 2758 largs.laggr_pktsumtot = &pktsumtot; 2759 2760 dladm_print_output(&state->gs_print, state->gs_parseable, 2761 print_aggr_stats_callback, &largs); 2762 2763 if (status != DLADM_STATUS_OK) 2764 goto done; 2765 2766 for (i = 0; i < ginfop->lg_nports; i++) { 2767 largs.laggr_lport = i; 2768 largs.laggr_prevstats = &state->gs_prevstats[i]; 2769 dladm_print_output(&state->gs_print, state->gs_parseable, 2770 print_aggr_stats_callback, &largs); 2771 if (status != DLADM_STATUS_OK) 2772 goto done; 2773 } 2774 2775 status = DLADM_STATUS_OK; 2776 done: 2777 return (status); 2778 } 2779 2780 static dladm_status_t 2781 print_aggr(show_grp_state_t *state, datalink_id_t linkid) 2782 { 2783 char link[MAXLINKNAMELEN]; 2784 dladm_aggr_grp_attr_t ginfo; 2785 uint32_t flags; 2786 dladm_status_t status; 2787 2788 bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t)); 2789 if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link, 2790 MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 2791 return (status); 2792 } 2793 2794 if (!(state->gs_flags & flags)) 2795 return (DLADM_STATUS_NOTFOUND); 2796 2797 status = dladm_aggr_info(linkid, &ginfo, state->gs_flags); 2798 if (status != DLADM_STATUS_OK) 2799 return (status); 2800 2801 if (state->gs_lacp) 2802 status = print_aggr_lacp(state, link, &ginfo); 2803 else if (state->gs_extended) 2804 status = print_aggr_extended(state, link, &ginfo); 2805 else if (state->gs_stats) 2806 status = print_aggr_stats(state, link, &ginfo); 2807 else { 2808 status = print_aggr_info(state, link, &ginfo); 2809 } 2810 2811 done: 2812 free(ginfo.lg_ports); 2813 return (status); 2814 } 2815 2816 static int 2817 show_aggr(datalink_id_t linkid, void *arg) 2818 { 2819 show_grp_state_t *state = arg; 2820 dladm_status_t status; 2821 2822 status = print_aggr(state, linkid); 2823 if (status != DLADM_STATUS_OK) 2824 goto done; 2825 2826 done: 2827 state->gs_status = status; 2828 return (DLADM_WALK_CONTINUE); 2829 } 2830 2831 static void 2832 do_show_link(int argc, char *argv[], const char *use) 2833 { 2834 int option; 2835 boolean_t s_arg = B_FALSE; 2836 boolean_t S_arg = B_FALSE; 2837 boolean_t i_arg = B_FALSE; 2838 uint32_t flags = DLADM_OPT_ACTIVE; 2839 boolean_t p_arg = B_FALSE; 2840 datalink_id_t linkid = DATALINK_ALL_LINKID; 2841 char linkname[MAXLINKNAMELEN]; 2842 int interval = 0; 2843 show_state_t state; 2844 dladm_status_t status; 2845 boolean_t o_arg = B_FALSE; 2846 char *fields_str = NULL; 2847 print_field_t **fields; 2848 uint_t nfields; 2849 char *all_active_fields = "link,class,mtu,state,over"; 2850 char *all_inactive_fields = "link,class,over"; 2851 char *allstat_fields = 2852 "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; 2853 2854 bzero(&state, sizeof (state)); 2855 2856 opterr = 0; 2857 while ((option = getopt_long(argc, argv, ":pPsSi:o:", 2858 show_lopts, NULL)) != -1) { 2859 switch (option) { 2860 case 'p': 2861 if (p_arg) 2862 die_optdup(option); 2863 2864 p_arg = B_TRUE; 2865 break; 2866 case 's': 2867 if (s_arg) 2868 die_optdup(option); 2869 2870 s_arg = B_TRUE; 2871 break; 2872 case 'P': 2873 if (flags != DLADM_OPT_ACTIVE) 2874 die_optdup(option); 2875 2876 flags = DLADM_OPT_PERSIST; 2877 break; 2878 case 'S': 2879 if (S_arg) 2880 die_optdup(option); 2881 2882 S_arg = B_TRUE; 2883 break; 2884 case 'o': 2885 o_arg = B_TRUE; 2886 fields_str = optarg; 2887 break; 2888 case 'i': 2889 if (i_arg) 2890 die_optdup(option); 2891 2892 i_arg = B_TRUE; 2893 if (!str2int(optarg, &interval) || interval == 0) 2894 die("invalid interval value '%s'", optarg); 2895 break; 2896 default: 2897 die_opterr(optopt, option, use); 2898 break; 2899 } 2900 } 2901 2902 if (i_arg && !(s_arg || S_arg)) 2903 die("the option -i can be used only with -s or -S"); 2904 2905 if (s_arg && S_arg) 2906 die("the -s option cannot be used with -S"); 2907 2908 if (s_arg && flags != DLADM_OPT_ACTIVE) 2909 die("the option -P cannot be used with -s"); 2910 2911 if (S_arg && (p_arg || flags != DLADM_OPT_ACTIVE)) 2912 die("the option -%c cannot be used with -S", p_arg ? 'p' : 'P'); 2913 2914 /* get link name (optional last argument) */ 2915 if (optind == (argc-1)) { 2916 uint32_t f; 2917 2918 if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN) 2919 >= MAXLINKNAMELEN) { 2920 (void) fprintf(stderr, 2921 gettext("%s: link name too long\n"), 2922 progname); 2923 exit(1); 2924 } 2925 if ((status = dladm_name2info(linkname, &linkid, &f, 2926 NULL, NULL)) != DLADM_STATUS_OK) { 2927 die_dlerr(status, "link %s is not valid", linkname); 2928 } 2929 2930 if (!(f & flags)) { 2931 die_dlerr(DLADM_STATUS_BADARG, "link %s is %s", 2932 argv[optind], flags == DLADM_OPT_PERSIST ? 2933 "a temporary link" : "temporarily removed"); 2934 } 2935 } else if (optind != argc) { 2936 usage(); 2937 } 2938 2939 if (p_arg && !o_arg) 2940 die("-p requires -o"); 2941 2942 if (S_arg) { 2943 dladm_continuous(linkid, NULL, interval, LINK_REPORT); 2944 return; 2945 } 2946 2947 if (p_arg && strcasecmp(fields_str, "all") == 0) 2948 die("\"-o all\" is invalid with -p"); 2949 2950 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 2951 if (s_arg) 2952 fields_str = allstat_fields; 2953 else if (flags & DLADM_OPT_ACTIVE) 2954 fields_str = all_active_fields; 2955 else 2956 fields_str = all_inactive_fields; 2957 } 2958 2959 state.ls_parseable = p_arg; 2960 state.ls_flags = flags; 2961 state.ls_donefirst = B_FALSE; 2962 2963 if (s_arg) { 2964 link_stats(linkid, interval, fields_str, &state); 2965 return; 2966 } 2967 2968 fields = parse_output_fields(fields_str, link_fields, DEV_LINK_FIELDS, 2969 CMD_TYPE_ANY, &nfields); 2970 2971 if (fields == NULL) 2972 die("invalid field(s) specified"); 2973 2974 state.ls_print.ps_fields = fields; 2975 state.ls_print.ps_nfields = nfields; 2976 2977 if (linkid == DATALINK_ALL_LINKID) { 2978 (void) dladm_walk_datalink_id(show_link, &state, 2979 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 2980 } else { 2981 (void) show_link(linkid, &state); 2982 if (state.ls_status != DLADM_STATUS_OK) { 2983 die_dlerr(state.ls_status, "failed to show link %s", 2984 argv[optind]); 2985 } 2986 } 2987 } 2988 2989 static void 2990 do_show_aggr(int argc, char *argv[], const char *use) 2991 { 2992 boolean_t L_arg = B_FALSE; 2993 boolean_t s_arg = B_FALSE; 2994 boolean_t i_arg = B_FALSE; 2995 boolean_t p_arg = B_FALSE; 2996 boolean_t x_arg = B_FALSE; 2997 show_grp_state_t state; 2998 uint32_t flags = DLADM_OPT_ACTIVE; 2999 datalink_id_t linkid = DATALINK_ALL_LINKID; 3000 int option; 3001 int interval = 0; 3002 int key; 3003 dladm_status_t status; 3004 boolean_t o_arg = B_FALSE; 3005 char *fields_str = NULL; 3006 print_field_t **fields; 3007 uint_t nfields; 3008 char *all_fields = 3009 "link,policy,addrpolicy,lacpactivity,lacptimer,flags"; 3010 char *all_lacp_fields = 3011 "link,port,aggregatable,sync,coll,dist,defaulted,expired"; 3012 char *all_stats_fields = 3013 "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist"; 3014 char *all_extended_fields = 3015 "link,port,speed,duplex,state,address,portstate"; 3016 print_field_t *pf; 3017 int pfmax; 3018 3019 bzero(&state, sizeof (state)); 3020 3021 opterr = 0; 3022 while ((option = getopt_long(argc, argv, ":LpPxsi:o:", 3023 show_lopts, NULL)) != -1) { 3024 switch (option) { 3025 case 'L': 3026 if (L_arg) 3027 die_optdup(option); 3028 3029 L_arg = B_TRUE; 3030 break; 3031 case 'p': 3032 if (p_arg) 3033 die_optdup(option); 3034 3035 p_arg = B_TRUE; 3036 break; 3037 case 'x': 3038 if (x_arg) 3039 die_optdup(option); 3040 3041 x_arg = B_TRUE; 3042 break; 3043 case 'P': 3044 if (flags != DLADM_OPT_ACTIVE) 3045 die_optdup(option); 3046 3047 flags = DLADM_OPT_PERSIST; 3048 break; 3049 case 's': 3050 if (s_arg) 3051 die_optdup(option); 3052 3053 s_arg = B_TRUE; 3054 break; 3055 case 'o': 3056 o_arg = B_TRUE; 3057 fields_str = optarg; 3058 break; 3059 case 'i': 3060 if (i_arg) 3061 die_optdup(option); 3062 3063 i_arg = B_TRUE; 3064 if (!str2int(optarg, &interval) || interval == 0) 3065 die("invalid interval value '%s'", optarg); 3066 break; 3067 default: 3068 die_opterr(optopt, option, use); 3069 break; 3070 } 3071 } 3072 3073 if (p_arg && !o_arg) 3074 die("-p requires -o"); 3075 3076 if (p_arg && strcasecmp(fields_str, "all") == 0) 3077 die("\"-o all\" is invalid with -p"); 3078 3079 if (i_arg && !s_arg) 3080 die("the option -i can be used only with -s"); 3081 3082 if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) { 3083 die("the option -%c cannot be used with -s", 3084 L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P'))); 3085 } 3086 3087 if (L_arg && flags != DLADM_OPT_ACTIVE) 3088 die("the option -P cannot be used with -L"); 3089 3090 if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE)) 3091 die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P'); 3092 3093 /* get aggregation key or aggrname (optional last argument) */ 3094 if (optind == (argc-1)) { 3095 if (!str2int(argv[optind], &key)) { 3096 status = dladm_name2info(argv[optind], &linkid, NULL, 3097 NULL, NULL); 3098 } else { 3099 status = dladm_key2linkid((uint16_t)key, 3100 &linkid, DLADM_OPT_ACTIVE); 3101 } 3102 3103 if (status != DLADM_STATUS_OK) 3104 die("non-existent aggregation '%s'", argv[optind]); 3105 3106 } else if (optind != argc) { 3107 usage(); 3108 } 3109 3110 bzero(&state, sizeof (state)); 3111 state.gs_lacp = L_arg; 3112 state.gs_stats = s_arg; 3113 state.gs_flags = flags; 3114 state.gs_parseable = p_arg; 3115 state.gs_extended = x_arg; 3116 3117 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3118 if (state.gs_lacp) 3119 fields_str = all_lacp_fields; 3120 else if (state.gs_stats) 3121 fields_str = all_stats_fields; 3122 else if (state.gs_extended) 3123 fields_str = all_extended_fields; 3124 else 3125 fields_str = all_fields; 3126 } 3127 3128 if (state.gs_lacp) { 3129 pf = aggr_l_fields; 3130 pfmax = AGGR_L_MAX_FIELDS; 3131 } else if (state.gs_stats) { 3132 pf = aggr_s_fields; 3133 pfmax = AGGR_S_MAX_FIELDS; 3134 } else if (state.gs_extended) { 3135 pf = aggr_x_fields; 3136 pfmax = AGGR_X_MAX_FIELDS; 3137 } else { 3138 pf = laggr_fields; 3139 pfmax = LAGGR_MAX_FIELDS; 3140 } 3141 fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY, 3142 &nfields); 3143 3144 if (fields == NULL) { 3145 die("invalid field(s) specified"); 3146 return; 3147 } 3148 3149 state.gs_print.ps_fields = fields; 3150 state.gs_print.ps_nfields = nfields; 3151 3152 if (s_arg) { 3153 aggr_stats(linkid, &state, interval); 3154 return; 3155 } 3156 3157 if (linkid == DATALINK_ALL_LINKID) { 3158 (void) dladm_walk_datalink_id(show_aggr, &state, 3159 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); 3160 } else { 3161 (void) show_aggr(linkid, &state); 3162 if (state.gs_status != DLADM_STATUS_OK) { 3163 die_dlerr(state.gs_status, "failed to show aggr %s", 3164 argv[optind]); 3165 } 3166 } 3167 } 3168 3169 static dladm_status_t 3170 print_phys_default(show_state_t *state, datalink_id_t linkid, 3171 const char *link, uint32_t flags, uint32_t media) 3172 { 3173 dladm_phys_attr_t dpa; 3174 dladm_status_t status; 3175 link_fields_buf_t pattr; 3176 3177 status = dladm_phys_info(linkid, &dpa, state->ls_flags); 3178 if (status != DLADM_STATUS_OK) 3179 goto done; 3180 3181 (void) snprintf(pattr.link_phys_device, 3182 sizeof (pattr.link_phys_device), "%s", dpa.dp_dev); 3183 (void) dladm_media2str(media, pattr.link_phys_media); 3184 if (state->ls_flags == DLADM_OPT_ACTIVE) { 3185 boolean_t islink; 3186 3187 if (!dpa.dp_novanity) { 3188 (void) strlcpy(pattr.link_name, link, 3189 sizeof (pattr.link_name)); 3190 islink = B_TRUE; 3191 } else { 3192 /* 3193 * This is a physical link that does not have 3194 * vanity naming support. 3195 */ 3196 (void) strlcpy(pattr.link_name, dpa.dp_dev, 3197 sizeof (pattr.link_name)); 3198 islink = B_FALSE; 3199 } 3200 3201 (void) get_linkstate(pattr.link_name, islink, 3202 pattr.link_phys_state); 3203 (void) snprintf(pattr.link_phys_speed, 3204 sizeof (pattr.link_phys_speed), "%u", 3205 (uint_t)((get_ifspeed(pattr.link_name, 3206 islink)) / 1000000ull)); 3207 (void) get_linkduplex(pattr.link_name, islink, 3208 pattr.link_phys_duplex); 3209 } else { 3210 (void) snprintf(pattr.link_name, sizeof (pattr.link_name), 3211 "%s", link); 3212 (void) snprintf(pattr.link_flags, sizeof (pattr.link_flags), 3213 "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r'); 3214 } 3215 3216 if (!state->ls_parseable && !state->ls_printheader) { 3217 print_header(&state->ls_print); 3218 state->ls_printheader = B_TRUE; 3219 } 3220 3221 dladm_print_output(&state->ls_print, state->ls_parseable, 3222 dladm_print_field, (void *)&pattr); 3223 3224 done: 3225 return (status); 3226 } 3227 3228 typedef struct { 3229 show_state_t *ms_state; 3230 char *ms_link; 3231 dladm_macaddr_attr_t *ms_mac_attr; 3232 } print_phys_mac_state_t; 3233 3234 /* callback of dladm_print_output() */ 3235 static char * 3236 print_phys_one_mac_callback(print_field_t *pf, void *arg) 3237 { 3238 print_phys_mac_state_t *mac_state = arg; 3239 dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr; 3240 static char buf[DLADM_STRSIZE]; 3241 boolean_t is_primary = (attr->ma_slot == 0); 3242 boolean_t is_parseable = mac_state->ms_state->ls_parseable; 3243 3244 switch (pf->pf_index) { 3245 case PHYS_M_LINK: 3246 (void) snprintf(buf, sizeof (buf), "%s", 3247 (is_primary || is_parseable) ? mac_state->ms_link : " "); 3248 break; 3249 case PHYS_M_SLOT: 3250 if (is_primary) 3251 (void) snprintf(buf, sizeof (buf), gettext("primary")); 3252 else 3253 (void) snprintf(buf, sizeof (buf), "%d", attr->ma_slot); 3254 break; 3255 case PHYS_M_ADDRESS: 3256 (void) dladm_aggr_macaddr2str(attr->ma_addr, buf); 3257 break; 3258 case PHYS_M_INUSE: 3259 (void) snprintf(buf, sizeof (buf), "%s", 3260 attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") : 3261 gettext("no")); 3262 break; 3263 case PHYS_M_CLIENT: 3264 /* 3265 * CR 6678526: resolve link id to actual link name if 3266 * it is valid. 3267 */ 3268 (void) snprintf(buf, sizeof (buf), "%s", attr->ma_client_name); 3269 break; 3270 } 3271 3272 return (buf); 3273 } 3274 3275 typedef struct { 3276 show_state_t *hs_state; 3277 char *hs_link; 3278 dladm_hwgrp_attr_t *hs_grp_attr; 3279 } print_phys_hwgrp_state_t; 3280 3281 static char * 3282 print_phys_one_hwgrp_callback(print_field_t *pf, void *arg) 3283 { 3284 print_phys_hwgrp_state_t *hg_state = arg; 3285 dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr; 3286 static char buf[DLADM_STRSIZE]; 3287 3288 switch (pf->pf_index) { 3289 case PHYS_H_LINK: 3290 (void) snprintf(buf, sizeof (buf), "%s", attr->hg_link_name); 3291 break; 3292 case PHYS_H_GROUP: 3293 (void) snprintf(buf, sizeof (buf), "%d", attr->hg_grp_num); 3294 break; 3295 case PHYS_H_GRPTYPE: 3296 (void) snprintf(buf, sizeof (buf), "%s", 3297 attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX"); 3298 break; 3299 case PHYS_H_RINGS: 3300 (void) snprintf(buf, sizeof (buf), "%d", attr->hg_n_rings); 3301 break; 3302 case PHYS_H_CLIENTS: 3303 if (attr->hg_client_names[0] == '\0') { 3304 (void) snprintf(buf, sizeof (buf), "--"); 3305 } else { 3306 (void) snprintf(buf, sizeof (buf), "%s ", 3307 attr->hg_client_names); 3308 } 3309 break; 3310 } 3311 3312 return (buf); 3313 } 3314 3315 /* callback of dladm_walk_macaddr, invoked for each MAC address slot */ 3316 static boolean_t 3317 print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr) 3318 { 3319 print_phys_mac_state_t *mac_state = arg; 3320 show_state_t *state = mac_state->ms_state; 3321 3322 if (!state->ls_parseable && !state->ls_printheader) { 3323 print_header(&state->ls_print); 3324 state->ls_printheader = B_TRUE; 3325 } 3326 3327 mac_state->ms_mac_attr = attr; 3328 dladm_print_output(&state->ls_print, state->ls_parseable, 3329 print_phys_one_mac_callback, mac_state); 3330 3331 return (B_TRUE); 3332 } 3333 3334 /* invoked by show-phys -m for each physical data-link */ 3335 static dladm_status_t 3336 print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link) 3337 { 3338 print_phys_mac_state_t mac_state; 3339 3340 mac_state.ms_state = state; 3341 mac_state.ms_link = link; 3342 3343 return (dladm_walk_macaddr(linkid, &mac_state, 3344 print_phys_mac_callback)); 3345 } 3346 3347 /* callback of dladm_walk_hwgrp, invoked for each MAC hwgrp */ 3348 static boolean_t 3349 print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr) 3350 { 3351 print_phys_hwgrp_state_t *hwgrp_state = arg; 3352 show_state_t *state = hwgrp_state->hs_state; 3353 3354 if (!state->ls_parseable && !state->ls_printheader) { 3355 print_header(&state->ls_print); 3356 state->ls_printheader = B_TRUE; 3357 } 3358 hwgrp_state->hs_grp_attr = attr; 3359 dladm_print_output(&state->ls_print, state->ls_parseable, 3360 print_phys_one_hwgrp_callback, hwgrp_state); 3361 3362 return (B_TRUE); 3363 } 3364 3365 /* invoked by show-phys -H for each physical data-link */ 3366 static dladm_status_t 3367 print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link) 3368 { 3369 print_phys_hwgrp_state_t hwgrp_state; 3370 3371 hwgrp_state.hs_state = state; 3372 hwgrp_state.hs_link = link; 3373 return (dladm_walk_hwgrp(linkid, &hwgrp_state, 3374 print_phys_hwgrp_callback)); 3375 } 3376 3377 static dladm_status_t 3378 print_phys(show_state_t *state, datalink_id_t linkid) 3379 { 3380 char link[MAXLINKNAMELEN]; 3381 uint32_t flags; 3382 dladm_status_t status; 3383 datalink_class_t class; 3384 uint32_t media; 3385 3386 if ((status = dladm_datalink_id2info(linkid, &flags, &class, &media, 3387 link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 3388 goto done; 3389 } 3390 3391 if (class != DATALINK_CLASS_PHYS) { 3392 status = DLADM_STATUS_BADARG; 3393 goto done; 3394 } 3395 3396 if (!(state->ls_flags & flags)) { 3397 status = DLADM_STATUS_NOTFOUND; 3398 goto done; 3399 } 3400 3401 if (state->ls_mac) 3402 status = print_phys_mac(state, linkid, link); 3403 else if (state->ls_hwgrp) 3404 status = print_phys_hwgrp(state, linkid, link); 3405 else 3406 status = print_phys_default(state, linkid, link, flags, media); 3407 3408 done: 3409 return (status); 3410 } 3411 3412 static int 3413 show_phys(datalink_id_t linkid, void *arg) 3414 { 3415 show_state_t *state = arg; 3416 3417 state->ls_status = print_phys(state, linkid); 3418 return (DLADM_WALK_CONTINUE); 3419 } 3420 3421 /* 3422 * Print the active topology information. 3423 */ 3424 static dladm_status_t 3425 print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l) 3426 { 3427 dladm_vlan_attr_t vinfo; 3428 uint32_t flags; 3429 dladm_status_t status; 3430 3431 if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, 3432 l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) { 3433 goto done; 3434 } 3435 3436 if (!(state->ls_flags & flags)) { 3437 status = DLADM_STATUS_NOTFOUND; 3438 goto done; 3439 } 3440 3441 if ((status = dladm_vlan_info(linkid, &vinfo, state->ls_flags)) != 3442 DLADM_STATUS_OK || (status = dladm_datalink_id2info( 3443 vinfo.dv_linkid, NULL, NULL, NULL, l->link_over, 3444 sizeof (l->link_over))) != DLADM_STATUS_OK) { 3445 goto done; 3446 } 3447 3448 (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d", 3449 vinfo.dv_vid); 3450 (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----", 3451 vinfo.dv_force ? 'f' : '-'); 3452 3453 done: 3454 return (status); 3455 } 3456 3457 static int 3458 show_vlan(datalink_id_t linkid, void *arg) 3459 { 3460 show_state_t *state = arg; 3461 dladm_status_t status; 3462 link_fields_buf_t lbuf; 3463 3464 bzero(&lbuf, sizeof (link_fields_buf_t)); 3465 status = print_vlan(state, linkid, &lbuf); 3466 if (status != DLADM_STATUS_OK) 3467 goto done; 3468 3469 if (!state->ls_parseable && !state->ls_printheader) { 3470 print_header(&state->ls_print); 3471 state->ls_printheader = B_TRUE; 3472 } 3473 3474 dladm_print_output(&state->ls_print, state->ls_parseable, 3475 dladm_print_field, (void *)&lbuf); 3476 3477 done: 3478 state->ls_status = status; 3479 return (DLADM_WALK_CONTINUE); 3480 } 3481 3482 static void 3483 do_show_phys(int argc, char *argv[], const char *use) 3484 { 3485 int option; 3486 uint32_t flags = DLADM_OPT_ACTIVE; 3487 boolean_t p_arg = B_FALSE; 3488 boolean_t o_arg = B_FALSE; 3489 boolean_t m_arg = B_FALSE; 3490 boolean_t H_arg = B_FALSE; 3491 datalink_id_t linkid = DATALINK_ALL_LINKID; 3492 show_state_t state; 3493 dladm_status_t status; 3494 char *fields_str = NULL; 3495 print_field_t **fields; 3496 uint_t nfields; 3497 char *all_active_fields = 3498 "link,media,state,speed,duplex,device"; 3499 char *all_inactive_fields = "link,device,media,flags"; 3500 char *all_mac_fields = "link,slot,address,inuse,client"; 3501 char *all_hwgrp_fields = 3502 "link,group,grouptype,rings,clients"; 3503 print_field_t *pf; 3504 int pfmax; 3505 3506 bzero(&state, sizeof (state)); 3507 opterr = 0; 3508 while ((option = getopt_long(argc, argv, ":pPo:mH", 3509 show_lopts, NULL)) != -1) { 3510 switch (option) { 3511 case 'p': 3512 if (p_arg) 3513 die_optdup(option); 3514 3515 p_arg = B_TRUE; 3516 break; 3517 case 'P': 3518 if (flags != DLADM_OPT_ACTIVE) 3519 die_optdup(option); 3520 3521 flags = DLADM_OPT_PERSIST; 3522 break; 3523 case 'o': 3524 o_arg = B_TRUE; 3525 fields_str = optarg; 3526 break; 3527 case 'm': 3528 m_arg = B_TRUE; 3529 break; 3530 case 'H': 3531 H_arg = B_TRUE; 3532 break; 3533 default: 3534 die_opterr(optopt, option, use); 3535 break; 3536 } 3537 } 3538 3539 if (p_arg && !o_arg) 3540 die("-p requires -o"); 3541 3542 if (m_arg && H_arg) 3543 die("-m cannot combine with -H"); 3544 3545 if (p_arg && strcasecmp(fields_str, "all") == 0) 3546 die("\"-o all\" is invalid with -p"); 3547 3548 /* get link name (optional last argument) */ 3549 if (optind == (argc-1)) { 3550 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 3551 NULL, NULL)) != DLADM_STATUS_OK) { 3552 die_dlerr(status, "link %s is not valid", argv[optind]); 3553 } 3554 } else if (optind != argc) { 3555 usage(); 3556 } 3557 3558 state.ls_parseable = p_arg; 3559 state.ls_flags = flags; 3560 state.ls_donefirst = B_FALSE; 3561 state.ls_mac = m_arg; 3562 state.ls_hwgrp = H_arg; 3563 3564 if (m_arg && !(flags & DLADM_OPT_ACTIVE)) { 3565 /* 3566 * We can only display the factory MAC addresses of 3567 * active data-links. 3568 */ 3569 die("-m not compatible with -P"); 3570 } 3571 3572 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3573 if (state.ls_mac) 3574 fields_str = all_mac_fields; 3575 else if (state.ls_hwgrp) 3576 fields_str = all_hwgrp_fields; 3577 else if (state.ls_flags & DLADM_OPT_ACTIVE) { 3578 fields_str = all_active_fields; 3579 } else { 3580 fields_str = all_inactive_fields; 3581 } 3582 } 3583 3584 if (state.ls_mac) { 3585 pf = phys_m_fields; 3586 pfmax = PHYS_M_MAX_FIELDS; 3587 } else if (state.ls_hwgrp) { 3588 pf = phys_h_fields; 3589 pfmax = PHYS_H_MAX_FIELDS; 3590 } else { 3591 pf = phys_fields; 3592 pfmax = PHYS_MAX_FIELDS; 3593 } 3594 3595 fields = parse_output_fields(fields_str, pf, 3596 pfmax, CMD_TYPE_ANY, &nfields); 3597 3598 if (fields == NULL) { 3599 die("invalid field(s) specified"); 3600 return; 3601 } 3602 3603 state.ls_print.ps_fields = fields; 3604 state.ls_print.ps_nfields = nfields; 3605 3606 if (linkid == DATALINK_ALL_LINKID) { 3607 (void) dladm_walk_datalink_id(show_phys, &state, 3608 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags); 3609 } else { 3610 (void) show_phys(linkid, &state); 3611 if (state.ls_status != DLADM_STATUS_OK) { 3612 die_dlerr(state.ls_status, 3613 "failed to show physical link %s", argv[optind]); 3614 } 3615 } 3616 } 3617 3618 static void 3619 do_show_vlan(int argc, char *argv[], const char *use) 3620 { 3621 int option; 3622 uint32_t flags = DLADM_OPT_ACTIVE; 3623 boolean_t p_arg = B_FALSE; 3624 datalink_id_t linkid = DATALINK_ALL_LINKID; 3625 show_state_t state; 3626 dladm_status_t status; 3627 boolean_t o_arg = B_FALSE; 3628 char *fields_str = NULL; 3629 print_field_t **fields; 3630 uint_t nfields; 3631 char *all_fields = "link,vid,over,flags"; 3632 3633 bzero(&state, sizeof (state)); 3634 3635 opterr = 0; 3636 while ((option = getopt_long(argc, argv, ":pPo:", 3637 show_lopts, NULL)) != -1) { 3638 switch (option) { 3639 case 'p': 3640 if (p_arg) 3641 die_optdup(option); 3642 3643 p_arg = B_TRUE; 3644 break; 3645 case 'P': 3646 if (flags != DLADM_OPT_ACTIVE) 3647 die_optdup(option); 3648 3649 flags = DLADM_OPT_PERSIST; 3650 break; 3651 case 'o': 3652 o_arg = B_TRUE; 3653 fields_str = optarg; 3654 break; 3655 default: 3656 die_opterr(optopt, option, use); 3657 break; 3658 } 3659 } 3660 3661 if (p_arg && !o_arg) 3662 die("-p requires -o"); 3663 3664 if (p_arg && strcasecmp(fields_str, "all") == 0) 3665 die("\"-o all\" is invalid with -p"); 3666 3667 /* get link name (optional last argument) */ 3668 if (optind == (argc-1)) { 3669 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 3670 NULL, NULL)) != DLADM_STATUS_OK) { 3671 die_dlerr(status, "link %s is not valid", argv[optind]); 3672 } 3673 } else if (optind != argc) { 3674 usage(); 3675 } 3676 3677 state.ls_parseable = p_arg; 3678 state.ls_flags = flags; 3679 state.ls_donefirst = B_FALSE; 3680 3681 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 3682 fields_str = all_fields; 3683 3684 fields = parse_output_fields(fields_str, vlan_fields, VLAN_MAX_FIELDS, 3685 CMD_TYPE_ANY, &nfields); 3686 3687 if (fields == NULL) { 3688 die("invalid field(s) specified"); 3689 return; 3690 } 3691 state.ls_print.ps_fields = fields; 3692 state.ls_print.ps_nfields = nfields; 3693 3694 if (linkid == DATALINK_ALL_LINKID) { 3695 (void) dladm_walk_datalink_id(show_vlan, &state, 3696 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags); 3697 } else { 3698 (void) show_vlan(linkid, &state); 3699 if (state.ls_status != DLADM_STATUS_OK) { 3700 die_dlerr(state.ls_status, "failed to show vlan %s", 3701 argv[optind]); 3702 } 3703 } 3704 } 3705 3706 static void 3707 do_create_vnic(int argc, char *argv[], const char *use) 3708 { 3709 datalink_id_t linkid, dev_linkid; 3710 char devname[MAXLINKNAMELEN]; 3711 char name[MAXLINKNAMELEN]; 3712 boolean_t l_arg = B_FALSE; 3713 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 3714 char *altroot = NULL; 3715 char option; 3716 char *endp = NULL; 3717 dladm_status_t status; 3718 vnic_mac_addr_type_t mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO; 3719 uchar_t *mac_addr; 3720 int mac_slot = -1, maclen = 0, mac_prefix_len = 0; 3721 dladm_arg_list_t *proplist = NULL; 3722 uint16_t vid = 0; 3723 3724 opterr = 0; 3725 while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:H", 3726 vnic_lopts, NULL)) != -1) { 3727 switch (option) { 3728 case 't': 3729 flags &= ~DLADM_OPT_PERSIST; 3730 break; 3731 case 'R': 3732 altroot = optarg; 3733 break; 3734 case 'l': 3735 if (strlcpy(devname, optarg, MAXLINKNAMELEN) >= 3736 MAXLINKNAMELEN) 3737 die("link name too long"); 3738 l_arg = B_TRUE; 3739 break; 3740 case 'm': 3741 if (strcmp(optarg, "fixed") == 0) { 3742 /* 3743 * A fixed MAC address must be specified 3744 * by its value, not by the keyword 'fixed'. 3745 */ 3746 die("'fixed' is not a valid MAC address"); 3747 } 3748 if (dladm_vnic_str2macaddrtype(optarg, 3749 &mac_addr_type) != DLADM_STATUS_OK) { 3750 mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED; 3751 /* MAC address specified by value */ 3752 mac_addr = _link_aton(optarg, &maclen); 3753 if (mac_addr == NULL) { 3754 if (maclen == -1) 3755 die("invalid MAC address"); 3756 else 3757 die("out of memory"); 3758 exit(1); 3759 } 3760 } 3761 break; 3762 case 'n': 3763 errno = 0; 3764 mac_slot = (int)strtol(optarg, &endp, 10); 3765 if (errno != 0 || *endp != '\0') 3766 die("invalid slot number"); 3767 break; 3768 case 'p': 3769 if (dladm_parse_link_props(optarg, &proplist, B_FALSE) 3770 != DLADM_STATUS_OK) 3771 die("invalid vnic property"); 3772 break; 3773 case 'r': 3774 mac_addr = _link_aton(optarg, &mac_prefix_len); 3775 if (mac_addr == NULL) { 3776 if (mac_prefix_len == -1) 3777 die("invalid MAC address"); 3778 else 3779 die("out of memory"); 3780 exit(1); 3781 } 3782 break; 3783 case 'v': 3784 vid = (int)strtol(optarg, &endp, 10); 3785 if (errno != 0 || *endp != '\0' || vid == 0) 3786 /* VID of 0 is invalid */ 3787 die("invalid VLAN id"); 3788 break; 3789 case 'f': 3790 flags |= DLADM_OPT_FORCE; 3791 break; 3792 case 'H': 3793 flags |= DLADM_OPT_HWRINGS; 3794 break; 3795 default: 3796 die_opterr(optopt, option, use); 3797 } 3798 } 3799 3800 /* 3801 * 'f' - force, flag can be specified only with 'v' - vlan. 3802 */ 3803 if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0) 3804 die("-f option can only be used with -v"); 3805 3806 if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM && 3807 mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED) 3808 usage(); 3809 3810 /* check required options */ 3811 if (!l_arg) 3812 usage(); 3813 3814 if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY) 3815 usage(); 3816 3817 /* the VNIC id is the required operand */ 3818 if (optind != (argc - 1)) 3819 usage(); 3820 3821 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 3822 die("link name too long '%s'", argv[optind]); 3823 3824 if (!dladm_valid_linkname(name)) 3825 die("invalid link name '%s'", argv[optind]); 3826 3827 if (altroot != NULL) 3828 altroot_cmd(altroot, argc, argv); 3829 3830 if (dladm_name2info(devname, &dev_linkid, NULL, NULL, NULL) != 3831 DLADM_STATUS_OK) 3832 die("invalid link name '%s'", devname); 3833 3834 status = dladm_vnic_create(name, dev_linkid, mac_addr_type, mac_addr, 3835 maclen, &mac_slot, mac_prefix_len, vid, &linkid, proplist, flags); 3836 if (status != DLADM_STATUS_OK) 3837 die_dlerr(status, "vnic creation over %s failed", devname); 3838 3839 dladm_free_props(proplist); 3840 } 3841 3842 static void 3843 do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub, 3844 uint32_t flags) 3845 { 3846 boolean_t is_etherstub; 3847 dladm_vnic_attr_t attr; 3848 3849 if (dladm_vnic_info(linkid, &attr, flags) != DLADM_STATUS_OK) { 3850 /* 3851 * Let the delete continue anyway. 3852 */ 3853 return; 3854 } 3855 is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID); 3856 if (is_etherstub != etherstub) { 3857 die("'%s' is not %s", name, 3858 (is_etherstub ? "a vnic" : "an etherstub")); 3859 } 3860 } 3861 3862 static void 3863 do_delete_vnic_common(int argc, char *argv[], const char *use, 3864 boolean_t etherstub) 3865 { 3866 char option; 3867 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 3868 datalink_id_t linkid; 3869 char *altroot = NULL; 3870 dladm_status_t status; 3871 3872 opterr = 0; 3873 while ((option = getopt_long(argc, argv, ":R:t", lopts, 3874 NULL)) != -1) { 3875 switch (option) { 3876 case 't': 3877 flags &= ~DLADM_OPT_PERSIST; 3878 break; 3879 case 'R': 3880 altroot = optarg; 3881 break; 3882 default: 3883 die_opterr(optopt, option, use); 3884 } 3885 } 3886 3887 /* get vnic name (required last argument) */ 3888 if (optind != (argc - 1)) 3889 usage(); 3890 3891 if (altroot != NULL) 3892 altroot_cmd(altroot, argc, argv); 3893 3894 status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL); 3895 if (status != DLADM_STATUS_OK) 3896 die("invalid link name '%s'", argv[optind]); 3897 3898 if ((flags & DLADM_OPT_ACTIVE) != 0) { 3899 do_etherstub_check(argv[optind], linkid, etherstub, 3900 DLADM_OPT_ACTIVE); 3901 } 3902 if ((flags & DLADM_OPT_PERSIST) != 0) { 3903 do_etherstub_check(argv[optind], linkid, etherstub, 3904 DLADM_OPT_PERSIST); 3905 } 3906 3907 status = dladm_vnic_delete(linkid, flags); 3908 if (status != DLADM_STATUS_OK) 3909 die_dlerr(status, "vnic deletion failed"); 3910 } 3911 3912 static void 3913 do_delete_vnic(int argc, char *argv[], const char *use) 3914 { 3915 do_delete_vnic_common(argc, argv, use, B_FALSE); 3916 } 3917 3918 /* ARGSUSED */ 3919 static void 3920 do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan) 3921 { 3922 datalink_id_t linkid = DATALINK_ALL_LINKID; 3923 dladm_status_t status; 3924 char *type; 3925 3926 type = vlan ? "vlan" : "vnic"; 3927 3928 /* 3929 * get the id or the name of the vnic/vlan (optional last argument) 3930 */ 3931 if (argc == 2) { 3932 status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL); 3933 if (status != DLADM_STATUS_OK) 3934 goto done; 3935 3936 } else if (argc > 2) { 3937 usage(); 3938 } 3939 3940 if (vlan) 3941 status = dladm_vlan_up(linkid); 3942 else 3943 status = dladm_vnic_up(linkid, 0); 3944 3945 done: 3946 if (status != DLADM_STATUS_OK) { 3947 if (argc == 2) { 3948 die_dlerr(status, 3949 "could not bring up %s '%s'", type, argv[1]); 3950 } else { 3951 die_dlerr(status, "could not bring %ss up", type); 3952 } 3953 } 3954 } 3955 3956 static void 3957 do_up_vnic(int argc, char *argv[], const char *use) 3958 { 3959 do_up_vnic_common(argc, argv, use, B_FALSE); 3960 } 3961 3962 static void 3963 dump_vnics_head(const char *dev) 3964 { 3965 if (strlen(dev)) 3966 (void) printf("%s", dev); 3967 3968 (void) printf("\tipackets rbytes opackets obytes "); 3969 3970 if (strlen(dev)) 3971 (void) printf("%%ipkts %%opkts\n"); 3972 else 3973 (void) printf("\n"); 3974 } 3975 3976 static void 3977 dump_vnic_stat(const char *name, datalink_id_t vnic_id, 3978 show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats) 3979 { 3980 pktsum_t diff_stats; 3981 pktsum_t *old_stats = &state->vs_prevstats[vnic_id]; 3982 3983 dladm_stats_diff(&diff_stats, vnic_stats, old_stats); 3984 3985 (void) printf("%s", name); 3986 3987 (void) printf("\t%-10llu", diff_stats.ipackets); 3988 (void) printf("%-12llu", diff_stats.rbytes); 3989 (void) printf("%-10llu", diff_stats.opackets); 3990 (void) printf("%-12llu", diff_stats.obytes); 3991 3992 if (tot_stats) { 3993 if (tot_stats->ipackets == 0) { 3994 (void) printf("\t-"); 3995 } else { 3996 (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 3997 (double)tot_stats->ipackets * 100); 3998 } 3999 if (tot_stats->opackets == 0) { 4000 (void) printf("\t-"); 4001 } else { 4002 (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 4003 (double)tot_stats->opackets * 100); 4004 } 4005 } 4006 (void) printf("\n"); 4007 4008 *old_stats = *vnic_stats; 4009 } 4010 4011 /* 4012 * Called from the walker dladm_vnic_walk_sys() for each vnic to display 4013 * vnic information or statistics. 4014 */ 4015 static dladm_status_t 4016 print_vnic(show_vnic_state_t *state, datalink_id_t linkid) 4017 { 4018 dladm_vnic_attr_t attr, *vnic = &attr; 4019 dladm_status_t status; 4020 boolean_t is_etherstub; 4021 char devname[MAXLINKNAMELEN]; 4022 char vnic_name[MAXLINKNAMELEN]; 4023 char mstr[MAXMACADDRLEN * 3]; 4024 vnic_fields_buf_t vbuf; 4025 4026 if ((status = dladm_vnic_info(linkid, vnic, state->vs_flags)) != 4027 DLADM_STATUS_OK) 4028 return (status); 4029 4030 is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID); 4031 if (state->vs_etherstub != is_etherstub) { 4032 /* 4033 * Want all etherstub but it's not one, or want 4034 * non-etherstub and it's one. 4035 */ 4036 return (DLADM_STATUS_OK); 4037 } 4038 4039 if (state->vs_link_id != DATALINK_ALL_LINKID) { 4040 if (state->vs_link_id != vnic->va_link_id) 4041 return (DLADM_STATUS_OK); 4042 } 4043 4044 if (dladm_datalink_id2info(linkid, NULL, NULL, 4045 NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK) 4046 return (DLADM_STATUS_BADARG); 4047 4048 bzero(devname, sizeof (devname)); 4049 if (!is_etherstub && 4050 dladm_datalink_id2info(vnic->va_link_id, NULL, NULL, 4051 NULL, devname, sizeof (devname)) != DLADM_STATUS_OK) 4052 return (DLADM_STATUS_BADARG); 4053 4054 state->vs_found = B_TRUE; 4055 if (state->vs_stats) { 4056 /* print vnic statistics */ 4057 pktsum_t vnic_stats; 4058 4059 if (state->vs_firstonly) { 4060 if (state->vs_donefirst) 4061 return (0); 4062 state->vs_donefirst = B_TRUE; 4063 } 4064 4065 if (!state->vs_printstats) { 4066 /* 4067 * get vnic statistics and add to the sum for the 4068 * named device. 4069 */ 4070 get_link_stats(vnic_name, &vnic_stats); 4071 dladm_stats_total(&state->vs_totalstats, &vnic_stats, 4072 &state->vs_prevstats[vnic->va_vnic_id]); 4073 } else { 4074 /* get and print vnic statistics */ 4075 get_link_stats(vnic_name, &vnic_stats); 4076 dump_vnic_stat(vnic_name, linkid, state, &vnic_stats, 4077 &state->vs_totalstats); 4078 } 4079 return (DLADM_STATUS_OK); 4080 } else { 4081 (void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link), 4082 "%s", vnic_name); 4083 4084 if (!is_etherstub) { 4085 4086 (void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over), 4087 "%s", devname); 4088 (void) snprintf(vbuf.vnic_speed, 4089 sizeof (vbuf.vnic_speed), "%u", 4090 (uint_t)((get_ifspeed(vnic_name, B_TRUE)) 4091 / 1000000ull)); 4092 4093 switch (vnic->va_mac_addr_type) { 4094 case VNIC_MAC_ADDR_TYPE_FIXED: 4095 case VNIC_MAC_ADDR_TYPE_PRIMARY: 4096 (void) snprintf(vbuf.vnic_macaddrtype, 4097 sizeof (vbuf.vnic_macaddrtype), 4098 gettext("fixed")); 4099 break; 4100 case VNIC_MAC_ADDR_TYPE_RANDOM: 4101 (void) snprintf(vbuf.vnic_macaddrtype, 4102 sizeof (vbuf.vnic_macaddrtype), 4103 gettext("random")); 4104 break; 4105 case VNIC_MAC_ADDR_TYPE_FACTORY: 4106 (void) snprintf(vbuf.vnic_macaddrtype, 4107 sizeof (vbuf.vnic_macaddrtype), 4108 gettext("factory, slot %d"), 4109 vnic->va_mac_slot); 4110 break; 4111 } 4112 4113 if (strlen(vbuf.vnic_macaddrtype) > 0) { 4114 (void) snprintf(vbuf.vnic_macaddr, 4115 sizeof (vbuf.vnic_macaddr), "%s", 4116 dladm_aggr_macaddr2str(vnic->va_mac_addr, 4117 mstr)); 4118 } 4119 4120 (void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid), 4121 "%d", vnic->va_vid); 4122 } 4123 4124 if (!state->vs_parseable && !state->vs_printheader) { 4125 print_header(&state->vs_print); 4126 state->vs_printheader = B_TRUE; 4127 } 4128 4129 dladm_print_output(&state->vs_print, state->vs_parseable, 4130 dladm_print_field, (void *)&vbuf); 4131 4132 return (DLADM_STATUS_OK); 4133 } 4134 } 4135 4136 static int 4137 show_vnic(datalink_id_t linkid, void *arg) 4138 { 4139 show_vnic_state_t *state = arg; 4140 4141 state->vs_status = print_vnic(state, linkid); 4142 return (DLADM_WALK_CONTINUE); 4143 } 4144 4145 static void 4146 do_show_vnic_common(int argc, char *argv[], const char *use, 4147 boolean_t etherstub) 4148 { 4149 int option; 4150 boolean_t s_arg = B_FALSE; 4151 boolean_t i_arg = B_FALSE; 4152 boolean_t l_arg = B_FALSE; 4153 char *endp = NULL; 4154 uint32_t interval = 0, flags = DLADM_OPT_ACTIVE; 4155 datalink_id_t linkid = DATALINK_ALL_LINKID; 4156 datalink_id_t dev_linkid = DATALINK_ALL_LINKID; 4157 show_vnic_state_t state; 4158 dladm_status_t status; 4159 boolean_t o_arg = B_FALSE; 4160 char *fields_str = NULL; 4161 print_field_t **fields; 4162 print_field_t *pf; 4163 int pfmax; 4164 uint_t nfields; 4165 char *all_fields = 4166 "link,over,speed,macaddr,macaddrtype,vid"; 4167 char *all_e_fields = 4168 "link"; 4169 4170 bzero(&state, sizeof (state)); 4171 opterr = 0; 4172 while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts, 4173 NULL)) != -1) { 4174 switch (option) { 4175 case 'p': 4176 state.vs_parseable = B_TRUE; 4177 break; 4178 case 'P': 4179 flags = DLADM_OPT_PERSIST; 4180 break; 4181 case 'l': 4182 if (etherstub) 4183 die("option not supported for this command"); 4184 4185 if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >= 4186 MAXLINKNAMELEN) 4187 die("link name too long"); 4188 4189 l_arg = B_TRUE; 4190 break; 4191 case 's': 4192 if (s_arg) { 4193 die("the option -s cannot be specified " 4194 "more than once"); 4195 } 4196 s_arg = B_TRUE; 4197 break; 4198 case 'i': 4199 if (i_arg) { 4200 die("the option -i cannot be specified " 4201 "more than once"); 4202 } 4203 i_arg = B_TRUE; 4204 interval = (int)strtol(optarg, &endp, 10); 4205 if (errno != 0 || interval == 0 || *endp != '\0') 4206 die("invalid interval value '%s'", optarg); 4207 break; 4208 case 'o': 4209 o_arg = B_TRUE; 4210 fields_str = optarg; 4211 break; 4212 default: 4213 die_opterr(optopt, option, use); 4214 } 4215 } 4216 4217 if (i_arg && !s_arg) 4218 die("the option -i can be used only with -s"); 4219 4220 /* get vnic ID (optional last argument) */ 4221 if (optind == (argc - 1)) { 4222 status = dladm_name2info(argv[optind], &linkid, NULL, 4223 NULL, NULL); 4224 if (status != DLADM_STATUS_OK) { 4225 die_dlerr(status, "invalid vnic name '%s'", 4226 argv[optind]); 4227 } 4228 (void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN); 4229 } else if (optind != argc) { 4230 usage(); 4231 } 4232 4233 if (l_arg) { 4234 status = dladm_name2info(state.vs_link, &dev_linkid, NULL, 4235 NULL, NULL); 4236 if (status != DLADM_STATUS_OK) { 4237 die_dlerr(status, "invalid link name '%s'", 4238 state.vs_link); 4239 } 4240 } 4241 4242 state.vs_vnic_id = linkid; 4243 state.vs_link_id = dev_linkid; 4244 state.vs_etherstub = etherstub; 4245 state.vs_found = B_FALSE; 4246 state.vs_flags = flags; 4247 4248 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 4249 if (etherstub) 4250 fields_str = all_e_fields; 4251 else 4252 fields_str = all_fields; 4253 } 4254 4255 pf = vnic_fields; 4256 pfmax = VNIC_MAX_FIELDS; 4257 4258 fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY, 4259 &nfields); 4260 4261 if (fields == NULL) { 4262 die("invalid field(s) specified"); 4263 return; 4264 } 4265 4266 state.vs_print.ps_fields = fields; 4267 state.vs_print.ps_nfields = nfields; 4268 4269 if (s_arg) { 4270 /* Display vnic statistics */ 4271 vnic_stats(&state, interval); 4272 return; 4273 } 4274 4275 /* Display vnic information */ 4276 state.vs_donefirst = B_FALSE; 4277 4278 if (linkid == DATALINK_ALL_LINKID) { 4279 (void) dladm_walk_datalink_id(show_vnic, &state, 4280 DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB, 4281 DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 4282 } else { 4283 (void) show_vnic(linkid, &state); 4284 if (state.vs_status != DLADM_STATUS_OK) { 4285 die_dlerr(state.vs_status, "failed to show vnic '%s'", 4286 state.vs_vnic); 4287 } 4288 } 4289 } 4290 4291 static void 4292 do_show_vnic(int argc, char *argv[], const char *use) 4293 { 4294 do_show_vnic_common(argc, argv, use, B_FALSE); 4295 } 4296 4297 static void 4298 do_create_etherstub(int argc, char *argv[], const char *use) 4299 { 4300 uint32_t flags; 4301 char *altroot = NULL; 4302 char option; 4303 dladm_status_t status; 4304 char name[MAXLINKNAMELEN]; 4305 uchar_t mac_addr[ETHERADDRL]; 4306 4307 name[0] = '\0'; 4308 bzero(mac_addr, sizeof (mac_addr)); 4309 flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4310 4311 opterr = 0; 4312 while ((option = getopt_long(argc, argv, "tR:", 4313 etherstub_lopts, NULL)) != -1) { 4314 switch (option) { 4315 case 't': 4316 flags &= ~DLADM_OPT_PERSIST; 4317 break; 4318 case 'R': 4319 altroot = optarg; 4320 break; 4321 default: 4322 die_opterr(optopt, option, use); 4323 } 4324 } 4325 4326 /* the etherstub id is the required operand */ 4327 if (optind != (argc - 1)) 4328 usage(); 4329 4330 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 4331 die("link name too long '%s'", argv[optind]); 4332 4333 if (!dladm_valid_linkname(name)) 4334 die("invalid link name '%s'", argv[optind]); 4335 4336 if (altroot != NULL) 4337 altroot_cmd(altroot, argc, argv); 4338 4339 status = dladm_vnic_create(name, DATALINK_INVALID_LINKID, 4340 VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, NULL, 4341 NULL, flags); 4342 if (status != DLADM_STATUS_OK) 4343 die_dlerr(status, "etherstub creation failed"); 4344 4345 4346 } 4347 4348 static void 4349 do_delete_etherstub(int argc, char *argv[], const char *use) 4350 { 4351 do_delete_vnic_common(argc, argv, use, B_TRUE); 4352 } 4353 4354 /* ARGSUSED */ 4355 static void 4356 do_show_etherstub(int argc, char *argv[], const char *use) 4357 { 4358 do_show_vnic_common(argc, argv, use, B_TRUE); 4359 } 4360 4361 static void 4362 link_stats(datalink_id_t linkid, uint_t interval, char *fields_str, 4363 show_state_t *state) 4364 { 4365 print_field_t **fields; 4366 uint_t nfields; 4367 4368 fields = parse_output_fields(fields_str, devs_fields, DEVS_MAX_FIELDS, 4369 CMD_TYPE_ANY, &nfields); 4370 if (fields == NULL) { 4371 die("invalid field(s) specified"); 4372 return; 4373 } 4374 4375 state->ls_print.ps_fields = fields; 4376 state->ls_print.ps_nfields = nfields; 4377 4378 /* 4379 * If an interval is specified, continuously show the stats 4380 * only for the first MAC port. 4381 */ 4382 state->ls_firstonly = (interval != 0); 4383 4384 if (!state->ls_parseable) 4385 print_header(&state->ls_print); 4386 for (;;) { 4387 state->ls_donefirst = B_FALSE; 4388 if (linkid == DATALINK_ALL_LINKID) { 4389 (void) dladm_walk_datalink_id(show_link_stats, state, 4390 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 4391 DLADM_OPT_ACTIVE); 4392 } else { 4393 (void) show_link_stats(linkid, state); 4394 } 4395 4396 if (interval == 0) 4397 break; 4398 4399 (void) sleep(interval); 4400 } 4401 } 4402 4403 static void 4404 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) 4405 { 4406 /* 4407 * If an interval is specified, continuously show the stats 4408 * only for the first group. 4409 */ 4410 state->gs_firstonly = (interval != 0); 4411 4412 for (;;) { 4413 state->gs_donefirst = B_FALSE; 4414 if (linkid == DATALINK_ALL_LINKID) 4415 (void) dladm_walk_datalink_id(show_aggr, state, 4416 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 4417 DLADM_OPT_ACTIVE); 4418 else 4419 (void) show_aggr(linkid, state); 4420 4421 if (interval == 0) 4422 break; 4423 4424 (void) sleep(interval); 4425 } 4426 } 4427 4428 /* ARGSUSED */ 4429 static void 4430 vnic_stats(show_vnic_state_t *sp, uint32_t interval) 4431 { 4432 show_vnic_state_t state; 4433 boolean_t specific_link, specific_dev; 4434 4435 /* Display vnic statistics */ 4436 dump_vnics_head(sp->vs_link); 4437 4438 bzero(&state, sizeof (state)); 4439 state.vs_stats = B_TRUE; 4440 state.vs_vnic_id = sp->vs_vnic_id; 4441 state.vs_link_id = sp->vs_link_id; 4442 4443 /* 4444 * If an interval is specified, and a vnic ID is not specified, 4445 * continuously show the stats only for the first vnic. 4446 */ 4447 specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID); 4448 specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID); 4449 4450 for (;;) { 4451 /* Get stats for each vnic */ 4452 state.vs_found = B_FALSE; 4453 state.vs_donefirst = B_FALSE; 4454 state.vs_printstats = B_FALSE; 4455 state.vs_flags = DLADM_OPT_ACTIVE; 4456 4457 if (!specific_link) { 4458 (void) dladm_walk_datalink_id(show_vnic, &state, 4459 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 4460 DLADM_OPT_ACTIVE); 4461 } else { 4462 (void) show_vnic(sp->vs_vnic_id, &state); 4463 if (state.vs_status != DLADM_STATUS_OK) { 4464 die_dlerr(state.vs_status, 4465 "failed to show vnic '%s'", sp->vs_vnic); 4466 } 4467 } 4468 4469 if (specific_link && !state.vs_found) 4470 die("non-existent vnic '%s'", sp->vs_vnic); 4471 if (specific_dev && !state.vs_found) 4472 die("device %s has no vnics", sp->vs_link); 4473 4474 /* Show totals */ 4475 if ((specific_link | specific_dev) && !interval) { 4476 (void) printf("Total"); 4477 (void) printf("\t%-10llu", 4478 state.vs_totalstats.ipackets); 4479 (void) printf("%-12llu", 4480 state.vs_totalstats.rbytes); 4481 (void) printf("%-10llu", 4482 state.vs_totalstats.opackets); 4483 (void) printf("%-12llu\n", 4484 state.vs_totalstats.obytes); 4485 } 4486 4487 /* Show stats for each vnic */ 4488 state.vs_donefirst = B_FALSE; 4489 state.vs_printstats = B_TRUE; 4490 4491 if (!specific_link) { 4492 (void) dladm_walk_datalink_id(show_vnic, &state, 4493 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 4494 DLADM_OPT_ACTIVE); 4495 } else { 4496 (void) show_vnic(sp->vs_vnic_id, &state); 4497 if (state.vs_status != DLADM_STATUS_OK) { 4498 die_dlerr(state.vs_status, 4499 "failed to show vnic '%s'", sp->vs_vnic); 4500 } 4501 } 4502 4503 if (interval == 0) 4504 break; 4505 4506 (void) sleep(interval); 4507 } 4508 } 4509 4510 static void 4511 get_mac_stats(const char *dev, pktsum_t *stats) 4512 { 4513 kstat_ctl_t *kcp; 4514 kstat_t *ksp; 4515 char module[DLPI_LINKNAME_MAX]; 4516 uint_t instance; 4517 4518 4519 bzero(stats, sizeof (*stats)); 4520 4521 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 4522 return; 4523 4524 if ((kcp = kstat_open()) == NULL) { 4525 warn("kstat open operation failed"); 4526 return; 4527 } 4528 4529 ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL); 4530 if (ksp != NULL) 4531 dladm_get_stats(kcp, ksp, stats); 4532 4533 (void) kstat_close(kcp); 4534 4535 } 4536 4537 static void 4538 get_link_stats(const char *link, pktsum_t *stats) 4539 { 4540 kstat_ctl_t *kcp; 4541 kstat_t *ksp; 4542 4543 bzero(stats, sizeof (*stats)); 4544 4545 if ((kcp = kstat_open()) == NULL) { 4546 warn("kstat_open operation failed"); 4547 return; 4548 } 4549 4550 ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL); 4551 4552 if (ksp != NULL) 4553 dladm_get_stats(kcp, ksp, stats); 4554 4555 (void) kstat_close(kcp); 4556 } 4557 4558 static int 4559 query_kstat(char *module, int instance, const char *name, const char *stat, 4560 uint8_t type, void *val) 4561 { 4562 kstat_ctl_t *kcp; 4563 kstat_t *ksp; 4564 4565 if ((kcp = kstat_open()) == NULL) { 4566 warn("kstat open operation failed"); 4567 return (-1); 4568 } 4569 4570 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 4571 /* 4572 * The kstat query could fail if the underlying MAC 4573 * driver was already detached. 4574 */ 4575 goto bail; 4576 } 4577 4578 if (kstat_read(kcp, ksp, NULL) == -1) { 4579 warn("kstat read failed"); 4580 goto bail; 4581 } 4582 4583 if (dladm_kstat_value(ksp, stat, type, val) < 0) 4584 goto bail; 4585 4586 (void) kstat_close(kcp); 4587 return (0); 4588 4589 bail: 4590 (void) kstat_close(kcp); 4591 return (-1); 4592 } 4593 4594 static int 4595 get_one_kstat(const char *name, const char *stat, uint8_t type, 4596 void *val, boolean_t islink) 4597 { 4598 char module[DLPI_LINKNAME_MAX]; 4599 uint_t instance; 4600 4601 if (islink) { 4602 return (query_kstat("link", 0, name, stat, type, val)); 4603 } else { 4604 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS) 4605 return (-1); 4606 4607 return (query_kstat(module, instance, "mac", stat, type, val)); 4608 } 4609 } 4610 4611 static uint64_t 4612 get_ifspeed(const char *name, boolean_t islink) 4613 { 4614 uint64_t ifspeed = 0; 4615 4616 (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64, 4617 &ifspeed, islink); 4618 4619 return (ifspeed); 4620 } 4621 4622 static const char * 4623 get_linkstate(const char *name, boolean_t islink, char *buf) 4624 { 4625 link_state_t linkstate; 4626 4627 if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32, 4628 &linkstate, islink) != 0) { 4629 (void) strlcpy(buf, "?", DLADM_STRSIZE); 4630 return (buf); 4631 } 4632 return (dladm_linkstate2str(linkstate, buf)); 4633 } 4634 4635 static const char * 4636 get_linkduplex(const char *name, boolean_t islink, char *buf) 4637 { 4638 link_duplex_t linkduplex; 4639 4640 if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32, 4641 &linkduplex, islink) != 0) { 4642 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 4643 return (buf); 4644 } 4645 4646 return (dladm_linkduplex2str(linkduplex, buf)); 4647 } 4648 4649 typedef struct { 4650 char *s_buf; 4651 char **s_fields; /* array of pointer to the fields in s_buf */ 4652 uint_t s_nfields; /* the number of fields in s_buf */ 4653 } split_t; 4654 4655 /* 4656 * Free the split_t structure pointed to by `sp'. 4657 */ 4658 static void 4659 splitfree(split_t *sp) 4660 { 4661 free(sp->s_buf); 4662 free(sp->s_fields); 4663 free(sp); 4664 } 4665 4666 /* 4667 * Split `str' into at most `maxfields' fields, each field at most `maxlen' in 4668 * length. Return a pointer to a split_t containing the split fields, or NULL 4669 * on failure. 4670 */ 4671 static split_t * 4672 split(const char *str, uint_t maxfields, uint_t maxlen) 4673 { 4674 char *field, *token, *lasts = NULL; 4675 split_t *sp; 4676 4677 if (*str == '\0' || maxfields == 0 || maxlen == 0) 4678 return (NULL); 4679 4680 sp = calloc(sizeof (split_t), 1); 4681 if (sp == NULL) 4682 return (NULL); 4683 4684 sp->s_buf = strdup(str); 4685 sp->s_fields = malloc(sizeof (char *) * maxfields); 4686 if (sp->s_buf == NULL || sp->s_fields == NULL) 4687 goto fail; 4688 4689 token = sp->s_buf; 4690 while ((field = strtok_r(token, ",", &lasts)) != NULL) { 4691 if (sp->s_nfields == maxfields || strlen(field) > maxlen) 4692 goto fail; 4693 token = NULL; 4694 sp->s_fields[sp->s_nfields++] = field; 4695 } 4696 return (sp); 4697 fail: 4698 splitfree(sp); 4699 return (NULL); 4700 } 4701 4702 static int 4703 parse_wifi_fields(char *str, print_field_t ***fields, uint_t *countp, 4704 uint_t cmdtype) 4705 { 4706 4707 if (cmdtype == WIFI_CMD_SCAN) { 4708 if (str == NULL) 4709 str = def_scan_wifi_fields; 4710 if (strcasecmp(str, "all") == 0) 4711 str = all_scan_wifi_fields; 4712 } else if (cmdtype == WIFI_CMD_SHOW) { 4713 if (str == NULL) 4714 str = def_show_wifi_fields; 4715 if (strcasecmp(str, "all") == 0) 4716 str = all_show_wifi_fields; 4717 } else { 4718 return (-1); 4719 } 4720 *fields = parse_output_fields(str, wifi_fields, WIFI_MAX_FIELDS, 4721 cmdtype, countp); 4722 if (*fields != NULL) 4723 return (0); 4724 return (-1); 4725 } 4726 static print_field_t ** 4727 parse_output_fields(char *str, print_field_t *template, int max_fields, 4728 uint_t cmdtype, uint_t *countp) 4729 { 4730 split_t *sp; 4731 boolean_t good_match = B_FALSE; 4732 uint_t i, j; 4733 print_field_t **pf = NULL; 4734 4735 sp = split(str, max_fields, MAX_FIELD_LEN); 4736 4737 if (sp == NULL) 4738 return (NULL); 4739 4740 pf = malloc(sp->s_nfields * sizeof (print_field_t *)); 4741 if (pf == NULL) 4742 goto fail; 4743 4744 for (i = 0; i < sp->s_nfields; i++) { 4745 for (j = 0; j < max_fields; j++) { 4746 if (strcasecmp(sp->s_fields[i], 4747 template[j].pf_name) == 0) { 4748 good_match = template[j]. pf_cmdtype & cmdtype; 4749 break; 4750 } 4751 } 4752 if (!good_match) 4753 goto fail; 4754 4755 good_match = B_FALSE; 4756 pf[i] = &template[j]; 4757 } 4758 *countp = i; 4759 splitfree(sp); 4760 return (pf); 4761 fail: 4762 free(pf); 4763 splitfree(sp); 4764 return (NULL); 4765 } 4766 4767 typedef struct print_wifi_state { 4768 char *ws_link; 4769 boolean_t ws_parseable; 4770 boolean_t ws_header; 4771 print_state_t ws_print_state; 4772 } print_wifi_state_t; 4773 4774 typedef struct wlan_scan_args_s { 4775 print_wifi_state_t *ws_state; 4776 void *ws_attr; 4777 } wlan_scan_args_t; 4778 4779 static void 4780 print_field(print_state_t *statep, print_field_t *pfp, const char *value, 4781 boolean_t parseable) 4782 { 4783 uint_t width = pfp->pf_width; 4784 uint_t valwidth; 4785 uint_t compress; 4786 4787 /* 4788 * Parsable fields are separated by ':'. If such a field contains 4789 * a ':' or '\', this character is prefixed by a '\'. 4790 */ 4791 if (parseable) { 4792 char c; 4793 4794 if (statep->ps_nfields == 1) { 4795 (void) printf("%s", value); 4796 return; 4797 } 4798 while ((c = *value++) != '\0') { 4799 if (c == ':' || c == '\\') 4800 (void) putchar('\\'); 4801 (void) putchar(c); 4802 } 4803 if (!statep->ps_lastfield) 4804 (void) putchar(':'); 4805 return; 4806 } else { 4807 if (value[0] == '\0') 4808 value = STR_UNDEF_VAL; 4809 if (statep->ps_lastfield) { 4810 (void) printf("%s", value); 4811 statep->ps_overflow = 0; 4812 return; 4813 } 4814 4815 valwidth = strlen(value); 4816 if (valwidth > width) { 4817 statep->ps_overflow += valwidth - width; 4818 } else if (valwidth < width && statep->ps_overflow > 0) { 4819 compress = min(statep->ps_overflow, width - valwidth); 4820 statep->ps_overflow -= compress; 4821 width -= compress; 4822 } 4823 (void) printf("%-*s", width, value); 4824 } 4825 4826 if (!statep->ps_lastfield) 4827 (void) putchar(' '); 4828 } 4829 4830 static char * 4831 print_wlan_attr(print_field_t *wfp, void *warg) 4832 { 4833 static char buf[DLADM_STRSIZE]; 4834 wlan_scan_args_t *w = warg; 4835 print_wifi_state_t *statep = w->ws_state; 4836 dladm_wlan_attr_t *attrp = w->ws_attr; 4837 4838 if (wfp->pf_index == 0) { 4839 return ((char *)statep->ws_link); 4840 } 4841 4842 if ((wfp->pf_index & attrp->wa_valid) == 0) { 4843 return (""); 4844 } 4845 4846 switch (wfp->pf_index) { 4847 case DLADM_WLAN_ATTR_ESSID: 4848 (void) dladm_wlan_essid2str(&attrp->wa_essid, buf); 4849 break; 4850 case DLADM_WLAN_ATTR_BSSID: 4851 (void) dladm_wlan_bssid2str(&attrp->wa_bssid, buf); 4852 break; 4853 case DLADM_WLAN_ATTR_SECMODE: 4854 (void) dladm_wlan_secmode2str(&attrp->wa_secmode, buf); 4855 break; 4856 case DLADM_WLAN_ATTR_STRENGTH: 4857 (void) dladm_wlan_strength2str(&attrp->wa_strength, buf); 4858 break; 4859 case DLADM_WLAN_ATTR_MODE: 4860 (void) dladm_wlan_mode2str(&attrp->wa_mode, buf); 4861 break; 4862 case DLADM_WLAN_ATTR_SPEED: 4863 (void) dladm_wlan_speed2str(&attrp->wa_speed, buf); 4864 (void) strlcat(buf, "Mb", sizeof (buf)); 4865 break; 4866 case DLADM_WLAN_ATTR_AUTH: 4867 (void) dladm_wlan_auth2str(&attrp->wa_auth, buf); 4868 break; 4869 case DLADM_WLAN_ATTR_BSSTYPE: 4870 (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf); 4871 break; 4872 } 4873 4874 return (buf); 4875 } 4876 4877 static boolean_t 4878 print_scan_results(void *arg, dladm_wlan_attr_t *attrp) 4879 { 4880 print_wifi_state_t *statep = arg; 4881 wlan_scan_args_t warg; 4882 4883 if (statep->ws_header) { 4884 statep->ws_header = B_FALSE; 4885 if (!statep->ws_parseable) 4886 print_header(&statep->ws_print_state); 4887 } 4888 4889 statep->ws_print_state.ps_overflow = 0; 4890 bzero(&warg, sizeof (warg)); 4891 warg.ws_state = statep; 4892 warg.ws_attr = attrp; 4893 dladm_print_output(&statep->ws_print_state, statep->ws_parseable, 4894 print_wlan_attr, &warg); 4895 return (B_TRUE); 4896 } 4897 4898 static int 4899 scan_wifi(datalink_id_t linkid, void *arg) 4900 { 4901 print_wifi_state_t *statep = arg; 4902 dladm_status_t status; 4903 char link[MAXLINKNAMELEN]; 4904 4905 if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, 4906 sizeof (link))) != DLADM_STATUS_OK) { 4907 return (DLADM_WALK_CONTINUE); 4908 } 4909 4910 statep->ws_link = link; 4911 status = dladm_wlan_scan(linkid, statep, print_scan_results); 4912 if (status != DLADM_STATUS_OK) 4913 die_dlerr(status, "cannot scan link '%s'", statep->ws_link); 4914 4915 return (DLADM_WALK_CONTINUE); 4916 } 4917 4918 static char * 4919 print_link_attr(print_field_t *wfp, void *warg) 4920 { 4921 static char buf[DLADM_STRSIZE]; 4922 char *ptr; 4923 wlan_scan_args_t *w = warg, w1; 4924 print_wifi_state_t *statep = w->ws_state; 4925 dladm_wlan_linkattr_t *attrp = w->ws_attr; 4926 4927 if (strcmp(wfp->pf_name, "status") == 0) { 4928 if ((wfp->pf_index & attrp->la_valid) != 0) 4929 (void) dladm_wlan_linkstatus2str( 4930 &attrp->la_status, buf); 4931 return (buf); 4932 } 4933 statep->ws_print_state.ps_overflow = 0; 4934 bzero(&w1, sizeof (w1)); 4935 w1.ws_state = statep; 4936 w1.ws_attr = &attrp->la_wlan_attr; 4937 ptr = print_wlan_attr(wfp, &w1); 4938 return (ptr); 4939 } 4940 4941 static int 4942 show_wifi(datalink_id_t linkid, void *arg) 4943 { 4944 print_wifi_state_t *statep = arg; 4945 dladm_wlan_linkattr_t attr; 4946 dladm_status_t status; 4947 char link[MAXLINKNAMELEN]; 4948 wlan_scan_args_t warg; 4949 4950 if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, 4951 sizeof (link))) != DLADM_STATUS_OK) { 4952 return (DLADM_WALK_CONTINUE); 4953 } 4954 4955 /* dladm_wlan_get_linkattr() memsets attr with 0 */ 4956 status = dladm_wlan_get_linkattr(linkid, &attr); 4957 if (status != DLADM_STATUS_OK) 4958 die_dlerr(status, "cannot get link attributes for %s", link); 4959 4960 statep->ws_link = link; 4961 4962 if (statep->ws_header) { 4963 statep->ws_header = B_FALSE; 4964 if (!statep->ws_parseable) 4965 print_header(&statep->ws_print_state); 4966 } 4967 4968 statep->ws_print_state.ps_overflow = 0; 4969 bzero(&warg, sizeof (warg)); 4970 warg.ws_state = statep; 4971 warg.ws_attr = &attr; 4972 dladm_print_output(&statep->ws_print_state, statep->ws_parseable, 4973 print_link_attr, &warg); 4974 return (DLADM_WALK_CONTINUE); 4975 } 4976 4977 static void 4978 do_display_wifi(int argc, char **argv, int cmd, const char *use) 4979 { 4980 int option; 4981 char *fields_str = NULL; 4982 print_field_t **fields; 4983 int (*callback)(datalink_id_t, void *); 4984 uint_t nfields; 4985 print_wifi_state_t state; 4986 datalink_id_t linkid = DATALINK_ALL_LINKID; 4987 dladm_status_t status; 4988 4989 if (cmd == WIFI_CMD_SCAN) 4990 callback = scan_wifi; 4991 else if (cmd == WIFI_CMD_SHOW) 4992 callback = show_wifi; 4993 else 4994 return; 4995 4996 state.ws_parseable = B_FALSE; 4997 state.ws_header = B_TRUE; 4998 opterr = 0; 4999 while ((option = getopt_long(argc, argv, ":o:p", 5000 wifi_longopts, NULL)) != -1) { 5001 switch (option) { 5002 case 'o': 5003 fields_str = optarg; 5004 break; 5005 case 'p': 5006 state.ws_parseable = B_TRUE; 5007 break; 5008 default: 5009 die_opterr(optopt, option, use); 5010 } 5011 } 5012 5013 if (state.ws_parseable && fields_str == NULL) 5014 die("-p requires -o"); 5015 5016 if (state.ws_parseable && strcasecmp(fields_str, "all") == 0) 5017 die("\"-o all\" is invalid with -p"); 5018 5019 if (optind == (argc - 1)) { 5020 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 5021 NULL, NULL)) != DLADM_STATUS_OK) { 5022 die_dlerr(status, "link %s is not valid", argv[optind]); 5023 } 5024 } else if (optind != argc) { 5025 usage(); 5026 } 5027 5028 if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) 5029 die("invalid field(s) specified"); 5030 5031 bzero(&state.ws_print_state, sizeof (state.ws_print_state)); 5032 state.ws_print_state.ps_fields = fields; 5033 state.ws_print_state.ps_nfields = nfields; 5034 5035 if (linkid == DATALINK_ALL_LINKID) { 5036 (void) dladm_walk_datalink_id(callback, &state, 5037 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 5038 } else { 5039 (void) (*callback)(linkid, &state); 5040 } 5041 free(fields); 5042 } 5043 5044 static void 5045 do_scan_wifi(int argc, char **argv, const char *use) 5046 { 5047 do_display_wifi(argc, argv, WIFI_CMD_SCAN, use); 5048 } 5049 5050 static void 5051 do_show_wifi(int argc, char **argv, const char *use) 5052 { 5053 do_display_wifi(argc, argv, WIFI_CMD_SHOW, use); 5054 } 5055 5056 typedef struct wlan_count_attr { 5057 uint_t wc_count; 5058 datalink_id_t wc_linkid; 5059 } wlan_count_attr_t; 5060 5061 static int 5062 do_count_wlan(datalink_id_t linkid, void *arg) 5063 { 5064 wlan_count_attr_t *cp = arg; 5065 5066 if (cp->wc_count == 0) 5067 cp->wc_linkid = linkid; 5068 cp->wc_count++; 5069 return (DLADM_WALK_CONTINUE); 5070 } 5071 5072 static int 5073 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) 5074 { 5075 uint_t i; 5076 split_t *sp; 5077 dladm_wlan_key_t *wk; 5078 5079 sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_KEYNAME_LEN); 5080 if (sp == NULL) 5081 return (-1); 5082 5083 wk = malloc(sp->s_nfields * sizeof (dladm_wlan_key_t)); 5084 if (wk == NULL) 5085 goto fail; 5086 5087 for (i = 0; i < sp->s_nfields; i++) { 5088 char *s; 5089 dladm_secobj_class_t class; 5090 dladm_status_t status; 5091 5092 (void) strlcpy(wk[i].wk_name, sp->s_fields[i], 5093 DLADM_WLAN_MAX_KEYNAME_LEN); 5094 5095 wk[i].wk_idx = 1; 5096 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 5097 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 5098 goto fail; 5099 5100 wk[i].wk_idx = (uint_t)(s[1] - '0'); 5101 *s = '\0'; 5102 } 5103 wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN; 5104 5105 status = dladm_get_secobj(wk[i].wk_name, &class, 5106 wk[i].wk_val, &wk[i].wk_len, 0); 5107 if (status != DLADM_STATUS_OK) { 5108 if (status == DLADM_STATUS_NOTFOUND) { 5109 status = dladm_get_secobj(wk[i].wk_name, 5110 &class, wk[i].wk_val, &wk[i].wk_len, 5111 DLADM_OPT_PERSIST); 5112 } 5113 if (status != DLADM_STATUS_OK) 5114 goto fail; 5115 } 5116 wk[i].wk_class = class; 5117 } 5118 *keys = wk; 5119 *key_countp = i; 5120 splitfree(sp); 5121 return (0); 5122 fail: 5123 free(wk); 5124 splitfree(sp); 5125 return (-1); 5126 } 5127 5128 static void 5129 do_connect_wifi(int argc, char **argv, const char *use) 5130 { 5131 int option; 5132 dladm_wlan_attr_t attr, *attrp; 5133 dladm_status_t status = DLADM_STATUS_OK; 5134 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 5135 datalink_id_t linkid = DATALINK_ALL_LINKID; 5136 dladm_wlan_key_t *keys = NULL; 5137 uint_t key_count = 0; 5138 uint_t flags = 0; 5139 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 5140 char buf[DLADM_STRSIZE]; 5141 5142 opterr = 0; 5143 (void) memset(&attr, 0, sizeof (attr)); 5144 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 5145 wifi_longopts, NULL)) != -1) { 5146 switch (option) { 5147 case 'e': 5148 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 5149 if (status != DLADM_STATUS_OK) 5150 die("invalid ESSID '%s'", optarg); 5151 5152 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 5153 /* 5154 * Try to connect without doing a scan. 5155 */ 5156 flags |= DLADM_WLAN_CONNECT_NOSCAN; 5157 break; 5158 case 'i': 5159 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 5160 if (status != DLADM_STATUS_OK) 5161 die("invalid BSSID %s", optarg); 5162 5163 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 5164 break; 5165 case 'a': 5166 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 5167 if (status != DLADM_STATUS_OK) 5168 die("invalid authentication mode '%s'", optarg); 5169 5170 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 5171 break; 5172 case 'm': 5173 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 5174 if (status != DLADM_STATUS_OK) 5175 die("invalid mode '%s'", optarg); 5176 5177 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 5178 break; 5179 case 'b': 5180 if ((status = dladm_wlan_str2bsstype(optarg, 5181 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 5182 die("invalid bsstype '%s'", optarg); 5183 } 5184 5185 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 5186 break; 5187 case 's': 5188 if ((status = dladm_wlan_str2secmode(optarg, 5189 &attr.wa_secmode)) != DLADM_STATUS_OK) { 5190 die("invalid security mode '%s'", optarg); 5191 } 5192 5193 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 5194 break; 5195 case 'k': 5196 if (parse_wlan_keys(optarg, &keys, &key_count) < 0) 5197 die("invalid key(s) '%s'", optarg); 5198 5199 if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP) 5200 keysecmode = DLADM_WLAN_SECMODE_WEP; 5201 else 5202 keysecmode = DLADM_WLAN_SECMODE_WPA; 5203 break; 5204 case 'T': 5205 if (strcasecmp(optarg, "forever") == 0) { 5206 timeout = -1; 5207 break; 5208 } 5209 if (!str2int(optarg, &timeout) || timeout < 0) 5210 die("invalid timeout value '%s'", optarg); 5211 break; 5212 case 'c': 5213 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 5214 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 5215 break; 5216 default: 5217 die_opterr(optopt, option, use); 5218 break; 5219 } 5220 } 5221 5222 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 5223 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) { 5224 die("key required for security mode '%s'", 5225 dladm_wlan_secmode2str(&attr.wa_secmode, buf)); 5226 } 5227 } else { 5228 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 5229 attr.wa_secmode != keysecmode) 5230 die("incompatible -s and -k options"); 5231 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 5232 attr.wa_secmode = keysecmode; 5233 } 5234 5235 if (optind == (argc - 1)) { 5236 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 5237 NULL, NULL)) != DLADM_STATUS_OK) { 5238 die_dlerr(status, "link %s is not valid", argv[optind]); 5239 } 5240 } else if (optind != argc) { 5241 usage(); 5242 } 5243 5244 if (linkid == DATALINK_ALL_LINKID) { 5245 wlan_count_attr_t wcattr; 5246 5247 wcattr.wc_linkid = DATALINK_INVALID_LINKID; 5248 wcattr.wc_count = 0; 5249 (void) dladm_walk_datalink_id(do_count_wlan, &wcattr, 5250 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 5251 if (wcattr.wc_count == 0) { 5252 die("no wifi links are available"); 5253 } else if (wcattr.wc_count > 1) { 5254 die("link name is required when more than one wifi " 5255 "link is available"); 5256 } 5257 linkid = wcattr.wc_linkid; 5258 } 5259 attrp = (attr.wa_valid == 0) ? NULL : &attr; 5260 again: 5261 if ((status = dladm_wlan_connect(linkid, attrp, timeout, keys, 5262 key_count, flags)) != DLADM_STATUS_OK) { 5263 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 5264 /* 5265 * Try again with scanning and filtering. 5266 */ 5267 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 5268 goto again; 5269 } 5270 5271 if (status == DLADM_STATUS_NOTFOUND) { 5272 if (attr.wa_valid == 0) { 5273 die("no wifi networks are available"); 5274 } else { 5275 die("no wifi networks with the specified " 5276 "criteria are available"); 5277 } 5278 } 5279 die_dlerr(status, "cannot connect"); 5280 } 5281 free(keys); 5282 } 5283 5284 /* ARGSUSED */ 5285 static int 5286 do_all_disconnect_wifi(datalink_id_t linkid, void *arg) 5287 { 5288 dladm_status_t status; 5289 5290 status = dladm_wlan_disconnect(linkid); 5291 if (status != DLADM_STATUS_OK) 5292 warn_dlerr(status, "cannot disconnect link"); 5293 5294 return (DLADM_WALK_CONTINUE); 5295 } 5296 5297 static void 5298 do_disconnect_wifi(int argc, char **argv, const char *use) 5299 { 5300 int option; 5301 datalink_id_t linkid = DATALINK_ALL_LINKID; 5302 boolean_t all_links = B_FALSE; 5303 dladm_status_t status; 5304 wlan_count_attr_t wcattr; 5305 5306 opterr = 0; 5307 while ((option = getopt_long(argc, argv, ":a", 5308 wifi_longopts, NULL)) != -1) { 5309 switch (option) { 5310 case 'a': 5311 all_links = B_TRUE; 5312 break; 5313 default: 5314 die_opterr(optopt, option, use); 5315 break; 5316 } 5317 } 5318 5319 if (optind == (argc - 1)) { 5320 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 5321 NULL, NULL)) != DLADM_STATUS_OK) { 5322 die_dlerr(status, "link %s is not valid", argv[optind]); 5323 } 5324 } else if (optind != argc) { 5325 usage(); 5326 } 5327 5328 if (linkid == DATALINK_ALL_LINKID) { 5329 if (!all_links) { 5330 wcattr.wc_linkid = linkid; 5331 wcattr.wc_count = 0; 5332 (void) dladm_walk_datalink_id(do_count_wlan, &wcattr, 5333 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 5334 if (wcattr.wc_count == 0) { 5335 die("no wifi links are available"); 5336 } else if (wcattr.wc_count > 1) { 5337 die("link name is required when more than " 5338 "one wifi link is available"); 5339 } 5340 linkid = wcattr.wc_linkid; 5341 } else { 5342 (void) dladm_walk_datalink_id(do_all_disconnect_wifi, 5343 NULL, DATALINK_CLASS_PHYS, DL_WIFI, 5344 DLADM_OPT_ACTIVE); 5345 return; 5346 } 5347 } 5348 status = dladm_wlan_disconnect(linkid); 5349 if (status != DLADM_STATUS_OK) 5350 die_dlerr(status, "cannot disconnect"); 5351 } 5352 5353 static void 5354 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, 5355 const char *propname, dladm_prop_type_t type, 5356 const char *format, char **pptr) 5357 { 5358 int i; 5359 char *ptr, *lim; 5360 char buf[DLADM_STRSIZE]; 5361 char *unknown = "--", *notsup = ""; 5362 char **propvals = statep->ls_propvals; 5363 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5364 dladm_status_t status; 5365 5366 status = dladm_get_linkprop(linkid, type, propname, propvals, &valcnt); 5367 if (status != DLADM_STATUS_OK) { 5368 if (status == DLADM_STATUS_TEMPONLY) { 5369 if (type == DLADM_PROP_VAL_MODIFIABLE && 5370 statep->ls_persist) { 5371 valcnt = 1; 5372 propvals = &unknown; 5373 } else { 5374 statep->ls_status = status; 5375 statep->ls_retstatus = status; 5376 return; 5377 } 5378 } else if (status == DLADM_STATUS_NOTSUP || 5379 statep->ls_persist) { 5380 valcnt = 1; 5381 if (type == DLADM_PROP_VAL_CURRENT || 5382 type == DLADM_PROP_VAL_PERM) 5383 propvals = &unknown; 5384 else 5385 propvals = ¬sup; 5386 } else if (status == DLADM_STATUS_NOTDEFINED) { 5387 propvals = ¬sup; /* STR_UNDEF_VAL */ 5388 } else { 5389 if (statep->ls_proplist && 5390 statep->ls_status == DLADM_STATUS_OK) { 5391 warn_dlerr(status, 5392 "cannot get link property '%s' for %s", 5393 propname, statep->ls_link); 5394 } 5395 statep->ls_status = status; 5396 statep->ls_retstatus = status; 5397 return; 5398 } 5399 } 5400 5401 statep->ls_status = DLADM_STATUS_OK; 5402 5403 ptr = buf; 5404 lim = buf + DLADM_STRSIZE; 5405 for (i = 0; i < valcnt; i++) { 5406 if (propvals[i][0] == '\0' && !statep->ls_parseable) 5407 ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL","); 5408 else 5409 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 5410 if (ptr >= lim) 5411 break; 5412 } 5413 if (valcnt > 0) 5414 buf[strlen(buf) - 1] = '\0'; 5415 5416 lim = statep->ls_line + MAX_PROP_LINE; 5417 if (statep->ls_parseable) { 5418 *pptr += snprintf(*pptr, lim - *pptr, 5419 "%s", buf); 5420 } else { 5421 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 5422 } 5423 } 5424 5425 static char * 5426 linkprop_callback(print_field_t *pf, void *ls_arg) 5427 { 5428 linkprop_args_t *arg = ls_arg; 5429 char *propname = arg->ls_propname; 5430 show_linkprop_state_t *statep = arg->ls_state; 5431 char *ptr = statep->ls_line; 5432 char *lim = ptr + MAX_PROP_LINE; 5433 datalink_id_t linkid = arg->ls_linkid; 5434 5435 switch (pf->pf_index) { 5436 case LINKPROP_LINK: 5437 (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); 5438 break; 5439 case LINKPROP_PROPERTY: 5440 (void) snprintf(ptr, lim - ptr, "%s", propname); 5441 break; 5442 case LINKPROP_VALUE: 5443 print_linkprop(linkid, statep, propname, 5444 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 5445 DLADM_PROP_VAL_CURRENT, "%s", &ptr); 5446 /* 5447 * If we failed to query the link property, for example, query 5448 * the persistent value of a non-persistable link property, 5449 * simply skip the output. 5450 */ 5451 if (statep->ls_status != DLADM_STATUS_OK) 5452 goto skip; 5453 ptr = statep->ls_line; 5454 break; 5455 case LINKPROP_PERM: 5456 print_linkprop(linkid, statep, propname, 5457 DLADM_PROP_VAL_PERM, "%s", &ptr); 5458 if (statep->ls_status != DLADM_STATUS_OK) 5459 goto skip; 5460 ptr = statep->ls_line; 5461 break; 5462 case LINKPROP_DEFAULT: 5463 print_linkprop(linkid, statep, propname, 5464 DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 5465 if (statep->ls_status != DLADM_STATUS_OK) 5466 goto skip; 5467 ptr = statep->ls_line; 5468 break; 5469 case LINKPROP_POSSIBLE: 5470 print_linkprop(linkid, statep, propname, 5471 DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 5472 if (statep->ls_status != DLADM_STATUS_OK) 5473 goto skip; 5474 ptr = statep->ls_line; 5475 break; 5476 default: 5477 die("invalid input"); 5478 break; 5479 } 5480 return (ptr); 5481 skip: 5482 if (statep->ls_status != DLADM_STATUS_OK) 5483 return (NULL); 5484 else 5485 return (""); 5486 } 5487 5488 static boolean_t 5489 linkprop_is_supported(datalink_id_t linkid, const char *propname, 5490 show_linkprop_state_t *statep) 5491 { 5492 dladm_status_t status; 5493 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5494 5495 status = dladm_get_linkprop(linkid, DLADM_PROP_VAL_DEFAULT, 5496 propname, statep->ls_propvals, &valcnt); 5497 5498 if (status == DLADM_STATUS_OK) 5499 return (B_TRUE); 5500 5501 /* 5502 * A system wide default value is not available for the 5503 * property. Check if current value can be retrieved. 5504 */ 5505 status = dladm_get_linkprop(linkid, DLADM_PROP_VAL_CURRENT, 5506 propname, statep->ls_propvals, &valcnt); 5507 5508 return (status == DLADM_STATUS_OK); 5509 } 5510 5511 static int 5512 show_linkprop(datalink_id_t linkid, const char *propname, void *arg) 5513 { 5514 show_linkprop_state_t *statep = arg; 5515 linkprop_args_t ls_arg; 5516 5517 bzero(&ls_arg, sizeof (ls_arg)); 5518 ls_arg.ls_state = statep; 5519 ls_arg.ls_propname = (char *)propname; 5520 ls_arg.ls_linkid = linkid; 5521 5522 if (statep->ls_header) { 5523 statep->ls_header = B_FALSE; 5524 if (!statep->ls_parseable) 5525 print_header(&statep->ls_print); 5526 } 5527 if (!statep->ls_parseable && 5528 !linkprop_is_supported(linkid, propname, statep)) 5529 return (DLADM_WALK_CONTINUE); 5530 5531 dladm_print_output(&statep->ls_print, statep->ls_parseable, 5532 linkprop_callback, (void *)&ls_arg); 5533 5534 return (DLADM_WALK_CONTINUE); 5535 } 5536 5537 static void 5538 do_show_linkprop(int argc, char **argv, const char *use) 5539 { 5540 int option; 5541 dladm_arg_list_t *proplist = NULL; 5542 datalink_id_t linkid = DATALINK_ALL_LINKID; 5543 show_linkprop_state_t state; 5544 uint32_t flags = DLADM_OPT_ACTIVE; 5545 dladm_status_t status; 5546 char *fields_str = NULL; 5547 print_field_t **fields; 5548 uint_t nfields; 5549 boolean_t o_arg = B_FALSE; 5550 char *all_fields = 5551 "link,property,perm,value,default,possible"; 5552 5553 fields_str = all_fields; 5554 5555 opterr = 0; 5556 state.ls_propvals = NULL; 5557 state.ls_line = NULL; 5558 state.ls_parseable = B_FALSE; 5559 state.ls_persist = B_FALSE; 5560 state.ls_header = B_TRUE; 5561 state.ls_retstatus = DLADM_STATUS_OK; 5562 while ((option = getopt_long(argc, argv, ":p:cPo:", 5563 prop_longopts, NULL)) != -1) { 5564 switch (option) { 5565 case 'p': 5566 if (dladm_parse_link_props(optarg, &proplist, B_TRUE) 5567 != DLADM_STATUS_OK) 5568 die("invalid link properties specified"); 5569 break; 5570 case 'c': 5571 state.ls_parseable = B_TRUE; 5572 break; 5573 case 'P': 5574 state.ls_persist = B_TRUE; 5575 flags = DLADM_OPT_PERSIST; 5576 break; 5577 case 'o': 5578 o_arg = B_TRUE; 5579 if (strcasecmp(optarg, "all") == 0) 5580 fields_str = all_fields; 5581 else 5582 fields_str = optarg; 5583 break; 5584 default: 5585 die_opterr(optopt, option, use); 5586 break; 5587 } 5588 } 5589 5590 if (state.ls_parseable && !o_arg) 5591 die("-c requires -o"); 5592 5593 if (state.ls_parseable && fields_str == all_fields) 5594 die("\"-o all\" is invalid with -c"); 5595 5596 if (optind == (argc - 1)) { 5597 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 5598 NULL, NULL)) != DLADM_STATUS_OK) { 5599 die_dlerr(status, "link %s is not valid", argv[optind]); 5600 } 5601 } else if (optind != argc) { 5602 usage(); 5603 } 5604 5605 bzero(&state.ls_print, sizeof (print_state_t)); 5606 state.ls_proplist = proplist; 5607 state.ls_status = DLADM_STATUS_OK; 5608 5609 fields = parse_output_fields(fields_str, linkprop_fields, 5610 LINKPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 5611 5612 if (fields == NULL) { 5613 die("invalid field(s) specified"); 5614 return; 5615 } 5616 5617 state.ls_print.ps_fields = fields; 5618 state.ls_print.ps_nfields = nfields; 5619 if (linkid == DATALINK_ALL_LINKID) { 5620 (void) dladm_walk_datalink_id(show_linkprop_onelink, &state, 5621 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 5622 } else { 5623 (void) show_linkprop_onelink(linkid, &state); 5624 } 5625 dladm_free_props(proplist); 5626 5627 if (state.ls_retstatus != DLADM_STATUS_OK) 5628 exit(EXIT_FAILURE); 5629 } 5630 5631 static int 5632 show_linkprop_onelink(datalink_id_t linkid, void *arg) 5633 { 5634 int i; 5635 char *buf; 5636 uint32_t flags; 5637 dladm_arg_list_t *proplist = NULL; 5638 show_linkprop_state_t *statep = arg; 5639 dlpi_handle_t dh = NULL; 5640 5641 statep->ls_status = DLADM_STATUS_OK; 5642 5643 if (dladm_datalink_id2info(linkid, &flags, NULL, NULL, statep->ls_link, 5644 MAXLINKNAMELEN) != DLADM_STATUS_OK) { 5645 statep->ls_status = DLADM_STATUS_NOTFOUND; 5646 return (DLADM_WALK_CONTINUE); 5647 } 5648 5649 if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) || 5650 (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) { 5651 statep->ls_status = DLADM_STATUS_BADARG; 5652 return (DLADM_WALK_CONTINUE); 5653 } 5654 5655 proplist = statep->ls_proplist; 5656 5657 /* 5658 * When some WiFi links are opened for the first time, their hardware 5659 * automatically scans for APs and does other slow operations. Thus, 5660 * if there are no open links, the retrieval of link properties 5661 * (below) will proceed slowly unless we hold the link open. 5662 * 5663 * Note that failure of dlpi_open() does not necessarily mean invalid 5664 * link properties, because dlpi_open() may fail because of incorrect 5665 * autopush configuration. Therefore, we ingore the return value of 5666 * dlpi_open(). 5667 */ 5668 if (!statep->ls_persist) 5669 (void) dlpi_open(statep->ls_link, &dh, 0); 5670 5671 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 5672 DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 5673 if (buf == NULL) 5674 die("insufficient memory"); 5675 5676 statep->ls_propvals = (char **)(void *)buf; 5677 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 5678 statep->ls_propvals[i] = buf + 5679 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 5680 i * DLADM_PROP_VAL_MAX; 5681 } 5682 statep->ls_line = buf + 5683 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 5684 5685 if (proplist != NULL) { 5686 for (i = 0; i < proplist->al_count; i++) { 5687 (void) show_linkprop(linkid, 5688 proplist->al_info[i].ai_name, statep); 5689 } 5690 } else { 5691 (void) dladm_walk_linkprop(linkid, statep, show_linkprop); 5692 } 5693 if (dh != NULL) 5694 dlpi_close(dh); 5695 free(buf); 5696 return (DLADM_WALK_CONTINUE); 5697 } 5698 5699 static dladm_status_t 5700 set_linkprop_persist(datalink_id_t linkid, const char *prop_name, 5701 char **prop_val, uint_t val_cnt, boolean_t reset) 5702 { 5703 dladm_status_t status; 5704 5705 status = dladm_set_linkprop(linkid, prop_name, prop_val, val_cnt, 5706 DLADM_OPT_PERSIST); 5707 5708 if (status != DLADM_STATUS_OK) { 5709 warn_dlerr(status, "cannot persistently %s link property '%s'", 5710 reset ? "reset" : "set", prop_name); 5711 } 5712 return (status); 5713 } 5714 5715 static int 5716 reset_one_linkprop(datalink_id_t linkid, const char *propname, void *arg) 5717 { 5718 set_linkprop_state_t *statep = arg; 5719 dladm_status_t status; 5720 5721 status = dladm_set_linkprop(linkid, propname, NULL, 0, 5722 DLADM_OPT_ACTIVE); 5723 if (status != DLADM_STATUS_OK) { 5724 warn_dlerr(status, "cannot reset link property '%s' on '%s'", 5725 propname, statep->ls_name); 5726 } 5727 if (!statep->ls_temp) { 5728 dladm_status_t s; 5729 5730 s = set_linkprop_persist(linkid, propname, NULL, 0, 5731 statep->ls_reset); 5732 if (s != DLADM_STATUS_OK) 5733 status = s; 5734 } 5735 if (status != DLADM_STATUS_OK) 5736 statep->ls_status = status; 5737 5738 return (DLADM_WALK_CONTINUE); 5739 } 5740 5741 static void 5742 set_linkprop(int argc, char **argv, boolean_t reset, const char *use) 5743 { 5744 int i, option; 5745 char errmsg[DLADM_STRSIZE]; 5746 char *altroot = NULL; 5747 datalink_id_t linkid; 5748 boolean_t temp = B_FALSE; 5749 dladm_status_t status = DLADM_STATUS_OK; 5750 dladm_arg_list_t *proplist = NULL; 5751 5752 opterr = 0; 5753 while ((option = getopt_long(argc, argv, ":p:R:t", 5754 prop_longopts, NULL)) != -1) { 5755 switch (option) { 5756 case 'p': 5757 if (dladm_parse_link_props(optarg, &proplist, reset) != 5758 DLADM_STATUS_OK) { 5759 die("invalid link properties specified"); 5760 } 5761 break; 5762 case 't': 5763 temp = B_TRUE; 5764 break; 5765 case 'R': 5766 altroot = optarg; 5767 break; 5768 default: 5769 die_opterr(optopt, option, use); 5770 5771 } 5772 } 5773 5774 /* get link name (required last argument) */ 5775 if (optind != (argc - 1)) 5776 usage(); 5777 5778 if (proplist == NULL && !reset) 5779 die("link property must be specified"); 5780 5781 if (altroot != NULL) { 5782 dladm_free_props(proplist); 5783 altroot_cmd(altroot, argc, argv); 5784 } 5785 5786 status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL); 5787 if (status != DLADM_STATUS_OK) 5788 die_dlerr(status, "link %s is not valid", argv[optind]); 5789 5790 if (proplist == NULL) { 5791 set_linkprop_state_t state; 5792 5793 state.ls_name = argv[optind]; 5794 state.ls_reset = reset; 5795 state.ls_temp = temp; 5796 state.ls_status = DLADM_STATUS_OK; 5797 5798 (void) dladm_walk_linkprop(linkid, &state, reset_one_linkprop); 5799 5800 status = state.ls_status; 5801 goto done; 5802 } 5803 5804 for (i = 0; i < proplist->al_count; i++) { 5805 dladm_arg_info_t *aip = &proplist->al_info[i]; 5806 char **val; 5807 uint_t count; 5808 dladm_status_t s; 5809 5810 if (reset) { 5811 val = NULL; 5812 count = 0; 5813 } else { 5814 val = aip->ai_val; 5815 count = aip->ai_count; 5816 if (count == 0) { 5817 warn("no value specified for '%s'", 5818 aip->ai_name); 5819 status = DLADM_STATUS_BADARG; 5820 continue; 5821 } 5822 } 5823 s = dladm_set_linkprop(linkid, aip->ai_name, val, count, 5824 DLADM_OPT_ACTIVE); 5825 if (s == DLADM_STATUS_OK) { 5826 if (!temp) { 5827 s = set_linkprop_persist(linkid, 5828 aip->ai_name, val, count, reset); 5829 if (s != DLADM_STATUS_OK) 5830 status = s; 5831 } 5832 continue; 5833 } 5834 status = s; 5835 switch (s) { 5836 case DLADM_STATUS_NOTFOUND: 5837 warn("invalid link property '%s'", aip->ai_name); 5838 break; 5839 case DLADM_STATUS_BADVAL: { 5840 int j; 5841 char *ptr, *lim; 5842 char **propvals = NULL; 5843 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5844 5845 ptr = malloc((sizeof (char *) + 5846 DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 5847 MAX_PROP_LINE); 5848 5849 propvals = (char **)(void *)ptr; 5850 if (propvals == NULL) 5851 die("insufficient memory"); 5852 5853 for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 5854 propvals[j] = ptr + sizeof (char *) * 5855 DLADM_MAX_PROP_VALCNT + 5856 j * DLADM_PROP_VAL_MAX; 5857 } 5858 s = dladm_get_linkprop(linkid, 5859 DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals, 5860 &valcnt); 5861 5862 if (s != DLADM_STATUS_OK) { 5863 warn_dlerr(status, "cannot set link property " 5864 "'%s' on '%s'", aip->ai_name, argv[optind]); 5865 free(propvals); 5866 break; 5867 } 5868 5869 ptr = errmsg; 5870 lim = ptr + DLADM_STRSIZE; 5871 *ptr = '\0'; 5872 for (j = 0; j < valcnt; j++) { 5873 ptr += snprintf(ptr, lim - ptr, "%s,", 5874 propvals[j]); 5875 if (ptr >= lim) 5876 break; 5877 } 5878 if (ptr > errmsg) { 5879 *(ptr - 1) = '\0'; 5880 warn("link property '%s' must be one of: %s", 5881 aip->ai_name, errmsg); 5882 } else 5883 warn("invalid link property '%s'", *val); 5884 free(propvals); 5885 break; 5886 } 5887 default: 5888 if (reset) { 5889 warn_dlerr(status, "cannot reset link property " 5890 "'%s' on '%s'", aip->ai_name, argv[optind]); 5891 } else { 5892 warn_dlerr(status, "cannot set link property " 5893 "'%s' on '%s'", aip->ai_name, argv[optind]); 5894 } 5895 break; 5896 } 5897 } 5898 done: 5899 dladm_free_props(proplist); 5900 if (status != DLADM_STATUS_OK) 5901 exit(1); 5902 } 5903 5904 static void 5905 do_set_linkprop(int argc, char **argv, const char *use) 5906 { 5907 set_linkprop(argc, argv, B_FALSE, use); 5908 } 5909 5910 static void 5911 do_reset_linkprop(int argc, char **argv, const char *use) 5912 { 5913 set_linkprop(argc, argv, B_TRUE, use); 5914 } 5915 5916 static int 5917 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 5918 dladm_secobj_class_t class) 5919 { 5920 int error = 0; 5921 5922 if (class == DLADM_SECOBJ_CLASS_WPA) { 5923 if (len < 8 || len > 63) 5924 return (EINVAL); 5925 (void) memcpy(obj_val, buf, len); 5926 *obj_lenp = len; 5927 return (error); 5928 } 5929 5930 if (class == DLADM_SECOBJ_CLASS_WEP) { 5931 switch (len) { 5932 case 5: /* ASCII key sizes */ 5933 case 13: 5934 (void) memcpy(obj_val, buf, len); 5935 *obj_lenp = len; 5936 break; 5937 case 10: /* Hex key sizes, not preceded by 0x */ 5938 case 26: 5939 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 5940 break; 5941 case 12: /* Hex key sizes, preceded by 0x */ 5942 case 28: 5943 if (strncmp(buf, "0x", 2) != 0) 5944 return (EINVAL); 5945 error = hexascii_to_octet(buf + 2, len - 2, 5946 obj_val, obj_lenp); 5947 break; 5948 default: 5949 return (EINVAL); 5950 } 5951 return (error); 5952 } 5953 5954 return (ENOENT); 5955 } 5956 5957 /* ARGSUSED */ 5958 static void 5959 defersig(int sig) 5960 { 5961 signalled = sig; 5962 } 5963 5964 static int 5965 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 5966 { 5967 uint_t len = 0; 5968 int c; 5969 struct termios stored, current; 5970 void (*sigfunc)(int); 5971 5972 /* 5973 * Turn off echo -- but before we do so, defer SIGINT handling 5974 * so that a ^C doesn't leave the terminal corrupted. 5975 */ 5976 sigfunc = signal(SIGINT, defersig); 5977 (void) fflush(stdin); 5978 (void) tcgetattr(0, &stored); 5979 current = stored; 5980 current.c_lflag &= ~(ICANON|ECHO); 5981 current.c_cc[VTIME] = 0; 5982 current.c_cc[VMIN] = 1; 5983 (void) tcsetattr(0, TCSANOW, ¤t); 5984 again: 5985 if (try == 1) 5986 (void) printf(gettext("provide value for '%s': "), objname); 5987 else 5988 (void) printf(gettext("confirm value for '%s': "), objname); 5989 5990 (void) fflush(stdout); 5991 while (signalled == 0) { 5992 c = getchar(); 5993 if (c == '\n' || c == '\r') { 5994 if (len != 0) 5995 break; 5996 (void) putchar('\n'); 5997 goto again; 5998 } 5999 6000 buf[len++] = c; 6001 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 6002 break; 6003 (void) putchar('*'); 6004 } 6005 6006 (void) putchar('\n'); 6007 (void) fflush(stdin); 6008 6009 /* 6010 * Restore terminal setting and handle deferred signals. 6011 */ 6012 (void) tcsetattr(0, TCSANOW, &stored); 6013 6014 (void) signal(SIGINT, sigfunc); 6015 if (signalled != 0) 6016 (void) kill(getpid(), signalled); 6017 6018 return (len); 6019 } 6020 6021 static int 6022 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 6023 dladm_secobj_class_t class, FILE *filep) 6024 { 6025 int rval; 6026 uint_t len, len2; 6027 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 6028 6029 if (filep == NULL) { 6030 len = get_secobj_from_tty(1, obj_name, buf); 6031 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 6032 if (rval == 0) { 6033 len2 = get_secobj_from_tty(2, obj_name, buf2); 6034 if (len != len2 || memcmp(buf, buf2, len) != 0) 6035 rval = ENOTSUP; 6036 } 6037 return (rval); 6038 } else { 6039 for (;;) { 6040 if (fgets(buf, sizeof (buf), filep) == NULL) 6041 break; 6042 if (isspace(buf[0])) 6043 continue; 6044 6045 len = strlen(buf); 6046 if (buf[len - 1] == '\n') { 6047 buf[len - 1] = '\0'; 6048 len--; 6049 } 6050 break; 6051 } 6052 (void) fclose(filep); 6053 } 6054 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 6055 } 6056 6057 static boolean_t 6058 check_auth(const char *auth) 6059 { 6060 struct passwd *pw; 6061 6062 if ((pw = getpwuid(getuid())) == NULL) 6063 return (B_FALSE); 6064 6065 return (chkauthattr(auth, pw->pw_name) != 0); 6066 } 6067 6068 static void 6069 audit_secobj(char *auth, char *class, char *obj, 6070 boolean_t success, boolean_t create) 6071 { 6072 adt_session_data_t *ah; 6073 adt_event_data_t *event; 6074 au_event_t flag; 6075 char *errstr; 6076 6077 if (create) { 6078 flag = ADT_dladm_create_secobj; 6079 errstr = "ADT_dladm_create_secobj"; 6080 } else { 6081 flag = ADT_dladm_delete_secobj; 6082 errstr = "ADT_dladm_delete_secobj"; 6083 } 6084 6085 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 6086 die("adt_start_session: %s", strerror(errno)); 6087 6088 if ((event = adt_alloc_event(ah, flag)) == NULL) 6089 die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 6090 6091 /* fill in audit info */ 6092 if (create) { 6093 event->adt_dladm_create_secobj.auth_used = auth; 6094 event->adt_dladm_create_secobj.obj_class = class; 6095 event->adt_dladm_create_secobj.obj_name = obj; 6096 } else { 6097 event->adt_dladm_delete_secobj.auth_used = auth; 6098 event->adt_dladm_delete_secobj.obj_class = class; 6099 event->adt_dladm_delete_secobj.obj_name = obj; 6100 } 6101 6102 if (success) { 6103 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 6104 die("adt_put_event (%s, success): %s", errstr, 6105 strerror(errno)); 6106 } 6107 } else { 6108 if (adt_put_event(event, ADT_FAILURE, 6109 ADT_FAIL_VALUE_AUTH) != 0) { 6110 die("adt_put_event: (%s, failure): %s", errstr, 6111 strerror(errno)); 6112 } 6113 } 6114 6115 adt_free_event(event); 6116 (void) adt_end_session(ah); 6117 } 6118 6119 #define MAX_SECOBJS 32 6120 #define MAX_SECOBJ_NAMELEN 32 6121 static void 6122 do_create_secobj(int argc, char **argv, const char *use) 6123 { 6124 int option, rval; 6125 FILE *filep = NULL; 6126 char *obj_name = NULL; 6127 char *class_name = NULL; 6128 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 6129 uint_t obj_len; 6130 boolean_t success, temp = B_FALSE; 6131 dladm_status_t status; 6132 dladm_secobj_class_t class = -1; 6133 uid_t euid; 6134 6135 opterr = 0; 6136 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 6137 while ((option = getopt_long(argc, argv, ":f:c:R:t", 6138 wifi_longopts, NULL)) != -1) { 6139 switch (option) { 6140 case 'f': 6141 euid = geteuid(); 6142 (void) seteuid(getuid()); 6143 filep = fopen(optarg, "r"); 6144 if (filep == NULL) { 6145 die("cannot open %s: %s", optarg, 6146 strerror(errno)); 6147 } 6148 (void) seteuid(euid); 6149 break; 6150 case 'c': 6151 class_name = optarg; 6152 status = dladm_str2secobjclass(optarg, &class); 6153 if (status != DLADM_STATUS_OK) { 6154 die("invalid secure object class '%s', " 6155 "valid values are: wep, wpa", optarg); 6156 } 6157 break; 6158 case 't': 6159 temp = B_TRUE; 6160 break; 6161 case 'R': 6162 status = dladm_set_rootdir(optarg); 6163 if (status != DLADM_STATUS_OK) { 6164 die_dlerr(status, "invalid directory " 6165 "specified"); 6166 } 6167 break; 6168 default: 6169 die_opterr(optopt, option, use); 6170 break; 6171 } 6172 } 6173 6174 if (optind == (argc - 1)) 6175 obj_name = argv[optind]; 6176 else if (optind != argc) 6177 usage(); 6178 6179 if (class == -1) 6180 die("secure object class required"); 6181 6182 if (obj_name == NULL) 6183 die("secure object name required"); 6184 6185 success = check_auth(LINK_SEC_AUTH); 6186 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 6187 if (!success) 6188 die("authorization '%s' is required", LINK_SEC_AUTH); 6189 6190 rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 6191 if (rval != 0) { 6192 switch (rval) { 6193 case ENOENT: 6194 die("invalid secure object class"); 6195 break; 6196 case EINVAL: 6197 die("invalid secure object value"); 6198 break; 6199 case ENOTSUP: 6200 die("verification failed"); 6201 break; 6202 default: 6203 die("invalid secure object: %s", strerror(rval)); 6204 break; 6205 } 6206 } 6207 6208 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 6209 DLADM_OPT_CREATE | DLADM_OPT_ACTIVE); 6210 if (status != DLADM_STATUS_OK) { 6211 die_dlerr(status, "could not create secure object '%s'", 6212 obj_name); 6213 } 6214 if (temp) 6215 return; 6216 6217 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 6218 DLADM_OPT_PERSIST); 6219 if (status != DLADM_STATUS_OK) { 6220 warn_dlerr(status, "could not persistently create secure " 6221 "object '%s'", obj_name); 6222 } 6223 } 6224 6225 static void 6226 do_delete_secobj(int argc, char **argv, const char *use) 6227 { 6228 int i, option; 6229 boolean_t temp = B_FALSE; 6230 split_t *sp = NULL; 6231 boolean_t success; 6232 dladm_status_t status, pstatus; 6233 6234 opterr = 0; 6235 status = pstatus = DLADM_STATUS_OK; 6236 while ((option = getopt_long(argc, argv, ":R:t", 6237 wifi_longopts, NULL)) != -1) { 6238 switch (option) { 6239 case 't': 6240 temp = B_TRUE; 6241 break; 6242 case 'R': 6243 status = dladm_set_rootdir(optarg); 6244 if (status != DLADM_STATUS_OK) { 6245 die_dlerr(status, "invalid directory " 6246 "specified"); 6247 } 6248 break; 6249 default: 6250 die_opterr(optopt, option, use); 6251 break; 6252 } 6253 } 6254 6255 if (optind == (argc - 1)) { 6256 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 6257 if (sp == NULL) { 6258 die("invalid secure object name(s): '%s'", 6259 argv[optind]); 6260 } 6261 } else if (optind != argc) 6262 usage(); 6263 6264 if (sp == NULL || sp->s_nfields < 1) 6265 die("secure object name required"); 6266 6267 success = check_auth(LINK_SEC_AUTH); 6268 audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE); 6269 if (!success) 6270 die("authorization '%s' is required", LINK_SEC_AUTH); 6271 6272 for (i = 0; i < sp->s_nfields; i++) { 6273 status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_ACTIVE); 6274 if (!temp) { 6275 pstatus = dladm_unset_secobj(sp->s_fields[i], 6276 DLADM_OPT_PERSIST); 6277 } else { 6278 pstatus = DLADM_STATUS_OK; 6279 } 6280 6281 if (status != DLADM_STATUS_OK) { 6282 warn_dlerr(status, "could not delete secure object " 6283 "'%s'", sp->s_fields[i]); 6284 } 6285 if (pstatus != DLADM_STATUS_OK) { 6286 warn_dlerr(pstatus, "could not persistently delete " 6287 "secure object '%s'", sp->s_fields[i]); 6288 } 6289 } 6290 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) 6291 exit(1); 6292 } 6293 6294 typedef struct show_secobj_state { 6295 boolean_t ss_persist; 6296 boolean_t ss_parseable; 6297 boolean_t ss_header; 6298 print_state_t ss_print; 6299 } show_secobj_state_t; 6300 6301 6302 static boolean_t 6303 show_secobj(void *arg, const char *obj_name) 6304 { 6305 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 6306 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 6307 char buf[DLADM_STRSIZE]; 6308 uint_t flags = 0; 6309 dladm_secobj_class_t class; 6310 show_secobj_state_t *statep = arg; 6311 dladm_status_t status; 6312 secobj_fields_buf_t sbuf; 6313 6314 bzero(&sbuf, sizeof (secobj_fields_buf_t)); 6315 if (statep->ss_persist) 6316 flags |= DLADM_OPT_PERSIST; 6317 6318 status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags); 6319 if (status != DLADM_STATUS_OK) 6320 die_dlerr(status, "cannot get secure object '%s'", obj_name); 6321 6322 if (statep->ss_header) { 6323 statep->ss_header = B_FALSE; 6324 if (!statep->ss_parseable) 6325 print_header(&statep->ss_print); 6326 } 6327 6328 (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), 6329 obj_name); 6330 (void) dladm_secobjclass2str(class, buf); 6331 (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf); 6332 if (getuid() == 0) { 6333 char val[DLADM_SECOBJ_VAL_MAX * 2]; 6334 uint_t len = sizeof (val); 6335 6336 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) 6337 (void) snprintf(sbuf.ss_val, 6338 sizeof (sbuf.ss_val), "%s", val); 6339 } 6340 dladm_print_output(&statep->ss_print, statep->ss_parseable, 6341 dladm_print_field, (void *)&sbuf); 6342 return (B_TRUE); 6343 } 6344 6345 static void 6346 do_show_secobj(int argc, char **argv, const char *use) 6347 { 6348 int option; 6349 show_secobj_state_t state; 6350 dladm_status_t status; 6351 boolean_t o_arg = B_FALSE; 6352 uint_t i; 6353 split_t *sp; 6354 uint_t flags; 6355 char *fields_str = NULL; 6356 print_field_t **fields; 6357 uint_t nfields; 6358 char *def_fields = "object,class"; 6359 char *all_fields = "object,class,value"; 6360 6361 opterr = 0; 6362 bzero(&state, sizeof (state)); 6363 state.ss_parseable = B_FALSE; 6364 fields_str = def_fields; 6365 state.ss_persist = B_FALSE; 6366 state.ss_parseable = B_FALSE; 6367 state.ss_header = B_TRUE; 6368 while ((option = getopt_long(argc, argv, ":pPo:", 6369 wifi_longopts, NULL)) != -1) { 6370 switch (option) { 6371 case 'p': 6372 state.ss_parseable = B_TRUE; 6373 break; 6374 case 'P': 6375 state.ss_persist = B_TRUE; 6376 break; 6377 case 'o': 6378 o_arg = B_TRUE; 6379 if (strcasecmp(optarg, "all") == 0) 6380 fields_str = all_fields; 6381 else 6382 fields_str = optarg; 6383 break; 6384 default: 6385 die_opterr(optopt, option, use); 6386 break; 6387 } 6388 } 6389 6390 if (state.ss_parseable && !o_arg) 6391 die("option -c requires -o"); 6392 6393 if (state.ss_parseable && fields_str == all_fields) 6394 die("\"-o all\" is invalid with -p"); 6395 6396 fields = parse_output_fields(fields_str, secobj_fields, 6397 DEV_SOBJ_FIELDS, CMD_TYPE_ANY, &nfields); 6398 6399 if (fields == NULL) { 6400 die("invalid field(s) specified"); 6401 return; 6402 } 6403 state.ss_print.ps_fields = fields; 6404 state.ss_print.ps_nfields = nfields; 6405 6406 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 6407 if (optind == (argc - 1)) { 6408 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 6409 if (sp == NULL) { 6410 die("invalid secure object name(s): '%s'", 6411 argv[optind]); 6412 } 6413 for (i = 0; i < sp->s_nfields; i++) { 6414 if (!show_secobj(&state, sp->s_fields[i])) 6415 break; 6416 } 6417 splitfree(sp); 6418 return; 6419 } else if (optind != argc) 6420 usage(); 6421 6422 status = dladm_walk_secobj(&state, show_secobj, flags); 6423 if (status != DLADM_STATUS_OK) 6424 die_dlerr(status, "show-secobj"); 6425 } 6426 6427 /*ARGSUSED*/ 6428 static int 6429 i_dladm_init_linkprop(datalink_id_t linkid, void *arg) 6430 { 6431 (void) dladm_init_linkprop(linkid, B_TRUE); 6432 return (DLADM_WALK_CONTINUE); 6433 } 6434 6435 /*ARGSUSED*/ 6436 void 6437 do_init_linkprop(int argc, char **argv, const char *use) 6438 { 6439 int option; 6440 dladm_status_t status; 6441 datalink_id_t linkid = DATALINK_ALL_LINKID; 6442 datalink_media_t media = DATALINK_ANY_MEDIATYPE; 6443 uint_t any_media = B_TRUE; 6444 6445 opterr = 0; 6446 while ((option = getopt(argc, argv, ":w")) != -1) { 6447 switch (option) { 6448 case 'w': 6449 media = DL_WIFI; 6450 any_media = B_FALSE; 6451 break; 6452 default: 6453 /* 6454 * Because init-linkprop is not a public command, 6455 * print the usage instead. 6456 */ 6457 usage(); 6458 break; 6459 } 6460 } 6461 6462 if (optind == (argc - 1)) { 6463 if ((status = dladm_name2info(argv[optind], &linkid, NULL, NULL, 6464 NULL)) != DLADM_STATUS_OK) 6465 die_dlerr(status, "link %s is not valid", argv[optind]); 6466 } else if (optind != argc) { 6467 usage(); 6468 } 6469 6470 if (linkid == DATALINK_ALL_LINKID) { 6471 /* 6472 * linkprops of links of other classes have been initialized as 6473 * part of the dladm up-xxx operation. 6474 */ 6475 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL, 6476 DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST); 6477 } else { 6478 (void) dladm_init_linkprop(linkid, any_media); 6479 } 6480 } 6481 6482 /* ARGSUSED */ 6483 static void 6484 do_show_ether(int argc, char **argv, const char *use) 6485 { 6486 int option; 6487 datalink_id_t linkid; 6488 print_ether_state_t state; 6489 print_field_t **fields; 6490 boolean_t o_arg = B_FALSE; 6491 char *fields_str; 6492 uint_t nfields; 6493 char *all_fields = 6494 "link,ptype,state,auto,speed-duplex,pause,rem_fault"; 6495 char *default_fields = 6496 "link,ptype,state,auto,speed-duplex,pause"; 6497 6498 fields_str = default_fields; 6499 bzero(&state, sizeof (state)); 6500 state.es_link = NULL; 6501 state.es_parseable = B_FALSE; 6502 6503 while ((option = getopt_long(argc, argv, "o:px", 6504 showeth_lopts, NULL)) != -1) { 6505 switch (option) { 6506 case 'x': 6507 state.es_extended = B_TRUE; 6508 break; 6509 case 'p': 6510 state.es_parseable = B_TRUE; 6511 break; 6512 case 'o': 6513 o_arg = B_TRUE; 6514 if (strcasecmp(optarg, "all") == 0) 6515 fields_str = all_fields; 6516 else 6517 fields_str = optarg; 6518 break; 6519 default: 6520 die_opterr(optopt, option, use); 6521 break; 6522 } 6523 } 6524 6525 if (state.es_parseable && !o_arg) 6526 die("-p requires -o"); 6527 6528 if (state.es_parseable && fields_str == all_fields) 6529 die("\"-o all\" is invalid with -p"); 6530 6531 if (optind == (argc - 1)) 6532 state.es_link = argv[optind]; 6533 6534 fields = parse_output_fields(fields_str, ether_fields, 6535 ETHER_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 6536 6537 if (fields == NULL) { 6538 die("invalid field(s) specified"); 6539 exit(EXIT_FAILURE); 6540 } 6541 state.es_print.ps_fields = fields; 6542 state.es_print.ps_nfields = nfields; 6543 6544 if (state.es_link == NULL) { 6545 (void) dladm_walk_datalink_id(show_etherprop, &state, 6546 DATALINK_CLASS_PHYS, DL_ETHER, 6547 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 6548 } else { 6549 if (!link_is_ether(state.es_link, &linkid)) { 6550 die("invalid link specified"); 6551 } 6552 (void) show_etherprop(linkid, &state); 6553 } 6554 6555 exit(DLADM_STATUS_OK); 6556 6557 } 6558 6559 static char * 6560 dladm_print_field(print_field_t *pf, void *arg) 6561 { 6562 char *value; 6563 6564 value = (char *)arg + pf->pf_offset; 6565 return (value); 6566 } 6567 6568 static int 6569 show_etherprop(datalink_id_t linkid, void *arg) 6570 { 6571 print_ether_state_t *statep = arg; 6572 char buf[DLADM_STRSIZE]; 6573 int speed; 6574 uint64_t s; 6575 uint32_t autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf; 6576 ether_fields_buf_t ebuf; 6577 char speed_unit = 'M'; 6578 6579 bzero(&ebuf, sizeof (ether_fields_buf_t)); 6580 if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, 6581 ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) { 6582 return (DLADM_WALK_CONTINUE); 6583 } 6584 6585 if (!statep->es_header && !statep->es_parseable) { 6586 print_header(&statep->es_print); 6587 statep->es_header = B_TRUE; 6588 } 6589 (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 6590 "%s", "current"); 6591 6592 (void) dladm_get_single_mac_stat(linkid, "link_autoneg", 6593 KSTAT_DATA_UINT32, &autoneg); 6594 (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 6595 "%s", (autoneg ? "yes" : "no")); 6596 6597 (void) dladm_get_single_mac_stat(linkid, "link_pause", 6598 KSTAT_DATA_UINT32, &pause); 6599 (void) dladm_get_single_mac_stat(linkid, "link_asmpause", 6600 KSTAT_DATA_UINT32, &asmpause); 6601 (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 6602 "%s", pause_str(pause, asmpause)); 6603 6604 (void) dladm_get_single_mac_stat(linkid, "ifspeed", 6605 KSTAT_DATA_UINT64, &s); 6606 speed = (int)(s/1000000ull); 6607 6608 if (speed >= 1000) { 6609 speed = speed/1000; 6610 speed_unit = 'G'; 6611 } 6612 (void) get_linkduplex(ebuf.eth_link, B_TRUE, buf); 6613 (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%d%c-%c", 6614 speed, speed_unit, buf[0]); 6615 6616 (void) get_linkstate(ebuf.eth_link, B_TRUE, buf); 6617 (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), 6618 "%s", buf); 6619 6620 (void) dladm_get_single_mac_stat(linkid, "adv_rem_fault", 6621 KSTAT_DATA_UINT32, &adv_rf); 6622 (void) dladm_get_single_mac_stat(linkid, "cap_rem_fault", 6623 KSTAT_DATA_UINT32, &cap_rf); 6624 (void) dladm_get_single_mac_stat(linkid, "lp_rem_fault", 6625 KSTAT_DATA_UINT32, &lp_rf); 6626 (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 6627 "%s", (adv_rf == 0 && lp_rf == 0 ? "none" : "fault")); 6628 6629 dladm_print_output(&statep->es_print, statep->es_parseable, 6630 dladm_print_field, &ebuf); 6631 6632 if (statep->es_extended) 6633 show_ether_xprop(linkid, arg); 6634 6635 return (DLADM_WALK_CONTINUE); 6636 } 6637 6638 /* ARGSUSED */ 6639 static void 6640 do_init_secobj(int argc, char **argv, const char *use) 6641 { 6642 dladm_status_t status; 6643 6644 status = dladm_init_secobj(); 6645 if (status != DLADM_STATUS_OK) 6646 die_dlerr(status, "secure object initialization failed"); 6647 } 6648 6649 /* 6650 * "-R" option support. It is used for live upgrading. Append dladm commands 6651 * to a upgrade script which will be run when the alternative root boots up: 6652 * 6653 * - If the /etc/dladm/datalink.conf file exists on the alternative root, 6654 * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink 6655 * script. This script will be run as part of the network/physical service. 6656 * We cannot defer this to /var/svc/profile/upgrade because then the 6657 * configuration will not be able to take effect before network/physical 6658 * plumbs various interfaces. 6659 * 6660 * - If the /etc/dladm/datalink.conf file does not exist on the alternative 6661 * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script, 6662 * which will be run in the manifest-import service. 6663 * 6664 * Note that the SMF team is considering to move the manifest-import service 6665 * to be run at the very begining of boot. Once that is done, the need for 6666 * the /var/svc/profile/upgrade_datalink script will not exist any more. 6667 */ 6668 static void 6669 altroot_cmd(char *altroot, int argc, char *argv[]) 6670 { 6671 char path[MAXPATHLEN]; 6672 struct stat stbuf; 6673 FILE *fp; 6674 int i; 6675 6676 /* 6677 * Check for the existence of the /etc/dladm/datalink.conf 6678 * configuration file, and determine the name of script file. 6679 */ 6680 (void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf", 6681 altroot); 6682 if (stat(path, &stbuf) < 0) { 6683 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 6684 SMF_UPGRADE_FILE); 6685 } else { 6686 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 6687 SMF_UPGRADEDATALINK_FILE); 6688 } 6689 6690 if ((fp = fopen(path, "a+")) == NULL) 6691 die("operation not supported on %s", altroot); 6692 6693 (void) fprintf(fp, "/sbin/dladm "); 6694 for (i = 0; i < argc; i++) { 6695 /* 6696 * Directly write to the file if it is not the "-R <altroot>" 6697 * option. In which case, skip it. 6698 */ 6699 if (strcmp(argv[i], "-R") != 0) 6700 (void) fprintf(fp, "%s ", argv[i]); 6701 else 6702 i ++; 6703 } 6704 (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG); 6705 (void) fclose(fp); 6706 exit(0); 6707 } 6708 6709 /* 6710 * Convert the string to an integer. Note that the string must not have any 6711 * trailing non-integer characters. 6712 */ 6713 static boolean_t 6714 str2int(const char *str, int *valp) 6715 { 6716 int val; 6717 char *endp = NULL; 6718 6719 errno = 0; 6720 val = strtol(str, &endp, 10); 6721 if (errno != 0 || *endp != '\0') 6722 return (B_FALSE); 6723 6724 *valp = val; 6725 return (B_TRUE); 6726 } 6727 6728 /* PRINTFLIKE1 */ 6729 static void 6730 warn(const char *format, ...) 6731 { 6732 va_list alist; 6733 6734 format = gettext(format); 6735 (void) fprintf(stderr, "%s: warning: ", progname); 6736 6737 va_start(alist, format); 6738 (void) vfprintf(stderr, format, alist); 6739 va_end(alist); 6740 6741 (void) putchar('\n'); 6742 } 6743 6744 /* PRINTFLIKE2 */ 6745 static void 6746 warn_dlerr(dladm_status_t err, const char *format, ...) 6747 { 6748 va_list alist; 6749 char errmsg[DLADM_STRSIZE]; 6750 6751 format = gettext(format); 6752 (void) fprintf(stderr, gettext("%s: warning: "), progname); 6753 6754 va_start(alist, format); 6755 (void) vfprintf(stderr, format, alist); 6756 va_end(alist); 6757 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 6758 } 6759 6760 /* PRINTFLIKE2 */ 6761 static void 6762 die_dlerr(dladm_status_t err, const char *format, ...) 6763 { 6764 va_list alist; 6765 char errmsg[DLADM_STRSIZE]; 6766 6767 format = gettext(format); 6768 (void) fprintf(stderr, "%s: ", progname); 6769 6770 va_start(alist, format); 6771 (void) vfprintf(stderr, format, alist); 6772 va_end(alist); 6773 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 6774 6775 exit(EXIT_FAILURE); 6776 } 6777 6778 /* PRINTFLIKE1 */ 6779 static void 6780 die(const char *format, ...) 6781 { 6782 va_list alist; 6783 6784 format = gettext(format); 6785 (void) fprintf(stderr, "%s: ", progname); 6786 6787 va_start(alist, format); 6788 (void) vfprintf(stderr, format, alist); 6789 va_end(alist); 6790 6791 (void) putchar('\n'); 6792 exit(EXIT_FAILURE); 6793 } 6794 6795 static void 6796 die_optdup(int opt) 6797 { 6798 die("the option -%c cannot be specified more than once", opt); 6799 } 6800 6801 static void 6802 die_opterr(int opt, int opterr, const char *usage) 6803 { 6804 switch (opterr) { 6805 case ':': 6806 die("option '-%c' requires a value\nusage: %s", opt, 6807 gettext(usage)); 6808 break; 6809 case '?': 6810 default: 6811 die("unrecognized option '-%c'\nusage: %s", opt, 6812 gettext(usage)); 6813 break; 6814 } 6815 } 6816 6817 static void 6818 show_ether_xprop(datalink_id_t linkid, void *arg) 6819 { 6820 print_ether_state_t *statep = arg; 6821 char buf[DLADM_STRSIZE]; 6822 uint32_t autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf; 6823 boolean_t add_comma, r1; 6824 ether_fields_buf_t ebuf; 6825 6826 /* capable */ 6827 bzero(&ebuf, sizeof (ebuf)); 6828 (void) snprintf(ebuf.eth_link, sizeof (ebuf.eth_link), ""); 6829 6830 (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 6831 "%s", "capable"); 6832 (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), ""); 6833 6834 (void) dladm_get_single_mac_stat(linkid, "cap_autoneg", 6835 KSTAT_DATA_UINT32, &autoneg); 6836 (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 6837 "%s", (autoneg ? "yes" : "no")); 6838 6839 add_comma = B_FALSE; 6840 bzero(buf, sizeof (buf)); 6841 r1 = get_speed_duplex(linkid, "cap_1000", buf, "1G", B_FALSE); 6842 if (r1) 6843 add_comma = B_TRUE; 6844 r1 = get_speed_duplex(linkid, "cap_100", buf, "100M", add_comma); 6845 if (r1) 6846 add_comma = B_TRUE; 6847 r1 = get_speed_duplex(linkid, "cap_10", buf, "10M", add_comma); 6848 add_comma = B_FALSE; 6849 (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); 6850 6851 (void) dladm_get_single_mac_stat(linkid, "cap_pause", 6852 KSTAT_DATA_UINT32, &pause); 6853 (void) dladm_get_single_mac_stat(linkid, "cap_asmpause", 6854 KSTAT_DATA_UINT32, &asmpause); 6855 (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 6856 "%s", pause_str(pause, asmpause)); 6857 6858 (void) dladm_get_single_mac_stat(linkid, "adv_rem_fault", 6859 KSTAT_DATA_UINT32, &adv_rf); 6860 (void) dladm_get_single_mac_stat(linkid, "cap_rem_fault", 6861 KSTAT_DATA_UINT32, &cap_rf); 6862 (void) dladm_get_single_mac_stat(linkid, "lp_rem_fault", 6863 KSTAT_DATA_UINT32, &lp_rf); 6864 6865 (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 6866 "%s", (cap_rf ? "yes" : "no")); 6867 6868 dladm_print_output(&statep->es_print, statep->es_parseable, 6869 dladm_print_field, &ebuf); 6870 6871 /* advertised */ 6872 bzero(&ebuf, sizeof (ebuf)); 6873 (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 6874 "%s", "adv"); 6875 (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), ""); 6876 6877 (void) dladm_get_single_mac_stat(linkid, "adv_cap_autoneg", 6878 KSTAT_DATA_UINT32, &autoneg); 6879 (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 6880 "%s", (autoneg ? "yes" : "no")); 6881 6882 add_comma = B_FALSE; 6883 bzero(buf, sizeof (buf)); 6884 r1 = get_speed_duplex(linkid, "adv_cap_1000", buf, "1G", add_comma); 6885 if (r1) 6886 add_comma = B_TRUE; 6887 r1 = get_speed_duplex(linkid, "adv_cap_100", buf, "100M", add_comma); 6888 if (r1) 6889 add_comma = B_TRUE; 6890 r1 = get_speed_duplex(linkid, "adv_cap_10", buf, "10M", add_comma); 6891 add_comma = B_FALSE; 6892 (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); 6893 6894 (void) dladm_get_single_mac_stat(linkid, "adv_cap_pause", 6895 KSTAT_DATA_UINT32, &pause); 6896 (void) dladm_get_single_mac_stat(linkid, "adv_cap_asmpause", 6897 KSTAT_DATA_UINT32, &asmpause); 6898 (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 6899 "%s", pause_str(pause, asmpause)); 6900 6901 (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 6902 "%s", (adv_rf ? "fault" : "none")); 6903 6904 dladm_print_output(&statep->es_print, statep->es_parseable, 6905 dladm_print_field, &ebuf); 6906 6907 /* peeradv */ 6908 bzero(&ebuf, sizeof (ebuf)); 6909 (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 6910 "%s", "peeradv"); 6911 (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), ""); 6912 6913 (void) dladm_get_single_mac_stat(linkid, "lp_cap_autoneg", 6914 KSTAT_DATA_UINT32, &autoneg); 6915 (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 6916 "%s", (autoneg ? "yes" : "no")); 6917 6918 add_comma = B_FALSE; 6919 bzero(buf, sizeof (buf)); 6920 r1 = get_speed_duplex(linkid, "lp_cap_1000", buf, "1G", add_comma); 6921 if (r1) 6922 add_comma = B_TRUE; 6923 r1 = get_speed_duplex(linkid, "lp_cap_100", buf, "100M", add_comma); 6924 if (r1) 6925 add_comma = B_TRUE; 6926 r1 = get_speed_duplex(linkid, "lp_cap_10", buf, "10M", add_comma); 6927 (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); 6928 6929 (void) dladm_get_single_mac_stat(linkid, "lp_cap_pause", 6930 KSTAT_DATA_UINT32, &pause); 6931 (void) dladm_get_single_mac_stat(linkid, "lp_cap_asmpause", 6932 KSTAT_DATA_UINT32, &asmpause); 6933 (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 6934 "%s", pause_str(pause, asmpause)); 6935 6936 (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 6937 "%s", (lp_rf ? "fault" : "none")); 6938 6939 dladm_print_output(&statep->es_print, statep->es_parseable, 6940 dladm_print_field, &ebuf); 6941 } 6942 6943 static boolean_t 6944 get_speed_duplex(datalink_id_t linkid, const char *mii_prop_prefix, 6945 char *spbuf, char *sp, boolean_t add_comma) 6946 { 6947 int speed, duplex = 0; 6948 boolean_t ret = B_FALSE; 6949 char mii_prop[DLADM_STRSIZE]; 6950 6951 (void) snprintf(mii_prop, DLADM_STRSIZE, "%sfdx", mii_prop_prefix); 6952 (void) dladm_get_single_mac_stat(linkid, mii_prop, KSTAT_DATA_UINT32, 6953 &speed); 6954 if (speed) { 6955 ret = B_TRUE; 6956 duplex |= IS_FDX; 6957 } 6958 (void) snprintf(mii_prop, DLADM_STRSIZE, "%shdx", mii_prop_prefix); 6959 (void) dladm_get_single_mac_stat(linkid, mii_prop, 6960 KSTAT_DATA_UINT32, &speed); 6961 if (speed) { 6962 ret = B_TRUE; 6963 duplex |= IS_HDX; 6964 } 6965 if (ret) { 6966 if (add_comma) 6967 (void) strncat(spbuf, ",", DLADM_STRSIZE); 6968 (void) strncat(spbuf, sp, DLADM_STRSIZE); 6969 if ((duplex & (IS_FDX|IS_HDX)) == (IS_FDX|IS_HDX)) 6970 (void) strncat(spbuf, "-fh", DLADM_STRSIZE); 6971 else if (duplex & IS_FDX) 6972 (void) strncat(spbuf, "-f", DLADM_STRSIZE); 6973 else if (duplex & IS_HDX) 6974 (void) strncat(spbuf, "-h", DLADM_STRSIZE); 6975 } 6976 return (ret); 6977 } 6978 6979 static void 6980 dladm_print_output(print_state_t *statep, boolean_t parseable, 6981 print_callback_t fn, void *arg) 6982 { 6983 int i; 6984 char *value; 6985 print_field_t **pf; 6986 6987 pf = statep->ps_fields; 6988 for (i = 0; i < statep->ps_nfields; i++) { 6989 statep->ps_lastfield = (i + 1 == statep->ps_nfields); 6990 value = (*fn)(pf[i], arg); 6991 if (value != NULL) 6992 print_field(statep, pf[i], value, parseable); 6993 } 6994 (void) putchar('\n'); 6995 } 6996 6997 static void 6998 print_header(print_state_t *ps) 6999 { 7000 int i; 7001 print_field_t **pf; 7002 7003 pf = ps->ps_fields; 7004 for (i = 0; i < ps->ps_nfields; i++) { 7005 ps->ps_lastfield = (i + 1 == ps->ps_nfields); 7006 print_field(ps, pf[i], pf[i]->pf_header, B_FALSE); 7007 } 7008 (void) putchar('\n'); 7009 } 7010 7011 static char * 7012 pause_str(int pause, int asmpause) 7013 { 7014 if (pause == 1) 7015 return ("bi"); 7016 if (asmpause == 1) 7017 return ("tx"); 7018 return ("none"); 7019 } 7020 7021 static boolean_t 7022 link_is_ether(const char *link, datalink_id_t *linkid) 7023 { 7024 uint32_t media; 7025 datalink_class_t class; 7026 7027 if (dladm_name2info(link, linkid, NULL, &class, &media) == 7028 DLADM_STATUS_OK) { 7029 if (class == DATALINK_CLASS_PHYS && media == DL_ETHER) 7030 return (B_TRUE); 7031 } 7032 return (B_FALSE); 7033 } 7034