1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <ctype.h> 28 #include <locale.h> 29 #include <signal.h> 30 #include <stdarg.h> 31 #include <stdlib.h> 32 #include <fcntl.h> 33 #include <string.h> 34 #include <stropts.h> 35 #include <sys/stat.h> 36 #include <errno.h> 37 #include <kstat.h> 38 #include <strings.h> 39 #include <getopt.h> 40 #include <unistd.h> 41 #include <priv.h> 42 #include <termios.h> 43 #include <pwd.h> 44 #include <auth_attr.h> 45 #include <auth_list.h> 46 #include <libintl.h> 47 #include <libdevinfo.h> 48 #include <libdlpi.h> 49 #include <libdladm.h> 50 #include <libdllink.h> 51 #include <libdlstat.h> 52 #include <libdlaggr.h> 53 #include <libdlwlan.h> 54 #include <libdlvlan.h> 55 #include <libdlvnic.h> 56 #include <libdlether.h> 57 #include <libinetutil.h> 58 #include <bsm/adt.h> 59 #include <bsm/adt_event.h> 60 #include <libdlvnic.h> 61 #include <sys/types.h> 62 #include <sys/socket.h> 63 #include <sys/processor.h> 64 #include <netinet/in.h> 65 #include <arpa/inet.h> 66 #include <net/if_types.h> 67 #include <stddef.h> 68 69 #define STR_UNDEF_VAL "--" 70 #define MAXPORT 256 71 #define MAXVNIC 256 72 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) 73 #define MAXLINELEN 1024 74 #define SMF_UPGRADE_FILE "/var/svc/profile/upgrade" 75 #define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink" 76 #define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)" 77 78 #define CMD_TYPE_ANY 0xffffffff 79 #define WIFI_CMD_SCAN 0x00000001 80 #define WIFI_CMD_SHOW 0x00000002 81 #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 82 83 /* 84 * Data structures and routines for printing output. 85 * All non-parseable output is assumed to be in a columnar format. 86 * Multiple fields in parsable output are separated by ':'; single 87 * field output is printed as-is. 88 * 89 * Each sub-command is associated with a global array of pointers, 90 * print_field_t *fields[], where the print_field_t contains information 91 * about the format in which the output is to be printed. 92 * 93 * Sub-commands may be implemented in one of two ways: 94 * (i) the implementation could get all field values into a character 95 * buffer, with pf_offset containing the offset (for pf_name) within 96 * the buffer. The sub-command would make the needed system calls 97 * to obtain all possible column values and then invoke the 98 * dladm_print_field() function to print the specific fields 99 * requested in the command line. See the comments for dladm_print_field 100 * for further details. 101 * (ii) Alternatively, each fields[i] entry could store a pf_index value 102 * that uniquely identifies the column to be printed. The implementation 103 * of the sub-command would then invoke dladm_print_output() with a 104 * callback function whose semantics are described below (see comments 105 * for dladm_print_output()) 106 * 107 * Thus, an implementation of a sub-command must provide the following: 108 * 109 * static print_field_t sub_command_fields[] = { 110 * {<name>, <header>,<field width>, <offset_or_index>, cmdtype}, 111 * : 112 * {<name>, <header>,<field width>, <offset_or_index>, cmdtype} 113 * }; 114 * 115 * #define SUB_COMMAND_MAX_FIELDS sizeof \ 116 * (sub_comand_fields) / sizeof (print_field_t)) 117 * 118 * print_state_t sub_command_print_state; 119 * 120 * The function that parses command line arguments (typically 121 * do_sub_command()) should then contain an invocation like: 122 * 123 * fields = parse_output_fields(fields_str, sub_command_fields, 124 * SUB_COMMAND_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 125 * 126 * and store the resulting fields and nfields value in a print_state_t 127 * structure tracked for the command. 128 * 129 * sub_command_print_state.ps_fields = fields; 130 * sub_command_print_state.ps_nfields = nfields; 131 * 132 * To print the column header for the output, the print_header() 133 * function must then be invoked by do_sub_command(). 134 * 135 * Then if method (i) is used for the sub_command, the do_sub_command() 136 * function should make the necessary system calls to fill up the buffer 137 * and then invoke dladm_print_field(). An example of this method is 138 * the implementation of do_show_link() and show_link(); 139 * 140 * If method (ii) is used, do_sub_command should invoke dladm_print_output() 141 * with a callback function that will be called for each field to be printed. 142 * The callback function will be passed a pointer to the print_field_t 143 * for the field, and the pf_index may then be used to identify the 144 * system call required to find the value to be printed. 145 */ 146 147 typedef struct print_field_s { 148 const char *pf_name; /* name of column to be printed */ 149 const char *pf_header; /* header for this column */ 150 uint_t pf_width; 151 union { 152 uint_t _pf_index; /* private index for sub-command */ 153 size_t _pf_offset; 154 }_pf_un; 155 #define pf_index _pf_un._pf_index 156 #define pf_offset _pf_un._pf_offset; 157 uint_t pf_cmdtype; 158 } print_field_t; 159 160 /* 161 * The state of the output is tracked in a print_state_t structure. 162 * Each ps_fields[i] entry points at the global print_field_t array for 163 * the sub-command, where ps_nfields is the number of requested fields. 164 */ 165 typedef struct print_state_s { 166 print_field_t **ps_fields; 167 uint_t ps_nfields; 168 boolean_t ps_lastfield; 169 uint_t ps_overflow; 170 } print_state_t; 171 172 typedef char *(*print_callback_t)(print_field_t *, void *); 173 static print_field_t **parse_output_fields(char *, print_field_t *, int, 174 uint_t, uint_t *); 175 /* 176 * print the header for the output 177 */ 178 static void print_header(print_state_t *); 179 static void print_field(print_state_t *, print_field_t *, const char *, 180 boolean_t); 181 182 /* 183 * to print output values, call dladm_print_output with a callback 184 * function (*func)() that should parse the args and return an 185 * unformatted character buffer with the value to be printed. 186 * 187 * dladm_print_output() prints the character buffer using the formatting 188 * information provided in the print_field_t for that column. 189 */ 190 static void dladm_print_output(print_state_t *, boolean_t, 191 print_callback_t, void *); 192 193 /* 194 * helper function that, when invoked as dladm_print_field(pf, buf) 195 * prints string which is offset by pf->pf_offset within buf. 196 */ 197 static char *dladm_print_field(print_field_t *, void *); 198 199 200 #define MAX_FIELD_LEN 32 201 202 203 typedef struct show_state { 204 boolean_t ls_firstonly; 205 boolean_t ls_donefirst; 206 pktsum_t ls_prevstats; 207 uint32_t ls_flags; 208 dladm_status_t ls_status; 209 print_state_t ls_print; 210 boolean_t ls_parseable; 211 boolean_t ls_printheader; 212 boolean_t ls_mac; 213 boolean_t ls_hwgrp; 214 } show_state_t; 215 216 typedef struct show_grp_state { 217 pktsum_t gs_prevstats[MAXPORT]; 218 uint32_t gs_flags; 219 dladm_status_t gs_status; 220 boolean_t gs_parseable; 221 boolean_t gs_lacp; 222 boolean_t gs_extended; 223 boolean_t gs_stats; 224 boolean_t gs_firstonly; 225 boolean_t gs_donefirst; 226 boolean_t gs_printheader; 227 print_state_t gs_print; 228 } show_grp_state_t; 229 230 typedef struct show_vnic_state { 231 datalink_id_t vs_vnic_id; 232 datalink_id_t vs_link_id; 233 char vs_vnic[MAXLINKNAMELEN]; 234 char vs_link[MAXLINKNAMELEN]; 235 boolean_t vs_parseable; 236 boolean_t vs_printheader; 237 boolean_t vs_found; 238 boolean_t vs_firstonly; 239 boolean_t vs_donefirst; 240 boolean_t vs_stats; 241 boolean_t vs_printstats; 242 pktsum_t vs_totalstats; 243 pktsum_t vs_prevstats[MAXVNIC]; 244 boolean_t vs_etherstub; 245 dladm_status_t vs_status; 246 uint32_t vs_flags; 247 print_state_t vs_print; 248 } show_vnic_state_t; 249 250 typedef struct show_usage_state_s { 251 boolean_t us_plot; 252 boolean_t us_parseable; 253 boolean_t us_printheader; 254 boolean_t us_first; 255 print_state_t us_print; 256 } show_usage_state_t; 257 258 typedef void cmdfunc_t(int, char **, const char *); 259 260 static cmdfunc_t do_show_link, do_show_wifi, do_show_phys; 261 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 262 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr; 263 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 264 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 265 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 266 static cmdfunc_t do_init_linkprop, do_init_secobj; 267 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan; 268 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys; 269 static cmdfunc_t do_show_linkmap; 270 static cmdfunc_t do_show_ether; 271 static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic; 272 static cmdfunc_t do_up_vnic; 273 static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub; 274 static cmdfunc_t do_show_usage; 275 276 static void do_up_vnic_common(int, char **, const char *, boolean_t); 277 278 static void altroot_cmd(char *, int, char **); 279 static int show_linkprop_onelink(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 (i_arg && !s_arg) 4255 die("the option -i can be used only with -s"); 4256 4257 /* get vnic ID (optional last argument) */ 4258 if (optind == (argc - 1)) { 4259 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 4260 NULL, NULL); 4261 if (status != DLADM_STATUS_OK) { 4262 die_dlerr(status, "invalid vnic name '%s'", 4263 argv[optind]); 4264 } 4265 (void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN); 4266 } else if (optind != argc) { 4267 usage(); 4268 } 4269 4270 if (l_arg) { 4271 status = dladm_name2info(handle, state.vs_link, &dev_linkid, 4272 NULL, NULL, NULL); 4273 if (status != DLADM_STATUS_OK) { 4274 die_dlerr(status, "invalid link name '%s'", 4275 state.vs_link); 4276 } 4277 } 4278 4279 state.vs_vnic_id = linkid; 4280 state.vs_link_id = dev_linkid; 4281 state.vs_etherstub = etherstub; 4282 state.vs_found = B_FALSE; 4283 state.vs_flags = flags; 4284 4285 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 4286 if (etherstub) 4287 fields_str = all_e_fields; 4288 else 4289 fields_str = all_fields; 4290 } 4291 4292 pf = vnic_fields; 4293 pfmax = VNIC_MAX_FIELDS; 4294 4295 fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY, 4296 &nfields); 4297 4298 if (fields == NULL) { 4299 die("invalid field(s) specified"); 4300 return; 4301 } 4302 4303 state.vs_print.ps_fields = fields; 4304 state.vs_print.ps_nfields = nfields; 4305 4306 if (s_arg) { 4307 /* Display vnic statistics */ 4308 vnic_stats(&state, interval); 4309 return; 4310 } 4311 4312 /* Display vnic information */ 4313 state.vs_donefirst = B_FALSE; 4314 4315 if (linkid == DATALINK_ALL_LINKID) { 4316 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4317 DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB, 4318 DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 4319 } else { 4320 (void) show_vnic(handle, linkid, &state); 4321 if (state.vs_status != DLADM_STATUS_OK) { 4322 die_dlerr(state.vs_status, "failed to show vnic '%s'", 4323 state.vs_vnic); 4324 } 4325 } 4326 } 4327 4328 static void 4329 do_show_vnic(int argc, char *argv[], const char *use) 4330 { 4331 do_show_vnic_common(argc, argv, use, B_FALSE); 4332 } 4333 4334 static void 4335 do_create_etherstub(int argc, char *argv[], const char *use) 4336 { 4337 uint32_t flags; 4338 char *altroot = NULL; 4339 char option; 4340 dladm_status_t status; 4341 char name[MAXLINKNAMELEN]; 4342 uchar_t mac_addr[ETHERADDRL]; 4343 4344 name[0] = '\0'; 4345 bzero(mac_addr, sizeof (mac_addr)); 4346 flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4347 4348 opterr = 0; 4349 while ((option = getopt_long(argc, argv, "tR:", 4350 etherstub_lopts, NULL)) != -1) { 4351 switch (option) { 4352 case 't': 4353 flags &= ~DLADM_OPT_PERSIST; 4354 break; 4355 case 'R': 4356 altroot = optarg; 4357 break; 4358 default: 4359 die_opterr(optopt, option, use); 4360 } 4361 } 4362 4363 /* the etherstub id is the required operand */ 4364 if (optind != (argc - 1)) 4365 usage(); 4366 4367 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 4368 die("link name too long '%s'", argv[optind]); 4369 4370 if (!dladm_valid_linkname(name)) 4371 die("invalid link name '%s'", argv[optind]); 4372 4373 if (altroot != NULL) 4374 altroot_cmd(altroot, argc, argv); 4375 4376 status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID, 4377 VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, NULL, 4378 NULL, flags); 4379 if (status != DLADM_STATUS_OK) 4380 die_dlerr(status, "etherstub creation failed"); 4381 4382 4383 } 4384 4385 static void 4386 do_delete_etherstub(int argc, char *argv[], const char *use) 4387 { 4388 do_delete_vnic_common(argc, argv, use, B_TRUE); 4389 } 4390 4391 /* ARGSUSED */ 4392 static void 4393 do_show_etherstub(int argc, char *argv[], const char *use) 4394 { 4395 do_show_vnic_common(argc, argv, use, B_TRUE); 4396 } 4397 4398 static void 4399 link_stats(datalink_id_t linkid, uint_t interval, char *fields_str, 4400 show_state_t *state) 4401 { 4402 print_field_t **fields; 4403 uint_t nfields; 4404 4405 fields = parse_output_fields(fields_str, devs_fields, DEVS_MAX_FIELDS, 4406 CMD_TYPE_ANY, &nfields); 4407 if (fields == NULL) { 4408 die("invalid field(s) specified"); 4409 return; 4410 } 4411 4412 state->ls_print.ps_fields = fields; 4413 state->ls_print.ps_nfields = nfields; 4414 4415 /* 4416 * If an interval is specified, continuously show the stats 4417 * only for the first MAC port. 4418 */ 4419 state->ls_firstonly = (interval != 0); 4420 4421 if (!state->ls_parseable) 4422 print_header(&state->ls_print); 4423 for (;;) { 4424 state->ls_donefirst = B_FALSE; 4425 if (linkid == DATALINK_ALL_LINKID) { 4426 (void) dladm_walk_datalink_id(show_link_stats, handle, 4427 state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 4428 DLADM_OPT_ACTIVE); 4429 } else { 4430 (void) show_link_stats(handle, linkid, state); 4431 } 4432 4433 if (interval == 0) 4434 break; 4435 4436 (void) sleep(interval); 4437 } 4438 } 4439 4440 static void 4441 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) 4442 { 4443 /* 4444 * If an interval is specified, continuously show the stats 4445 * only for the first group. 4446 */ 4447 state->gs_firstonly = (interval != 0); 4448 4449 for (;;) { 4450 state->gs_donefirst = B_FALSE; 4451 if (linkid == DATALINK_ALL_LINKID) 4452 (void) dladm_walk_datalink_id(show_aggr, handle, state, 4453 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 4454 DLADM_OPT_ACTIVE); 4455 else 4456 (void) show_aggr(handle, linkid, state); 4457 4458 if (interval == 0) 4459 break; 4460 4461 (void) sleep(interval); 4462 } 4463 } 4464 4465 /* ARGSUSED */ 4466 static void 4467 vnic_stats(show_vnic_state_t *sp, uint32_t interval) 4468 { 4469 show_vnic_state_t state; 4470 boolean_t specific_link, specific_dev; 4471 4472 /* Display vnic statistics */ 4473 dump_vnics_head(sp->vs_link); 4474 4475 bzero(&state, sizeof (state)); 4476 state.vs_stats = B_TRUE; 4477 state.vs_vnic_id = sp->vs_vnic_id; 4478 state.vs_link_id = sp->vs_link_id; 4479 4480 /* 4481 * If an interval is specified, and a vnic ID is not specified, 4482 * continuously show the stats only for the first vnic. 4483 */ 4484 specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID); 4485 specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID); 4486 4487 for (;;) { 4488 /* Get stats for each vnic */ 4489 state.vs_found = B_FALSE; 4490 state.vs_donefirst = B_FALSE; 4491 state.vs_printstats = B_FALSE; 4492 state.vs_flags = DLADM_OPT_ACTIVE; 4493 4494 if (!specific_link) { 4495 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4496 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 4497 DLADM_OPT_ACTIVE); 4498 } else { 4499 (void) show_vnic(handle, sp->vs_vnic_id, &state); 4500 if (state.vs_status != DLADM_STATUS_OK) { 4501 die_dlerr(state.vs_status, 4502 "failed to show vnic '%s'", sp->vs_vnic); 4503 } 4504 } 4505 4506 if (specific_link && !state.vs_found) 4507 die("non-existent vnic '%s'", sp->vs_vnic); 4508 if (specific_dev && !state.vs_found) 4509 die("device %s has no vnics", sp->vs_link); 4510 4511 /* Show totals */ 4512 if ((specific_link | specific_dev) && !interval) { 4513 (void) printf("Total"); 4514 (void) printf("\t%-10llu", 4515 state.vs_totalstats.ipackets); 4516 (void) printf("%-12llu", 4517 state.vs_totalstats.rbytes); 4518 (void) printf("%-10llu", 4519 state.vs_totalstats.opackets); 4520 (void) printf("%-12llu\n", 4521 state.vs_totalstats.obytes); 4522 } 4523 4524 /* Show stats for each vnic */ 4525 state.vs_donefirst = B_FALSE; 4526 state.vs_printstats = B_TRUE; 4527 4528 if (!specific_link) { 4529 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4530 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 4531 DLADM_OPT_ACTIVE); 4532 } else { 4533 (void) show_vnic(handle, sp->vs_vnic_id, &state); 4534 if (state.vs_status != DLADM_STATUS_OK) { 4535 die_dlerr(state.vs_status, 4536 "failed to show vnic '%s'", sp->vs_vnic); 4537 } 4538 } 4539 4540 if (interval == 0) 4541 break; 4542 4543 (void) sleep(interval); 4544 } 4545 } 4546 4547 static void 4548 get_mac_stats(const char *dev, pktsum_t *stats) 4549 { 4550 kstat_ctl_t *kcp; 4551 kstat_t *ksp; 4552 char module[DLPI_LINKNAME_MAX]; 4553 uint_t instance; 4554 4555 4556 bzero(stats, sizeof (*stats)); 4557 4558 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 4559 return; 4560 4561 if ((kcp = kstat_open()) == NULL) { 4562 warn("kstat open operation failed"); 4563 return; 4564 } 4565 4566 ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL); 4567 if (ksp != NULL) 4568 dladm_get_stats(kcp, ksp, stats); 4569 4570 (void) kstat_close(kcp); 4571 4572 } 4573 4574 static void 4575 get_link_stats(const char *link, pktsum_t *stats) 4576 { 4577 kstat_ctl_t *kcp; 4578 kstat_t *ksp; 4579 4580 bzero(stats, sizeof (*stats)); 4581 4582 if ((kcp = kstat_open()) == NULL) { 4583 warn("kstat_open operation failed"); 4584 return; 4585 } 4586 4587 ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL); 4588 4589 if (ksp != NULL) 4590 dladm_get_stats(kcp, ksp, stats); 4591 4592 (void) kstat_close(kcp); 4593 } 4594 4595 static int 4596 query_kstat(char *module, int instance, const char *name, const char *stat, 4597 uint8_t type, void *val) 4598 { 4599 kstat_ctl_t *kcp; 4600 kstat_t *ksp; 4601 4602 if ((kcp = kstat_open()) == NULL) { 4603 warn("kstat open operation failed"); 4604 return (-1); 4605 } 4606 4607 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 4608 /* 4609 * The kstat query could fail if the underlying MAC 4610 * driver was already detached. 4611 */ 4612 goto bail; 4613 } 4614 4615 if (kstat_read(kcp, ksp, NULL) == -1) { 4616 warn("kstat read failed"); 4617 goto bail; 4618 } 4619 4620 if (dladm_kstat_value(ksp, stat, type, val) < 0) 4621 goto bail; 4622 4623 (void) kstat_close(kcp); 4624 return (0); 4625 4626 bail: 4627 (void) kstat_close(kcp); 4628 return (-1); 4629 } 4630 4631 static int 4632 get_one_kstat(const char *name, const char *stat, uint8_t type, 4633 void *val, boolean_t islink) 4634 { 4635 char module[DLPI_LINKNAME_MAX]; 4636 uint_t instance; 4637 4638 if (islink) { 4639 return (query_kstat("link", 0, name, stat, type, val)); 4640 } else { 4641 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS) 4642 return (-1); 4643 4644 return (query_kstat(module, instance, "mac", stat, type, val)); 4645 } 4646 } 4647 4648 static uint64_t 4649 get_ifspeed(const char *name, boolean_t islink) 4650 { 4651 uint64_t ifspeed = 0; 4652 4653 (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64, 4654 &ifspeed, islink); 4655 4656 return (ifspeed); 4657 } 4658 4659 static const char * 4660 get_linkstate(const char *name, boolean_t islink, char *buf) 4661 { 4662 link_state_t linkstate; 4663 4664 if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32, 4665 &linkstate, islink) != 0) { 4666 (void) strlcpy(buf, "?", DLADM_STRSIZE); 4667 return (buf); 4668 } 4669 return (dladm_linkstate2str(linkstate, buf)); 4670 } 4671 4672 static const char * 4673 get_linkduplex(const char *name, boolean_t islink, char *buf) 4674 { 4675 link_duplex_t linkduplex; 4676 4677 if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32, 4678 &linkduplex, islink) != 0) { 4679 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 4680 return (buf); 4681 } 4682 4683 return (dladm_linkduplex2str(linkduplex, buf)); 4684 } 4685 4686 typedef struct { 4687 char *s_buf; 4688 char **s_fields; /* array of pointer to the fields in s_buf */ 4689 uint_t s_nfields; /* the number of fields in s_buf */ 4690 } split_t; 4691 4692 /* 4693 * Free the split_t structure pointed to by `sp'. 4694 */ 4695 static void 4696 splitfree(split_t *sp) 4697 { 4698 free(sp->s_buf); 4699 free(sp->s_fields); 4700 free(sp); 4701 } 4702 4703 /* 4704 * Split `str' into at most `maxfields' fields, each field at most `maxlen' in 4705 * length. Return a pointer to a split_t containing the split fields, or NULL 4706 * on failure. 4707 */ 4708 static split_t * 4709 split(const char *str, uint_t maxfields, uint_t maxlen) 4710 { 4711 char *field, *token, *lasts = NULL; 4712 split_t *sp; 4713 4714 if (*str == '\0' || maxfields == 0 || maxlen == 0) 4715 return (NULL); 4716 4717 sp = calloc(sizeof (split_t), 1); 4718 if (sp == NULL) 4719 return (NULL); 4720 4721 sp->s_buf = strdup(str); 4722 sp->s_fields = malloc(sizeof (char *) * maxfields); 4723 if (sp->s_buf == NULL || sp->s_fields == NULL) 4724 goto fail; 4725 4726 token = sp->s_buf; 4727 while ((field = strtok_r(token, ",", &lasts)) != NULL) { 4728 if (sp->s_nfields == maxfields || strlen(field) > maxlen) 4729 goto fail; 4730 token = NULL; 4731 sp->s_fields[sp->s_nfields++] = field; 4732 } 4733 return (sp); 4734 fail: 4735 splitfree(sp); 4736 return (NULL); 4737 } 4738 4739 static int 4740 parse_wifi_fields(char *str, print_field_t ***fields, uint_t *countp, 4741 uint_t cmdtype) 4742 { 4743 4744 if (cmdtype == WIFI_CMD_SCAN) { 4745 if (str == NULL) 4746 str = def_scan_wifi_fields; 4747 if (strcasecmp(str, "all") == 0) 4748 str = all_scan_wifi_fields; 4749 } else if (cmdtype == WIFI_CMD_SHOW) { 4750 if (str == NULL) 4751 str = def_show_wifi_fields; 4752 if (strcasecmp(str, "all") == 0) 4753 str = all_show_wifi_fields; 4754 } else { 4755 return (-1); 4756 } 4757 *fields = parse_output_fields(str, wifi_fields, WIFI_MAX_FIELDS, 4758 cmdtype, countp); 4759 if (*fields != NULL) 4760 return (0); 4761 return (-1); 4762 } 4763 static print_field_t ** 4764 parse_output_fields(char *str, print_field_t *template, int max_fields, 4765 uint_t cmdtype, uint_t *countp) 4766 { 4767 split_t *sp; 4768 boolean_t good_match = B_FALSE; 4769 uint_t i, j; 4770 print_field_t **pf = NULL; 4771 4772 sp = split(str, max_fields, MAX_FIELD_LEN); 4773 4774 if (sp == NULL) 4775 return (NULL); 4776 4777 pf = malloc(sp->s_nfields * sizeof (print_field_t *)); 4778 if (pf == NULL) 4779 goto fail; 4780 4781 for (i = 0; i < sp->s_nfields; i++) { 4782 for (j = 0; j < max_fields; j++) { 4783 if (strcasecmp(sp->s_fields[i], 4784 template[j].pf_name) == 0) { 4785 good_match = template[j]. pf_cmdtype & cmdtype; 4786 break; 4787 } 4788 } 4789 if (!good_match) 4790 goto fail; 4791 4792 good_match = B_FALSE; 4793 pf[i] = &template[j]; 4794 } 4795 *countp = i; 4796 splitfree(sp); 4797 return (pf); 4798 fail: 4799 free(pf); 4800 splitfree(sp); 4801 return (NULL); 4802 } 4803 4804 typedef struct print_wifi_state { 4805 char *ws_link; 4806 boolean_t ws_parseable; 4807 boolean_t ws_header; 4808 print_state_t ws_print_state; 4809 } print_wifi_state_t; 4810 4811 typedef struct wlan_scan_args_s { 4812 print_wifi_state_t *ws_state; 4813 void *ws_attr; 4814 } wlan_scan_args_t; 4815 4816 static void 4817 print_field(print_state_t *statep, print_field_t *pfp, const char *value, 4818 boolean_t parseable) 4819 { 4820 uint_t width = pfp->pf_width; 4821 uint_t valwidth; 4822 uint_t compress; 4823 4824 /* 4825 * Parsable fields are separated by ':'. If such a field contains 4826 * a ':' or '\', this character is prefixed by a '\'. 4827 */ 4828 if (parseable) { 4829 char c; 4830 4831 if (statep->ps_nfields == 1) { 4832 (void) printf("%s", value); 4833 return; 4834 } 4835 while ((c = *value++) != '\0') { 4836 if (c == ':' || c == '\\') 4837 (void) putchar('\\'); 4838 (void) putchar(c); 4839 } 4840 if (!statep->ps_lastfield) 4841 (void) putchar(':'); 4842 return; 4843 } else { 4844 if (value[0] == '\0') 4845 value = STR_UNDEF_VAL; 4846 if (statep->ps_lastfield) { 4847 (void) printf("%s", value); 4848 statep->ps_overflow = 0; 4849 return; 4850 } 4851 4852 valwidth = strlen(value); 4853 if (valwidth > width) { 4854 statep->ps_overflow += valwidth - width; 4855 } else if (valwidth < width && statep->ps_overflow > 0) { 4856 compress = min(statep->ps_overflow, width - valwidth); 4857 statep->ps_overflow -= compress; 4858 width -= compress; 4859 } 4860 (void) printf("%-*s", width, value); 4861 } 4862 4863 if (!statep->ps_lastfield) 4864 (void) putchar(' '); 4865 } 4866 4867 static char * 4868 print_wlan_attr(print_field_t *wfp, void *warg) 4869 { 4870 static char buf[DLADM_STRSIZE]; 4871 wlan_scan_args_t *w = warg; 4872 print_wifi_state_t *statep = w->ws_state; 4873 dladm_wlan_attr_t *attrp = w->ws_attr; 4874 4875 if (wfp->pf_index == 0) { 4876 return ((char *)statep->ws_link); 4877 } 4878 4879 if ((wfp->pf_index & attrp->wa_valid) == 0) { 4880 return (""); 4881 } 4882 4883 switch (wfp->pf_index) { 4884 case DLADM_WLAN_ATTR_ESSID: 4885 (void) dladm_wlan_essid2str(&attrp->wa_essid, buf); 4886 break; 4887 case DLADM_WLAN_ATTR_BSSID: 4888 (void) dladm_wlan_bssid2str(&attrp->wa_bssid, buf); 4889 break; 4890 case DLADM_WLAN_ATTR_SECMODE: 4891 (void) dladm_wlan_secmode2str(&attrp->wa_secmode, buf); 4892 break; 4893 case DLADM_WLAN_ATTR_STRENGTH: 4894 (void) dladm_wlan_strength2str(&attrp->wa_strength, buf); 4895 break; 4896 case DLADM_WLAN_ATTR_MODE: 4897 (void) dladm_wlan_mode2str(&attrp->wa_mode, buf); 4898 break; 4899 case DLADM_WLAN_ATTR_SPEED: 4900 (void) dladm_wlan_speed2str(&attrp->wa_speed, buf); 4901 (void) strlcat(buf, "Mb", sizeof (buf)); 4902 break; 4903 case DLADM_WLAN_ATTR_AUTH: 4904 (void) dladm_wlan_auth2str(&attrp->wa_auth, buf); 4905 break; 4906 case DLADM_WLAN_ATTR_BSSTYPE: 4907 (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf); 4908 break; 4909 } 4910 4911 return (buf); 4912 } 4913 4914 static boolean_t 4915 print_scan_results(void *arg, dladm_wlan_attr_t *attrp) 4916 { 4917 print_wifi_state_t *statep = arg; 4918 wlan_scan_args_t warg; 4919 4920 if (statep->ws_header) { 4921 statep->ws_header = B_FALSE; 4922 if (!statep->ws_parseable) 4923 print_header(&statep->ws_print_state); 4924 } 4925 4926 statep->ws_print_state.ps_overflow = 0; 4927 bzero(&warg, sizeof (warg)); 4928 warg.ws_state = statep; 4929 warg.ws_attr = attrp; 4930 dladm_print_output(&statep->ws_print_state, statep->ws_parseable, 4931 print_wlan_attr, &warg); 4932 return (B_TRUE); 4933 } 4934 4935 static int 4936 scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4937 { 4938 print_wifi_state_t *statep = arg; 4939 dladm_status_t status; 4940 char link[MAXLINKNAMELEN]; 4941 4942 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 4943 sizeof (link))) != DLADM_STATUS_OK) { 4944 return (DLADM_WALK_CONTINUE); 4945 } 4946 4947 statep->ws_link = link; 4948 status = dladm_wlan_scan(dh, linkid, statep, print_scan_results); 4949 if (status != DLADM_STATUS_OK) 4950 die_dlerr(status, "cannot scan link '%s'", statep->ws_link); 4951 4952 return (DLADM_WALK_CONTINUE); 4953 } 4954 4955 static char * 4956 print_link_attr(print_field_t *wfp, void *warg) 4957 { 4958 static char buf[DLADM_STRSIZE]; 4959 char *ptr; 4960 wlan_scan_args_t *w = warg, w1; 4961 print_wifi_state_t *statep = w->ws_state; 4962 dladm_wlan_linkattr_t *attrp = w->ws_attr; 4963 4964 if (strcmp(wfp->pf_name, "status") == 0) { 4965 if ((wfp->pf_index & attrp->la_valid) != 0) 4966 (void) dladm_wlan_linkstatus2str( 4967 &attrp->la_status, buf); 4968 return (buf); 4969 } 4970 statep->ws_print_state.ps_overflow = 0; 4971 bzero(&w1, sizeof (w1)); 4972 w1.ws_state = statep; 4973 w1.ws_attr = &attrp->la_wlan_attr; 4974 ptr = print_wlan_attr(wfp, &w1); 4975 return (ptr); 4976 } 4977 4978 static int 4979 show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4980 { 4981 print_wifi_state_t *statep = arg; 4982 dladm_wlan_linkattr_t attr; 4983 dladm_status_t status; 4984 char link[MAXLINKNAMELEN]; 4985 wlan_scan_args_t warg; 4986 4987 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 4988 sizeof (link))) != DLADM_STATUS_OK) { 4989 return (DLADM_WALK_CONTINUE); 4990 } 4991 4992 /* dladm_wlan_get_linkattr() memsets attr with 0 */ 4993 status = dladm_wlan_get_linkattr(dh, linkid, &attr); 4994 if (status != DLADM_STATUS_OK) 4995 die_dlerr(status, "cannot get link attributes for %s", link); 4996 4997 statep->ws_link = link; 4998 4999 if (statep->ws_header) { 5000 statep->ws_header = B_FALSE; 5001 if (!statep->ws_parseable) 5002 print_header(&statep->ws_print_state); 5003 } 5004 5005 statep->ws_print_state.ps_overflow = 0; 5006 bzero(&warg, sizeof (warg)); 5007 warg.ws_state = statep; 5008 warg.ws_attr = &attr; 5009 dladm_print_output(&statep->ws_print_state, statep->ws_parseable, 5010 print_link_attr, &warg); 5011 return (DLADM_WALK_CONTINUE); 5012 } 5013 5014 static void 5015 do_display_wifi(int argc, char **argv, int cmd, const char *use) 5016 { 5017 int option; 5018 char *fields_str = NULL; 5019 print_field_t **fields; 5020 int (*callback)(dladm_handle_t, datalink_id_t, void *); 5021 uint_t nfields; 5022 print_wifi_state_t state; 5023 datalink_id_t linkid = DATALINK_ALL_LINKID; 5024 dladm_status_t status; 5025 5026 if (cmd == WIFI_CMD_SCAN) 5027 callback = scan_wifi; 5028 else if (cmd == WIFI_CMD_SHOW) 5029 callback = show_wifi; 5030 else 5031 return; 5032 5033 state.ws_parseable = B_FALSE; 5034 state.ws_header = B_TRUE; 5035 opterr = 0; 5036 while ((option = getopt_long(argc, argv, ":o:p", 5037 wifi_longopts, NULL)) != -1) { 5038 switch (option) { 5039 case 'o': 5040 fields_str = optarg; 5041 break; 5042 case 'p': 5043 state.ws_parseable = B_TRUE; 5044 break; 5045 default: 5046 die_opterr(optopt, option, use); 5047 } 5048 } 5049 5050 if (state.ws_parseable && fields_str == NULL) 5051 die("-p requires -o"); 5052 5053 if (state.ws_parseable && strcasecmp(fields_str, "all") == 0) 5054 die("\"-o all\" is invalid with -p"); 5055 5056 if (optind == (argc - 1)) { 5057 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5058 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5059 die_dlerr(status, "link %s is not valid", argv[optind]); 5060 } 5061 } else if (optind != argc) { 5062 usage(); 5063 } 5064 5065 if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) 5066 die("invalid field(s) specified"); 5067 5068 bzero(&state.ws_print_state, sizeof (state.ws_print_state)); 5069 state.ws_print_state.ps_fields = fields; 5070 state.ws_print_state.ps_nfields = nfields; 5071 5072 if (linkid == DATALINK_ALL_LINKID) { 5073 (void) dladm_walk_datalink_id(callback, handle, &state, 5074 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 5075 } else { 5076 (void) (*callback)(handle, linkid, &state); 5077 } 5078 free(fields); 5079 } 5080 5081 static void 5082 do_scan_wifi(int argc, char **argv, const char *use) 5083 { 5084 do_display_wifi(argc, argv, WIFI_CMD_SCAN, use); 5085 } 5086 5087 static void 5088 do_show_wifi(int argc, char **argv, const char *use) 5089 { 5090 do_display_wifi(argc, argv, WIFI_CMD_SHOW, use); 5091 } 5092 5093 typedef struct wlan_count_attr { 5094 uint_t wc_count; 5095 datalink_id_t wc_linkid; 5096 } wlan_count_attr_t; 5097 5098 /* ARGSUSED */ 5099 static int 5100 do_count_wlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5101 { 5102 wlan_count_attr_t *cp = arg; 5103 5104 if (cp->wc_count == 0) 5105 cp->wc_linkid = linkid; 5106 cp->wc_count++; 5107 return (DLADM_WALK_CONTINUE); 5108 } 5109 5110 static int 5111 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) 5112 { 5113 uint_t i; 5114 split_t *sp; 5115 dladm_wlan_key_t *wk; 5116 5117 sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_KEYNAME_LEN); 5118 if (sp == NULL) 5119 return (-1); 5120 5121 wk = malloc(sp->s_nfields * sizeof (dladm_wlan_key_t)); 5122 if (wk == NULL) 5123 goto fail; 5124 5125 for (i = 0; i < sp->s_nfields; i++) { 5126 char *s; 5127 dladm_secobj_class_t class; 5128 dladm_status_t status; 5129 5130 (void) strlcpy(wk[i].wk_name, sp->s_fields[i], 5131 DLADM_WLAN_MAX_KEYNAME_LEN); 5132 5133 wk[i].wk_idx = 1; 5134 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 5135 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 5136 goto fail; 5137 5138 wk[i].wk_idx = (uint_t)(s[1] - '0'); 5139 *s = '\0'; 5140 } 5141 wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN; 5142 5143 status = dladm_get_secobj(handle, wk[i].wk_name, &class, 5144 wk[i].wk_val, &wk[i].wk_len, 0); 5145 if (status != DLADM_STATUS_OK) { 5146 if (status == DLADM_STATUS_NOTFOUND) { 5147 status = dladm_get_secobj(handle, wk[i].wk_name, 5148 &class, wk[i].wk_val, &wk[i].wk_len, 5149 DLADM_OPT_PERSIST); 5150 } 5151 if (status != DLADM_STATUS_OK) 5152 goto fail; 5153 } 5154 wk[i].wk_class = class; 5155 } 5156 *keys = wk; 5157 *key_countp = i; 5158 splitfree(sp); 5159 return (0); 5160 fail: 5161 free(wk); 5162 splitfree(sp); 5163 return (-1); 5164 } 5165 5166 static void 5167 do_connect_wifi(int argc, char **argv, const char *use) 5168 { 5169 int option; 5170 dladm_wlan_attr_t attr, *attrp; 5171 dladm_status_t status = DLADM_STATUS_OK; 5172 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 5173 datalink_id_t linkid = DATALINK_ALL_LINKID; 5174 dladm_wlan_key_t *keys = NULL; 5175 uint_t key_count = 0; 5176 uint_t flags = 0; 5177 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 5178 char buf[DLADM_STRSIZE]; 5179 5180 opterr = 0; 5181 (void) memset(&attr, 0, sizeof (attr)); 5182 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 5183 wifi_longopts, NULL)) != -1) { 5184 switch (option) { 5185 case 'e': 5186 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 5187 if (status != DLADM_STATUS_OK) 5188 die("invalid ESSID '%s'", optarg); 5189 5190 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 5191 /* 5192 * Try to connect without doing a scan. 5193 */ 5194 flags |= DLADM_WLAN_CONNECT_NOSCAN; 5195 break; 5196 case 'i': 5197 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 5198 if (status != DLADM_STATUS_OK) 5199 die("invalid BSSID %s", optarg); 5200 5201 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 5202 break; 5203 case 'a': 5204 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 5205 if (status != DLADM_STATUS_OK) 5206 die("invalid authentication mode '%s'", optarg); 5207 5208 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 5209 break; 5210 case 'm': 5211 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 5212 if (status != DLADM_STATUS_OK) 5213 die("invalid mode '%s'", optarg); 5214 5215 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 5216 break; 5217 case 'b': 5218 if ((status = dladm_wlan_str2bsstype(optarg, 5219 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 5220 die("invalid bsstype '%s'", optarg); 5221 } 5222 5223 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 5224 break; 5225 case 's': 5226 if ((status = dladm_wlan_str2secmode(optarg, 5227 &attr.wa_secmode)) != DLADM_STATUS_OK) { 5228 die("invalid security mode '%s'", optarg); 5229 } 5230 5231 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 5232 break; 5233 case 'k': 5234 if (parse_wlan_keys(optarg, &keys, &key_count) < 0) 5235 die("invalid key(s) '%s'", optarg); 5236 5237 if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP) 5238 keysecmode = DLADM_WLAN_SECMODE_WEP; 5239 else 5240 keysecmode = DLADM_WLAN_SECMODE_WPA; 5241 break; 5242 case 'T': 5243 if (strcasecmp(optarg, "forever") == 0) { 5244 timeout = -1; 5245 break; 5246 } 5247 if (!str2int(optarg, &timeout) || timeout < 0) 5248 die("invalid timeout value '%s'", optarg); 5249 break; 5250 case 'c': 5251 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 5252 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 5253 break; 5254 default: 5255 die_opterr(optopt, option, use); 5256 break; 5257 } 5258 } 5259 5260 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 5261 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) { 5262 die("key required for security mode '%s'", 5263 dladm_wlan_secmode2str(&attr.wa_secmode, buf)); 5264 } 5265 } else { 5266 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 5267 attr.wa_secmode != keysecmode) 5268 die("incompatible -s and -k options"); 5269 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 5270 attr.wa_secmode = keysecmode; 5271 } 5272 5273 if (optind == (argc - 1)) { 5274 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5275 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5276 die_dlerr(status, "link %s is not valid", argv[optind]); 5277 } 5278 } else if (optind != argc) { 5279 usage(); 5280 } 5281 5282 if (linkid == DATALINK_ALL_LINKID) { 5283 wlan_count_attr_t wcattr; 5284 5285 wcattr.wc_linkid = DATALINK_INVALID_LINKID; 5286 wcattr.wc_count = 0; 5287 (void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr, 5288 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 5289 if (wcattr.wc_count == 0) { 5290 die("no wifi links are available"); 5291 } else if (wcattr.wc_count > 1) { 5292 die("link name is required when more than one wifi " 5293 "link is available"); 5294 } 5295 linkid = wcattr.wc_linkid; 5296 } 5297 attrp = (attr.wa_valid == 0) ? NULL : &attr; 5298 again: 5299 if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys, 5300 key_count, flags)) != DLADM_STATUS_OK) { 5301 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 5302 /* 5303 * Try again with scanning and filtering. 5304 */ 5305 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 5306 goto again; 5307 } 5308 5309 if (status == DLADM_STATUS_NOTFOUND) { 5310 if (attr.wa_valid == 0) { 5311 die("no wifi networks are available"); 5312 } else { 5313 die("no wifi networks with the specified " 5314 "criteria are available"); 5315 } 5316 } 5317 die_dlerr(status, "cannot connect"); 5318 } 5319 free(keys); 5320 } 5321 5322 /* ARGSUSED */ 5323 static int 5324 do_all_disconnect_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5325 { 5326 dladm_status_t status; 5327 5328 status = dladm_wlan_disconnect(dh, linkid); 5329 if (status != DLADM_STATUS_OK) 5330 warn_dlerr(status, "cannot disconnect link"); 5331 5332 return (DLADM_WALK_CONTINUE); 5333 } 5334 5335 static void 5336 do_disconnect_wifi(int argc, char **argv, const char *use) 5337 { 5338 int option; 5339 datalink_id_t linkid = DATALINK_ALL_LINKID; 5340 boolean_t all_links = B_FALSE; 5341 dladm_status_t status; 5342 wlan_count_attr_t wcattr; 5343 5344 opterr = 0; 5345 while ((option = getopt_long(argc, argv, ":a", 5346 wifi_longopts, NULL)) != -1) { 5347 switch (option) { 5348 case 'a': 5349 all_links = B_TRUE; 5350 break; 5351 default: 5352 die_opterr(optopt, option, use); 5353 break; 5354 } 5355 } 5356 5357 if (optind == (argc - 1)) { 5358 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5359 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5360 die_dlerr(status, "link %s is not valid", argv[optind]); 5361 } 5362 } else if (optind != argc) { 5363 usage(); 5364 } 5365 5366 if (linkid == DATALINK_ALL_LINKID) { 5367 if (!all_links) { 5368 wcattr.wc_linkid = linkid; 5369 wcattr.wc_count = 0; 5370 (void) dladm_walk_datalink_id(do_count_wlan, handle, 5371 &wcattr, DATALINK_CLASS_PHYS, DL_WIFI, 5372 DLADM_OPT_ACTIVE); 5373 if (wcattr.wc_count == 0) { 5374 die("no wifi links are available"); 5375 } else if (wcattr.wc_count > 1) { 5376 die("link name is required when more than " 5377 "one wifi link is available"); 5378 } 5379 linkid = wcattr.wc_linkid; 5380 } else { 5381 (void) dladm_walk_datalink_id(do_all_disconnect_wifi, 5382 handle, NULL, DATALINK_CLASS_PHYS, DL_WIFI, 5383 DLADM_OPT_ACTIVE); 5384 return; 5385 } 5386 } 5387 status = dladm_wlan_disconnect(handle, linkid); 5388 if (status != DLADM_STATUS_OK) 5389 die_dlerr(status, "cannot disconnect"); 5390 } 5391 5392 static void 5393 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, 5394 const char *propname, dladm_prop_type_t type, const char *format, 5395 char **pptr) 5396 { 5397 int i; 5398 char *ptr, *lim; 5399 char buf[DLADM_STRSIZE]; 5400 char *unknown = "--", *notsup = ""; 5401 char **propvals = statep->ls_propvals; 5402 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5403 dladm_status_t status; 5404 5405 status = dladm_get_linkprop(handle, linkid, type, propname, propvals, 5406 &valcnt); 5407 if (status != DLADM_STATUS_OK) { 5408 if (status == DLADM_STATUS_TEMPONLY) { 5409 if (type == DLADM_PROP_VAL_MODIFIABLE && 5410 statep->ls_persist) { 5411 valcnt = 1; 5412 propvals = &unknown; 5413 } else { 5414 statep->ls_status = status; 5415 statep->ls_retstatus = status; 5416 return; 5417 } 5418 } else if (status == DLADM_STATUS_NOTSUP || 5419 statep->ls_persist) { 5420 valcnt = 1; 5421 if (type == DLADM_PROP_VAL_CURRENT || 5422 type == DLADM_PROP_VAL_PERM) 5423 propvals = &unknown; 5424 else 5425 propvals = ¬sup; 5426 } else if (status == DLADM_STATUS_NOTDEFINED) { 5427 propvals = ¬sup; /* STR_UNDEF_VAL */ 5428 } else { 5429 if (statep->ls_proplist && 5430 statep->ls_status == DLADM_STATUS_OK) { 5431 warn_dlerr(status, 5432 "cannot get link property '%s' for %s", 5433 propname, statep->ls_link); 5434 } 5435 statep->ls_status = status; 5436 statep->ls_retstatus = status; 5437 return; 5438 } 5439 } 5440 5441 statep->ls_status = DLADM_STATUS_OK; 5442 5443 ptr = buf; 5444 lim = buf + DLADM_STRSIZE; 5445 for (i = 0; i < valcnt; i++) { 5446 if (propvals[i][0] == '\0' && !statep->ls_parseable) 5447 ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL","); 5448 else 5449 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 5450 if (ptr >= lim) 5451 break; 5452 } 5453 if (valcnt > 0) 5454 buf[strlen(buf) - 1] = '\0'; 5455 5456 lim = statep->ls_line + MAX_PROP_LINE; 5457 if (statep->ls_parseable) { 5458 *pptr += snprintf(*pptr, lim - *pptr, 5459 "%s", buf); 5460 } else { 5461 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 5462 } 5463 } 5464 5465 static char * 5466 linkprop_callback(print_field_t *pf, void *ls_arg) 5467 { 5468 linkprop_args_t *arg = ls_arg; 5469 char *propname = arg->ls_propname; 5470 show_linkprop_state_t *statep = arg->ls_state; 5471 char *ptr = statep->ls_line; 5472 char *lim = ptr + MAX_PROP_LINE; 5473 datalink_id_t linkid = arg->ls_linkid; 5474 5475 switch (pf->pf_index) { 5476 case LINKPROP_LINK: 5477 (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); 5478 break; 5479 case LINKPROP_PROPERTY: 5480 (void) snprintf(ptr, lim - ptr, "%s", propname); 5481 break; 5482 case LINKPROP_VALUE: 5483 print_linkprop(linkid, statep, propname, 5484 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 5485 DLADM_PROP_VAL_CURRENT, "%s", &ptr); 5486 /* 5487 * If we failed to query the link property, for example, query 5488 * the persistent value of a non-persistable link property, 5489 * simply skip the output. 5490 */ 5491 if (statep->ls_status != DLADM_STATUS_OK) 5492 goto skip; 5493 ptr = statep->ls_line; 5494 break; 5495 case LINKPROP_PERM: 5496 print_linkprop(linkid, statep, propname, 5497 DLADM_PROP_VAL_PERM, "%s", &ptr); 5498 if (statep->ls_status != DLADM_STATUS_OK) 5499 goto skip; 5500 ptr = statep->ls_line; 5501 break; 5502 case LINKPROP_DEFAULT: 5503 print_linkprop(linkid, statep, propname, 5504 DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 5505 if (statep->ls_status != DLADM_STATUS_OK) 5506 goto skip; 5507 ptr = statep->ls_line; 5508 break; 5509 case LINKPROP_POSSIBLE: 5510 print_linkprop(linkid, statep, propname, 5511 DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 5512 if (statep->ls_status != DLADM_STATUS_OK) 5513 goto skip; 5514 ptr = statep->ls_line; 5515 break; 5516 default: 5517 die("invalid input"); 5518 break; 5519 } 5520 return (ptr); 5521 skip: 5522 if (statep->ls_status != DLADM_STATUS_OK) 5523 return (NULL); 5524 else 5525 return (""); 5526 } 5527 5528 static boolean_t 5529 linkprop_is_supported(datalink_id_t linkid, const char *propname, 5530 show_linkprop_state_t *statep) 5531 { 5532 dladm_status_t status; 5533 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5534 5535 /* if used with -p flag, always print output */ 5536 if (statep->ls_proplist != NULL) 5537 return (B_TRUE); 5538 5539 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_DEFAULT, 5540 propname, statep->ls_propvals, &valcnt); 5541 5542 if (status == DLADM_STATUS_OK) 5543 return (B_TRUE); 5544 5545 /* 5546 * A system wide default value is not available for the 5547 * property. Check if current value can be retrieved. 5548 */ 5549 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT, 5550 propname, statep->ls_propvals, &valcnt); 5551 5552 return (status == DLADM_STATUS_OK); 5553 } 5554 5555 /* ARGSUSED */ 5556 static int 5557 show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname, 5558 void *arg) 5559 { 5560 show_linkprop_state_t *statep = arg; 5561 linkprop_args_t ls_arg; 5562 5563 bzero(&ls_arg, sizeof (ls_arg)); 5564 ls_arg.ls_state = statep; 5565 ls_arg.ls_propname = (char *)propname; 5566 ls_arg.ls_linkid = linkid; 5567 5568 if (statep->ls_header) { 5569 statep->ls_header = B_FALSE; 5570 if (!statep->ls_parseable) 5571 print_header(&statep->ls_print); 5572 } 5573 if (!statep->ls_parseable && 5574 !linkprop_is_supported(linkid, propname, statep)) 5575 return (DLADM_WALK_CONTINUE); 5576 5577 dladm_print_output(&statep->ls_print, statep->ls_parseable, 5578 linkprop_callback, (void *)&ls_arg); 5579 5580 return (DLADM_WALK_CONTINUE); 5581 } 5582 5583 static void 5584 do_show_linkprop(int argc, char **argv, const char *use) 5585 { 5586 int option; 5587 dladm_arg_list_t *proplist = NULL; 5588 datalink_id_t linkid = DATALINK_ALL_LINKID; 5589 show_linkprop_state_t state; 5590 uint32_t flags = DLADM_OPT_ACTIVE; 5591 dladm_status_t status; 5592 char *fields_str = NULL; 5593 print_field_t **fields; 5594 uint_t nfields; 5595 boolean_t o_arg = B_FALSE; 5596 char *all_fields = 5597 "link,property,perm,value,default,possible"; 5598 5599 fields_str = all_fields; 5600 5601 opterr = 0; 5602 state.ls_propvals = NULL; 5603 state.ls_line = NULL; 5604 state.ls_parseable = B_FALSE; 5605 state.ls_persist = B_FALSE; 5606 state.ls_header = B_TRUE; 5607 state.ls_retstatus = DLADM_STATUS_OK; 5608 while ((option = getopt_long(argc, argv, ":p:cPo:", 5609 prop_longopts, NULL)) != -1) { 5610 switch (option) { 5611 case 'p': 5612 if (dladm_parse_link_props(optarg, &proplist, B_TRUE) 5613 != DLADM_STATUS_OK) 5614 die("invalid link properties specified"); 5615 break; 5616 case 'c': 5617 state.ls_parseable = B_TRUE; 5618 break; 5619 case 'P': 5620 state.ls_persist = B_TRUE; 5621 flags = DLADM_OPT_PERSIST; 5622 break; 5623 case 'o': 5624 o_arg = B_TRUE; 5625 if (strcasecmp(optarg, "all") == 0) 5626 fields_str = all_fields; 5627 else 5628 fields_str = optarg; 5629 break; 5630 default: 5631 die_opterr(optopt, option, use); 5632 break; 5633 } 5634 } 5635 5636 if (state.ls_parseable && !o_arg) 5637 die("-c requires -o"); 5638 5639 if (state.ls_parseable && fields_str == all_fields) 5640 die("\"-o all\" is invalid with -c"); 5641 5642 if (optind == (argc - 1)) { 5643 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5644 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5645 die_dlerr(status, "link %s is not valid", argv[optind]); 5646 } 5647 } else if (optind != argc) { 5648 usage(); 5649 } 5650 5651 bzero(&state.ls_print, sizeof (print_state_t)); 5652 state.ls_proplist = proplist; 5653 state.ls_status = DLADM_STATUS_OK; 5654 5655 fields = parse_output_fields(fields_str, linkprop_fields, 5656 LINKPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 5657 5658 if (fields == NULL) { 5659 die("invalid field(s) specified"); 5660 return; 5661 } 5662 5663 state.ls_print.ps_fields = fields; 5664 state.ls_print.ps_nfields = nfields; 5665 if (linkid == DATALINK_ALL_LINKID) { 5666 (void) dladm_walk_datalink_id(show_linkprop_onelink, handle, 5667 &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 5668 } else { 5669 (void) show_linkprop_onelink(handle, linkid, &state); 5670 } 5671 dladm_free_props(proplist); 5672 5673 if (state.ls_retstatus != DLADM_STATUS_OK) { 5674 dladm_close(handle); 5675 exit(EXIT_FAILURE); 5676 } 5677 } 5678 5679 static int 5680 show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg) 5681 { 5682 int i; 5683 char *buf; 5684 uint32_t flags; 5685 dladm_arg_list_t *proplist = NULL; 5686 show_linkprop_state_t *statep = arg; 5687 dlpi_handle_t dh = NULL; 5688 5689 statep->ls_status = DLADM_STATUS_OK; 5690 5691 if (dladm_datalink_id2info(hdl, linkid, &flags, NULL, NULL, 5692 statep->ls_link, MAXLINKNAMELEN) != DLADM_STATUS_OK) { 5693 statep->ls_status = DLADM_STATUS_NOTFOUND; 5694 return (DLADM_WALK_CONTINUE); 5695 } 5696 5697 if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) || 5698 (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) { 5699 statep->ls_status = DLADM_STATUS_BADARG; 5700 return (DLADM_WALK_CONTINUE); 5701 } 5702 5703 proplist = statep->ls_proplist; 5704 5705 /* 5706 * When some WiFi links are opened for the first time, their hardware 5707 * automatically scans for APs and does other slow operations. Thus, 5708 * if there are no open links, the retrieval of link properties 5709 * (below) will proceed slowly unless we hold the link open. 5710 * 5711 * Note that failure of dlpi_open() does not necessarily mean invalid 5712 * link properties, because dlpi_open() may fail because of incorrect 5713 * autopush configuration. Therefore, we ingore the return value of 5714 * dlpi_open(). 5715 */ 5716 if (!statep->ls_persist) 5717 (void) dlpi_open(statep->ls_link, &dh, 0); 5718 5719 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 5720 DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 5721 if (buf == NULL) 5722 die("insufficient memory"); 5723 5724 statep->ls_propvals = (char **)(void *)buf; 5725 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 5726 statep->ls_propvals[i] = buf + 5727 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 5728 i * DLADM_PROP_VAL_MAX; 5729 } 5730 statep->ls_line = buf + 5731 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 5732 5733 if (proplist != NULL) { 5734 for (i = 0; i < proplist->al_count; i++) { 5735 (void) show_linkprop(hdl, linkid, 5736 proplist->al_info[i].ai_name, statep); 5737 } 5738 } else { 5739 (void) dladm_walk_linkprop(hdl, linkid, statep, 5740 show_linkprop); 5741 } 5742 if (dh != NULL) 5743 dlpi_close(dh); 5744 free(buf); 5745 return (DLADM_WALK_CONTINUE); 5746 } 5747 5748 static dladm_status_t 5749 set_linkprop_persist(datalink_id_t linkid, const char *prop_name, 5750 char **prop_val, uint_t val_cnt, boolean_t reset) 5751 { 5752 dladm_status_t status; 5753 5754 status = dladm_set_linkprop(handle, linkid, prop_name, prop_val, 5755 val_cnt, DLADM_OPT_PERSIST); 5756 5757 if (status != DLADM_STATUS_OK) { 5758 warn_dlerr(status, "cannot persistently %s link property '%s'", 5759 reset ? "reset" : "set", prop_name); 5760 } 5761 return (status); 5762 } 5763 5764 static int 5765 reset_one_linkprop(dladm_handle_t dh, datalink_id_t linkid, 5766 const char *propname, void *arg) 5767 { 5768 set_linkprop_state_t *statep = arg; 5769 dladm_status_t status; 5770 5771 status = dladm_set_linkprop(dh, linkid, propname, NULL, 0, 5772 DLADM_OPT_ACTIVE); 5773 if (status != DLADM_STATUS_OK) { 5774 warn_dlerr(status, "cannot reset link property '%s' on '%s'", 5775 propname, statep->ls_name); 5776 } 5777 if (!statep->ls_temp) { 5778 dladm_status_t s; 5779 5780 s = set_linkprop_persist(linkid, propname, NULL, 0, 5781 statep->ls_reset); 5782 if (s != DLADM_STATUS_OK) 5783 status = s; 5784 } 5785 if (status != DLADM_STATUS_OK) 5786 statep->ls_status = status; 5787 5788 return (DLADM_WALK_CONTINUE); 5789 } 5790 5791 static void 5792 set_linkprop(int argc, char **argv, boolean_t reset, const char *use) 5793 { 5794 int i, option; 5795 char errmsg[DLADM_STRSIZE]; 5796 char *altroot = NULL; 5797 datalink_id_t linkid; 5798 boolean_t temp = B_FALSE; 5799 dladm_status_t status = DLADM_STATUS_OK; 5800 dladm_arg_list_t *proplist = NULL; 5801 5802 opterr = 0; 5803 while ((option = getopt_long(argc, argv, ":p:R:t", 5804 prop_longopts, NULL)) != -1) { 5805 switch (option) { 5806 case 'p': 5807 if (dladm_parse_link_props(optarg, &proplist, reset) != 5808 DLADM_STATUS_OK) { 5809 die("invalid link properties specified"); 5810 } 5811 break; 5812 case 't': 5813 temp = B_TRUE; 5814 break; 5815 case 'R': 5816 altroot = optarg; 5817 break; 5818 default: 5819 die_opterr(optopt, option, use); 5820 5821 } 5822 } 5823 5824 /* get link name (required last argument) */ 5825 if (optind != (argc - 1)) 5826 usage(); 5827 5828 if (proplist == NULL && !reset) 5829 die("link property must be specified"); 5830 5831 if (altroot != NULL) { 5832 dladm_free_props(proplist); 5833 altroot_cmd(altroot, argc, argv); 5834 } 5835 5836 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 5837 NULL); 5838 if (status != DLADM_STATUS_OK) 5839 die_dlerr(status, "link %s is not valid", argv[optind]); 5840 5841 if (proplist == NULL) { 5842 set_linkprop_state_t state; 5843 5844 state.ls_name = argv[optind]; 5845 state.ls_reset = reset; 5846 state.ls_temp = temp; 5847 state.ls_status = DLADM_STATUS_OK; 5848 5849 (void) dladm_walk_linkprop(handle, linkid, &state, 5850 reset_one_linkprop); 5851 5852 status = state.ls_status; 5853 goto done; 5854 } 5855 5856 for (i = 0; i < proplist->al_count; i++) { 5857 dladm_arg_info_t *aip = &proplist->al_info[i]; 5858 char **val; 5859 uint_t count; 5860 dladm_status_t s; 5861 5862 if (reset) { 5863 val = NULL; 5864 count = 0; 5865 } else { 5866 val = aip->ai_val; 5867 count = aip->ai_count; 5868 if (count == 0) { 5869 warn("no value specified for '%s'", 5870 aip->ai_name); 5871 status = DLADM_STATUS_BADARG; 5872 continue; 5873 } 5874 } 5875 s = dladm_set_linkprop(handle, linkid, aip->ai_name, val, count, 5876 DLADM_OPT_ACTIVE); 5877 if (s == DLADM_STATUS_OK) { 5878 if (!temp) { 5879 s = set_linkprop_persist(linkid, 5880 aip->ai_name, val, count, reset); 5881 if (s != DLADM_STATUS_OK) 5882 status = s; 5883 } 5884 continue; 5885 } 5886 status = s; 5887 switch (s) { 5888 case DLADM_STATUS_NOTFOUND: 5889 warn("invalid link property '%s'", aip->ai_name); 5890 break; 5891 case DLADM_STATUS_BADVAL: { 5892 int j; 5893 char *ptr, *lim; 5894 char **propvals = NULL; 5895 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5896 5897 ptr = malloc((sizeof (char *) + 5898 DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 5899 MAX_PROP_LINE); 5900 5901 propvals = (char **)(void *)ptr; 5902 if (propvals == NULL) 5903 die("insufficient memory"); 5904 5905 for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 5906 propvals[j] = ptr + sizeof (char *) * 5907 DLADM_MAX_PROP_VALCNT + 5908 j * DLADM_PROP_VAL_MAX; 5909 } 5910 s = dladm_get_linkprop(handle, linkid, 5911 DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals, 5912 &valcnt); 5913 5914 if (s != DLADM_STATUS_OK) { 5915 warn_dlerr(status, "cannot set link property " 5916 "'%s' on '%s'", aip->ai_name, argv[optind]); 5917 free(propvals); 5918 break; 5919 } 5920 5921 ptr = errmsg; 5922 lim = ptr + DLADM_STRSIZE; 5923 *ptr = '\0'; 5924 for (j = 0; j < valcnt; j++) { 5925 ptr += snprintf(ptr, lim - ptr, "%s,", 5926 propvals[j]); 5927 if (ptr >= lim) 5928 break; 5929 } 5930 if (ptr > errmsg) { 5931 *(ptr - 1) = '\0'; 5932 warn("link property '%s' must be one of: %s", 5933 aip->ai_name, errmsg); 5934 } else 5935 warn("invalid link property '%s'", *val); 5936 free(propvals); 5937 break; 5938 } 5939 default: 5940 if (reset) { 5941 warn_dlerr(status, "cannot reset link property " 5942 "'%s' on '%s'", aip->ai_name, argv[optind]); 5943 } else { 5944 warn_dlerr(status, "cannot set link property " 5945 "'%s' on '%s'", aip->ai_name, argv[optind]); 5946 } 5947 break; 5948 } 5949 } 5950 done: 5951 dladm_free_props(proplist); 5952 if (status != DLADM_STATUS_OK) { 5953 dladm_close(handle); 5954 exit(1); 5955 } 5956 } 5957 5958 static void 5959 do_set_linkprop(int argc, char **argv, const char *use) 5960 { 5961 set_linkprop(argc, argv, B_FALSE, use); 5962 } 5963 5964 static void 5965 do_reset_linkprop(int argc, char **argv, const char *use) 5966 { 5967 set_linkprop(argc, argv, B_TRUE, use); 5968 } 5969 5970 static int 5971 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 5972 dladm_secobj_class_t class) 5973 { 5974 int error = 0; 5975 5976 if (class == DLADM_SECOBJ_CLASS_WPA) { 5977 if (len < 8 || len > 63) 5978 return (EINVAL); 5979 (void) memcpy(obj_val, buf, len); 5980 *obj_lenp = len; 5981 return (error); 5982 } 5983 5984 if (class == DLADM_SECOBJ_CLASS_WEP) { 5985 switch (len) { 5986 case 5: /* ASCII key sizes */ 5987 case 13: 5988 (void) memcpy(obj_val, buf, len); 5989 *obj_lenp = len; 5990 break; 5991 case 10: /* Hex key sizes, not preceded by 0x */ 5992 case 26: 5993 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 5994 break; 5995 case 12: /* Hex key sizes, preceded by 0x */ 5996 case 28: 5997 if (strncmp(buf, "0x", 2) != 0) 5998 return (EINVAL); 5999 error = hexascii_to_octet(buf + 2, len - 2, 6000 obj_val, obj_lenp); 6001 break; 6002 default: 6003 return (EINVAL); 6004 } 6005 return (error); 6006 } 6007 6008 return (ENOENT); 6009 } 6010 6011 static void 6012 defersig(int sig) 6013 { 6014 signalled = sig; 6015 } 6016 6017 static int 6018 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 6019 { 6020 uint_t len = 0; 6021 int c; 6022 struct termios stored, current; 6023 void (*sigfunc)(int); 6024 6025 /* 6026 * Turn off echo -- but before we do so, defer SIGINT handling 6027 * so that a ^C doesn't leave the terminal corrupted. 6028 */ 6029 sigfunc = signal(SIGINT, defersig); 6030 (void) fflush(stdin); 6031 (void) tcgetattr(0, &stored); 6032 current = stored; 6033 current.c_lflag &= ~(ICANON|ECHO); 6034 current.c_cc[VTIME] = 0; 6035 current.c_cc[VMIN] = 1; 6036 (void) tcsetattr(0, TCSANOW, ¤t); 6037 again: 6038 if (try == 1) 6039 (void) printf(gettext("provide value for '%s': "), objname); 6040 else 6041 (void) printf(gettext("confirm value for '%s': "), objname); 6042 6043 (void) fflush(stdout); 6044 while (signalled == 0) { 6045 c = getchar(); 6046 if (c == '\n' || c == '\r') { 6047 if (len != 0) 6048 break; 6049 (void) putchar('\n'); 6050 goto again; 6051 } 6052 6053 buf[len++] = c; 6054 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 6055 break; 6056 (void) putchar('*'); 6057 } 6058 6059 (void) putchar('\n'); 6060 (void) fflush(stdin); 6061 6062 /* 6063 * Restore terminal setting and handle deferred signals. 6064 */ 6065 (void) tcsetattr(0, TCSANOW, &stored); 6066 6067 (void) signal(SIGINT, sigfunc); 6068 if (signalled != 0) 6069 (void) kill(getpid(), signalled); 6070 6071 return (len); 6072 } 6073 6074 static int 6075 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 6076 dladm_secobj_class_t class, FILE *filep) 6077 { 6078 int rval; 6079 uint_t len, len2; 6080 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 6081 6082 if (filep == NULL) { 6083 len = get_secobj_from_tty(1, obj_name, buf); 6084 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 6085 if (rval == 0) { 6086 len2 = get_secobj_from_tty(2, obj_name, buf2); 6087 if (len != len2 || memcmp(buf, buf2, len) != 0) 6088 rval = ENOTSUP; 6089 } 6090 return (rval); 6091 } else { 6092 for (;;) { 6093 if (fgets(buf, sizeof (buf), filep) == NULL) 6094 break; 6095 if (isspace(buf[0])) 6096 continue; 6097 6098 len = strlen(buf); 6099 if (buf[len - 1] == '\n') { 6100 buf[len - 1] = '\0'; 6101 len--; 6102 } 6103 break; 6104 } 6105 (void) fclose(filep); 6106 } 6107 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 6108 } 6109 6110 static boolean_t 6111 check_auth(const char *auth) 6112 { 6113 struct passwd *pw; 6114 6115 if ((pw = getpwuid(getuid())) == NULL) 6116 return (B_FALSE); 6117 6118 return (chkauthattr(auth, pw->pw_name) != 0); 6119 } 6120 6121 static void 6122 audit_secobj(char *auth, char *class, char *obj, 6123 boolean_t success, boolean_t create) 6124 { 6125 adt_session_data_t *ah; 6126 adt_event_data_t *event; 6127 au_event_t flag; 6128 char *errstr; 6129 6130 if (create) { 6131 flag = ADT_dladm_create_secobj; 6132 errstr = "ADT_dladm_create_secobj"; 6133 } else { 6134 flag = ADT_dladm_delete_secobj; 6135 errstr = "ADT_dladm_delete_secobj"; 6136 } 6137 6138 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 6139 die("adt_start_session: %s", strerror(errno)); 6140 6141 if ((event = adt_alloc_event(ah, flag)) == NULL) 6142 die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 6143 6144 /* fill in audit info */ 6145 if (create) { 6146 event->adt_dladm_create_secobj.auth_used = auth; 6147 event->adt_dladm_create_secobj.obj_class = class; 6148 event->adt_dladm_create_secobj.obj_name = obj; 6149 } else { 6150 event->adt_dladm_delete_secobj.auth_used = auth; 6151 event->adt_dladm_delete_secobj.obj_class = class; 6152 event->adt_dladm_delete_secobj.obj_name = obj; 6153 } 6154 6155 if (success) { 6156 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 6157 die("adt_put_event (%s, success): %s", errstr, 6158 strerror(errno)); 6159 } 6160 } else { 6161 if (adt_put_event(event, ADT_FAILURE, 6162 ADT_FAIL_VALUE_AUTH) != 0) { 6163 die("adt_put_event: (%s, failure): %s", errstr, 6164 strerror(errno)); 6165 } 6166 } 6167 6168 adt_free_event(event); 6169 (void) adt_end_session(ah); 6170 } 6171 6172 #define MAX_SECOBJS 32 6173 #define MAX_SECOBJ_NAMELEN 32 6174 static void 6175 do_create_secobj(int argc, char **argv, const char *use) 6176 { 6177 int option, rval; 6178 FILE *filep = NULL; 6179 char *obj_name = NULL; 6180 char *class_name = NULL; 6181 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 6182 uint_t obj_len; 6183 boolean_t success, temp = B_FALSE; 6184 dladm_status_t status; 6185 dladm_secobj_class_t class = -1; 6186 uid_t euid; 6187 6188 opterr = 0; 6189 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 6190 while ((option = getopt_long(argc, argv, ":f:c:R:t", 6191 wifi_longopts, NULL)) != -1) { 6192 switch (option) { 6193 case 'f': 6194 euid = geteuid(); 6195 (void) seteuid(getuid()); 6196 filep = fopen(optarg, "r"); 6197 if (filep == NULL) { 6198 die("cannot open %s: %s", optarg, 6199 strerror(errno)); 6200 } 6201 (void) seteuid(euid); 6202 break; 6203 case 'c': 6204 class_name = optarg; 6205 status = dladm_str2secobjclass(optarg, &class); 6206 if (status != DLADM_STATUS_OK) { 6207 die("invalid secure object class '%s', " 6208 "valid values are: wep, wpa", optarg); 6209 } 6210 break; 6211 case 't': 6212 temp = B_TRUE; 6213 break; 6214 case 'R': 6215 status = dladm_set_rootdir(optarg); 6216 if (status != DLADM_STATUS_OK) { 6217 die_dlerr(status, "invalid directory " 6218 "specified"); 6219 } 6220 break; 6221 default: 6222 die_opterr(optopt, option, use); 6223 break; 6224 } 6225 } 6226 6227 if (optind == (argc - 1)) 6228 obj_name = argv[optind]; 6229 else if (optind != argc) 6230 usage(); 6231 6232 if (class == -1) 6233 die("secure object class required"); 6234 6235 if (obj_name == NULL) 6236 die("secure object name required"); 6237 6238 if (!dladm_valid_secobj_name(obj_name)) 6239 die("invalid secure object name '%s'", obj_name); 6240 6241 success = check_auth(LINK_SEC_AUTH); 6242 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 6243 if (!success) 6244 die("authorization '%s' is required", LINK_SEC_AUTH); 6245 6246 rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 6247 if (rval != 0) { 6248 switch (rval) { 6249 case ENOENT: 6250 die("invalid secure object class"); 6251 break; 6252 case EINVAL: 6253 die("invalid secure object value"); 6254 break; 6255 case ENOTSUP: 6256 die("verification failed"); 6257 break; 6258 default: 6259 die("invalid secure object: %s", strerror(rval)); 6260 break; 6261 } 6262 } 6263 6264 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 6265 DLADM_OPT_CREATE | DLADM_OPT_ACTIVE); 6266 if (status != DLADM_STATUS_OK) { 6267 die_dlerr(status, "could not create secure object '%s'", 6268 obj_name); 6269 } 6270 if (temp) 6271 return; 6272 6273 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 6274 DLADM_OPT_PERSIST); 6275 if (status != DLADM_STATUS_OK) { 6276 warn_dlerr(status, "could not persistently create secure " 6277 "object '%s'", obj_name); 6278 } 6279 } 6280 6281 static void 6282 do_delete_secobj(int argc, char **argv, const char *use) 6283 { 6284 int i, option; 6285 boolean_t temp = B_FALSE; 6286 split_t *sp = NULL; 6287 boolean_t success; 6288 dladm_status_t status, pstatus; 6289 6290 opterr = 0; 6291 status = pstatus = DLADM_STATUS_OK; 6292 while ((option = getopt_long(argc, argv, ":R:t", 6293 wifi_longopts, NULL)) != -1) { 6294 switch (option) { 6295 case 't': 6296 temp = B_TRUE; 6297 break; 6298 case 'R': 6299 status = dladm_set_rootdir(optarg); 6300 if (status != DLADM_STATUS_OK) { 6301 die_dlerr(status, "invalid directory " 6302 "specified"); 6303 } 6304 break; 6305 default: 6306 die_opterr(optopt, option, use); 6307 break; 6308 } 6309 } 6310 6311 if (optind == (argc - 1)) { 6312 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 6313 if (sp == NULL) { 6314 die("invalid secure object name(s): '%s'", 6315 argv[optind]); 6316 } 6317 } else if (optind != argc) 6318 usage(); 6319 6320 if (sp == NULL || sp->s_nfields < 1) 6321 die("secure object name required"); 6322 6323 success = check_auth(LINK_SEC_AUTH); 6324 audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE); 6325 if (!success) 6326 die("authorization '%s' is required", LINK_SEC_AUTH); 6327 6328 for (i = 0; i < sp->s_nfields; i++) { 6329 status = dladm_unset_secobj(handle, sp->s_fields[i], 6330 DLADM_OPT_ACTIVE); 6331 if (!temp) { 6332 pstatus = dladm_unset_secobj(handle, sp->s_fields[i], 6333 DLADM_OPT_PERSIST); 6334 } else { 6335 pstatus = DLADM_STATUS_OK; 6336 } 6337 6338 if (status != DLADM_STATUS_OK) { 6339 warn_dlerr(status, "could not delete secure object " 6340 "'%s'", sp->s_fields[i]); 6341 } 6342 if (pstatus != DLADM_STATUS_OK) { 6343 warn_dlerr(pstatus, "could not persistently delete " 6344 "secure object '%s'", sp->s_fields[i]); 6345 } 6346 } 6347 6348 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) { 6349 dladm_close(handle); 6350 exit(1); 6351 } 6352 } 6353 6354 typedef struct show_secobj_state { 6355 boolean_t ss_persist; 6356 boolean_t ss_parseable; 6357 boolean_t ss_header; 6358 print_state_t ss_print; 6359 } show_secobj_state_t; 6360 6361 6362 static boolean_t 6363 show_secobj(dladm_handle_t dh, void *arg, const char *obj_name) 6364 { 6365 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 6366 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 6367 char buf[DLADM_STRSIZE]; 6368 uint_t flags = 0; 6369 dladm_secobj_class_t class; 6370 show_secobj_state_t *statep = arg; 6371 dladm_status_t status; 6372 secobj_fields_buf_t sbuf; 6373 6374 bzero(&sbuf, sizeof (secobj_fields_buf_t)); 6375 if (statep->ss_persist) 6376 flags |= DLADM_OPT_PERSIST; 6377 6378 status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len, 6379 flags); 6380 if (status != DLADM_STATUS_OK) 6381 die_dlerr(status, "cannot get secure object '%s'", obj_name); 6382 6383 if (statep->ss_header) { 6384 statep->ss_header = B_FALSE; 6385 if (!statep->ss_parseable) 6386 print_header(&statep->ss_print); 6387 } 6388 6389 (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), 6390 obj_name); 6391 (void) dladm_secobjclass2str(class, buf); 6392 (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf); 6393 if (getuid() == 0) { 6394 char val[DLADM_SECOBJ_VAL_MAX * 2]; 6395 uint_t len = sizeof (val); 6396 6397 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) 6398 (void) snprintf(sbuf.ss_val, 6399 sizeof (sbuf.ss_val), "%s", val); 6400 } 6401 dladm_print_output(&statep->ss_print, statep->ss_parseable, 6402 dladm_print_field, (void *)&sbuf); 6403 return (B_TRUE); 6404 } 6405 6406 static void 6407 do_show_secobj(int argc, char **argv, const char *use) 6408 { 6409 int option; 6410 show_secobj_state_t state; 6411 dladm_status_t status; 6412 boolean_t o_arg = B_FALSE; 6413 uint_t i; 6414 split_t *sp; 6415 uint_t flags; 6416 char *fields_str = NULL; 6417 print_field_t **fields; 6418 uint_t nfields; 6419 char *def_fields = "object,class"; 6420 char *all_fields = "object,class,value"; 6421 6422 opterr = 0; 6423 bzero(&state, sizeof (state)); 6424 state.ss_parseable = B_FALSE; 6425 fields_str = def_fields; 6426 state.ss_persist = B_FALSE; 6427 state.ss_parseable = B_FALSE; 6428 state.ss_header = B_TRUE; 6429 while ((option = getopt_long(argc, argv, ":pPo:", 6430 wifi_longopts, NULL)) != -1) { 6431 switch (option) { 6432 case 'p': 6433 state.ss_parseable = B_TRUE; 6434 break; 6435 case 'P': 6436 state.ss_persist = B_TRUE; 6437 break; 6438 case 'o': 6439 o_arg = B_TRUE; 6440 if (strcasecmp(optarg, "all") == 0) 6441 fields_str = all_fields; 6442 else 6443 fields_str = optarg; 6444 break; 6445 default: 6446 die_opterr(optopt, option, use); 6447 break; 6448 } 6449 } 6450 6451 if (state.ss_parseable && !o_arg) 6452 die("option -c requires -o"); 6453 6454 if (state.ss_parseable && fields_str == all_fields) 6455 die("\"-o all\" is invalid with -p"); 6456 6457 fields = parse_output_fields(fields_str, secobj_fields, 6458 DEV_SOBJ_FIELDS, CMD_TYPE_ANY, &nfields); 6459 6460 if (fields == NULL) { 6461 die("invalid field(s) specified"); 6462 return; 6463 } 6464 state.ss_print.ps_fields = fields; 6465 state.ss_print.ps_nfields = nfields; 6466 6467 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 6468 6469 if (optind == (argc - 1)) { 6470 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 6471 if (sp == NULL) { 6472 die("invalid secure object name(s): '%s'", 6473 argv[optind]); 6474 } 6475 for (i = 0; i < sp->s_nfields; i++) { 6476 if (!show_secobj(handle, &state, sp->s_fields[i])) 6477 break; 6478 } 6479 splitfree(sp); 6480 return; 6481 } else if (optind != argc) 6482 usage(); 6483 6484 status = dladm_walk_secobj(handle, &state, show_secobj, flags); 6485 6486 if (status != DLADM_STATUS_OK) 6487 die_dlerr(status, "show-secobj"); 6488 } 6489 6490 /*ARGSUSED*/ 6491 static int 6492 i_dladm_init_linkprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6493 { 6494 (void) dladm_init_linkprop(dh, linkid, B_TRUE); 6495 return (DLADM_WALK_CONTINUE); 6496 } 6497 6498 /*ARGSUSED*/ 6499 void 6500 do_init_linkprop(int argc, char **argv, const char *use) 6501 { 6502 int option; 6503 dladm_status_t status; 6504 datalink_id_t linkid = DATALINK_ALL_LINKID; 6505 datalink_media_t media = DATALINK_ANY_MEDIATYPE; 6506 uint_t any_media = B_TRUE; 6507 6508 opterr = 0; 6509 while ((option = getopt(argc, argv, ":w")) != -1) { 6510 switch (option) { 6511 case 'w': 6512 media = DL_WIFI; 6513 any_media = B_FALSE; 6514 break; 6515 default: 6516 /* 6517 * Because init-linkprop is not a public command, 6518 * print the usage instead. 6519 */ 6520 usage(); 6521 break; 6522 } 6523 } 6524 6525 if (optind == (argc - 1)) { 6526 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6527 NULL, NULL, NULL)) != DLADM_STATUS_OK) 6528 die_dlerr(status, "link %s is not valid", argv[optind]); 6529 } else if (optind != argc) { 6530 usage(); 6531 } 6532 6533 if (linkid == DATALINK_ALL_LINKID) { 6534 /* 6535 * linkprops of links of other classes have been initialized as 6536 * part of the dladm up-xxx operation. 6537 */ 6538 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle, 6539 NULL, DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST); 6540 } else { 6541 (void) dladm_init_linkprop(handle, linkid, any_media); 6542 } 6543 } 6544 6545 static void 6546 do_show_ether(int argc, char **argv, const char *use) 6547 { 6548 int option; 6549 datalink_id_t linkid; 6550 print_ether_state_t state; 6551 print_field_t **fields; 6552 boolean_t o_arg = B_FALSE; 6553 char *fields_str; 6554 uint_t nfields; 6555 char *all_fields = 6556 "link,ptype,state,auto,speed-duplex,pause,rem_fault"; 6557 char *default_fields = 6558 "link,ptype,state,auto,speed-duplex,pause"; 6559 6560 fields_str = default_fields; 6561 bzero(&state, sizeof (state)); 6562 state.es_link = NULL; 6563 state.es_parseable = B_FALSE; 6564 6565 while ((option = getopt_long(argc, argv, "o:px", 6566 showeth_lopts, NULL)) != -1) { 6567 switch (option) { 6568 case 'x': 6569 state.es_extended = B_TRUE; 6570 break; 6571 case 'p': 6572 state.es_parseable = B_TRUE; 6573 break; 6574 case 'o': 6575 o_arg = B_TRUE; 6576 if (strcasecmp(optarg, "all") == 0) 6577 fields_str = all_fields; 6578 else 6579 fields_str = optarg; 6580 break; 6581 default: 6582 die_opterr(optopt, option, use); 6583 break; 6584 } 6585 } 6586 6587 if (state.es_parseable && !o_arg) 6588 die("-p requires -o"); 6589 6590 if (state.es_parseable && fields_str == all_fields) 6591 die("\"-o all\" is invalid with -p"); 6592 6593 if (optind == (argc - 1)) 6594 state.es_link = argv[optind]; 6595 6596 fields = parse_output_fields(fields_str, ether_fields, 6597 ETHER_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 6598 6599 if (fields == NULL) 6600 die("invalid field(s) specified"); 6601 6602 state.es_print.ps_fields = fields; 6603 state.es_print.ps_nfields = nfields; 6604 6605 6606 if (state.es_link == NULL) { 6607 (void) dladm_walk_datalink_id(show_etherprop, handle, &state, 6608 DATALINK_CLASS_PHYS, DL_ETHER, 6609 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 6610 } else { 6611 if (!link_is_ether(state.es_link, &linkid)) 6612 die("invalid link specified"); 6613 (void) show_etherprop(handle, linkid, &state); 6614 } 6615 } 6616 6617 static char * 6618 dladm_print_field(print_field_t *pf, void *arg) 6619 { 6620 char *value; 6621 6622 value = (char *)arg + pf->pf_offset; 6623 return (value); 6624 } 6625 6626 static int 6627 show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6628 { 6629 print_ether_state_t *statep = arg; 6630 ether_fields_buf_t ebuf; 6631 dladm_ether_info_t eattr; 6632 dladm_status_t status; 6633 6634 bzero(&ebuf, sizeof (ether_fields_buf_t)); 6635 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, 6636 ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) { 6637 return (DLADM_WALK_CONTINUE); 6638 } 6639 6640 if (!statep->es_header && !statep->es_parseable) { 6641 print_header(&statep->es_print); 6642 statep->es_header = B_TRUE; 6643 } 6644 6645 status = dladm_ether_info(dh, linkid, &eattr); 6646 if (status != DLADM_STATUS_OK) 6647 goto cleanup; 6648 6649 (void) strlcpy(ebuf.eth_ptype, "current", sizeof (ebuf.eth_ptype)); 6650 6651 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 6652 sizeof (ebuf.eth_autoneg), &eattr, CURRENT); 6653 (void) dladm_ether_pause2str(ebuf.eth_pause, 6654 sizeof (ebuf.eth_pause), &eattr, CURRENT); 6655 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 6656 sizeof (ebuf.eth_spdx), &eattr, CURRENT); 6657 (void) strlcpy(ebuf.eth_state, 6658 dladm_linkstate2str(eattr.lei_state, ebuf.eth_state), 6659 sizeof (ebuf.eth_state)); 6660 (void) strlcpy(ebuf.eth_rem_fault, 6661 (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"), 6662 sizeof (ebuf.eth_rem_fault)); 6663 6664 dladm_print_output(&statep->es_print, statep->es_parseable, 6665 dladm_print_field, &ebuf); 6666 6667 if (statep->es_extended) 6668 show_ether_xprop(arg, &eattr); 6669 6670 cleanup: 6671 dladm_ether_info_done(&eattr); 6672 return (DLADM_WALK_CONTINUE); 6673 } 6674 6675 /* ARGSUSED */ 6676 static void 6677 do_init_secobj(int argc, char **argv, const char *use) 6678 { 6679 dladm_status_t status; 6680 6681 status = dladm_init_secobj(handle); 6682 if (status != DLADM_STATUS_OK) 6683 die_dlerr(status, "secure object initialization failed"); 6684 } 6685 6686 /* 6687 * "-R" option support. It is used for live upgrading. Append dladm commands 6688 * to a upgrade script which will be run when the alternative root boots up: 6689 * 6690 * - If the /etc/dladm/datalink.conf file exists on the alternative root, 6691 * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink 6692 * script. This script will be run as part of the network/physical service. 6693 * We cannot defer this to /var/svc/profile/upgrade because then the 6694 * configuration will not be able to take effect before network/physical 6695 * plumbs various interfaces. 6696 * 6697 * - If the /etc/dladm/datalink.conf file does not exist on the alternative 6698 * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script, 6699 * which will be run in the manifest-import service. 6700 * 6701 * Note that the SMF team is considering to move the manifest-import service 6702 * to be run at the very begining of boot. Once that is done, the need for 6703 * the /var/svc/profile/upgrade_datalink script will not exist any more. 6704 */ 6705 static void 6706 altroot_cmd(char *altroot, int argc, char *argv[]) 6707 { 6708 char path[MAXPATHLEN]; 6709 struct stat stbuf; 6710 FILE *fp; 6711 int i; 6712 6713 /* 6714 * Check for the existence of the /etc/dladm/datalink.conf 6715 * configuration file, and determine the name of script file. 6716 */ 6717 (void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf", 6718 altroot); 6719 if (stat(path, &stbuf) < 0) { 6720 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 6721 SMF_UPGRADE_FILE); 6722 } else { 6723 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 6724 SMF_UPGRADEDATALINK_FILE); 6725 } 6726 6727 if ((fp = fopen(path, "a+")) == NULL) 6728 die("operation not supported on %s", altroot); 6729 6730 (void) fprintf(fp, "/sbin/dladm "); 6731 for (i = 0; i < argc; i++) { 6732 /* 6733 * Directly write to the file if it is not the "-R <altroot>" 6734 * option. In which case, skip it. 6735 */ 6736 if (strcmp(argv[i], "-R") != 0) 6737 (void) fprintf(fp, "%s ", argv[i]); 6738 else 6739 i ++; 6740 } 6741 (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG); 6742 (void) fclose(fp); 6743 dladm_close(handle); 6744 exit(0); 6745 } 6746 6747 /* 6748 * Convert the string to an integer. Note that the string must not have any 6749 * trailing non-integer characters. 6750 */ 6751 static boolean_t 6752 str2int(const char *str, int *valp) 6753 { 6754 int val; 6755 char *endp = NULL; 6756 6757 errno = 0; 6758 val = strtol(str, &endp, 10); 6759 if (errno != 0 || *endp != '\0') 6760 return (B_FALSE); 6761 6762 *valp = val; 6763 return (B_TRUE); 6764 } 6765 6766 /* PRINTFLIKE1 */ 6767 static void 6768 warn(const char *format, ...) 6769 { 6770 va_list alist; 6771 6772 format = gettext(format); 6773 (void) fprintf(stderr, "%s: warning: ", progname); 6774 6775 va_start(alist, format); 6776 (void) vfprintf(stderr, format, alist); 6777 va_end(alist); 6778 6779 (void) putchar('\n'); 6780 } 6781 6782 /* PRINTFLIKE2 */ 6783 static void 6784 warn_dlerr(dladm_status_t err, const char *format, ...) 6785 { 6786 va_list alist; 6787 char errmsg[DLADM_STRSIZE]; 6788 6789 format = gettext(format); 6790 (void) fprintf(stderr, gettext("%s: warning: "), progname); 6791 6792 va_start(alist, format); 6793 (void) vfprintf(stderr, format, alist); 6794 va_end(alist); 6795 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 6796 } 6797 6798 /* 6799 * Also closes the dladm handle if it is not NULL. 6800 */ 6801 /* PRINTFLIKE2 */ 6802 static void 6803 die_dlerr(dladm_status_t err, const char *format, ...) 6804 { 6805 va_list alist; 6806 char errmsg[DLADM_STRSIZE]; 6807 6808 format = gettext(format); 6809 (void) fprintf(stderr, "%s: ", progname); 6810 6811 va_start(alist, format); 6812 (void) vfprintf(stderr, format, alist); 6813 va_end(alist); 6814 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 6815 6816 /* close dladm handle if it was opened */ 6817 if (handle != NULL) 6818 dladm_close(handle); 6819 6820 exit(EXIT_FAILURE); 6821 } 6822 6823 /* PRINTFLIKE1 */ 6824 static void 6825 die(const char *format, ...) 6826 { 6827 va_list alist; 6828 6829 format = gettext(format); 6830 (void) fprintf(stderr, "%s: ", progname); 6831 6832 va_start(alist, format); 6833 (void) vfprintf(stderr, format, alist); 6834 va_end(alist); 6835 6836 (void) putchar('\n'); 6837 6838 /* close dladm handle if it was opened */ 6839 if (handle != NULL) 6840 dladm_close(handle); 6841 6842 exit(EXIT_FAILURE); 6843 } 6844 6845 static void 6846 die_optdup(int opt) 6847 { 6848 die("the option -%c cannot be specified more than once", opt); 6849 } 6850 6851 static void 6852 die_opterr(int opt, int opterr, const char *usage) 6853 { 6854 switch (opterr) { 6855 case ':': 6856 die("option '-%c' requires a value\nusage: %s", opt, 6857 gettext(usage)); 6858 break; 6859 case '?': 6860 default: 6861 die("unrecognized option '-%c'\nusage: %s", opt, 6862 gettext(usage)); 6863 break; 6864 } 6865 } 6866 6867 static void 6868 show_ether_xprop(void *arg, dladm_ether_info_t *eattr) 6869 { 6870 print_ether_state_t *statep = arg; 6871 ether_fields_buf_t ebuf; 6872 int i; 6873 6874 for (i = CAPABLE; i <= PEERADV; i++) { 6875 bzero(&ebuf, sizeof (ebuf)); 6876 (void) strlcpy(ebuf.eth_ptype, ptype[i], 6877 sizeof (ebuf.eth_ptype)); 6878 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 6879 sizeof (ebuf.eth_autoneg), eattr, i); 6880 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 6881 sizeof (ebuf.eth_spdx), eattr, i); 6882 (void) dladm_ether_pause2str(ebuf.eth_pause, 6883 sizeof (ebuf.eth_pause), eattr, i); 6884 (void) strlcpy(ebuf.eth_rem_fault, 6885 (eattr->lei_attr[i].le_fault ? "fault" : "none"), 6886 sizeof (ebuf.eth_rem_fault)); 6887 dladm_print_output(&statep->es_print, statep->es_parseable, 6888 dladm_print_field, &ebuf); 6889 } 6890 6891 } 6892 6893 static void 6894 dladm_print_output(print_state_t *statep, boolean_t parseable, 6895 print_callback_t fn, void *arg) 6896 { 6897 int i; 6898 char *value; 6899 print_field_t **pf; 6900 6901 pf = statep->ps_fields; 6902 for (i = 0; i < statep->ps_nfields; i++) { 6903 statep->ps_lastfield = (i + 1 == statep->ps_nfields); 6904 value = (*fn)(pf[i], arg); 6905 if (value != NULL) 6906 print_field(statep, pf[i], value, parseable); 6907 } 6908 (void) putchar('\n'); 6909 } 6910 6911 static void 6912 print_header(print_state_t *ps) 6913 { 6914 int i; 6915 print_field_t **pf; 6916 6917 pf = ps->ps_fields; 6918 for (i = 0; i < ps->ps_nfields; i++) { 6919 ps->ps_lastfield = (i + 1 == ps->ps_nfields); 6920 print_field(ps, pf[i], pf[i]->pf_header, B_FALSE); 6921 } 6922 (void) putchar('\n'); 6923 } 6924 6925 static boolean_t 6926 link_is_ether(const char *link, datalink_id_t *linkid) 6927 { 6928 uint32_t media; 6929 datalink_class_t class; 6930 6931 if (dladm_name2info(handle, link, linkid, NULL, &class, &media) == 6932 DLADM_STATUS_OK) { 6933 if (class == DATALINK_CLASS_PHYS && media == DL_ETHER) 6934 return (B_TRUE); 6935 } 6936 return (B_FALSE); 6937 } 6938