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