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