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