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