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 2010 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 <dlfcn.h> 29 #include <locale.h> 30 #include <signal.h> 31 #include <stdarg.h> 32 #include <stdlib.h> 33 #include <fcntl.h> 34 #include <string.h> 35 #include <stropts.h> 36 #include <sys/stat.h> 37 #include <errno.h> 38 #include <kstat.h> 39 #include <strings.h> 40 #include <getopt.h> 41 #include <unistd.h> 42 #include <priv.h> 43 #include <limits.h> 44 #include <termios.h> 45 #include <pwd.h> 46 #include <auth_attr.h> 47 #include <auth_list.h> 48 #include <libintl.h> 49 #include <libdevinfo.h> 50 #include <libdlpi.h> 51 #include <libdladm.h> 52 #include <libdllink.h> 53 #include <libdlstat.h> 54 #include <libdlaggr.h> 55 #include <libdlwlan.h> 56 #include <libdlvlan.h> 57 #include <libdlvnic.h> 58 #include <libdlether.h> 59 #include <libdliptun.h> 60 #include <libdlsim.h> 61 #include <libdlbridge.h> 62 #include <libinetutil.h> 63 #include <libvrrpadm.h> 64 #include <bsm/adt.h> 65 #include <bsm/adt_event.h> 66 #include <libdlvnic.h> 67 #include <sys/types.h> 68 #include <sys/socket.h> 69 #include <sys/processor.h> 70 #include <netinet/in.h> 71 #include <arpa/inet.h> 72 #include <net/if_types.h> 73 #include <stddef.h> 74 #include <stp_in.h> 75 #include <ofmt.h> 76 77 #define MAXPORT 256 78 #define MAXVNIC 256 79 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) 80 #define MAXLINELEN 1024 81 #define SMF_UPGRADE_FILE "/var/svc/profile/upgrade" 82 #define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink" 83 #define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)" 84 #define DLADM_DEFAULT_COL 80 85 86 /* 87 * used by the wifi show-* commands to set up ofmt_field_t structures. 88 */ 89 #define WIFI_CMD_SCAN 0x00000001 90 #define WIFI_CMD_SHOW 0x00000002 91 #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 92 93 /* No larger than pktsum_t */ 94 typedef struct brsum_s { 95 uint64_t drops; 96 uint64_t forward_dir; 97 uint64_t forward_mb; 98 uint64_t forward_unk; 99 uint64_t recv; 100 uint64_t sent; 101 } brsum_t; 102 103 /* No larger than pktsum_t */ 104 typedef struct brlsum_s { 105 uint32_t cfgbpdu; 106 uint32_t tcnbpdu; 107 uint32_t rstpbpdu; 108 uint32_t txbpdu; 109 uint64_t drops; 110 uint64_t recv; 111 uint64_t xmit; 112 } brlsum_t; 113 114 typedef struct show_state { 115 boolean_t ls_firstonly; 116 boolean_t ls_donefirst; 117 pktsum_t ls_prevstats; 118 uint32_t ls_flags; 119 dladm_status_t ls_status; 120 ofmt_handle_t ls_ofmt; 121 boolean_t ls_parsable; 122 boolean_t ls_mac; 123 boolean_t ls_hwgrp; 124 } show_state_t; 125 126 typedef struct show_grp_state { 127 pktsum_t gs_prevstats[MAXPORT]; 128 uint32_t gs_flags; 129 dladm_status_t gs_status; 130 boolean_t gs_parsable; 131 boolean_t gs_lacp; 132 boolean_t gs_extended; 133 boolean_t gs_stats; 134 boolean_t gs_firstonly; 135 boolean_t gs_donefirst; 136 ofmt_handle_t gs_ofmt; 137 } show_grp_state_t; 138 139 typedef struct show_vnic_state { 140 datalink_id_t vs_vnic_id; 141 datalink_id_t vs_link_id; 142 char vs_vnic[MAXLINKNAMELEN]; 143 char vs_link[MAXLINKNAMELEN]; 144 boolean_t vs_parsable; 145 boolean_t vs_found; 146 boolean_t vs_firstonly; 147 boolean_t vs_donefirst; 148 boolean_t vs_stats; 149 boolean_t vs_printstats; 150 pktsum_t vs_totalstats; 151 pktsum_t vs_prevstats[MAXVNIC]; 152 boolean_t vs_etherstub; 153 dladm_status_t vs_status; 154 uint32_t vs_flags; 155 ofmt_handle_t vs_ofmt; 156 } show_vnic_state_t; 157 158 typedef struct show_usage_state_s { 159 boolean_t us_plot; 160 boolean_t us_parsable; 161 boolean_t us_printheader; 162 boolean_t us_first; 163 boolean_t us_showall; 164 ofmt_handle_t us_ofmt; 165 } show_usage_state_t; 166 167 /* 168 * callback functions for printing output and error diagnostics. 169 */ 170 static ofmt_cb_t print_default_cb, print_link_stats_cb, print_linkprop_cb; 171 static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb; 172 static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb; 173 static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb; 174 static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb; 175 static void dladm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t); 176 177 typedef void cmdfunc_t(int, char **, const char *); 178 179 static cmdfunc_t do_show_link, do_show_wifi, do_show_phys; 180 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 181 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr; 182 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 183 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 184 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 185 static cmdfunc_t do_init_linkprop, do_init_secobj; 186 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan; 187 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys; 188 static cmdfunc_t do_show_linkmap; 189 static cmdfunc_t do_show_ether; 190 static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic; 191 static cmdfunc_t do_up_vnic; 192 static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub; 193 static cmdfunc_t do_create_simnet, do_modify_simnet; 194 static cmdfunc_t do_delete_simnet, do_show_simnet, do_up_simnet; 195 static cmdfunc_t do_show_usage; 196 static cmdfunc_t do_create_bridge, do_modify_bridge, do_delete_bridge; 197 static cmdfunc_t do_add_bridge, do_remove_bridge, do_show_bridge; 198 static cmdfunc_t do_create_iptun, do_modify_iptun, do_delete_iptun; 199 static cmdfunc_t do_show_iptun, do_up_iptun, do_down_iptun; 200 201 static void do_up_vnic_common(int, char **, const char *, boolean_t); 202 203 static void altroot_cmd(char *, int, char **); 204 static int show_linkprop_onelink(dladm_handle_t, datalink_id_t, void *); 205 206 static void link_stats(datalink_id_t, uint_t, char *, show_state_t *); 207 static void aggr_stats(datalink_id_t, show_grp_state_t *, uint_t); 208 static void vnic_stats(show_vnic_state_t *, uint32_t); 209 210 static int get_one_kstat(const char *, const char *, uint8_t, 211 void *, boolean_t); 212 static void get_mac_stats(const char *, pktsum_t *); 213 static void get_link_stats(const char *, pktsum_t *); 214 static uint64_t get_ifspeed(const char *, boolean_t); 215 static const char *get_linkstate(const char *, boolean_t, char *); 216 static const char *get_linkduplex(const char *, boolean_t, char *); 217 218 static iptun_type_t iptun_gettypebyname(char *); 219 static const char *iptun_gettypebyvalue(iptun_type_t); 220 static dladm_status_t print_iptun(dladm_handle_t, datalink_id_t, 221 show_state_t *); 222 static int print_iptun_walker(dladm_handle_t, datalink_id_t, void *); 223 224 static int show_etherprop(dladm_handle_t, datalink_id_t, void *); 225 static void show_ether_xprop(void *, dladm_ether_info_t *); 226 static boolean_t link_is_ether(const char *, datalink_id_t *); 227 228 static boolean_t str2int(const char *, int *); 229 static void die(const char *, ...); 230 static void die_optdup(int); 231 static void die_opterr(int, int, const char *); 232 static void die_dlerr(dladm_status_t, const char *, ...); 233 static void warn(const char *, ...); 234 static void warn_dlerr(dladm_status_t, const char *, ...); 235 236 typedef struct cmd { 237 char *c_name; 238 cmdfunc_t *c_fn; 239 const char *c_usage; 240 } cmd_t; 241 242 static cmd_t cmds[] = { 243 { "rename-link", do_rename_link, 244 " rename-link <oldlink> <newlink>" }, 245 { "show-link", do_show_link, 246 " show-link [-pP] [-o <field>,..] [-s [-i <interval>]] " 247 "[<link>]\n" }, 248 { "create-aggr", do_create_aggr, 249 " create-aggr [-t] [-P <policy>] [-L <mode>] [-T <time>] " 250 "[-u <address>]\n" 251 "\t\t -l <link> [-l <link>...] <link>" }, 252 { "delete-aggr", do_delete_aggr, 253 " delete-aggr [-t] <link>" }, 254 { "add-aggr", do_add_aggr, 255 " add-aggr [-t] -l <link> [-l <link>...] <link>" }, 256 { "remove-aggr", do_remove_aggr, 257 " remove-aggr [-t] -l <link> [-l <link>...] <link>" }, 258 { "modify-aggr", do_modify_aggr, 259 " modify-aggr [-t] [-P <policy>] [-L <mode>] [-T <time>] " 260 "[-u <address>]\n" 261 "\t\t <link>" }, 262 { "show-aggr", do_show_aggr, 263 " show-aggr [-pPLx] [-o <field>,..] [-s [-i <interval>]] " 264 "[<link>]\n" }, 265 { "up-aggr", do_up_aggr, NULL }, 266 { "scan-wifi", do_scan_wifi, 267 " scan-wifi [-p] [-o <field>,...] [<link>]" }, 268 { "connect-wifi", do_connect_wifi, 269 " connect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...] " 270 "[-s wep|wpa]\n" 271 "\t\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g] " 272 "[-T <time>]\n" 273 "\t\t [<link>]" }, 274 { "disconnect-wifi", do_disconnect_wifi, 275 " disconnect-wifi [-a] [<link>]" }, 276 { "show-wifi", do_show_wifi, 277 " show-wifi [-p] [-o <field>,...] [<link>]\n" }, 278 { "set-linkprop", do_set_linkprop, 279 " set-linkprop [-t] -p <prop>=<value>[,...] <name>" }, 280 { "reset-linkprop", do_reset_linkprop, 281 " reset-linkprop [-t] [-p <prop>,...] <name>" }, 282 { "show-linkprop", do_show_linkprop, 283 " show-linkprop [-cP] [-o <field>,...] [-p <prop>,...] " 284 "<name>\n" }, 285 { "show-ether", do_show_ether, 286 " show-ether [-px][-o <field>,...] <link>\n" }, 287 { "create-secobj", do_create_secobj, 288 " create-secobj [-t] [-f <file>] -c <class> <secobj>" }, 289 { "delete-secobj", do_delete_secobj, 290 " delete-secobj [-t] <secobj>[,...]" }, 291 { "show-secobj", do_show_secobj, 292 " show-secobj [-pP] [-o <field>,...] [<secobj>,...]\n" }, 293 { "init-linkprop", do_init_linkprop, NULL }, 294 { "init-secobj", do_init_secobj, NULL }, 295 { "create-vlan", do_create_vlan, 296 " create-vlan [-ft] -l <link> -v <vid> [link]" }, 297 { "delete-vlan", do_delete_vlan, 298 " delete-vlan [-t] <link>" }, 299 { "show-vlan", do_show_vlan, 300 " show-vlan [-pP] [-o <field>,..] [<link>]\n" }, 301 { "up-vlan", do_up_vlan, NULL }, 302 { "create-iptun", do_create_iptun, 303 " create-iptun [-t] -T <type> " 304 "[-a {local|remote}=<addr>,...] <link>]" }, 305 { "delete-iptun", do_delete_iptun, 306 " delete-iptun [-t] <link>" }, 307 { "modify-iptun", do_modify_iptun, 308 " modify-iptun [-t] -a {local|remote}=<addr>,... <link>" }, 309 { "show-iptun", do_show_iptun, 310 " show-iptun [-pP] [-o <field>,..] [<link>]\n" }, 311 { "up-iptun", do_up_iptun, NULL }, 312 { "down-iptun", do_down_iptun, NULL }, 313 { "delete-phys", do_delete_phys, 314 " delete-phys <link>" }, 315 { "show-phys", do_show_phys, 316 " show-phys [-pP] [-o <field>,..] [-H] [<link>]\n"}, 317 { "init-phys", do_init_phys, NULL }, 318 { "show-linkmap", do_show_linkmap, NULL }, 319 { "create-vnic", do_create_vnic, 320 " create-vnic [-t] -l <link> [-m <value> | auto |\n" 321 "\t\t {factory [-n <slot-id>]} | {random [-r <prefix>]} |\n" 322 "\t\t {vrrp -V <vrid> -A {inet | inet6}} [-v <vid> [-f]]\n" 323 "\t\t [-H] [-p <prop>=<value>[,...]] <vnic-link>" }, 324 { "delete-vnic", do_delete_vnic, 325 " delete-vnic [-t] <vnic-link>" }, 326 { "show-vnic", do_show_vnic, 327 " show-vnic [-pP] [-l <link>] [-s [-i <interval>]] " 328 "[<link>]\n" }, 329 { "up-vnic", do_up_vnic, NULL }, 330 { "create-etherstub", do_create_etherstub, 331 " create-etherstub [-t] <link>" }, 332 { "delete-etherstub", do_delete_etherstub, 333 " delete-etherstub [-t] <link>" }, 334 { "show-etherstub", do_show_etherstub, 335 " show-etherstub [-t] [<link>]\n" }, 336 { "create-simnet", do_create_simnet, NULL }, 337 { "modify-simnet", do_modify_simnet, NULL }, 338 { "delete-simnet", do_delete_simnet, NULL }, 339 { "show-simnet", do_show_simnet, NULL }, 340 { "up-simnet", do_up_simnet, NULL }, 341 { "create-bridge", do_create_bridge, 342 " create-bridge [-R <root-dir>] [-P <protect>] " 343 "[-p <priority>]\n" 344 "\t\t [-m <max-age>] [-h <hello-time>] [-d <forward-delay>]\n" 345 "\t\t [-f <force-protocol>] [-l <link>]... <bridge>" }, 346 { "modify-bridge", do_modify_bridge, 347 " modify-bridge [-R <root-dir>] [-P <protect>] " 348 "[-p <priority>]\n" 349 "\t\t [-m <max-age>] [-h <hello-time>] [-d <forward-delay>]\n" 350 "\t\t [-f <force-protocol>] <bridge>" }, 351 { "delete-bridge", do_delete_bridge, 352 " delete-bridge [-R <root-dir>] <bridge>" }, 353 { "add-bridge", do_add_bridge, 354 " add-bridge [-R <root-dir>] -l <link> [-l <link>]... " 355 "<bridge>" }, 356 { "remove-bridge", do_remove_bridge, 357 " remove-bridge [-R <root-dir>] -l <link> [-l <link>]... " 358 "<bridge>" }, 359 { "show-bridge", do_show_bridge, 360 " show-bridge [-p] [-o <field>,...] [-s [-i <interval>]] " 361 "[<bridge>]\n" 362 " show-bridge -l [-p] [-o <field>,...] [-s [-i <interval>]]" 363 " <bridge>\n" 364 " show-bridge -f [-p] [-o <field>,...] [-s [-i <interval>]]" 365 " <bridge>\n" 366 " show-bridge -t [-p] [-o <field>,...] [-s [-i <interval>]]" 367 " <bridge>\n" }, 368 { "show-usage", do_show_usage, 369 " show-usage [-a] [-d | -F <format>] " 370 "[-s <DD/MM/YYYY,HH:MM:SS>]\n" 371 "\t\t [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<link>]" } 372 }; 373 374 static const struct option lopts[] = { 375 {"vlan-id", required_argument, 0, 'v'}, 376 {"output", required_argument, 0, 'o'}, 377 {"dev", required_argument, 0, 'd'}, 378 {"policy", required_argument, 0, 'P'}, 379 {"lacp-mode", required_argument, 0, 'L'}, 380 {"lacp-timer", required_argument, 0, 'T'}, 381 {"unicast", required_argument, 0, 'u'}, 382 {"temporary", no_argument, 0, 't'}, 383 {"root-dir", required_argument, 0, 'R'}, 384 {"link", required_argument, 0, 'l'}, 385 {"forcible", no_argument, 0, 'f'}, 386 {"bw-limit", required_argument, 0, 'b'}, 387 {"mac-address", required_argument, 0, 'm'}, 388 {"slot", required_argument, 0, 'n'}, 389 { 0, 0, 0, 0 } 390 }; 391 392 static const struct option show_lopts[] = { 393 {"statistics", no_argument, 0, 's'}, 394 {"continuous", no_argument, 0, 'S'}, 395 {"interval", required_argument, 0, 'i'}, 396 {"parsable", no_argument, 0, 'p'}, 397 {"parseable", no_argument, 0, 'p'}, 398 {"extended", no_argument, 0, 'x'}, 399 {"output", required_argument, 0, 'o'}, 400 {"persistent", no_argument, 0, 'P'}, 401 {"lacp", no_argument, 0, 'L'}, 402 { 0, 0, 0, 0 } 403 }; 404 405 static const struct option iptun_lopts[] = { 406 {"output", required_argument, 0, 'o'}, 407 {"tunnel-type", required_argument, 0, 'T'}, 408 {"address", required_argument, 0, 'a'}, 409 {"root-dir", required_argument, 0, 'R'}, 410 {"parsable", no_argument, 0, 'p'}, 411 {"parseable", no_argument, 0, 'p'}, 412 {"persistent", no_argument, 0, 'P'}, 413 { 0, 0, 0, 0 } 414 }; 415 416 static char * const iptun_addropts[] = { 417 #define IPTUN_LOCAL 0 418 "local", 419 #define IPTUN_REMOTE 1 420 "remote", 421 NULL}; 422 423 static const struct { 424 const char *type_name; 425 iptun_type_t type_value; 426 } iptun_types[] = { 427 {"ipv4", IPTUN_TYPE_IPV4}, 428 {"ipv6", IPTUN_TYPE_IPV6}, 429 {"6to4", IPTUN_TYPE_6TO4}, 430 {NULL, 0} 431 }; 432 433 static const struct option prop_longopts[] = { 434 {"temporary", no_argument, 0, 't' }, 435 {"output", required_argument, 0, 'o' }, 436 {"root-dir", required_argument, 0, 'R' }, 437 {"prop", required_argument, 0, 'p' }, 438 {"parsable", no_argument, 0, 'c' }, 439 {"parseable", no_argument, 0, 'c' }, 440 {"persistent", no_argument, 0, 'P' }, 441 { 0, 0, 0, 0 } 442 }; 443 444 static const struct option wifi_longopts[] = { 445 {"parsable", no_argument, 0, 'p' }, 446 {"parseable", no_argument, 0, 'p' }, 447 {"output", required_argument, 0, 'o' }, 448 {"essid", required_argument, 0, 'e' }, 449 {"bsstype", required_argument, 0, 'b' }, 450 {"mode", required_argument, 0, 'm' }, 451 {"key", required_argument, 0, 'k' }, 452 {"sec", required_argument, 0, 's' }, 453 {"auth", required_argument, 0, 'a' }, 454 {"create-ibss", required_argument, 0, 'c' }, 455 {"timeout", required_argument, 0, 'T' }, 456 {"all-links", no_argument, 0, 'a' }, 457 {"temporary", no_argument, 0, 't' }, 458 {"root-dir", required_argument, 0, 'R' }, 459 {"persistent", no_argument, 0, 'P' }, 460 {"file", required_argument, 0, 'f' }, 461 { 0, 0, 0, 0 } 462 }; 463 464 static const struct option showeth_lopts[] = { 465 {"parsable", no_argument, 0, 'p' }, 466 {"parseable", no_argument, 0, 'p' }, 467 {"extended", no_argument, 0, 'x' }, 468 {"output", required_argument, 0, 'o' }, 469 { 0, 0, 0, 0 } 470 }; 471 472 static const struct option vnic_lopts[] = { 473 {"temporary", no_argument, 0, 't' }, 474 {"root-dir", required_argument, 0, 'R' }, 475 {"dev", required_argument, 0, 'd' }, 476 {"mac-address", required_argument, 0, 'm' }, 477 {"cpus", required_argument, 0, 'c' }, 478 {"bw-limit", required_argument, 0, 'b' }, 479 {"slot", required_argument, 0, 'n' }, 480 {"mac-prefix", required_argument, 0, 'r' }, 481 {"vrid", required_argument, 0, 'V' }, 482 {"address-family", required_argument, 0, 'A' }, 483 { 0, 0, 0, 0 } 484 }; 485 486 static const struct option etherstub_lopts[] = { 487 {"temporary", no_argument, 0, 't' }, 488 {"root-dir", required_argument, 0, 'R' }, 489 { 0, 0, 0, 0 } 490 }; 491 492 static const struct option usage_opts[] = { 493 {"file", required_argument, 0, 'f' }, 494 {"format", required_argument, 0, 'F' }, 495 {"start", required_argument, 0, 's' }, 496 {"stop", required_argument, 0, 'e' }, 497 { 0, 0, 0, 0 } 498 }; 499 500 static const struct option simnet_lopts[] = { 501 {"temporary", no_argument, 0, 't' }, 502 {"root-dir", required_argument, 0, 'R' }, 503 {"media", required_argument, 0, 'm' }, 504 {"peer", required_argument, 0, 'p' }, 505 { 0, 0, 0, 0 } 506 }; 507 508 static const struct option bridge_lopts[] = { 509 { "protect", required_argument, 0, 'P' }, 510 { "root-dir", required_argument, 0, 'R' }, 511 { "forward-delay", required_argument, 0, 'd' }, 512 { "force-protocol", required_argument, 0, 'f' }, 513 { "hello-time", required_argument, 0, 'h' }, 514 { "link", required_argument, 0, 'l' }, 515 { "max-age", required_argument, 0, 'm' }, 516 { "priority", required_argument, 0, 'p' }, 517 { NULL, NULL, 0, 0 } 518 }; 519 520 static const struct option bridge_show_lopts[] = { 521 { "forwarding", no_argument, 0, 'f' }, 522 { "interval", required_argument, 0, 'i' }, 523 { "link", no_argument, 0, 'l' }, 524 { "output", required_argument, 0, 'o' }, 525 { "parsable", no_argument, 0, 'p' }, 526 { "parseable", no_argument, 0, 'p' }, 527 { "statistics", no_argument, 0, 's' }, 528 { "trill", no_argument, 0, 't' }, 529 { 0, 0, 0, 0 } 530 }; 531 532 /* 533 * structures for 'dladm show-ether' 534 */ 535 static const char *ptype[] = {LEI_ATTR_NAMES}; 536 537 typedef struct ether_fields_buf_s 538 { 539 char eth_link[15]; 540 char eth_ptype[8]; 541 char eth_state[8]; 542 char eth_autoneg[5]; 543 char eth_spdx[31]; 544 char eth_pause[6]; 545 char eth_rem_fault[16]; 546 } ether_fields_buf_t; 547 548 static const ofmt_field_t ether_fields[] = { 549 /* name, field width, offset callback */ 550 { "LINK", 16, 551 offsetof(ether_fields_buf_t, eth_link), print_default_cb}, 552 { "PTYPE", 9, 553 offsetof(ether_fields_buf_t, eth_ptype), print_default_cb}, 554 { "STATE", 9, 555 offsetof(ether_fields_buf_t, eth_state), 556 print_default_cb}, 557 { "AUTO", 6, 558 offsetof(ether_fields_buf_t, eth_autoneg), print_default_cb}, 559 { "SPEED-DUPLEX", 32, 560 offsetof(ether_fields_buf_t, eth_spdx), print_default_cb}, 561 { "PAUSE", 7, 562 offsetof(ether_fields_buf_t, eth_pause), print_default_cb}, 563 { "REM_FAULT", 17, 564 offsetof(ether_fields_buf_t, eth_rem_fault), print_default_cb}, 565 {NULL, 0, 566 0, NULL}} 567 ; 568 569 typedef struct print_ether_state { 570 const char *es_link; 571 boolean_t es_parsable; 572 boolean_t es_header; 573 boolean_t es_extended; 574 ofmt_handle_t es_ofmt; 575 } print_ether_state_t; 576 577 /* 578 * structures for 'dladm show-link -s' (print statistics) 579 */ 580 typedef enum { 581 LINK_S_LINK, 582 LINK_S_IPKTS, 583 LINK_S_RBYTES, 584 LINK_S_IERRORS, 585 LINK_S_OPKTS, 586 LINK_S_OBYTES, 587 LINK_S_OERRORS 588 } link_s_field_index_t; 589 590 static const ofmt_field_t link_s_fields[] = { 591 /* name, field width, index, callback */ 592 { "LINK", 15, LINK_S_LINK, print_link_stats_cb}, 593 { "IPACKETS", 10, LINK_S_IPKTS, print_link_stats_cb}, 594 { "RBYTES", 8, LINK_S_RBYTES, print_link_stats_cb}, 595 { "IERRORS", 10, LINK_S_IERRORS, print_link_stats_cb}, 596 { "OPACKETS", 12, LINK_S_OPKTS, print_link_stats_cb}, 597 { "OBYTES", 12, LINK_S_OBYTES, print_link_stats_cb}, 598 { "OERRORS", 8, LINK_S_OERRORS, print_link_stats_cb}} 599 ; 600 601 typedef struct link_args_s { 602 char *link_s_link; 603 pktsum_t *link_s_psum; 604 } link_args_t; 605 606 /* 607 * buffer used by print functions for show-{link,phys,vlan} commands. 608 */ 609 typedef struct link_fields_buf_s { 610 char link_name[MAXLINKNAMELEN]; 611 char link_class[DLADM_STRSIZE]; 612 char link_mtu[11]; 613 char link_state[DLADM_STRSIZE]; 614 char link_bridge[MAXLINKNAMELEN]; 615 char link_over[MAXLINKNAMELEN]; 616 char link_phys_state[DLADM_STRSIZE]; 617 char link_phys_media[DLADM_STRSIZE]; 618 char link_phys_speed[DLADM_STRSIZE]; 619 char link_phys_duplex[DLPI_LINKNAME_MAX]; 620 char link_phys_device[DLPI_LINKNAME_MAX]; 621 char link_flags[6]; 622 char link_vlan_vid[6]; 623 } link_fields_buf_t; 624 625 /* 626 * structures for 'dladm show-link' 627 */ 628 static const ofmt_field_t link_fields[] = { 629 /* name, field width, index, callback */ 630 { "LINK", 12, 631 offsetof(link_fields_buf_t, link_name), print_default_cb}, 632 { "CLASS", 10, 633 offsetof(link_fields_buf_t, link_class), print_default_cb}, 634 { "MTU", 7, 635 offsetof(link_fields_buf_t, link_mtu), print_default_cb}, 636 { "STATE", 9, 637 offsetof(link_fields_buf_t, link_state), print_default_cb}, 638 { "BRIDGE", 11, 639 offsetof(link_fields_buf_t, link_bridge), print_default_cb}, 640 { "OVER", DLPI_LINKNAME_MAX, 641 offsetof(link_fields_buf_t, link_over), print_default_cb}, 642 { NULL, 0, 0, NULL}} 643 ; 644 645 /* 646 * structures for 'dladm show-aggr' 647 */ 648 typedef struct laggr_fields_buf_s { 649 char laggr_name[DLPI_LINKNAME_MAX]; 650 char laggr_policy[9]; 651 char laggr_addrpolicy[ETHERADDRL * 3 + 3]; 652 char laggr_lacpactivity[14]; 653 char laggr_lacptimer[DLADM_STRSIZE]; 654 char laggr_flags[7]; 655 } laggr_fields_buf_t; 656 657 typedef struct laggr_args_s { 658 int laggr_lport; /* -1 indicates the aggr itself */ 659 const char *laggr_link; 660 dladm_aggr_grp_attr_t *laggr_ginfop; 661 dladm_status_t *laggr_status; 662 pktsum_t *laggr_pktsumtot; /* -s only */ 663 pktsum_t *laggr_diffstats; /* -s only */ 664 boolean_t laggr_parsable; 665 } laggr_args_t; 666 667 static const ofmt_field_t laggr_fields[] = { 668 /* name, field width, offset, callback */ 669 { "LINK", 16, 670 offsetof(laggr_fields_buf_t, laggr_name), print_default_cb}, 671 { "POLICY", 9, 672 offsetof(laggr_fields_buf_t, laggr_policy), print_default_cb}, 673 { "ADDRPOLICY", ETHERADDRL * 3 + 3, 674 offsetof(laggr_fields_buf_t, laggr_addrpolicy), print_default_cb}, 675 { "LACPACTIVITY", 14, 676 offsetof(laggr_fields_buf_t, laggr_lacpactivity), print_default_cb}, 677 { "LACPTIMER", 12, 678 offsetof(laggr_fields_buf_t, laggr_lacptimer), print_default_cb}, 679 { "FLAGS", 8, 680 offsetof(laggr_fields_buf_t, laggr_flags), print_default_cb}, 681 { NULL, 0, 0, NULL}} 682 ; 683 684 /* 685 * structures for 'dladm show-aggr -x'. 686 */ 687 typedef enum { 688 AGGR_X_LINK, 689 AGGR_X_PORT, 690 AGGR_X_SPEED, 691 AGGR_X_DUPLEX, 692 AGGR_X_STATE, 693 AGGR_X_ADDRESS, 694 AGGR_X_PORTSTATE 695 } aggr_x_field_index_t; 696 697 static const ofmt_field_t aggr_x_fields[] = { 698 /* name, field width, index callback */ 699 { "LINK", 12, AGGR_X_LINK, print_xaggr_cb}, 700 { "PORT", 15, AGGR_X_PORT, print_xaggr_cb}, 701 { "SPEED", 5, AGGR_X_SPEED, print_xaggr_cb}, 702 { "DUPLEX", 10, AGGR_X_DUPLEX, print_xaggr_cb}, 703 { "STATE", 10, AGGR_X_STATE, print_xaggr_cb}, 704 { "ADDRESS", 19, AGGR_X_ADDRESS, print_xaggr_cb}, 705 { "PORTSTATE", 16, AGGR_X_PORTSTATE, print_xaggr_cb}, 706 { NULL, 0, 0, NULL}} 707 ; 708 709 /* 710 * structures for 'dladm show-aggr -s'. 711 */ 712 typedef enum { 713 AGGR_S_LINK, 714 AGGR_S_PORT, 715 AGGR_S_IPKTS, 716 AGGR_S_RBYTES, 717 AGGR_S_OPKTS, 718 AGGR_S_OBYTES, 719 AGGR_S_IPKTDIST, 720 AGGR_S_OPKTDIST 721 } aggr_s_field_index_t; 722 723 static const ofmt_field_t aggr_s_fields[] = { 724 { "LINK", 12, AGGR_S_LINK, print_aggr_stats_cb}, 725 { "PORT", 10, AGGR_S_PORT, print_aggr_stats_cb}, 726 { "IPACKETS", 8, AGGR_S_IPKTS, print_aggr_stats_cb}, 727 { "RBYTES", 8, AGGR_S_RBYTES, print_aggr_stats_cb}, 728 { "OPACKETS", 8, AGGR_S_OPKTS, print_aggr_stats_cb}, 729 { "OBYTES", 8, AGGR_S_OBYTES, print_aggr_stats_cb}, 730 { "IPKTDIST", 9, AGGR_S_IPKTDIST, print_aggr_stats_cb}, 731 { "OPKTDIST", 15, AGGR_S_OPKTDIST, print_aggr_stats_cb}, 732 { NULL, 0, 0, NULL}} 733 ; 734 735 /* 736 * structures for 'dladm show-aggr -L'. 737 */ 738 typedef enum { 739 AGGR_L_LINK, 740 AGGR_L_PORT, 741 AGGR_L_AGGREGATABLE, 742 AGGR_L_SYNC, 743 AGGR_L_COLL, 744 AGGR_L_DIST, 745 AGGR_L_DEFAULTED, 746 AGGR_L_EXPIRED 747 } aggr_l_field_index_t; 748 749 static const ofmt_field_t aggr_l_fields[] = { 750 /* name, field width, index */ 751 { "LINK", 12, AGGR_L_LINK, print_lacp_cb}, 752 { "PORT", 13, AGGR_L_PORT, print_lacp_cb}, 753 { "AGGREGATABLE", 13, AGGR_L_AGGREGATABLE, print_lacp_cb}, 754 { "SYNC", 5, AGGR_L_SYNC, print_lacp_cb}, 755 { "COLL", 5, AGGR_L_COLL, print_lacp_cb}, 756 { "DIST", 5, AGGR_L_DIST, print_lacp_cb}, 757 { "DEFAULTED", 10, AGGR_L_DEFAULTED, print_lacp_cb}, 758 { "EXPIRED", 15, AGGR_L_EXPIRED, print_lacp_cb}, 759 { NULL, 0, 0, NULL}} 760 ; 761 762 /* 763 * structures for 'dladm show-phys' 764 */ 765 766 static const ofmt_field_t phys_fields[] = { 767 /* name, field width, offset */ 768 { "LINK", 13, 769 offsetof(link_fields_buf_t, link_name), print_default_cb}, 770 { "MEDIA", 21, 771 offsetof(link_fields_buf_t, link_phys_media), print_default_cb}, 772 { "STATE", 11, 773 offsetof(link_fields_buf_t, link_phys_state), print_default_cb}, 774 { "SPEED", 7, 775 offsetof(link_fields_buf_t, link_phys_speed), print_default_cb}, 776 { "DUPLEX", 10, 777 offsetof(link_fields_buf_t, link_phys_duplex), print_default_cb}, 778 { "DEVICE", 13, 779 offsetof(link_fields_buf_t, link_phys_device), print_default_cb}, 780 { "FLAGS", 7, 781 offsetof(link_fields_buf_t, link_flags), print_default_cb}, 782 { NULL, 0, NULL, 0}} 783 ; 784 785 /* 786 * structures for 'dladm show-phys -m' 787 */ 788 789 typedef enum { 790 PHYS_M_LINK, 791 PHYS_M_SLOT, 792 PHYS_M_ADDRESS, 793 PHYS_M_INUSE, 794 PHYS_M_CLIENT 795 } phys_m_field_index_t; 796 797 static const ofmt_field_t phys_m_fields[] = { 798 /* name, field width, offset */ 799 { "LINK", 13, PHYS_M_LINK, print_phys_one_mac_cb}, 800 { "SLOT", 9, PHYS_M_SLOT, print_phys_one_mac_cb}, 801 { "ADDRESS", 19, PHYS_M_ADDRESS, print_phys_one_mac_cb}, 802 { "INUSE", 5, PHYS_M_INUSE, print_phys_one_mac_cb}, 803 { "CLIENT", 13, PHYS_M_CLIENT, print_phys_one_mac_cb}, 804 { NULL, 0, 0, NULL}} 805 ; 806 807 /* 808 * structures for 'dladm show-phys -H' 809 */ 810 811 typedef enum { 812 PHYS_H_LINK, 813 PHYS_H_GROUP, 814 PHYS_H_GRPTYPE, 815 PHYS_H_RINGS, 816 PHYS_H_CLIENTS 817 } phys_h_field_index_t; 818 819 static const ofmt_field_t phys_h_fields[] = { 820 { "LINK", 13, PHYS_H_LINK, print_phys_one_hwgrp_cb}, 821 { "GROUP", 9, PHYS_H_GROUP, print_phys_one_hwgrp_cb}, 822 { "GROUPTYPE", 7, PHYS_H_GRPTYPE, print_phys_one_hwgrp_cb}, 823 { "RINGS", 17, PHYS_H_RINGS, print_phys_one_hwgrp_cb}, 824 { "CLIENTS", 21, PHYS_H_CLIENTS, print_phys_one_hwgrp_cb}, 825 { NULL, 0, 0, NULL}} 826 ; 827 828 /* 829 * structures for 'dladm show-vlan' 830 */ 831 static const ofmt_field_t vlan_fields[] = { 832 { "LINK", 16, 833 offsetof(link_fields_buf_t, link_name), print_default_cb}, 834 { "VID", 9, 835 offsetof(link_fields_buf_t, link_vlan_vid), print_default_cb}, 836 { "OVER", 13, 837 offsetof(link_fields_buf_t, link_over), print_default_cb}, 838 { "FLAGS", 7, 839 offsetof(link_fields_buf_t, link_flags), print_default_cb}, 840 { NULL, 0, 0, NULL}} 841 ; 842 843 /* 844 * structures common to 'dladm scan-wifi' and 'dladm show-wifi' 845 * callback will be determined in parse_wifi_fields. 846 */ 847 static ofmt_field_t wifi_common_fields[] = { 848 { "LINK", 11, 0, NULL}, 849 { "ESSID", 20, DLADM_WLAN_ATTR_ESSID, NULL}, 850 { "BSSID", 18, DLADM_WLAN_ATTR_BSSID, NULL}, 851 { "IBSSID", 18, DLADM_WLAN_ATTR_BSSID, NULL}, 852 { "MODE", 7, DLADM_WLAN_ATTR_MODE, NULL}, 853 { "SPEED", 7, DLADM_WLAN_ATTR_SPEED, NULL}, 854 { "BSSTYPE", 9, DLADM_WLAN_ATTR_BSSTYPE, NULL}, 855 { "SEC", 7, DLADM_WLAN_ATTR_SECMODE, NULL}, 856 { "STRENGTH", 11, DLADM_WLAN_ATTR_STRENGTH, NULL}, 857 { NULL, 0, 0, NULL}}; 858 859 /* 860 * the 'show-wifi' command supports all the fields in wifi_common_fields 861 * plus the AUTH and STATUS fields. 862 */ 863 static ofmt_field_t wifi_show_fields[A_CNT(wifi_common_fields) + 2] = { 864 { "AUTH", 9, DLADM_WLAN_ATTR_AUTH, NULL}, 865 { "STATUS", 18, DLADM_WLAN_LINKATTR_STATUS, print_wifi_status_cb}, 866 /* copy wifi_common_fields here */ 867 }; 868 869 static char *all_scan_wifi_fields = 870 "link,essid,bssid,sec,strength,mode,speed,bsstype"; 871 static char *all_show_wifi_fields = 872 "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 873 static char *def_scan_wifi_fields = 874 "link,essid,bssid,sec,strength,mode,speed"; 875 static char *def_show_wifi_fields = 876 "link,status,essid,sec,strength,mode,speed"; 877 878 /* 879 * structures for 'dladm show-linkprop' 880 */ 881 typedef enum { 882 LINKPROP_LINK, 883 LINKPROP_PROPERTY, 884 LINKPROP_PERM, 885 LINKPROP_VALUE, 886 LINKPROP_DEFAULT, 887 LINKPROP_POSSIBLE 888 } linkprop_field_index_t; 889 890 static const ofmt_field_t linkprop_fields[] = { 891 /* name, field width, index */ 892 { "LINK", 13, LINKPROP_LINK, print_linkprop_cb}, 893 { "PROPERTY", 16, LINKPROP_PROPERTY, print_linkprop_cb}, 894 { "PERM", 5, LINKPROP_PERM, print_linkprop_cb}, 895 { "VALUE", 15, LINKPROP_VALUE, print_linkprop_cb}, 896 { "DEFAULT", 15, LINKPROP_DEFAULT, print_linkprop_cb}, 897 { "POSSIBLE", 20, LINKPROP_POSSIBLE, print_linkprop_cb}, 898 { NULL, 0, 0, NULL}} 899 ; 900 901 #define MAX_PROP_LINE 512 902 903 typedef struct show_linkprop_state { 904 char ls_link[MAXLINKNAMELEN]; 905 char *ls_line; 906 char **ls_propvals; 907 dladm_arg_list_t *ls_proplist; 908 boolean_t ls_parsable; 909 boolean_t ls_persist; 910 boolean_t ls_header; 911 dladm_status_t ls_status; 912 dladm_status_t ls_retstatus; 913 ofmt_handle_t ls_ofmt; 914 } show_linkprop_state_t; 915 916 typedef struct set_linkprop_state { 917 const char *ls_name; 918 boolean_t ls_reset; 919 boolean_t ls_temp; 920 dladm_status_t ls_status; 921 } set_linkprop_state_t; 922 923 typedef struct linkprop_args_s { 924 show_linkprop_state_t *ls_state; 925 char *ls_propname; 926 datalink_id_t ls_linkid; 927 } linkprop_args_t; 928 929 /* 930 * structures for 'dladm show-secobj' 931 */ 932 typedef struct secobj_fields_buf_s { 933 char ss_obj_name[DLADM_SECOBJ_VAL_MAX]; 934 char ss_class[20]; 935 char ss_val[30]; 936 } secobj_fields_buf_t; 937 938 static const ofmt_field_t secobj_fields[] = { 939 { "OBJECT", 21, 940 offsetof(secobj_fields_buf_t, ss_obj_name), print_default_cb}, 941 { "CLASS", 21, 942 offsetof(secobj_fields_buf_t, ss_class), print_default_cb}, 943 { "VALUE", 31, 944 offsetof(secobj_fields_buf_t, ss_val), print_default_cb}, 945 { NULL, 0, 0, NULL}} 946 ; 947 948 /* 949 * structures for 'dladm show-vnic' 950 */ 951 typedef struct vnic_fields_buf_s 952 { 953 char vnic_link[DLPI_LINKNAME_MAX]; 954 char vnic_over[DLPI_LINKNAME_MAX]; 955 char vnic_speed[6]; 956 char vnic_macaddr[18]; 957 char vnic_macaddrtype[19]; 958 char vnic_vid[6]; 959 } vnic_fields_buf_t; 960 961 static const ofmt_field_t vnic_fields[] = { 962 { "LINK", 13, 963 offsetof(vnic_fields_buf_t, vnic_link), print_default_cb}, 964 { "OVER", 13, 965 offsetof(vnic_fields_buf_t, vnic_over), print_default_cb}, 966 { "SPEED", 7, 967 offsetof(vnic_fields_buf_t, vnic_speed), print_default_cb}, 968 { "MACADDRESS", 18, 969 offsetof(vnic_fields_buf_t, vnic_macaddr), print_default_cb}, 970 { "MACADDRTYPE", 20, 971 offsetof(vnic_fields_buf_t, vnic_macaddrtype), print_default_cb}, 972 { "VID", 7, 973 offsetof(vnic_fields_buf_t, vnic_vid), print_default_cb}, 974 { NULL, 0, 0, NULL}} 975 ; 976 977 /* 978 * structures for 'dladm show-simnet' 979 */ 980 typedef struct simnet_fields_buf_s 981 { 982 char simnet_name[DLPI_LINKNAME_MAX]; 983 char simnet_media[DLADM_STRSIZE]; 984 char simnet_macaddr[18]; 985 char simnet_otherlink[DLPI_LINKNAME_MAX]; 986 } simnet_fields_buf_t; 987 988 static const ofmt_field_t simnet_fields[] = { 989 { "LINK", 12, 990 offsetof(simnet_fields_buf_t, simnet_name), print_default_cb}, 991 { "MEDIA", 20, 992 offsetof(simnet_fields_buf_t, simnet_media), print_default_cb}, 993 { "MACADDRESS", 18, 994 offsetof(simnet_fields_buf_t, simnet_macaddr), print_default_cb}, 995 { "OTHERLINK", 12, 996 offsetof(simnet_fields_buf_t, simnet_otherlink), print_default_cb}, 997 { NULL, 0, 0, NULL}} 998 ; 999 1000 /* 1001 * structures for 'dladm show-usage' 1002 */ 1003 1004 typedef struct usage_fields_buf_s { 1005 char usage_link[12]; 1006 char usage_duration[10]; 1007 char usage_ipackets[9]; 1008 char usage_rbytes[10]; 1009 char usage_opackets[9]; 1010 char usage_obytes[10]; 1011 char usage_bandwidth[14]; 1012 } usage_fields_buf_t; 1013 1014 static const ofmt_field_t usage_fields[] = { 1015 { "LINK", 13, 1016 offsetof(usage_fields_buf_t, usage_link), print_default_cb}, 1017 { "DURATION", 11, 1018 offsetof(usage_fields_buf_t, usage_duration), print_default_cb}, 1019 { "IPACKETS", 10, 1020 offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb}, 1021 { "RBYTES", 11, 1022 offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb}, 1023 { "OPACKETS", 10, 1024 offsetof(usage_fields_buf_t, usage_opackets), print_default_cb}, 1025 { "OBYTES", 11, 1026 offsetof(usage_fields_buf_t, usage_obytes), print_default_cb}, 1027 { "BANDWIDTH", 15, 1028 offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb}, 1029 { NULL, 0, 0, NULL}} 1030 ; 1031 1032 1033 /* 1034 * structures for 'dladm show-usage link' 1035 */ 1036 1037 typedef struct usage_l_fields_buf_s { 1038 char usage_l_link[12]; 1039 char usage_l_stime[13]; 1040 char usage_l_etime[13]; 1041 char usage_l_rbytes[8]; 1042 char usage_l_obytes[8]; 1043 char usage_l_bandwidth[14]; 1044 } usage_l_fields_buf_t; 1045 1046 static const ofmt_field_t usage_l_fields[] = { 1047 /* name, field width, offset */ 1048 { "LINK", 13, 1049 offsetof(usage_l_fields_buf_t, usage_l_link), print_default_cb}, 1050 { "START", 14, 1051 offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb}, 1052 { "END", 14, 1053 offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb}, 1054 { "RBYTES", 9, 1055 offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb}, 1056 { "OBYTES", 9, 1057 offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb}, 1058 { "BANDWIDTH", 15, 1059 offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb}, 1060 { NULL, 0, 0, NULL}} 1061 ; 1062 1063 /* IPTUN_*FLAG_INDEX values are indices into iptun_flags below. */ 1064 enum { IPTUN_SFLAG_INDEX, IPTUN_IFLAG_INDEX, IPTUN_NUM_FLAGS }; 1065 1066 /* 1067 * structures for 'dladm show-iptun' 1068 */ 1069 typedef struct iptun_fields_buf_s { 1070 char iptun_name[MAXLINKNAMELEN]; 1071 char iptun_type[5]; 1072 char iptun_laddr[NI_MAXHOST]; 1073 char iptun_raddr[NI_MAXHOST]; 1074 char iptun_flags[IPTUN_NUM_FLAGS + 1]; 1075 } iptun_fields_buf_t; 1076 1077 static const ofmt_field_t iptun_fields[] = { 1078 { "LINK", 16, 1079 offsetof(iptun_fields_buf_t, iptun_name), print_default_cb }, 1080 { "TYPE", 6, 1081 offsetof(iptun_fields_buf_t, iptun_type), print_default_cb }, 1082 { "FLAGS", 7, 1083 offsetof(iptun_fields_buf_t, iptun_flags), print_default_cb }, 1084 { "LOCAL", 20, 1085 offsetof(iptun_fields_buf_t, iptun_laddr), print_default_cb }, 1086 { "REMOTE", 20, 1087 offsetof(iptun_fields_buf_t, iptun_raddr), print_default_cb }, 1088 { NULL, 0, 0, NULL} 1089 }; 1090 1091 /* 1092 * structures for 'dladm show-bridge'. These are based on sections 14.8.1.1.3 1093 * and 14.8.1.2.2 of IEEE 802.1D-2004. 1094 */ 1095 typedef struct bridge_fields_buf_s { 1096 char bridge_name[MAXLINKNAMELEN]; /* 14.4.1.2.3(b) */ 1097 char bridge_protect[7]; /* stp or trill */ 1098 char bridge_address[24]; /* 17.18.3, 7.12.5, 14.4.1.2.3(a) */ 1099 char bridge_priority[7]; /* 17.18.3 9.2.5 - only upper 4 bits */ 1100 char bridge_bmaxage[7]; /* 17.18.4 configured */ 1101 char bridge_bhellotime[7]; /* 17.18.4 configured */ 1102 char bridge_bfwddelay[7]; /* 17.18.4 configured */ 1103 char bridge_forceproto[3]; /* 17.13.4 configured */ 1104 char bridge_tctime[12]; /* 14.8.1.1.3(b) */ 1105 char bridge_tccount[12]; /* 17.17.8 */ 1106 char bridge_tchange[12]; /* 17.17.8 */ 1107 char bridge_desroot[24]; /* 17.18.6 priority "/" MAC */ 1108 char bridge_rootcost[12]; /* 17.18.6 */ 1109 char bridge_rootport[12]; /* 17.18.6 */ 1110 char bridge_maxage[7]; /* 17.18.7 for root */ 1111 char bridge_hellotime[7]; /* 17.13.6 for root */ 1112 char bridge_fwddelay[7]; /* 17.13.5 for root */ 1113 char bridge_holdtime[12]; /* 17.13.12 for root */ 1114 } bridge_fields_buf_t; 1115 1116 static ofmt_field_t bridge_fields[] = { 1117 /* name, field width, offset, callback */ 1118 { "BRIDGE", 12, 1119 offsetof(bridge_fields_buf_t, bridge_name), print_default_cb }, 1120 { "PROTECT", 8, 1121 offsetof(bridge_fields_buf_t, bridge_protect), print_default_cb }, 1122 { "ADDRESS", 19, 1123 offsetof(bridge_fields_buf_t, bridge_address), print_default_cb }, 1124 { "PRIORITY", 9, 1125 offsetof(bridge_fields_buf_t, bridge_priority), print_default_cb }, 1126 { "BMAXAGE", 8, 1127 offsetof(bridge_fields_buf_t, bridge_bmaxage), print_default_cb }, 1128 { "BHELLOTIME", 11, 1129 offsetof(bridge_fields_buf_t, bridge_bhellotime), print_default_cb }, 1130 { "BFWDDELAY", 10, 1131 offsetof(bridge_fields_buf_t, bridge_bfwddelay), print_default_cb }, 1132 { "FORCEPROTO", 11, 1133 offsetof(bridge_fields_buf_t, bridge_forceproto), print_default_cb }, 1134 { "TCTIME", 10, 1135 offsetof(bridge_fields_buf_t, bridge_tctime), print_default_cb }, 1136 { "TCCOUNT", 10, 1137 offsetof(bridge_fields_buf_t, bridge_tccount), print_default_cb }, 1138 { "TCHANGE", 10, 1139 offsetof(bridge_fields_buf_t, bridge_tchange), print_default_cb }, 1140 { "DESROOT", 23, 1141 offsetof(bridge_fields_buf_t, bridge_desroot), print_default_cb }, 1142 { "ROOTCOST", 11, 1143 offsetof(bridge_fields_buf_t, bridge_rootcost), print_default_cb }, 1144 { "ROOTPORT", 11, 1145 offsetof(bridge_fields_buf_t, bridge_rootport), print_default_cb }, 1146 { "MAXAGE", 8, 1147 offsetof(bridge_fields_buf_t, bridge_maxage), print_default_cb }, 1148 { "HELLOTIME", 10, 1149 offsetof(bridge_fields_buf_t, bridge_hellotime), print_default_cb }, 1150 { "FWDDELAY", 9, 1151 offsetof(bridge_fields_buf_t, bridge_fwddelay), print_default_cb }, 1152 { "HOLDTIME", 9, 1153 offsetof(bridge_fields_buf_t, bridge_holdtime), print_default_cb }, 1154 { NULL, 0, 0, NULL}}; 1155 1156 /* 1157 * structures for 'dladm show-bridge -l'. These are based on 14.4.1.2.3 and 1158 * 14.8.2.1.3 of IEEE 802.1D-2004. 1159 */ 1160 typedef struct bridge_link_fields_buf_s { 1161 char bridgel_link[MAXLINKNAMELEN]; 1162 char bridgel_index[7]; /* 14.4.1.2.3(d1) */ 1163 char bridgel_state[11]; /* 14.8.2.1.3(b) */ 1164 char bridgel_uptime[7]; /* 14.8.2.1.3(a) */ 1165 char bridgel_opercost[7] /* 14.8.2.1.3(d) */; 1166 char bridgel_operp2p[4]; /* 14.8.2.1.3(p) */ 1167 char bridgel_operedge[4]; /* 14.8.2.1.3(k) */ 1168 char bridgel_desroot[23]; /* 14.8.2.1.3(e) */ 1169 char bridgel_descost[12]; /* 14.8.2.1.3(f) */ 1170 char bridgel_desbridge[23]; /* 14.8.2.1.3(g) */ 1171 char bridgel_desport[7]; /* 14.8.2.1.3(h) */ 1172 char bridgel_tcack[4]; /* 14.8.2.1.3(i) */ 1173 } bridge_link_fields_buf_t; 1174 1175 static ofmt_field_t bridge_link_fields[] = { 1176 /* name, field width, offset, callback */ 1177 { "LINK", 12, 1178 offsetof(bridge_link_fields_buf_t, bridgel_link), print_default_cb }, 1179 { "INDEX", 8, 1180 offsetof(bridge_link_fields_buf_t, bridgel_index), print_default_cb }, 1181 { "STATE", 12, 1182 offsetof(bridge_link_fields_buf_t, bridgel_state), print_default_cb }, 1183 { "UPTIME", 8, 1184 offsetof(bridge_link_fields_buf_t, bridgel_uptime), print_default_cb }, 1185 { "OPERCOST", 9, 1186 offsetof(bridge_link_fields_buf_t, bridgel_opercost), print_default_cb }, 1187 { "OPERP2P", 8, 1188 offsetof(bridge_link_fields_buf_t, bridgel_operp2p), print_default_cb }, 1189 { "OPEREDGE", 9, 1190 offsetof(bridge_link_fields_buf_t, bridgel_operedge), print_default_cb }, 1191 { "DESROOT", 22, 1192 offsetof(bridge_link_fields_buf_t, bridgel_desroot), print_default_cb }, 1193 { "DESCOST", 11, 1194 offsetof(bridge_link_fields_buf_t, bridgel_descost), print_default_cb }, 1195 { "DESBRIDGE", 22, 1196 offsetof(bridge_link_fields_buf_t, bridgel_desbridge), print_default_cb }, 1197 { "DESPORT", 8, 1198 offsetof(bridge_link_fields_buf_t, bridgel_desport), print_default_cb }, 1199 { "TCACK", 6, 1200 offsetof(bridge_link_fields_buf_t, bridgel_tcack), print_default_cb }, 1201 { NULL, 0, 0, NULL}}; 1202 1203 /* 1204 * structures for 'dladm show-bridge -s'. These are not based on IEEE 1205 * 802.1D-2004. 1206 */ 1207 #define ULONG_DIG (((sizeof (ulong_t) * NBBY) * 3 / 10) + 1) 1208 #define UINT64_DIG (((sizeof (uint64_t) * NBBY) * 3 / 10) + 1) 1209 typedef struct bridge_statfields_buf_s { 1210 char bridges_name[MAXLINKNAMELEN]; 1211 char bridges_drops[UINT64_DIG]; 1212 char bridges_forwards[UINT64_DIG]; 1213 char bridges_mbcast[UINT64_DIG]; 1214 char bridges_unknown[UINT64_DIG]; 1215 char bridges_recv[UINT64_DIG]; 1216 char bridges_sent[UINT64_DIG]; 1217 } bridge_statfields_buf_t; 1218 1219 static ofmt_field_t bridge_statfields[] = { 1220 /* name, field width, offset, callback */ 1221 { "BRIDGE", 12, 1222 offsetof(bridge_statfields_buf_t, bridges_name), print_default_cb }, 1223 { "DROPS", 12, 1224 offsetof(bridge_statfields_buf_t, bridges_drops), print_default_cb }, 1225 { "FORWARDS", 12, 1226 offsetof(bridge_statfields_buf_t, bridges_forwards), print_default_cb }, 1227 { "MBCAST", 12, 1228 offsetof(bridge_statfields_buf_t, bridges_mbcast), print_default_cb }, 1229 { "UNKNOWN", 12, 1230 offsetof(bridge_statfields_buf_t, bridges_unknown), print_default_cb }, 1231 { "RECV", 12, 1232 offsetof(bridge_statfields_buf_t, bridges_recv), print_default_cb }, 1233 { "SENT", 12, 1234 offsetof(bridge_statfields_buf_t, bridges_sent), print_default_cb }, 1235 { NULL, 0, 0, NULL}}; 1236 1237 /* 1238 * structures for 'dladm show-bridge -s -l'. These are based in part on 1239 * section 14.6.1.1.3 of IEEE 802.1D-2004. 1240 */ 1241 typedef struct bridge_link_statfields_buf_s { 1242 char bridgels_link[MAXLINKNAMELEN]; 1243 char bridgels_cfgbpdu[ULONG_DIG]; 1244 char bridgels_tcnbpdu[ULONG_DIG]; 1245 char bridgels_rstpbpdu[ULONG_DIG]; 1246 char bridgels_txbpdu[ULONG_DIG]; 1247 char bridgels_drops[UINT64_DIG]; /* 14.6.1.1.3(d) */ 1248 char bridgels_recv[UINT64_DIG]; /* 14.6.1.1.3(a) */ 1249 char bridgels_xmit[UINT64_DIG]; /* 14.6.1.1.3(c) */ 1250 } bridge_link_statfields_buf_t; 1251 1252 static ofmt_field_t bridge_link_statfields[] = { 1253 /* name, field width, offset, callback */ 1254 { "LINK", 12, 1255 offsetof(bridge_link_statfields_buf_t, bridgels_link), print_default_cb }, 1256 { "CFGBPDU", 9, 1257 offsetof(bridge_link_statfields_buf_t, bridgels_cfgbpdu), 1258 print_default_cb }, 1259 { "TCNBPDU", 9, 1260 offsetof(bridge_link_statfields_buf_t, bridgels_tcnbpdu), 1261 print_default_cb }, 1262 { "RSTPBPDU", 9, 1263 offsetof(bridge_link_statfields_buf_t, bridgels_rstpbpdu), 1264 print_default_cb }, 1265 { "TXBPDU", 9, 1266 offsetof(bridge_link_statfields_buf_t, bridgels_txbpdu), print_default_cb }, 1267 { "DROPS", 9, 1268 offsetof(bridge_link_statfields_buf_t, bridgels_drops), print_default_cb }, 1269 { "RECV", 9, 1270 offsetof(bridge_link_statfields_buf_t, bridgels_recv), print_default_cb }, 1271 { "XMIT", 9, 1272 offsetof(bridge_link_statfields_buf_t, bridgels_xmit), print_default_cb }, 1273 { NULL, 0, 0, NULL}}; 1274 1275 /* 1276 * structures for 'dladm show-bridge -f'. These are based in part on 1277 * section 14.7.6.3.3 of IEEE 802.1D-2004. 1278 */ 1279 typedef struct bridge_fwd_fields_buf_s { 1280 char bridgef_dest[18]; /* 14.7.6.3.3(a) */ 1281 char bridgef_age[8]; 1282 char bridgef_flags[6]; 1283 char bridgef_output[MAXLINKNAMELEN]; /* 14.7.6.3.3(c) */ 1284 } bridge_fwd_fields_buf_t; 1285 1286 static ofmt_field_t bridge_fwd_fields[] = { 1287 /* name, field width, offset, callback */ 1288 { "DEST", 17, 1289 offsetof(bridge_fwd_fields_buf_t, bridgef_dest), print_default_cb }, 1290 { "AGE", 7, 1291 offsetof(bridge_fwd_fields_buf_t, bridgef_age), print_default_cb }, 1292 { "FLAGS", 6, 1293 offsetof(bridge_fwd_fields_buf_t, bridgef_flags), print_default_cb }, 1294 { "OUTPUT", 12, 1295 offsetof(bridge_fwd_fields_buf_t, bridgef_output), print_default_cb }, 1296 { NULL, 0, 0, NULL}}; 1297 1298 /* 1299 * structures for 'dladm show-bridge -t'. 1300 */ 1301 typedef struct bridge_trill_fields_buf_s { 1302 char bridget_nick[6]; 1303 char bridget_flags[6]; 1304 char bridget_link[MAXLINKNAMELEN]; 1305 char bridget_nexthop[18]; 1306 } bridge_trill_fields_buf_t; 1307 1308 static ofmt_field_t bridge_trill_fields[] = { 1309 /* name, field width, offset, callback */ 1310 { "NICK", 5, 1311 offsetof(bridge_trill_fields_buf_t, bridget_nick), print_default_cb }, 1312 { "FLAGS", 6, 1313 offsetof(bridge_trill_fields_buf_t, bridget_flags), print_default_cb }, 1314 { "LINK", 12, 1315 offsetof(bridge_trill_fields_buf_t, bridget_link), print_default_cb }, 1316 { "NEXTHOP", 17, 1317 offsetof(bridge_trill_fields_buf_t, bridget_nexthop), print_default_cb }, 1318 { NULL, 0, 0, NULL}}; 1319 1320 static char *progname; 1321 static sig_atomic_t signalled; 1322 1323 /* 1324 * Handle to libdladm. Opened in main() before the sub-command 1325 * specific function is called. 1326 */ 1327 static dladm_handle_t handle = NULL; 1328 1329 #define DLADM_ETHERSTUB_NAME "etherstub" 1330 #define DLADM_IS_ETHERSTUB(id) (id == DATALINK_INVALID_LINKID) 1331 1332 static void 1333 usage(void) 1334 { 1335 int i; 1336 cmd_t *cmdp; 1337 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ..." 1338 "\n")); 1339 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 1340 cmdp = &cmds[i]; 1341 if (cmdp->c_usage != NULL) 1342 (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage)); 1343 } 1344 1345 /* close dladm handle if it was opened */ 1346 if (handle != NULL) 1347 dladm_close(handle); 1348 1349 exit(EXIT_FAILURE); 1350 } 1351 1352 int 1353 main(int argc, char *argv[]) 1354 { 1355 int i; 1356 cmd_t *cmdp; 1357 dladm_status_t status; 1358 1359 (void) setlocale(LC_ALL, ""); 1360 #if !defined(TEXT_DOMAIN) 1361 #define TEXT_DOMAIN "SYS_TEST" 1362 #endif 1363 (void) textdomain(TEXT_DOMAIN); 1364 1365 progname = argv[0]; 1366 1367 if (argc < 2) 1368 usage(); 1369 1370 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 1371 cmdp = &cmds[i]; 1372 if (strcmp(argv[1], cmdp->c_name) == 0) { 1373 /* Open the libdladm handle */ 1374 if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) { 1375 die_dlerr(status, 1376 "could not open /dev/dld"); 1377 } 1378 1379 cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage); 1380 1381 dladm_close(handle); 1382 return (EXIT_SUCCESS); 1383 } 1384 } 1385 1386 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 1387 progname, argv[1]); 1388 usage(); 1389 return (EXIT_FAILURE); 1390 } 1391 1392 /*ARGSUSED*/ 1393 static int 1394 show_usage_date(dladm_usage_t *usage, void *arg) 1395 { 1396 show_usage_state_t *state = (show_usage_state_t *)arg; 1397 time_t stime; 1398 char timebuf[20]; 1399 dladm_status_t status; 1400 uint32_t flags; 1401 1402 /* 1403 * Only show usage information for existing links unless '-a' 1404 * is specified. 1405 */ 1406 if (!state->us_showall) { 1407 if ((status = dladm_name2info(handle, usage->du_name, 1408 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1409 return (status); 1410 } 1411 if ((flags & DLADM_OPT_ACTIVE) == 0) 1412 return (DLADM_STATUS_LINKINVAL); 1413 } 1414 1415 stime = usage->du_stime; 1416 (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y", 1417 localtime(&stime)); 1418 (void) printf("%s\n", timebuf); 1419 1420 return (DLADM_STATUS_OK); 1421 } 1422 1423 static int 1424 show_usage_time(dladm_usage_t *usage, void *arg) 1425 { 1426 show_usage_state_t *state = (show_usage_state_t *)arg; 1427 char buf[DLADM_STRSIZE]; 1428 usage_l_fields_buf_t ubuf; 1429 time_t time; 1430 double bw; 1431 dladm_status_t status; 1432 uint32_t flags; 1433 1434 /* 1435 * Only show usage information for existing links unless '-a' 1436 * is specified. 1437 */ 1438 if (!state->us_showall) { 1439 if ((status = dladm_name2info(handle, usage->du_name, 1440 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1441 return (status); 1442 } 1443 if ((flags & DLADM_OPT_ACTIVE) == 0) 1444 return (DLADM_STATUS_LINKINVAL); 1445 } 1446 1447 if (state->us_plot) { 1448 if (!state->us_printheader) { 1449 if (state->us_first) { 1450 (void) printf("# Time"); 1451 state->us_first = B_FALSE; 1452 } 1453 (void) printf(" %s", usage->du_name); 1454 if (usage->du_last) { 1455 (void) printf("\n"); 1456 state->us_first = B_TRUE; 1457 state->us_printheader = B_TRUE; 1458 } 1459 } else { 1460 if (state->us_first) { 1461 time = usage->du_etime; 1462 (void) strftime(buf, sizeof (buf), "%T", 1463 localtime(&time)); 1464 state->us_first = B_FALSE; 1465 (void) printf("%s", buf); 1466 } 1467 bw = (double)usage->du_bandwidth/1000; 1468 (void) printf(" %.2f", bw); 1469 if (usage->du_last) { 1470 (void) printf("\n"); 1471 state->us_first = B_TRUE; 1472 } 1473 } 1474 return (DLADM_STATUS_OK); 1475 } 1476 1477 bzero(&ubuf, sizeof (ubuf)); 1478 1479 (void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s", 1480 usage->du_name); 1481 time = usage->du_stime; 1482 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1483 (void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s", 1484 buf); 1485 time = usage->du_etime; 1486 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1487 (void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s", 1488 buf); 1489 (void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes), 1490 "%llu", usage->du_rbytes); 1491 (void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes), 1492 "%llu", usage->du_obytes); 1493 (void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth), 1494 "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1495 1496 ofmt_print(state->us_ofmt, &ubuf); 1497 return (DLADM_STATUS_OK); 1498 } 1499 1500 static int 1501 show_usage_res(dladm_usage_t *usage, void *arg) 1502 { 1503 show_usage_state_t *state = (show_usage_state_t *)arg; 1504 char buf[DLADM_STRSIZE]; 1505 usage_fields_buf_t ubuf; 1506 dladm_status_t status; 1507 uint32_t flags; 1508 1509 /* 1510 * Only show usage information for existing links unless '-a' 1511 * is specified. 1512 */ 1513 if (!state->us_showall) { 1514 if ((status = dladm_name2info(handle, usage->du_name, 1515 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1516 return (status); 1517 } 1518 if ((flags & DLADM_OPT_ACTIVE) == 0) 1519 return (DLADM_STATUS_LINKINVAL); 1520 } 1521 1522 bzero(&ubuf, sizeof (ubuf)); 1523 1524 (void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s", 1525 usage->du_name); 1526 (void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration), 1527 "%llu", usage->du_duration); 1528 (void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets), 1529 "%llu", usage->du_ipackets); 1530 (void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes), 1531 "%llu", usage->du_rbytes); 1532 (void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets), 1533 "%llu", usage->du_opackets); 1534 (void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes), 1535 "%llu", usage->du_obytes); 1536 (void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth), 1537 "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1538 1539 ofmt_print(state->us_ofmt, &ubuf); 1540 1541 return (DLADM_STATUS_OK); 1542 } 1543 1544 static boolean_t 1545 valid_formatspec(char *formatspec_str) 1546 { 1547 if (strcmp(formatspec_str, "gnuplot") == 0) 1548 return (B_TRUE); 1549 return (B_FALSE); 1550 1551 } 1552 1553 /*ARGSUSED*/ 1554 static void 1555 do_show_usage(int argc, char *argv[], const char *use) 1556 { 1557 char *file = NULL; 1558 int opt; 1559 dladm_status_t status; 1560 boolean_t d_arg = B_FALSE; 1561 char *stime = NULL; 1562 char *etime = NULL; 1563 char *resource = NULL; 1564 show_usage_state_t state; 1565 boolean_t o_arg = B_FALSE; 1566 boolean_t F_arg = B_FALSE; 1567 char *fields_str = NULL; 1568 char *formatspec_str = NULL; 1569 char *all_l_fields = 1570 "link,start,end,rbytes,obytes,bandwidth"; 1571 ofmt_handle_t ofmt; 1572 ofmt_status_t oferr; 1573 uint_t ofmtflags = 0; 1574 1575 bzero(&state, sizeof (show_usage_state_t)); 1576 state.us_parsable = B_FALSE; 1577 state.us_printheader = B_FALSE; 1578 state.us_plot = B_FALSE; 1579 state.us_first = B_TRUE; 1580 1581 while ((opt = getopt_long(argc, argv, "das:e:o:f:F:", 1582 usage_opts, NULL)) != -1) { 1583 switch (opt) { 1584 case 'd': 1585 d_arg = B_TRUE; 1586 break; 1587 case 'a': 1588 state.us_showall = B_TRUE; 1589 break; 1590 case 'f': 1591 file = optarg; 1592 break; 1593 case 's': 1594 stime = optarg; 1595 break; 1596 case 'e': 1597 etime = optarg; 1598 break; 1599 case 'o': 1600 o_arg = B_TRUE; 1601 fields_str = optarg; 1602 break; 1603 case 'F': 1604 state.us_plot = F_arg = B_TRUE; 1605 formatspec_str = optarg; 1606 break; 1607 default: 1608 die_opterr(optopt, opt, use); 1609 break; 1610 } 1611 } 1612 1613 if (file == NULL) 1614 die("show-usage requires a file"); 1615 1616 if (optind == (argc-1)) { 1617 uint32_t flags; 1618 1619 resource = argv[optind]; 1620 if (!state.us_showall && 1621 (((status = dladm_name2info(handle, resource, NULL, &flags, 1622 NULL, NULL)) != DLADM_STATUS_OK) || 1623 ((flags & DLADM_OPT_ACTIVE) == 0))) { 1624 die("invalid link: '%s'", resource); 1625 } 1626 } 1627 1628 if (F_arg && d_arg) 1629 die("incompatible -d and -F options"); 1630 1631 if (F_arg && valid_formatspec(formatspec_str) == B_FALSE) 1632 die("Format specifier %s not supported", formatspec_str); 1633 1634 if (state.us_parsable) 1635 ofmtflags |= OFMT_PARSABLE; 1636 1637 if (resource == NULL && stime == NULL && etime == NULL) { 1638 oferr = ofmt_open(fields_str, usage_fields, ofmtflags, 0, 1639 &ofmt); 1640 } else { 1641 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 1642 fields_str = all_l_fields; 1643 oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags, 0, 1644 &ofmt); 1645 1646 } 1647 dladm_ofmt_check(oferr, state.us_parsable, ofmt); 1648 state.us_ofmt = ofmt; 1649 1650 if (d_arg) { 1651 /* Print log dates */ 1652 status = dladm_usage_dates(show_usage_date, 1653 DLADM_LOGTYPE_LINK, file, resource, &state); 1654 } else if (resource == NULL && stime == NULL && etime == NULL && 1655 !F_arg) { 1656 /* Print summary */ 1657 status = dladm_usage_summary(show_usage_res, 1658 DLADM_LOGTYPE_LINK, file, &state); 1659 } else if (resource != NULL) { 1660 /* Print log entries for named resource */ 1661 status = dladm_walk_usage_res(show_usage_time, 1662 DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state); 1663 } else { 1664 /* Print time and information for each link */ 1665 status = dladm_walk_usage_time(show_usage_time, 1666 DLADM_LOGTYPE_LINK, file, stime, etime, &state); 1667 } 1668 1669 if (status != DLADM_STATUS_OK) 1670 die_dlerr(status, "show-usage"); 1671 ofmt_close(ofmt); 1672 } 1673 1674 static void 1675 do_create_aggr(int argc, char *argv[], const char *use) 1676 { 1677 int option; 1678 int key = 0; 1679 uint32_t policy = AGGR_POLICY_L4; 1680 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 1681 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 1682 dladm_aggr_port_attr_db_t port[MAXPORT]; 1683 uint_t n, ndev, nlink; 1684 uint8_t mac_addr[ETHERADDRL]; 1685 boolean_t mac_addr_fixed = B_FALSE; 1686 boolean_t P_arg = B_FALSE; 1687 boolean_t l_arg = B_FALSE; 1688 boolean_t u_arg = B_FALSE; 1689 boolean_t T_arg = B_FALSE; 1690 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1691 char *altroot = NULL; 1692 char name[MAXLINKNAMELEN]; 1693 char *devs[MAXPORT]; 1694 char *links[MAXPORT]; 1695 dladm_status_t status; 1696 dladm_status_t pstatus; 1697 char propstr[DLADM_STRSIZE]; 1698 dladm_arg_list_t *proplist = NULL; 1699 int i; 1700 datalink_id_t linkid; 1701 1702 ndev = nlink = opterr = 0; 1703 bzero(propstr, DLADM_STRSIZE); 1704 1705 while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:", 1706 lopts, NULL)) != -1) { 1707 switch (option) { 1708 case 'd': 1709 if (ndev + nlink >= MAXPORT) 1710 die("too many ports specified"); 1711 1712 devs[ndev++] = optarg; 1713 break; 1714 case 'P': 1715 if (P_arg) 1716 die_optdup(option); 1717 1718 P_arg = B_TRUE; 1719 if (!dladm_aggr_str2policy(optarg, &policy)) 1720 die("invalid policy '%s'", optarg); 1721 break; 1722 case 'u': 1723 if (u_arg) 1724 die_optdup(option); 1725 1726 u_arg = B_TRUE; 1727 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 1728 mac_addr)) 1729 die("invalid MAC address '%s'", optarg); 1730 break; 1731 case 'l': 1732 if (isdigit(optarg[strlen(optarg) - 1])) { 1733 1734 /* 1735 * Ended with digit, possibly a link name. 1736 */ 1737 if (ndev + nlink >= MAXPORT) 1738 die("too many ports specified"); 1739 1740 links[nlink++] = optarg; 1741 break; 1742 } 1743 /* FALLTHROUGH */ 1744 case 'L': 1745 if (l_arg) 1746 die_optdup(option); 1747 1748 l_arg = B_TRUE; 1749 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 1750 die("invalid LACP mode '%s'", optarg); 1751 break; 1752 case 'T': 1753 if (T_arg) 1754 die_optdup(option); 1755 1756 T_arg = B_TRUE; 1757 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 1758 die("invalid LACP timer value '%s'", optarg); 1759 break; 1760 case 't': 1761 flags &= ~DLADM_OPT_PERSIST; 1762 break; 1763 case 'f': 1764 flags |= DLADM_OPT_FORCE; 1765 break; 1766 case 'R': 1767 altroot = optarg; 1768 break; 1769 case 'p': 1770 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 1771 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 1772 DLADM_STRSIZE) 1773 die("property list too long '%s'", propstr); 1774 break; 1775 1776 default: 1777 die_opterr(optopt, option, use); 1778 break; 1779 } 1780 } 1781 1782 if (ndev + nlink == 0) 1783 usage(); 1784 1785 /* get key value or the aggregation name (required last argument) */ 1786 if (optind != (argc-1)) 1787 usage(); 1788 1789 if (!str2int(argv[optind], &key)) { 1790 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= 1791 MAXLINKNAMELEN) { 1792 die("link name too long '%s'", argv[optind]); 1793 } 1794 1795 if (!dladm_valid_linkname(name)) 1796 die("invalid link name '%s'", argv[optind]); 1797 } else { 1798 (void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key); 1799 } 1800 1801 if (altroot != NULL) 1802 altroot_cmd(altroot, argc, argv); 1803 1804 for (n = 0; n < ndev; n++) { 1805 if ((status = dladm_dev2linkid(handle, devs[n], 1806 &port[n].lp_linkid)) != DLADM_STATUS_OK) { 1807 die_dlerr(status, "invalid dev name '%s'", devs[n]); 1808 } 1809 } 1810 1811 for (n = 0; n < nlink; n++) { 1812 if ((status = dladm_name2info(handle, links[n], 1813 &port[ndev + n].lp_linkid, NULL, NULL, NULL)) != 1814 DLADM_STATUS_OK) { 1815 die_dlerr(status, "invalid link name '%s'", links[n]); 1816 } 1817 } 1818 1819 status = dladm_aggr_create(handle, name, key, ndev + nlink, port, 1820 policy, mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, 1821 lacp_timer, flags); 1822 if (status != DLADM_STATUS_OK) 1823 goto done; 1824 1825 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 1826 != DLADM_STATUS_OK) 1827 die("invalid aggregation property"); 1828 1829 if (proplist == NULL) 1830 return; 1831 1832 status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL); 1833 if (status != DLADM_STATUS_OK) 1834 goto done; 1835 1836 for (i = 0; i < proplist->al_count; i++) { 1837 dladm_arg_info_t *aip = &proplist->al_info[i]; 1838 1839 pstatus = dladm_set_linkprop(handle, linkid, aip->ai_name, 1840 aip->ai_val, aip->ai_count, flags); 1841 1842 if (pstatus != DLADM_STATUS_OK) { 1843 die_dlerr(pstatus, 1844 "aggr creation succeeded but " 1845 "could not set property '%s'", aip->ai_name); 1846 } 1847 } 1848 done: 1849 dladm_free_props(proplist); 1850 if (status != DLADM_STATUS_OK) { 1851 if (status == DLADM_STATUS_NONOTIF) { 1852 die("not all links have link up/down detection; must " 1853 "use -f (see dladm(1M))"); 1854 } else { 1855 die_dlerr(status, "create operation failed"); 1856 } 1857 } 1858 } 1859 1860 /* 1861 * arg is either the key or the aggr name. Validate it and convert it to 1862 * the linkid if altroot is NULL. 1863 */ 1864 static dladm_status_t 1865 i_dladm_aggr_get_linkid(const char *altroot, const char *arg, 1866 datalink_id_t *linkidp, uint32_t flags) 1867 { 1868 int key = 0; 1869 char *aggr = NULL; 1870 dladm_status_t status; 1871 1872 if (!str2int(arg, &key)) 1873 aggr = (char *)arg; 1874 1875 if (aggr == NULL && key == 0) 1876 return (DLADM_STATUS_LINKINVAL); 1877 1878 if (altroot != NULL) 1879 return (DLADM_STATUS_OK); 1880 1881 if (aggr != NULL) { 1882 status = dladm_name2info(handle, aggr, linkidp, NULL, NULL, 1883 NULL); 1884 } else { 1885 status = dladm_key2linkid(handle, key, linkidp, flags); 1886 } 1887 1888 return (status); 1889 } 1890 1891 static void 1892 do_delete_aggr(int argc, char *argv[], const char *use) 1893 { 1894 int option; 1895 char *altroot = NULL; 1896 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1897 dladm_status_t status; 1898 datalink_id_t linkid; 1899 1900 opterr = 0; 1901 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 1902 switch (option) { 1903 case 't': 1904 flags &= ~DLADM_OPT_PERSIST; 1905 break; 1906 case 'R': 1907 altroot = optarg; 1908 break; 1909 default: 1910 die_opterr(optopt, option, use); 1911 break; 1912 } 1913 } 1914 1915 /* get key value or the aggregation name (required last argument) */ 1916 if (optind != (argc-1)) 1917 usage(); 1918 1919 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1920 if (status != DLADM_STATUS_OK) 1921 goto done; 1922 1923 if (altroot != NULL) 1924 altroot_cmd(altroot, argc, argv); 1925 1926 status = dladm_aggr_delete(handle, linkid, flags); 1927 done: 1928 if (status != DLADM_STATUS_OK) 1929 die_dlerr(status, "delete operation failed"); 1930 } 1931 1932 static void 1933 do_add_aggr(int argc, char *argv[], const char *use) 1934 { 1935 int option; 1936 uint_t n, ndev, nlink; 1937 char *altroot = NULL; 1938 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1939 datalink_id_t linkid; 1940 dladm_status_t status; 1941 dladm_aggr_port_attr_db_t port[MAXPORT]; 1942 char *devs[MAXPORT]; 1943 char *links[MAXPORT]; 1944 1945 ndev = nlink = opterr = 0; 1946 while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts, 1947 NULL)) != -1) { 1948 switch (option) { 1949 case 'd': 1950 if (ndev + nlink >= MAXPORT) 1951 die("too many ports specified"); 1952 1953 devs[ndev++] = optarg; 1954 break; 1955 case 'l': 1956 if (ndev + nlink >= MAXPORT) 1957 die("too many ports specified"); 1958 1959 links[nlink++] = optarg; 1960 break; 1961 case 't': 1962 flags &= ~DLADM_OPT_PERSIST; 1963 break; 1964 case 'f': 1965 flags |= DLADM_OPT_FORCE; 1966 break; 1967 case 'R': 1968 altroot = optarg; 1969 break; 1970 default: 1971 die_opterr(optopt, option, use); 1972 break; 1973 } 1974 } 1975 1976 if (ndev + nlink == 0) 1977 usage(); 1978 1979 /* get key value or the aggregation name (required last argument) */ 1980 if (optind != (argc-1)) 1981 usage(); 1982 1983 if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, 1984 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) != 1985 DLADM_STATUS_OK) { 1986 goto done; 1987 } 1988 1989 if (altroot != NULL) 1990 altroot_cmd(altroot, argc, argv); 1991 1992 for (n = 0; n < ndev; n++) { 1993 if ((status = dladm_dev2linkid(handle, devs[n], 1994 &(port[n].lp_linkid))) != DLADM_STATUS_OK) { 1995 die_dlerr(status, "invalid <dev> '%s'", devs[n]); 1996 } 1997 } 1998 1999 for (n = 0; n < nlink; n++) { 2000 if ((status = dladm_name2info(handle, links[n], 2001 &port[n + ndev].lp_linkid, NULL, NULL, NULL)) != 2002 DLADM_STATUS_OK) { 2003 die_dlerr(status, "invalid <link> '%s'", links[n]); 2004 } 2005 } 2006 2007 status = dladm_aggr_add(handle, linkid, ndev + nlink, port, flags); 2008 done: 2009 if (status != DLADM_STATUS_OK) { 2010 /* 2011 * checking DLADM_STATUS_NOTSUP is a temporary workaround 2012 * and should be removed once 6399681 is fixed. 2013 */ 2014 if (status == DLADM_STATUS_NOTSUP) { 2015 die("add operation failed: link capabilities don't " 2016 "match"); 2017 } else if (status == DLADM_STATUS_NONOTIF) { 2018 die("not all links have link up/down detection; must " 2019 "use -f (see dladm(1M))"); 2020 } else { 2021 die_dlerr(status, "add operation failed"); 2022 } 2023 } 2024 } 2025 2026 static void 2027 do_remove_aggr(int argc, char *argv[], const char *use) 2028 { 2029 int option; 2030 dladm_aggr_port_attr_db_t port[MAXPORT]; 2031 uint_t n, ndev, nlink; 2032 char *devs[MAXPORT]; 2033 char *links[MAXPORT]; 2034 char *altroot = NULL; 2035 uint32_t flags; 2036 datalink_id_t linkid; 2037 dladm_status_t status; 2038 2039 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 2040 ndev = nlink = opterr = 0; 2041 while ((option = getopt_long(argc, argv, ":d:l:R:t", 2042 lopts, NULL)) != -1) { 2043 switch (option) { 2044 case 'd': 2045 if (ndev + nlink >= MAXPORT) 2046 die("too many ports specified"); 2047 2048 devs[ndev++] = optarg; 2049 break; 2050 case 'l': 2051 if (ndev + nlink >= MAXPORT) 2052 die("too many ports specified"); 2053 2054 links[nlink++] = optarg; 2055 break; 2056 case 't': 2057 flags &= ~DLADM_OPT_PERSIST; 2058 break; 2059 case 'R': 2060 altroot = optarg; 2061 break; 2062 default: 2063 die_opterr(optopt, option, use); 2064 break; 2065 } 2066 } 2067 2068 if (ndev + nlink == 0) 2069 usage(); 2070 2071 /* get key value or the aggregation name (required last argument) */ 2072 if (optind != (argc-1)) 2073 usage(); 2074 2075 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 2076 if (status != DLADM_STATUS_OK) 2077 goto done; 2078 2079 if (altroot != NULL) 2080 altroot_cmd(altroot, argc, argv); 2081 2082 for (n = 0; n < ndev; n++) { 2083 if ((status = dladm_dev2linkid(handle, devs[n], 2084 &(port[n].lp_linkid))) != DLADM_STATUS_OK) { 2085 die_dlerr(status, "invalid <dev> '%s'", devs[n]); 2086 } 2087 } 2088 2089 for (n = 0; n < nlink; n++) { 2090 if ((status = dladm_name2info(handle, links[n], 2091 &port[n + ndev].lp_linkid, NULL, NULL, NULL)) != 2092 DLADM_STATUS_OK) { 2093 die_dlerr(status, "invalid <link> '%s'", links[n]); 2094 } 2095 } 2096 2097 status = dladm_aggr_remove(handle, linkid, ndev + nlink, port, flags); 2098 done: 2099 if (status != DLADM_STATUS_OK) 2100 die_dlerr(status, "remove operation failed"); 2101 } 2102 2103 static void 2104 do_modify_aggr(int argc, char *argv[], const char *use) 2105 { 2106 int option; 2107 uint32_t policy = AGGR_POLICY_L4; 2108 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 2109 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 2110 uint8_t mac_addr[ETHERADDRL]; 2111 boolean_t mac_addr_fixed = B_FALSE; 2112 uint8_t modify_mask = 0; 2113 char *altroot = NULL; 2114 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 2115 datalink_id_t linkid; 2116 dladm_status_t status; 2117 2118 opterr = 0; 2119 while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts, 2120 NULL)) != -1) { 2121 switch (option) { 2122 case 'P': 2123 if (modify_mask & DLADM_AGGR_MODIFY_POLICY) 2124 die_optdup(option); 2125 2126 modify_mask |= DLADM_AGGR_MODIFY_POLICY; 2127 2128 if (!dladm_aggr_str2policy(optarg, &policy)) 2129 die("invalid policy '%s'", optarg); 2130 break; 2131 case 'u': 2132 if (modify_mask & DLADM_AGGR_MODIFY_MAC) 2133 die_optdup(option); 2134 2135 modify_mask |= DLADM_AGGR_MODIFY_MAC; 2136 2137 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 2138 mac_addr)) 2139 die("invalid MAC address '%s'", optarg); 2140 break; 2141 case 'l': 2142 case 'L': 2143 if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE) 2144 die_optdup(option); 2145 2146 modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE; 2147 2148 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 2149 die("invalid LACP mode '%s'", optarg); 2150 break; 2151 case 'T': 2152 if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER) 2153 die_optdup(option); 2154 2155 modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER; 2156 2157 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 2158 die("invalid LACP timer value '%s'", optarg); 2159 break; 2160 case 't': 2161 flags &= ~DLADM_OPT_PERSIST; 2162 break; 2163 case 'R': 2164 altroot = optarg; 2165 break; 2166 default: 2167 die_opterr(optopt, option, use); 2168 break; 2169 } 2170 } 2171 2172 if (modify_mask == 0) 2173 die("at least one of the -PulT options must be specified"); 2174 2175 /* get key value or the aggregation name (required last argument) */ 2176 if (optind != (argc-1)) 2177 usage(); 2178 2179 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 2180 if (status != DLADM_STATUS_OK) 2181 goto done; 2182 2183 if (altroot != NULL) 2184 altroot_cmd(altroot, argc, argv); 2185 2186 status = dladm_aggr_modify(handle, linkid, modify_mask, policy, 2187 mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, lacp_timer, 2188 flags); 2189 2190 done: 2191 if (status != DLADM_STATUS_OK) 2192 die_dlerr(status, "modify operation failed"); 2193 } 2194 2195 /*ARGSUSED*/ 2196 static void 2197 do_up_aggr(int argc, char *argv[], const char *use) 2198 { 2199 datalink_id_t linkid = DATALINK_ALL_LINKID; 2200 dladm_status_t status; 2201 2202 /* 2203 * get the key or the name of the aggregation (optional last argument) 2204 */ 2205 if (argc == 2) { 2206 if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid, 2207 DLADM_OPT_PERSIST)) != DLADM_STATUS_OK) 2208 goto done; 2209 } else if (argc > 2) { 2210 usage(); 2211 } 2212 2213 status = dladm_aggr_up(handle, linkid); 2214 done: 2215 if (status != DLADM_STATUS_OK) { 2216 if (argc == 2) { 2217 die_dlerr(status, 2218 "could not bring up aggregation '%s'", argv[1]); 2219 } else { 2220 die_dlerr(status, "could not bring aggregations up"); 2221 } 2222 } 2223 } 2224 2225 static void 2226 do_create_vlan(int argc, char *argv[], const char *use) 2227 { 2228 char *link = NULL; 2229 char drv[DLPI_LINKNAME_MAX]; 2230 uint_t ppa; 2231 datalink_id_t linkid; 2232 datalink_id_t dev_linkid; 2233 int vid = 0; 2234 int option; 2235 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2236 char *altroot = NULL; 2237 char vlan[MAXLINKNAMELEN]; 2238 char propstr[DLADM_STRSIZE]; 2239 dladm_arg_list_t *proplist = NULL; 2240 dladm_status_t status; 2241 2242 opterr = 0; 2243 bzero(propstr, DLADM_STRSIZE); 2244 2245 while ((option = getopt_long(argc, argv, ":tfR:l:v:p:", 2246 lopts, NULL)) != -1) { 2247 switch (option) { 2248 case 'v': 2249 if (vid != 0) 2250 die_optdup(option); 2251 2252 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 2253 die("invalid VLAN identifier '%s'", optarg); 2254 2255 break; 2256 case 'l': 2257 if (link != NULL) 2258 die_optdup(option); 2259 2260 link = optarg; 2261 break; 2262 case 't': 2263 flags &= ~DLADM_OPT_PERSIST; 2264 break; 2265 case 'R': 2266 altroot = optarg; 2267 break; 2268 case 'p': 2269 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 2270 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 2271 DLADM_STRSIZE) 2272 die("property list too long '%s'", propstr); 2273 break; 2274 case 'f': 2275 flags |= DLADM_OPT_FORCE; 2276 break; 2277 default: 2278 die_opterr(optopt, option, use); 2279 break; 2280 } 2281 } 2282 2283 /* get vlan name if there is any */ 2284 if ((vid == 0) || (link == NULL) || (argc - optind > 1)) 2285 usage(); 2286 2287 if (optind == (argc - 1)) { 2288 if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >= 2289 MAXLINKNAMELEN) { 2290 die("vlan name too long '%s'", argv[optind]); 2291 } 2292 } else { 2293 if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) || 2294 (ppa >= 1000) || 2295 (dlpi_makelink(vlan, drv, vid * 1000 + ppa) != 2296 DLPI_SUCCESS)) { 2297 die("invalid link name '%s'", link); 2298 } 2299 } 2300 2301 if (altroot != NULL) 2302 altroot_cmd(altroot, argc, argv); 2303 2304 if (dladm_name2info(handle, link, &dev_linkid, NULL, NULL, NULL) != 2305 DLADM_STATUS_OK) { 2306 die("invalid link name '%s'", link); 2307 } 2308 2309 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 2310 != DLADM_STATUS_OK) 2311 die("invalid vlan property"); 2312 2313 status = dladm_vlan_create(handle, vlan, dev_linkid, vid, proplist, 2314 flags, &linkid); 2315 switch (status) { 2316 case DLADM_STATUS_OK: 2317 break; 2318 2319 case DLADM_STATUS_NOTSUP: 2320 die("VLAN over '%s' may require lowered MTU; must use -f (see " 2321 "dladm(1M))", link); 2322 break; 2323 2324 case DLADM_STATUS_LINKBUSY: 2325 die("VLAN over '%s' may not use default_tag ID " 2326 "(see dladm(1M))", link); 2327 break; 2328 2329 default: 2330 die_dlerr(status, "create operation failed"); 2331 } 2332 } 2333 2334 static void 2335 do_delete_vlan(int argc, char *argv[], const char *use) 2336 { 2337 int option; 2338 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2339 char *altroot = NULL; 2340 datalink_id_t linkid; 2341 dladm_status_t status; 2342 2343 opterr = 0; 2344 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 2345 switch (option) { 2346 case 't': 2347 flags &= ~DLADM_OPT_PERSIST; 2348 break; 2349 case 'R': 2350 altroot = optarg; 2351 break; 2352 default: 2353 die_opterr(optopt, option, use); 2354 break; 2355 } 2356 } 2357 2358 /* get VLAN link name (required last argument) */ 2359 if (optind != (argc - 1)) 2360 usage(); 2361 2362 if (altroot != NULL) 2363 altroot_cmd(altroot, argc, argv); 2364 2365 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 2366 NULL); 2367 if (status != DLADM_STATUS_OK) 2368 goto done; 2369 2370 status = dladm_vlan_delete(handle, linkid, flags); 2371 done: 2372 if (status != DLADM_STATUS_OK) 2373 die_dlerr(status, "delete operation failed"); 2374 } 2375 2376 /*ARGSUSED*/ 2377 static void 2378 do_up_vlan(int argc, char *argv[], const char *use) 2379 { 2380 do_up_vnic_common(argc, argv, use, B_TRUE); 2381 } 2382 2383 static void 2384 do_rename_link(int argc, char *argv[], const char *use) 2385 { 2386 int option; 2387 char *link1, *link2; 2388 char *altroot = NULL; 2389 dladm_status_t status; 2390 2391 opterr = 0; 2392 while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) { 2393 switch (option) { 2394 case 'R': 2395 altroot = optarg; 2396 break; 2397 default: 2398 die_opterr(optopt, option, use); 2399 break; 2400 } 2401 } 2402 2403 /* get link1 and link2 name (required the last 2 arguments) */ 2404 if (optind != (argc - 2)) 2405 usage(); 2406 2407 if (altroot != NULL) 2408 altroot_cmd(altroot, argc, argv); 2409 2410 link1 = argv[optind++]; 2411 link2 = argv[optind]; 2412 if ((status = dladm_rename_link(handle, link1, link2)) != 2413 DLADM_STATUS_OK) 2414 die_dlerr(status, "rename operation failed"); 2415 } 2416 2417 /*ARGSUSED*/ 2418 static void 2419 do_delete_phys(int argc, char *argv[], const char *use) 2420 { 2421 datalink_id_t linkid = DATALINK_ALL_LINKID; 2422 dladm_status_t status; 2423 2424 /* get link name (required the last argument) */ 2425 if (argc > 2) 2426 usage(); 2427 2428 if (argc == 2) { 2429 if ((status = dladm_name2info(handle, argv[1], &linkid, NULL, 2430 NULL, NULL)) != DLADM_STATUS_OK) 2431 die_dlerr(status, "cannot delete '%s'", argv[1]); 2432 } 2433 2434 if ((status = dladm_phys_delete(handle, linkid)) != DLADM_STATUS_OK) { 2435 if (argc == 2) 2436 die_dlerr(status, "cannot delete '%s'", argv[1]); 2437 else 2438 die_dlerr(status, "delete operation failed"); 2439 } 2440 } 2441 2442 /*ARGSUSED*/ 2443 static int 2444 i_dladm_walk_linkmap(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2445 { 2446 char name[MAXLINKNAMELEN]; 2447 char mediabuf[DLADM_STRSIZE]; 2448 char classbuf[DLADM_STRSIZE]; 2449 datalink_class_t class; 2450 uint32_t media; 2451 uint32_t flags; 2452 2453 if (dladm_datalink_id2info(dh, linkid, &flags, &class, &media, name, 2454 MAXLINKNAMELEN) == DLADM_STATUS_OK) { 2455 (void) dladm_class2str(class, classbuf); 2456 (void) dladm_media2str(media, mediabuf); 2457 (void) printf("%-12s%8d %-12s%-20s %6d\n", name, 2458 linkid, classbuf, mediabuf, flags); 2459 } 2460 return (DLADM_WALK_CONTINUE); 2461 } 2462 2463 /*ARGSUSED*/ 2464 static void 2465 do_show_linkmap(int argc, char *argv[], const char *use) 2466 { 2467 if (argc != 1) 2468 die("invalid arguments"); 2469 2470 (void) printf("%-12s%8s %-12s%-20s %6s\n", "NAME", "LINKID", 2471 "CLASS", "MEDIA", "FLAGS"); 2472 2473 (void) dladm_walk_datalink_id(i_dladm_walk_linkmap, handle, NULL, 2474 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 2475 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2476 } 2477 2478 /* 2479 * Delete inactive physical links. 2480 */ 2481 /*ARGSUSED*/ 2482 static int 2483 purge_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2484 { 2485 datalink_class_t class; 2486 uint32_t flags; 2487 2488 if (dladm_datalink_id2info(dh, linkid, &flags, &class, NULL, NULL, 0) 2489 != DLADM_STATUS_OK) { 2490 return (DLADM_WALK_CONTINUE); 2491 } 2492 2493 if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE)) 2494 (void) dladm_phys_delete(dh, linkid); 2495 2496 return (DLADM_WALK_CONTINUE); 2497 } 2498 2499 /*ARGSUSED*/ 2500 static void 2501 do_init_phys(int argc, char *argv[], const char *use) 2502 { 2503 di_node_t devtree; 2504 2505 if (argc > 1) 2506 usage(); 2507 2508 /* 2509 * Force all the devices to attach, therefore all the network physical 2510 * devices can be known to the dlmgmtd daemon. 2511 */ 2512 if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL) 2513 di_fini(devtree); 2514 2515 (void) dladm_walk_datalink_id(purge_phys, handle, NULL, 2516 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 2517 } 2518 2519 /* 2520 * Print the active topology information. 2521 */ 2522 void 2523 print_link_topology(show_state_t *state, datalink_id_t linkid, 2524 datalink_class_t class, link_fields_buf_t *lbuf) 2525 { 2526 uint32_t flags = state->ls_flags; 2527 dladm_status_t status; 2528 char tmpbuf[MAXLINKNAMELEN]; 2529 2530 lbuf->link_over[0] = '\0'; 2531 lbuf->link_bridge[0] = '\0'; 2532 2533 switch (class) { 2534 case DATALINK_CLASS_AGGR: 2535 case DATALINK_CLASS_PHYS: 2536 case DATALINK_CLASS_ETHERSTUB: 2537 status = dladm_bridge_getlink(handle, linkid, lbuf->link_bridge, 2538 sizeof (lbuf->link_bridge)); 2539 if (status != DLADM_STATUS_OK && 2540 status != DLADM_STATUS_NOTFOUND) 2541 (void) strcpy(lbuf->link_bridge, "?"); 2542 break; 2543 } 2544 2545 switch (class) { 2546 case DATALINK_CLASS_VLAN: { 2547 dladm_vlan_attr_t vinfo; 2548 2549 if (dladm_vlan_info(handle, linkid, &vinfo, flags) != 2550 DLADM_STATUS_OK) { 2551 (void) strcpy(lbuf->link_over, "?"); 2552 break; 2553 } 2554 if (dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, NULL, 2555 NULL, lbuf->link_over, sizeof (lbuf->link_over)) != 2556 DLADM_STATUS_OK) 2557 (void) strcpy(lbuf->link_over, "?"); 2558 break; 2559 } 2560 case DATALINK_CLASS_AGGR: { 2561 dladm_aggr_grp_attr_t ginfo; 2562 int i; 2563 2564 if (dladm_aggr_info(handle, linkid, &ginfo, flags) != 2565 DLADM_STATUS_OK || ginfo.lg_nports == 0) { 2566 (void) strcpy(lbuf->link_over, "?"); 2567 break; 2568 } 2569 for (i = 0; i < ginfo.lg_nports; i++) { 2570 if (dladm_datalink_id2info(handle, 2571 ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, 2572 tmpbuf, sizeof (tmpbuf)) != DLADM_STATUS_OK) { 2573 (void) strcpy(lbuf->link_over, "?"); 2574 break; 2575 } 2576 (void) strlcat(lbuf->link_over, tmpbuf, 2577 sizeof (lbuf->link_over)); 2578 if (i != (ginfo.lg_nports - 1)) { 2579 (void) strlcat(lbuf->link_over, " ", 2580 sizeof (lbuf->link_over)); 2581 } 2582 } 2583 free(ginfo.lg_ports); 2584 break; 2585 } 2586 case DATALINK_CLASS_VNIC: { 2587 dladm_vnic_attr_t vinfo; 2588 2589 if (dladm_vnic_info(handle, linkid, &vinfo, flags) != 2590 DLADM_STATUS_OK) { 2591 (void) strcpy(lbuf->link_over, "?"); 2592 break; 2593 } 2594 if (dladm_datalink_id2info(handle, vinfo.va_link_id, NULL, NULL, 2595 NULL, lbuf->link_over, sizeof (lbuf->link_over)) != 2596 DLADM_STATUS_OK) 2597 (void) strcpy(lbuf->link_over, "?"); 2598 break; 2599 } 2600 case DATALINK_CLASS_BRIDGE: { 2601 datalink_id_t *dlp; 2602 uint_t i, nports; 2603 2604 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, 2605 NULL, tmpbuf, sizeof (tmpbuf)) != DLADM_STATUS_OK) { 2606 (void) strcpy(lbuf->link_over, "?"); 2607 break; 2608 } 2609 if (tmpbuf[0] != '\0') 2610 tmpbuf[strlen(tmpbuf) - 1] = '\0'; 2611 dlp = dladm_bridge_get_portlist(tmpbuf, &nports); 2612 if (dlp == NULL) { 2613 (void) strcpy(lbuf->link_over, "?"); 2614 break; 2615 } 2616 for (i = 0; i < nports; i++) { 2617 if (dladm_datalink_id2info(handle, dlp[i], NULL, 2618 NULL, NULL, tmpbuf, sizeof (tmpbuf)) != 2619 DLADM_STATUS_OK) { 2620 (void) strcpy(lbuf->link_over, "?"); 2621 break; 2622 } 2623 (void) strlcat(lbuf->link_over, tmpbuf, 2624 sizeof (lbuf->link_over)); 2625 if (i != nports - 1) { 2626 (void) strlcat(lbuf->link_over, " ", 2627 sizeof (lbuf->link_over)); 2628 } 2629 } 2630 dladm_bridge_free_portlist(dlp); 2631 break; 2632 } 2633 2634 case DATALINK_CLASS_SIMNET: { 2635 dladm_simnet_attr_t slinfo; 2636 2637 if (dladm_simnet_info(handle, linkid, &slinfo, flags) != 2638 DLADM_STATUS_OK) { 2639 (void) strcpy(lbuf->link_over, "?"); 2640 break; 2641 } 2642 if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID) { 2643 if (dladm_datalink_id2info(handle, 2644 slinfo.sna_peer_link_id, NULL, NULL, NULL, 2645 lbuf->link_over, sizeof (lbuf->link_over)) != 2646 DLADM_STATUS_OK) 2647 (void) strcpy(lbuf->link_over, "?"); 2648 } 2649 break; 2650 } 2651 } 2652 } 2653 2654 static dladm_status_t 2655 print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf) 2656 { 2657 char link[MAXLINKNAMELEN]; 2658 datalink_class_t class; 2659 uint_t mtu; 2660 uint32_t flags; 2661 dladm_status_t status; 2662 2663 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 2664 NULL, link, sizeof (link))) != DLADM_STATUS_OK) { 2665 goto done; 2666 } 2667 2668 if (!(state->ls_flags & flags)) { 2669 status = DLADM_STATUS_NOTFOUND; 2670 goto done; 2671 } 2672 2673 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2674 dladm_attr_t dlattr; 2675 2676 if (class == DATALINK_CLASS_PHYS) { 2677 dladm_phys_attr_t dpa; 2678 dlpi_handle_t dh; 2679 dlpi_info_t dlinfo; 2680 2681 if ((status = dladm_phys_info(handle, linkid, &dpa, 2682 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2683 goto done; 2684 } 2685 2686 if (!dpa.dp_novanity) 2687 goto link_mtu; 2688 2689 /* 2690 * This is a physical link that does not have 2691 * vanity naming support. 2692 */ 2693 if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) != 2694 DLPI_SUCCESS) { 2695 status = DLADM_STATUS_NOTFOUND; 2696 goto done; 2697 } 2698 2699 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 2700 dlpi_close(dh); 2701 status = DLADM_STATUS_BADARG; 2702 goto done; 2703 } 2704 2705 dlpi_close(dh); 2706 mtu = dlinfo.di_max_sdu; 2707 } else { 2708 link_mtu: 2709 status = dladm_info(handle, linkid, &dlattr); 2710 if (status != DLADM_STATUS_OK) 2711 goto done; 2712 mtu = dlattr.da_max_sdu; 2713 } 2714 } 2715 2716 (void) snprintf(lbuf->link_name, sizeof (lbuf->link_name), 2717 "%s", link); 2718 (void) dladm_class2str(class, lbuf->link_class); 2719 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2720 (void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu), 2721 "%u", mtu); 2722 (void) get_linkstate(link, B_TRUE, lbuf->link_state); 2723 } 2724 2725 print_link_topology(state, linkid, class, lbuf); 2726 done: 2727 return (status); 2728 } 2729 2730 /* ARGSUSED */ 2731 static int 2732 show_link(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2733 { 2734 show_state_t *state = (show_state_t *)arg; 2735 dladm_status_t status; 2736 link_fields_buf_t lbuf; 2737 2738 /* 2739 * first get all the link attributes into lbuf; 2740 */ 2741 bzero(&lbuf, sizeof (link_fields_buf_t)); 2742 if ((status = print_link(state, linkid, &lbuf)) == DLADM_STATUS_OK) 2743 ofmt_print(state->ls_ofmt, &lbuf); 2744 state->ls_status = status; 2745 return (DLADM_WALK_CONTINUE); 2746 } 2747 2748 static boolean_t 2749 print_link_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2750 { 2751 link_args_t *largs = ofarg->ofmt_cbarg; 2752 pktsum_t *diff_stats = largs->link_s_psum; 2753 2754 switch (ofarg->ofmt_id) { 2755 case LINK_S_LINK: 2756 (void) snprintf(buf, bufsize, "%s", largs->link_s_link); 2757 break; 2758 case LINK_S_IPKTS: 2759 (void) snprintf(buf, bufsize, "%llu", diff_stats->ipackets); 2760 break; 2761 case LINK_S_RBYTES: 2762 (void) snprintf(buf, bufsize, "%llu", diff_stats->rbytes); 2763 break; 2764 case LINK_S_IERRORS: 2765 (void) snprintf(buf, bufsize, "%u", diff_stats->ierrors); 2766 break; 2767 case LINK_S_OPKTS: 2768 (void) snprintf(buf, bufsize, "%llu", diff_stats->opackets); 2769 break; 2770 case LINK_S_OBYTES: 2771 (void) snprintf(buf, bufsize, "%llu", diff_stats->obytes); 2772 break; 2773 case LINK_S_OERRORS: 2774 (void) snprintf(buf, bufsize, "%u", diff_stats->oerrors); 2775 break; 2776 default: 2777 die("invalid input"); 2778 break; 2779 } 2780 return (B_TRUE); 2781 } 2782 2783 static int 2784 show_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2785 { 2786 char link[DLPI_LINKNAME_MAX]; 2787 datalink_class_t class; 2788 show_state_t *state = arg; 2789 pktsum_t stats, diff_stats; 2790 dladm_phys_attr_t dpa; 2791 link_args_t largs; 2792 2793 if (state->ls_firstonly) { 2794 if (state->ls_donefirst) 2795 return (DLADM_WALK_CONTINUE); 2796 state->ls_donefirst = B_TRUE; 2797 } else { 2798 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 2799 } 2800 2801 if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, link, 2802 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2803 return (DLADM_WALK_CONTINUE); 2804 } 2805 2806 if (class == DATALINK_CLASS_PHYS) { 2807 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) != 2808 DLADM_STATUS_OK) { 2809 return (DLADM_WALK_CONTINUE); 2810 } 2811 if (dpa.dp_novanity) 2812 get_mac_stats(dpa.dp_dev, &stats); 2813 else 2814 get_link_stats(link, &stats); 2815 } else { 2816 get_link_stats(link, &stats); 2817 } 2818 dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats); 2819 2820 largs.link_s_link = link; 2821 largs.link_s_psum = &diff_stats; 2822 ofmt_print(state->ls_ofmt, &largs); 2823 2824 state->ls_prevstats = stats; 2825 return (DLADM_WALK_CONTINUE); 2826 } 2827 2828 2829 static dladm_status_t 2830 print_aggr_info(show_grp_state_t *state, const char *link, 2831 dladm_aggr_grp_attr_t *ginfop) 2832 { 2833 char addr_str[ETHERADDRL * 3]; 2834 laggr_fields_buf_t lbuf; 2835 2836 (void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name), 2837 "%s", link); 2838 2839 (void) dladm_aggr_policy2str(ginfop->lg_policy, 2840 lbuf.laggr_policy); 2841 2842 if (ginfop->lg_mac_fixed) { 2843 (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); 2844 (void) snprintf(lbuf.laggr_addrpolicy, 2845 sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str); 2846 } else { 2847 (void) snprintf(lbuf.laggr_addrpolicy, 2848 sizeof (lbuf.laggr_addrpolicy), "auto"); 2849 } 2850 2851 (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, 2852 lbuf.laggr_lacpactivity); 2853 (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, 2854 lbuf.laggr_lacptimer); 2855 (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----", 2856 ginfop->lg_force ? 'f' : '-'); 2857 2858 ofmt_print(state->gs_ofmt, &lbuf); 2859 2860 return (DLADM_STATUS_OK); 2861 } 2862 2863 static boolean_t 2864 print_xaggr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2865 { 2866 const laggr_args_t *l = ofarg->ofmt_cbarg; 2867 boolean_t is_port = (l->laggr_lport >= 0); 2868 char tmpbuf[DLADM_STRSIZE]; 2869 const char *objname; 2870 dladm_aggr_port_attr_t *portp; 2871 dladm_phys_attr_t dpa; 2872 2873 if (is_port) { 2874 portp = &(l->laggr_ginfop->lg_ports[l->laggr_lport]); 2875 if (dladm_phys_info(handle, portp->lp_linkid, &dpa, 2876 DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) 2877 objname = "?"; 2878 else 2879 objname = dpa.dp_dev; 2880 } else { 2881 objname = l->laggr_link; 2882 } 2883 2884 switch (ofarg->ofmt_id) { 2885 case AGGR_X_LINK: 2886 (void) snprintf(buf, bufsize, "%s", 2887 (is_port && !l->laggr_parsable ? " " : l->laggr_link)); 2888 break; 2889 case AGGR_X_PORT: 2890 if (is_port) { 2891 if (dladm_datalink_id2info(handle, portp->lp_linkid, 2892 NULL, NULL, NULL, buf, bufsize) != DLADM_STATUS_OK) 2893 (void) sprintf(buf, "?"); 2894 } 2895 break; 2896 2897 case AGGR_X_SPEED: 2898 (void) snprintf(buf, bufsize, "%uMb", 2899 (uint_t)((get_ifspeed(objname, !is_port)) / 1000000ull)); 2900 break; 2901 2902 case AGGR_X_DUPLEX: 2903 (void) get_linkduplex(objname, !is_port, tmpbuf); 2904 (void) strlcpy(buf, tmpbuf, bufsize); 2905 break; 2906 2907 case AGGR_X_STATE: 2908 (void) get_linkstate(objname, !is_port, tmpbuf); 2909 (void) strlcpy(buf, tmpbuf, bufsize); 2910 break; 2911 case AGGR_X_ADDRESS: 2912 (void) dladm_aggr_macaddr2str( 2913 (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac), 2914 tmpbuf); 2915 (void) strlcpy(buf, tmpbuf, bufsize); 2916 break; 2917 case AGGR_X_PORTSTATE: 2918 if (is_port) { 2919 (void) dladm_aggr_portstate2str(portp->lp_state, 2920 tmpbuf); 2921 (void) strlcpy(buf, tmpbuf, bufsize); 2922 } 2923 break; 2924 } 2925 err: 2926 *(l->laggr_status) = DLADM_STATUS_OK; 2927 return (B_TRUE); 2928 } 2929 2930 static dladm_status_t 2931 print_aggr_extended(show_grp_state_t *state, const char *link, 2932 dladm_aggr_grp_attr_t *ginfop) 2933 { 2934 int i; 2935 dladm_status_t status; 2936 laggr_args_t largs; 2937 2938 largs.laggr_lport = -1; 2939 largs.laggr_link = link; 2940 largs.laggr_ginfop = ginfop; 2941 largs.laggr_status = &status; 2942 largs.laggr_parsable = state->gs_parsable; 2943 2944 ofmt_print(state->gs_ofmt, &largs); 2945 2946 if (status != DLADM_STATUS_OK) 2947 goto done; 2948 2949 for (i = 0; i < ginfop->lg_nports; i++) { 2950 largs.laggr_lport = i; 2951 ofmt_print(state->gs_ofmt, &largs); 2952 if (status != DLADM_STATUS_OK) 2953 goto done; 2954 } 2955 2956 status = DLADM_STATUS_OK; 2957 done: 2958 return (status); 2959 } 2960 2961 static boolean_t 2962 print_lacp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2963 { 2964 const laggr_args_t *l = ofarg->ofmt_cbarg; 2965 int portnum; 2966 boolean_t is_port = (l->laggr_lport >= 0); 2967 dladm_aggr_port_attr_t *portp; 2968 aggr_lacp_state_t *lstate; 2969 2970 if (!is_port) 2971 return (B_FALSE); /* cannot happen! */ 2972 2973 portnum = l->laggr_lport; 2974 portp = &(l->laggr_ginfop->lg_ports[portnum]); 2975 lstate = &(portp->lp_lacp_state); 2976 2977 switch (ofarg->ofmt_id) { 2978 case AGGR_L_LINK: 2979 (void) snprintf(buf, bufsize, "%s", 2980 (portnum > 0 ? "" : l->laggr_link)); 2981 break; 2982 2983 case AGGR_L_PORT: 2984 if (dladm_datalink_id2info(handle, portp->lp_linkid, NULL, NULL, 2985 NULL, buf, bufsize) != DLADM_STATUS_OK) 2986 (void) sprintf(buf, "?"); 2987 break; 2988 2989 case AGGR_L_AGGREGATABLE: 2990 (void) snprintf(buf, bufsize, "%s", 2991 (lstate->bit.aggregation ? "yes" : "no")); 2992 break; 2993 2994 case AGGR_L_SYNC: 2995 (void) snprintf(buf, bufsize, "%s", 2996 (lstate->bit.sync ? "yes" : "no")); 2997 break; 2998 2999 case AGGR_L_COLL: 3000 (void) snprintf(buf, bufsize, "%s", 3001 (lstate->bit.collecting ? "yes" : "no")); 3002 break; 3003 3004 case AGGR_L_DIST: 3005 (void) snprintf(buf, bufsize, "%s", 3006 (lstate->bit.distributing ? "yes" : "no")); 3007 break; 3008 3009 case AGGR_L_DEFAULTED: 3010 (void) snprintf(buf, bufsize, "%s", 3011 (lstate->bit.defaulted ? "yes" : "no")); 3012 break; 3013 3014 case AGGR_L_EXPIRED: 3015 (void) snprintf(buf, bufsize, "%s", 3016 (lstate->bit.expired ? "yes" : "no")); 3017 break; 3018 } 3019 3020 *(l->laggr_status) = DLADM_STATUS_OK; 3021 return (B_TRUE); 3022 } 3023 3024 static dladm_status_t 3025 print_aggr_lacp(show_grp_state_t *state, const char *link, 3026 dladm_aggr_grp_attr_t *ginfop) 3027 { 3028 int i; 3029 dladm_status_t status; 3030 laggr_args_t largs; 3031 3032 largs.laggr_link = link; 3033 largs.laggr_ginfop = ginfop; 3034 largs.laggr_status = &status; 3035 3036 for (i = 0; i < ginfop->lg_nports; i++) { 3037 largs.laggr_lport = i; 3038 ofmt_print(state->gs_ofmt, &largs); 3039 if (status != DLADM_STATUS_OK) 3040 goto done; 3041 } 3042 3043 status = DLADM_STATUS_OK; 3044 done: 3045 return (status); 3046 } 3047 3048 static boolean_t 3049 print_aggr_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3050 { 3051 const laggr_args_t *l = ofarg->ofmt_cbarg; 3052 int portnum; 3053 boolean_t is_port = (l->laggr_lport >= 0); 3054 dladm_aggr_port_attr_t *portp; 3055 dladm_status_t *stat, status; 3056 pktsum_t *diff_stats; 3057 3058 stat = l->laggr_status; 3059 *stat = DLADM_STATUS_OK; 3060 3061 if (is_port) { 3062 portnum = l->laggr_lport; 3063 portp = &(l->laggr_ginfop->lg_ports[portnum]); 3064 3065 if ((status = dladm_datalink_id2info(handle, 3066 portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) != 3067 DLADM_STATUS_OK) { 3068 goto err; 3069 } 3070 diff_stats = l->laggr_diffstats; 3071 } 3072 3073 switch (ofarg->ofmt_id) { 3074 case AGGR_S_LINK: 3075 (void) snprintf(buf, bufsize, "%s", 3076 (is_port ? "" : l->laggr_link)); 3077 break; 3078 case AGGR_S_PORT: 3079 /* 3080 * if (is_port), buf has port name. Otherwise we print 3081 * STR_UNDEF_VAL 3082 */ 3083 break; 3084 3085 case AGGR_S_IPKTS: 3086 if (is_port) { 3087 (void) snprintf(buf, bufsize, "%llu", 3088 diff_stats->ipackets); 3089 } else { 3090 (void) snprintf(buf, bufsize, "%llu", 3091 l->laggr_pktsumtot->ipackets); 3092 } 3093 break; 3094 3095 case AGGR_S_RBYTES: 3096 if (is_port) { 3097 (void) snprintf(buf, bufsize, "%llu", 3098 diff_stats->rbytes); 3099 } else { 3100 (void) snprintf(buf, bufsize, "%llu", 3101 l->laggr_pktsumtot->rbytes); 3102 } 3103 break; 3104 3105 case AGGR_S_OPKTS: 3106 if (is_port) { 3107 (void) snprintf(buf, bufsize, "%llu", 3108 diff_stats->opackets); 3109 } else { 3110 (void) snprintf(buf, bufsize, "%llu", 3111 l->laggr_pktsumtot->opackets); 3112 } 3113 break; 3114 case AGGR_S_OBYTES: 3115 if (is_port) { 3116 (void) snprintf(buf, bufsize, "%llu", 3117 diff_stats->obytes); 3118 } else { 3119 (void) snprintf(buf, bufsize, "%llu", 3120 l->laggr_pktsumtot->obytes); 3121 } 3122 break; 3123 3124 case AGGR_S_IPKTDIST: 3125 if (is_port) { 3126 (void) snprintf(buf, bufsize, "%-6.1f", 3127 (double)diff_stats->ipackets/ 3128 (double)l->laggr_pktsumtot->ipackets * 100); 3129 } 3130 break; 3131 case AGGR_S_OPKTDIST: 3132 if (is_port) { 3133 (void) snprintf(buf, bufsize, "%-6.1f", 3134 (double)diff_stats->opackets/ 3135 (double)l->laggr_pktsumtot->opackets * 100); 3136 } 3137 break; 3138 } 3139 return (B_TRUE); 3140 3141 err: 3142 *stat = status; 3143 return (B_TRUE); 3144 } 3145 3146 static dladm_status_t 3147 print_aggr_stats(show_grp_state_t *state, const char *link, 3148 dladm_aggr_grp_attr_t *ginfop) 3149 { 3150 dladm_phys_attr_t dpa; 3151 dladm_aggr_port_attr_t *portp; 3152 pktsum_t pktsumtot, *port_stat; 3153 dladm_status_t status; 3154 int i; 3155 laggr_args_t largs; 3156 3157 /* sum the ports statistics */ 3158 bzero(&pktsumtot, sizeof (pktsumtot)); 3159 3160 /* Allocate memory to keep stats of each port */ 3161 port_stat = malloc(ginfop->lg_nports * sizeof (pktsum_t)); 3162 if (port_stat == NULL) { 3163 /* Bail out; no memory */ 3164 return (DLADM_STATUS_NOMEM); 3165 } 3166 3167 3168 for (i = 0; i < ginfop->lg_nports; i++) { 3169 3170 portp = &(ginfop->lg_ports[i]); 3171 if ((status = dladm_phys_info(handle, portp->lp_linkid, &dpa, 3172 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 3173 goto done; 3174 } 3175 3176 get_mac_stats(dpa.dp_dev, &port_stat[i]); 3177 3178 /* 3179 * Let's re-use gs_prevstats[] to store the difference of the 3180 * counters since last use. We will store the new stats from 3181 * port_stat[] once we have the stats displayed. 3182 */ 3183 3184 dladm_stats_diff(&state->gs_prevstats[i], &port_stat[i], 3185 &state->gs_prevstats[i]); 3186 dladm_stats_total(&pktsumtot, &pktsumtot, 3187 &state->gs_prevstats[i]); 3188 } 3189 3190 largs.laggr_lport = -1; 3191 largs.laggr_link = link; 3192 largs.laggr_ginfop = ginfop; 3193 largs.laggr_status = &status; 3194 largs.laggr_pktsumtot = &pktsumtot; 3195 3196 ofmt_print(state->gs_ofmt, &largs); 3197 3198 if (status != DLADM_STATUS_OK) 3199 goto done; 3200 3201 for (i = 0; i < ginfop->lg_nports; i++) { 3202 largs.laggr_lport = i; 3203 largs.laggr_diffstats = &state->gs_prevstats[i]; 3204 ofmt_print(state->gs_ofmt, &largs); 3205 if (status != DLADM_STATUS_OK) 3206 goto done; 3207 } 3208 3209 status = DLADM_STATUS_OK; 3210 for (i = 0; i < ginfop->lg_nports; i++) 3211 state->gs_prevstats[i] = port_stat[i]; 3212 3213 done: 3214 free(port_stat); 3215 return (status); 3216 } 3217 3218 static dladm_status_t 3219 print_aggr(show_grp_state_t *state, datalink_id_t linkid) 3220 { 3221 char link[MAXLINKNAMELEN]; 3222 dladm_aggr_grp_attr_t ginfo; 3223 uint32_t flags; 3224 dladm_status_t status; 3225 3226 bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t)); 3227 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 3228 NULL, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 3229 return (status); 3230 } 3231 3232 if (!(state->gs_flags & flags)) 3233 return (DLADM_STATUS_NOTFOUND); 3234 3235 status = dladm_aggr_info(handle, linkid, &ginfo, state->gs_flags); 3236 if (status != DLADM_STATUS_OK) 3237 return (status); 3238 3239 if (state->gs_lacp) 3240 status = print_aggr_lacp(state, link, &ginfo); 3241 else if (state->gs_extended) 3242 status = print_aggr_extended(state, link, &ginfo); 3243 else if (state->gs_stats) 3244 status = print_aggr_stats(state, link, &ginfo); 3245 else 3246 status = print_aggr_info(state, link, &ginfo); 3247 3248 done: 3249 free(ginfo.lg_ports); 3250 return (status); 3251 } 3252 3253 /* ARGSUSED */ 3254 static int 3255 show_aggr(dladm_handle_t dh, datalink_id_t linkid, void *arg) 3256 { 3257 show_grp_state_t *state = arg; 3258 3259 state->gs_status = print_aggr(state, linkid); 3260 return (DLADM_WALK_CONTINUE); 3261 } 3262 3263 static void 3264 do_show_link(int argc, char *argv[], const char *use) 3265 { 3266 int option; 3267 boolean_t s_arg = B_FALSE; 3268 boolean_t S_arg = B_FALSE; 3269 boolean_t i_arg = B_FALSE; 3270 uint32_t flags = DLADM_OPT_ACTIVE; 3271 boolean_t p_arg = B_FALSE; 3272 datalink_id_t linkid = DATALINK_ALL_LINKID; 3273 char linkname[MAXLINKNAMELEN]; 3274 uint32_t interval = 0; 3275 show_state_t state; 3276 dladm_status_t status; 3277 boolean_t o_arg = B_FALSE; 3278 char *fields_str = NULL; 3279 char *all_active_fields = "link,class,mtu,state,bridge,over"; 3280 char *all_inactive_fields = "link,class,bridge,over"; 3281 char *allstat_fields = 3282 "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; 3283 ofmt_handle_t ofmt; 3284 ofmt_status_t oferr; 3285 uint_t ofmtflags = 0; 3286 3287 bzero(&state, sizeof (state)); 3288 3289 opterr = 0; 3290 while ((option = getopt_long(argc, argv, ":pPsSi:o:", 3291 show_lopts, NULL)) != -1) { 3292 switch (option) { 3293 case 'p': 3294 if (p_arg) 3295 die_optdup(option); 3296 3297 p_arg = B_TRUE; 3298 break; 3299 case 's': 3300 if (s_arg) 3301 die_optdup(option); 3302 3303 s_arg = B_TRUE; 3304 break; 3305 case 'P': 3306 if (flags != DLADM_OPT_ACTIVE) 3307 die_optdup(option); 3308 3309 flags = DLADM_OPT_PERSIST; 3310 break; 3311 case 'S': 3312 if (S_arg) 3313 die_optdup(option); 3314 3315 S_arg = B_TRUE; 3316 break; 3317 case 'o': 3318 o_arg = B_TRUE; 3319 fields_str = optarg; 3320 break; 3321 case 'i': 3322 if (i_arg) 3323 die_optdup(option); 3324 3325 i_arg = B_TRUE; 3326 if (!dladm_str2interval(optarg, &interval)) 3327 die("invalid interval value '%s'", optarg); 3328 break; 3329 default: 3330 die_opterr(optopt, option, use); 3331 break; 3332 } 3333 } 3334 3335 if (i_arg && !(s_arg || S_arg)) 3336 die("the option -i can be used only with -s or -S"); 3337 3338 if (s_arg && S_arg) 3339 die("the -s option cannot be used with -S"); 3340 3341 if (s_arg && flags != DLADM_OPT_ACTIVE) 3342 die("the option -P cannot be used with -s"); 3343 3344 if (S_arg && (p_arg || flags != DLADM_OPT_ACTIVE)) 3345 die("the option -%c cannot be used with -S", p_arg ? 'p' : 'P'); 3346 3347 /* get link name (optional last argument) */ 3348 if (optind == (argc-1)) { 3349 uint32_t f; 3350 3351 if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN) >= 3352 MAXLINKNAMELEN) 3353 die("link name too long"); 3354 if ((status = dladm_name2info(handle, linkname, &linkid, &f, 3355 NULL, NULL)) != DLADM_STATUS_OK) { 3356 die_dlerr(status, "link %s is not valid", linkname); 3357 } 3358 3359 if (!(f & flags)) { 3360 die_dlerr(DLADM_STATUS_BADARG, "link %s is %s", 3361 argv[optind], flags == DLADM_OPT_PERSIST ? 3362 "a temporary link" : "temporarily removed"); 3363 } 3364 } else if (optind != argc) { 3365 usage(); 3366 } 3367 3368 if (p_arg && !o_arg) 3369 die("-p requires -o"); 3370 3371 if (S_arg) { 3372 dladm_continuous(handle, linkid, NULL, interval, LINK_REPORT); 3373 return; 3374 } 3375 3376 if (p_arg && strcasecmp(fields_str, "all") == 0) 3377 die("\"-o all\" is invalid with -p"); 3378 3379 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3380 if (s_arg) 3381 fields_str = allstat_fields; 3382 else if (flags & DLADM_OPT_ACTIVE) 3383 fields_str = all_active_fields; 3384 else 3385 fields_str = all_inactive_fields; 3386 } 3387 3388 state.ls_parsable = p_arg; 3389 state.ls_flags = flags; 3390 state.ls_donefirst = B_FALSE; 3391 3392 if (s_arg) { 3393 link_stats(linkid, interval, fields_str, &state); 3394 return; 3395 } 3396 if (state.ls_parsable) 3397 ofmtflags |= OFMT_PARSABLE; 3398 oferr = ofmt_open(fields_str, link_fields, ofmtflags, 0, &ofmt); 3399 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 3400 state.ls_ofmt = ofmt; 3401 3402 if (linkid == DATALINK_ALL_LINKID) { 3403 (void) dladm_walk_datalink_id(show_link, handle, &state, 3404 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 3405 } else { 3406 (void) show_link(handle, linkid, &state); 3407 if (state.ls_status != DLADM_STATUS_OK) { 3408 die_dlerr(state.ls_status, "failed to show link %s", 3409 argv[optind]); 3410 } 3411 } 3412 ofmt_close(ofmt); 3413 } 3414 3415 static void 3416 do_show_aggr(int argc, char *argv[], const char *use) 3417 { 3418 boolean_t L_arg = B_FALSE; 3419 boolean_t s_arg = B_FALSE; 3420 boolean_t i_arg = B_FALSE; 3421 boolean_t p_arg = B_FALSE; 3422 boolean_t x_arg = B_FALSE; 3423 show_grp_state_t state; 3424 uint32_t flags = DLADM_OPT_ACTIVE; 3425 datalink_id_t linkid = DATALINK_ALL_LINKID; 3426 int option; 3427 uint32_t interval = 0; 3428 int key; 3429 dladm_status_t status; 3430 boolean_t o_arg = B_FALSE; 3431 char *fields_str = NULL; 3432 char *all_fields = 3433 "link,policy,addrpolicy,lacpactivity,lacptimer,flags"; 3434 char *all_lacp_fields = 3435 "link,port,aggregatable,sync,coll,dist,defaulted,expired"; 3436 char *all_stats_fields = 3437 "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist"; 3438 char *all_extended_fields = 3439 "link,port,speed,duplex,state,address,portstate"; 3440 const ofmt_field_t *pf; 3441 ofmt_handle_t ofmt; 3442 ofmt_status_t oferr; 3443 uint_t ofmtflags = 0; 3444 3445 opterr = 0; 3446 while ((option = getopt_long(argc, argv, ":LpPxsi:o:", 3447 show_lopts, NULL)) != -1) { 3448 switch (option) { 3449 case 'L': 3450 if (L_arg) 3451 die_optdup(option); 3452 3453 L_arg = B_TRUE; 3454 break; 3455 case 'p': 3456 if (p_arg) 3457 die_optdup(option); 3458 3459 p_arg = B_TRUE; 3460 break; 3461 case 'x': 3462 if (x_arg) 3463 die_optdup(option); 3464 3465 x_arg = B_TRUE; 3466 break; 3467 case 'P': 3468 if (flags != DLADM_OPT_ACTIVE) 3469 die_optdup(option); 3470 3471 flags = DLADM_OPT_PERSIST; 3472 break; 3473 case 's': 3474 if (s_arg) 3475 die_optdup(option); 3476 3477 s_arg = B_TRUE; 3478 break; 3479 case 'o': 3480 o_arg = B_TRUE; 3481 fields_str = optarg; 3482 break; 3483 case 'i': 3484 if (i_arg) 3485 die_optdup(option); 3486 3487 i_arg = B_TRUE; 3488 if (!dladm_str2interval(optarg, &interval)) 3489 die("invalid interval value '%s'", optarg); 3490 break; 3491 default: 3492 die_opterr(optopt, option, use); 3493 break; 3494 } 3495 } 3496 3497 if (p_arg && !o_arg) 3498 die("-p requires -o"); 3499 3500 if (p_arg && strcasecmp(fields_str, "all") == 0) 3501 die("\"-o all\" is invalid with -p"); 3502 3503 if (i_arg && !s_arg) 3504 die("the option -i can be used only with -s"); 3505 3506 if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) { 3507 die("the option -%c cannot be used with -s", 3508 L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P'))); 3509 } 3510 3511 if (L_arg && flags != DLADM_OPT_ACTIVE) 3512 die("the option -P cannot be used with -L"); 3513 3514 if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE)) 3515 die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P'); 3516 3517 /* get aggregation key or aggrname (optional last argument) */ 3518 if (optind == (argc-1)) { 3519 if (!str2int(argv[optind], &key)) { 3520 status = dladm_name2info(handle, argv[optind], 3521 &linkid, NULL, NULL, NULL); 3522 } else { 3523 status = dladm_key2linkid(handle, (uint16_t)key, 3524 &linkid, DLADM_OPT_ACTIVE); 3525 } 3526 3527 if (status != DLADM_STATUS_OK) 3528 die("non-existent aggregation '%s'", argv[optind]); 3529 3530 } else if (optind != argc) { 3531 usage(); 3532 } 3533 3534 bzero(&state, sizeof (state)); 3535 state.gs_lacp = L_arg; 3536 state.gs_stats = s_arg; 3537 state.gs_flags = flags; 3538 state.gs_parsable = p_arg; 3539 state.gs_extended = x_arg; 3540 3541 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3542 if (state.gs_lacp) 3543 fields_str = all_lacp_fields; 3544 else if (state.gs_stats) 3545 fields_str = all_stats_fields; 3546 else if (state.gs_extended) 3547 fields_str = all_extended_fields; 3548 else 3549 fields_str = all_fields; 3550 } 3551 3552 if (state.gs_lacp) { 3553 pf = aggr_l_fields; 3554 } else if (state.gs_stats) { 3555 pf = aggr_s_fields; 3556 } else if (state.gs_extended) { 3557 pf = aggr_x_fields; 3558 } else { 3559 pf = laggr_fields; 3560 } 3561 3562 if (state.gs_parsable) 3563 ofmtflags |= OFMT_PARSABLE; 3564 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 3565 dladm_ofmt_check(oferr, state.gs_parsable, ofmt); 3566 state.gs_ofmt = ofmt; 3567 3568 if (s_arg) { 3569 aggr_stats(linkid, &state, interval); 3570 ofmt_close(ofmt); 3571 return; 3572 } 3573 3574 if (linkid == DATALINK_ALL_LINKID) { 3575 (void) dladm_walk_datalink_id(show_aggr, handle, &state, 3576 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); 3577 } else { 3578 (void) show_aggr(handle, linkid, &state); 3579 if (state.gs_status != DLADM_STATUS_OK) { 3580 die_dlerr(state.gs_status, "failed to show aggr %s", 3581 argv[optind]); 3582 } 3583 } 3584 ofmt_close(ofmt); 3585 } 3586 3587 static dladm_status_t 3588 print_phys_default(show_state_t *state, datalink_id_t linkid, 3589 const char *link, uint32_t flags, uint32_t media) 3590 { 3591 dladm_phys_attr_t dpa; 3592 dladm_status_t status; 3593 link_fields_buf_t pattr; 3594 3595 status = dladm_phys_info(handle, linkid, &dpa, state->ls_flags); 3596 if (status != DLADM_STATUS_OK) 3597 goto done; 3598 3599 (void) snprintf(pattr.link_phys_device, 3600 sizeof (pattr.link_phys_device), "%s", dpa.dp_dev); 3601 (void) dladm_media2str(media, pattr.link_phys_media); 3602 if (state->ls_flags == DLADM_OPT_ACTIVE) { 3603 boolean_t islink; 3604 3605 if (!dpa.dp_novanity) { 3606 (void) strlcpy(pattr.link_name, link, 3607 sizeof (pattr.link_name)); 3608 islink = B_TRUE; 3609 } else { 3610 /* 3611 * This is a physical link that does not have 3612 * vanity naming support. 3613 */ 3614 (void) strlcpy(pattr.link_name, dpa.dp_dev, 3615 sizeof (pattr.link_name)); 3616 islink = B_FALSE; 3617 } 3618 3619 (void) get_linkstate(pattr.link_name, islink, 3620 pattr.link_phys_state); 3621 (void) snprintf(pattr.link_phys_speed, 3622 sizeof (pattr.link_phys_speed), "%u", 3623 (uint_t)((get_ifspeed(pattr.link_name, 3624 islink)) / 1000000ull)); 3625 (void) get_linkduplex(pattr.link_name, islink, 3626 pattr.link_phys_duplex); 3627 } else { 3628 (void) snprintf(pattr.link_name, sizeof (pattr.link_name), 3629 "%s", link); 3630 (void) snprintf(pattr.link_flags, sizeof (pattr.link_flags), 3631 "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r'); 3632 } 3633 3634 ofmt_print(state->ls_ofmt, &pattr); 3635 3636 done: 3637 return (status); 3638 } 3639 3640 typedef struct { 3641 show_state_t *ms_state; 3642 char *ms_link; 3643 dladm_macaddr_attr_t *ms_mac_attr; 3644 } print_phys_mac_state_t; 3645 3646 /* 3647 * callback for ofmt_print() 3648 */ 3649 static boolean_t 3650 print_phys_one_mac_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3651 { 3652 print_phys_mac_state_t *mac_state = ofarg->ofmt_cbarg; 3653 dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr; 3654 boolean_t is_primary = (attr->ma_slot == 0); 3655 boolean_t is_parsable = mac_state->ms_state->ls_parsable; 3656 3657 switch (ofarg->ofmt_id) { 3658 case PHYS_M_LINK: 3659 (void) snprintf(buf, bufsize, "%s", 3660 (is_primary || is_parsable) ? mac_state->ms_link : " "); 3661 break; 3662 case PHYS_M_SLOT: 3663 if (is_primary) 3664 (void) snprintf(buf, bufsize, gettext("primary")); 3665 else 3666 (void) snprintf(buf, bufsize, "%d", attr->ma_slot); 3667 break; 3668 case PHYS_M_ADDRESS: 3669 (void) dladm_aggr_macaddr2str(attr->ma_addr, buf); 3670 break; 3671 case PHYS_M_INUSE: 3672 (void) snprintf(buf, bufsize, "%s", 3673 attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") : 3674 gettext("no")); 3675 break; 3676 case PHYS_M_CLIENT: 3677 /* 3678 * CR 6678526: resolve link id to actual link name if 3679 * it is valid. 3680 */ 3681 (void) snprintf(buf, bufsize, "%s", attr->ma_client_name); 3682 break; 3683 } 3684 3685 return (B_TRUE); 3686 } 3687 3688 typedef struct { 3689 show_state_t *hs_state; 3690 char *hs_link; 3691 dladm_hwgrp_attr_t *hs_grp_attr; 3692 } print_phys_hwgrp_state_t; 3693 3694 static boolean_t 3695 print_phys_one_hwgrp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3696 { 3697 print_phys_hwgrp_state_t *hg_state = ofarg->ofmt_cbarg; 3698 dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr; 3699 3700 switch (ofarg->ofmt_id) { 3701 case PHYS_H_LINK: 3702 (void) snprintf(buf, bufsize, "%s", attr->hg_link_name); 3703 break; 3704 case PHYS_H_GROUP: 3705 (void) snprintf(buf, bufsize, "%d", attr->hg_grp_num); 3706 break; 3707 case PHYS_H_GRPTYPE: 3708 (void) snprintf(buf, bufsize, "%s", 3709 attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX"); 3710 break; 3711 case PHYS_H_RINGS: 3712 (void) snprintf(buf, bufsize, "%d", attr->hg_n_rings); 3713 break; 3714 case PHYS_H_CLIENTS: 3715 if (attr->hg_client_names[0] == '\0') { 3716 (void) snprintf(buf, bufsize, "--"); 3717 } else { 3718 (void) snprintf(buf, bufsize, "%s ", 3719 attr->hg_client_names); 3720 } 3721 break; 3722 } 3723 3724 return (B_TRUE); 3725 } 3726 3727 /* 3728 * callback for dladm_walk_macaddr, invoked for each MAC address slot 3729 */ 3730 static boolean_t 3731 print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr) 3732 { 3733 print_phys_mac_state_t *mac_state = arg; 3734 show_state_t *state = mac_state->ms_state; 3735 3736 mac_state->ms_mac_attr = attr; 3737 ofmt_print(state->ls_ofmt, mac_state); 3738 3739 return (B_TRUE); 3740 } 3741 3742 /* 3743 * invoked by show-phys -m for each physical data-link 3744 */ 3745 static dladm_status_t 3746 print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link) 3747 { 3748 print_phys_mac_state_t mac_state; 3749 3750 mac_state.ms_state = state; 3751 mac_state.ms_link = link; 3752 3753 return (dladm_walk_macaddr(handle, linkid, &mac_state, 3754 print_phys_mac_callback)); 3755 } 3756 3757 /* 3758 * callback for dladm_walk_hwgrp, invoked for each MAC hwgrp 3759 */ 3760 static boolean_t 3761 print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr) 3762 { 3763 print_phys_hwgrp_state_t *hwgrp_state = arg; 3764 show_state_t *state = hwgrp_state->hs_state; 3765 3766 hwgrp_state->hs_grp_attr = attr; 3767 ofmt_print(state->ls_ofmt, hwgrp_state); 3768 3769 return (B_TRUE); 3770 } 3771 3772 /* invoked by show-phys -H for each physical data-link */ 3773 static dladm_status_t 3774 print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link) 3775 { 3776 print_phys_hwgrp_state_t hwgrp_state; 3777 3778 hwgrp_state.hs_state = state; 3779 hwgrp_state.hs_link = link; 3780 return (dladm_walk_hwgrp(handle, linkid, &hwgrp_state, 3781 print_phys_hwgrp_callback)); 3782 } 3783 3784 /* 3785 * Parse the "local=<laddr>,remote=<raddr>" sub-options for the -a option of 3786 * *-iptun subcommands. 3787 */ 3788 static void 3789 iptun_process_addrarg(char *addrarg, iptun_params_t *params) 3790 { 3791 char *addrval; 3792 3793 while (*addrarg != '\0') { 3794 switch (getsubopt(&addrarg, iptun_addropts, &addrval)) { 3795 case IPTUN_LOCAL: 3796 params->iptun_param_flags |= IPTUN_PARAM_LADDR; 3797 if (strlcpy(params->iptun_param_laddr, addrval, 3798 sizeof (params->iptun_param_laddr)) >= 3799 sizeof (params->iptun_param_laddr)) 3800 die("tunnel source address is too long"); 3801 break; 3802 case IPTUN_REMOTE: 3803 params->iptun_param_flags |= IPTUN_PARAM_RADDR; 3804 if (strlcpy(params->iptun_param_raddr, addrval, 3805 sizeof (params->iptun_param_raddr)) >= 3806 sizeof (params->iptun_param_raddr)) 3807 die("tunnel destination address is too long"); 3808 break; 3809 default: 3810 die("invalid address type: %s", addrval); 3811 break; 3812 } 3813 } 3814 } 3815 3816 /* 3817 * Convenience routine to process iptun-create/modify/delete subcommand 3818 * arguments. 3819 */ 3820 static void 3821 iptun_process_args(int argc, char *argv[], const char *opts, 3822 iptun_params_t *params, uint32_t *flags, char *name, const char *use) 3823 { 3824 int option; 3825 char *altroot = NULL; 3826 3827 if (params != NULL) 3828 bzero(params, sizeof (*params)); 3829 *flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 3830 3831 opterr = 0; 3832 while ((option = getopt_long(argc, argv, opts, iptun_lopts, NULL)) != 3833 -1) { 3834 switch (option) { 3835 case 'a': 3836 iptun_process_addrarg(optarg, params); 3837 break; 3838 case 'R': 3839 altroot = optarg; 3840 break; 3841 case 't': 3842 *flags &= ~DLADM_OPT_PERSIST; 3843 break; 3844 case 'T': 3845 params->iptun_param_type = iptun_gettypebyname(optarg); 3846 if (params->iptun_param_type == IPTUN_TYPE_UNKNOWN) 3847 die("unknown tunnel type: %s", optarg); 3848 params->iptun_param_flags |= IPTUN_PARAM_TYPE; 3849 break; 3850 default: 3851 die_opterr(optopt, option, use); 3852 break; 3853 } 3854 } 3855 3856 /* Get the required tunnel name argument. */ 3857 if (argc - optind != 1) 3858 usage(); 3859 3860 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 3861 die("tunnel name is too long"); 3862 3863 if (altroot != NULL) 3864 altroot_cmd(altroot, argc, argv); 3865 } 3866 3867 static void 3868 do_create_iptun(int argc, char *argv[], const char *use) 3869 { 3870 iptun_params_t params; 3871 dladm_status_t status; 3872 uint32_t flags; 3873 char name[MAXLINKNAMELEN]; 3874 3875 iptun_process_args(argc, argv, ":a:R:tT:", ¶ms, &flags, name, 3876 use); 3877 3878 status = dladm_iptun_create(handle, name, ¶ms, flags); 3879 if (status != DLADM_STATUS_OK) 3880 die_dlerr(status, "could not create tunnel"); 3881 } 3882 3883 static void 3884 do_delete_iptun(int argc, char *argv[], const char *use) 3885 { 3886 uint32_t flags; 3887 datalink_id_t linkid; 3888 dladm_status_t status; 3889 char name[MAXLINKNAMELEN]; 3890 3891 iptun_process_args(argc, argv, ":R:t", NULL, &flags, name, use); 3892 3893 status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL); 3894 if (status != DLADM_STATUS_OK) 3895 die_dlerr(status, "could not delete tunnel"); 3896 status = dladm_iptun_delete(handle, linkid, flags); 3897 if (status != DLADM_STATUS_OK) 3898 die_dlerr(status, "could not delete tunnel"); 3899 } 3900 3901 static void 3902 do_modify_iptun(int argc, char *argv[], const char *use) 3903 { 3904 iptun_params_t params; 3905 uint32_t flags; 3906 dladm_status_t status; 3907 char name[MAXLINKNAMELEN]; 3908 3909 iptun_process_args(argc, argv, ":a:R:t", ¶ms, &flags, name, use); 3910 3911 if ((status = dladm_name2info(handle, name, ¶ms.iptun_param_linkid, 3912 NULL, NULL, NULL)) != DLADM_STATUS_OK) 3913 die_dlerr(status, "could not modify tunnel"); 3914 status = dladm_iptun_modify(handle, ¶ms, flags); 3915 if (status != DLADM_STATUS_OK) 3916 die_dlerr(status, "could not modify tunnel"); 3917 } 3918 3919 static void 3920 do_show_iptun(int argc, char *argv[], const char *use) 3921 { 3922 char option; 3923 datalink_id_t linkid; 3924 uint32_t flags = DLADM_OPT_ACTIVE; 3925 char *name = NULL; 3926 dladm_status_t status; 3927 const char *fields_str = NULL; 3928 show_state_t state; 3929 ofmt_handle_t ofmt; 3930 ofmt_status_t oferr; 3931 uint_t ofmtflags = 0; 3932 3933 bzero(&state, sizeof (state)); 3934 opterr = 0; 3935 while ((option = getopt_long(argc, argv, ":pPo:", 3936 iptun_lopts, NULL)) != -1) { 3937 switch (option) { 3938 case 'o': 3939 fields_str = optarg; 3940 break; 3941 case 'p': 3942 state.ls_parsable = B_TRUE; 3943 ofmtflags = OFMT_PARSABLE; 3944 break; 3945 case 'P': 3946 flags = DLADM_OPT_PERSIST; 3947 break; 3948 default: 3949 die_opterr(optopt, option, use); 3950 break; 3951 } 3952 } 3953 3954 /* 3955 * Get the optional tunnel name argument. If there is one, it must 3956 * be the last thing remaining on the command-line. 3957 */ 3958 if (argc - optind > 1) 3959 die(gettext(use)); 3960 if (argc - optind == 1) 3961 name = argv[optind]; 3962 3963 oferr = ofmt_open(fields_str, iptun_fields, ofmtflags, 3964 DLADM_DEFAULT_COL, &ofmt); 3965 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 3966 3967 state.ls_ofmt = ofmt; 3968 state.ls_flags = flags; 3969 3970 if (name == NULL) { 3971 (void) dladm_walk_datalink_id(print_iptun_walker, handle, 3972 &state, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE, 3973 flags); 3974 status = state.ls_status; 3975 } else { 3976 if ((status = dladm_name2info(handle, name, &linkid, NULL, NULL, 3977 NULL)) == DLADM_STATUS_OK) 3978 status = print_iptun(handle, linkid, &state); 3979 } 3980 3981 if (status != DLADM_STATUS_OK) 3982 die_dlerr(status, "unable to obtain tunnel status"); 3983 } 3984 3985 /* ARGSUSED */ 3986 static void 3987 do_up_iptun(int argc, char *argv[], const char *use) 3988 { 3989 datalink_id_t linkid = DATALINK_ALL_LINKID; 3990 dladm_status_t status = DLADM_STATUS_OK; 3991 3992 /* 3993 * Get the optional tunnel name argument. If there is one, it must 3994 * be the last thing remaining on the command-line. 3995 */ 3996 if (argc - optind > 1) 3997 usage(); 3998 if (argc - optind == 1) { 3999 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 4000 NULL, NULL); 4001 } 4002 if (status == DLADM_STATUS_OK) 4003 status = dladm_iptun_up(handle, linkid); 4004 if (status != DLADM_STATUS_OK) 4005 die_dlerr(status, "unable to configure IP tunnel links"); 4006 } 4007 4008 /* ARGSUSED */ 4009 static void 4010 do_down_iptun(int argc, char *argv[], const char *use) 4011 { 4012 datalink_id_t linkid = DATALINK_ALL_LINKID; 4013 dladm_status_t status = DLADM_STATUS_OK; 4014 4015 /* 4016 * Get the optional tunnel name argument. If there is one, it must 4017 * be the last thing remaining on the command-line. 4018 */ 4019 if (argc - optind > 1) 4020 usage(); 4021 if (argc - optind == 1) { 4022 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 4023 NULL, NULL); 4024 } 4025 if (status == DLADM_STATUS_OK) 4026 status = dladm_iptun_down(handle, linkid); 4027 if (status != DLADM_STATUS_OK) 4028 die_dlerr(status, "unable to bring down IP tunnel links"); 4029 } 4030 4031 static iptun_type_t 4032 iptun_gettypebyname(char *typestr) 4033 { 4034 int i; 4035 4036 for (i = 0; iptun_types[i].type_name != NULL; i++) { 4037 if (strncmp(iptun_types[i].type_name, typestr, 4038 strlen(iptun_types[i].type_name)) == 0) { 4039 return (iptun_types[i].type_value); 4040 } 4041 } 4042 return (IPTUN_TYPE_UNKNOWN); 4043 } 4044 4045 static const char * 4046 iptun_gettypebyvalue(iptun_type_t type) 4047 { 4048 int i; 4049 4050 for (i = 0; iptun_types[i].type_name != NULL; i++) { 4051 if (iptun_types[i].type_value == type) 4052 return (iptun_types[i].type_name); 4053 } 4054 return (NULL); 4055 } 4056 4057 static dladm_status_t 4058 print_iptun(dladm_handle_t dh, datalink_id_t linkid, show_state_t *state) 4059 { 4060 dladm_status_t status; 4061 iptun_params_t params; 4062 iptun_fields_buf_t lbuf; 4063 const char *laddr; 4064 const char *raddr; 4065 4066 params.iptun_param_linkid = linkid; 4067 status = dladm_iptun_getparams(dh, ¶ms, state->ls_flags); 4068 if (status != DLADM_STATUS_OK) 4069 return (status); 4070 4071 /* LINK */ 4072 status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, 4073 lbuf.iptun_name, sizeof (lbuf.iptun_name)); 4074 if (status != DLADM_STATUS_OK) 4075 return (status); 4076 4077 /* TYPE */ 4078 (void) strlcpy(lbuf.iptun_type, 4079 iptun_gettypebyvalue(params.iptun_param_type), 4080 sizeof (lbuf.iptun_type)); 4081 4082 /* FLAGS */ 4083 (void) memset(lbuf.iptun_flags, '-', IPTUN_NUM_FLAGS); 4084 lbuf.iptun_flags[IPTUN_NUM_FLAGS] = '\0'; 4085 if (params.iptun_param_flags & IPTUN_PARAM_IPSECPOL) 4086 lbuf.iptun_flags[IPTUN_SFLAG_INDEX] = 's'; 4087 if (params.iptun_param_flags & IPTUN_PARAM_IMPLICIT) 4088 lbuf.iptun_flags[IPTUN_IFLAG_INDEX] = 'i'; 4089 4090 /* LOCAL */ 4091 if (params.iptun_param_flags & IPTUN_PARAM_LADDR) 4092 laddr = params.iptun_param_laddr; 4093 else 4094 laddr = (state->ls_parsable) ? "" : "--"; 4095 (void) strlcpy(lbuf.iptun_laddr, laddr, sizeof (lbuf.iptun_laddr)); 4096 4097 /* REMOTE */ 4098 if (params.iptun_param_flags & IPTUN_PARAM_RADDR) 4099 raddr = params.iptun_param_raddr; 4100 else 4101 raddr = (state->ls_parsable) ? "" : "--"; 4102 (void) strlcpy(lbuf.iptun_raddr, raddr, sizeof (lbuf.iptun_raddr)); 4103 4104 ofmt_print(state->ls_ofmt, &lbuf); 4105 4106 return (DLADM_STATUS_OK); 4107 } 4108 4109 static int 4110 print_iptun_walker(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4111 { 4112 ((show_state_t *)arg)->ls_status = print_iptun(dh, linkid, arg); 4113 return (DLADM_WALK_CONTINUE); 4114 } 4115 4116 static dladm_status_t 4117 print_phys(show_state_t *state, datalink_id_t linkid) 4118 { 4119 char link[MAXLINKNAMELEN]; 4120 uint32_t flags; 4121 dladm_status_t status; 4122 datalink_class_t class; 4123 uint32_t media; 4124 4125 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 4126 &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 4127 goto done; 4128 } 4129 4130 if (class != DATALINK_CLASS_PHYS) { 4131 status = DLADM_STATUS_BADARG; 4132 goto done; 4133 } 4134 4135 if (!(state->ls_flags & flags)) { 4136 status = DLADM_STATUS_NOTFOUND; 4137 goto done; 4138 } 4139 4140 if (state->ls_mac) 4141 status = print_phys_mac(state, linkid, link); 4142 else if (state->ls_hwgrp) 4143 status = print_phys_hwgrp(state, linkid, link); 4144 else 4145 status = print_phys_default(state, linkid, link, flags, media); 4146 4147 done: 4148 return (status); 4149 } 4150 4151 /* ARGSUSED */ 4152 static int 4153 show_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4154 { 4155 show_state_t *state = arg; 4156 4157 state->ls_status = print_phys(state, linkid); 4158 return (DLADM_WALK_CONTINUE); 4159 } 4160 4161 /* 4162 * Print the active topology information. 4163 */ 4164 static dladm_status_t 4165 print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l) 4166 { 4167 dladm_vlan_attr_t vinfo; 4168 uint32_t flags; 4169 dladm_status_t status; 4170 4171 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL, 4172 l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) { 4173 goto done; 4174 } 4175 4176 if (!(state->ls_flags & flags)) { 4177 status = DLADM_STATUS_NOTFOUND; 4178 goto done; 4179 } 4180 4181 if ((status = dladm_vlan_info(handle, linkid, &vinfo, 4182 state->ls_flags)) != DLADM_STATUS_OK || 4183 (status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, 4184 NULL, NULL, l->link_over, sizeof (l->link_over))) != 4185 DLADM_STATUS_OK) { 4186 goto done; 4187 } 4188 4189 (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d", 4190 vinfo.dv_vid); 4191 (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----", 4192 vinfo.dv_force ? 'f' : '-'); 4193 4194 done: 4195 return (status); 4196 } 4197 4198 /* ARGSUSED */ 4199 static int 4200 show_vlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4201 { 4202 show_state_t *state = arg; 4203 dladm_status_t status; 4204 link_fields_buf_t lbuf; 4205 4206 bzero(&lbuf, sizeof (link_fields_buf_t)); 4207 status = print_vlan(state, linkid, &lbuf); 4208 if (status != DLADM_STATUS_OK) 4209 goto done; 4210 4211 ofmt_print(state->ls_ofmt, &lbuf); 4212 4213 done: 4214 state->ls_status = status; 4215 return (DLADM_WALK_CONTINUE); 4216 } 4217 4218 static void 4219 do_show_phys(int argc, char *argv[], const char *use) 4220 { 4221 int option; 4222 uint32_t flags = DLADM_OPT_ACTIVE; 4223 boolean_t p_arg = B_FALSE; 4224 boolean_t o_arg = B_FALSE; 4225 boolean_t m_arg = B_FALSE; 4226 boolean_t H_arg = B_FALSE; 4227 datalink_id_t linkid = DATALINK_ALL_LINKID; 4228 show_state_t state; 4229 dladm_status_t status; 4230 char *fields_str = NULL; 4231 char *all_active_fields = 4232 "link,media,state,speed,duplex,device"; 4233 char *all_inactive_fields = "link,device,media,flags"; 4234 char *all_mac_fields = "link,slot,address,inuse,client"; 4235 char *all_hwgrp_fields = 4236 "link,group,grouptype,rings,clients"; 4237 const ofmt_field_t *pf; 4238 ofmt_handle_t ofmt; 4239 ofmt_status_t oferr; 4240 uint_t ofmtflags = 0; 4241 4242 bzero(&state, sizeof (state)); 4243 opterr = 0; 4244 while ((option = getopt_long(argc, argv, ":pPo:mH", 4245 show_lopts, NULL)) != -1) { 4246 switch (option) { 4247 case 'p': 4248 if (p_arg) 4249 die_optdup(option); 4250 4251 p_arg = B_TRUE; 4252 break; 4253 case 'P': 4254 if (flags != DLADM_OPT_ACTIVE) 4255 die_optdup(option); 4256 4257 flags = DLADM_OPT_PERSIST; 4258 break; 4259 case 'o': 4260 o_arg = B_TRUE; 4261 fields_str = optarg; 4262 break; 4263 case 'm': 4264 m_arg = B_TRUE; 4265 break; 4266 case 'H': 4267 H_arg = B_TRUE; 4268 break; 4269 default: 4270 die_opterr(optopt, option, use); 4271 break; 4272 } 4273 } 4274 4275 if (p_arg && !o_arg) 4276 die("-p requires -o"); 4277 4278 if (m_arg && H_arg) 4279 die("-m cannot combine with -H"); 4280 4281 if (p_arg && strcasecmp(fields_str, "all") == 0) 4282 die("\"-o all\" is invalid with -p"); 4283 4284 /* get link name (optional last argument) */ 4285 if (optind == (argc-1)) { 4286 if ((status = dladm_name2info(handle, argv[optind], &linkid, 4287 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 4288 die_dlerr(status, "link %s is not valid", argv[optind]); 4289 } 4290 } else if (optind != argc) { 4291 usage(); 4292 } 4293 4294 state.ls_parsable = p_arg; 4295 state.ls_flags = flags; 4296 state.ls_donefirst = B_FALSE; 4297 state.ls_mac = m_arg; 4298 state.ls_hwgrp = H_arg; 4299 4300 if (m_arg && !(flags & DLADM_OPT_ACTIVE)) { 4301 /* 4302 * We can only display the factory MAC addresses of 4303 * active data-links. 4304 */ 4305 die("-m not compatible with -P"); 4306 } 4307 4308 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 4309 if (state.ls_mac) 4310 fields_str = all_mac_fields; 4311 else if (state.ls_hwgrp) 4312 fields_str = all_hwgrp_fields; 4313 else if (state.ls_flags & DLADM_OPT_ACTIVE) { 4314 fields_str = all_active_fields; 4315 } else { 4316 fields_str = all_inactive_fields; 4317 } 4318 } 4319 4320 if (state.ls_mac) { 4321 pf = phys_m_fields; 4322 } else if (state.ls_hwgrp) { 4323 pf = phys_h_fields; 4324 } else { 4325 pf = phys_fields; 4326 } 4327 4328 if (state.ls_parsable) 4329 ofmtflags |= OFMT_PARSABLE; 4330 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 4331 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 4332 state.ls_ofmt = ofmt; 4333 4334 if (linkid == DATALINK_ALL_LINKID) { 4335 (void) dladm_walk_datalink_id(show_phys, handle, &state, 4336 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags); 4337 } else { 4338 (void) show_phys(handle, linkid, &state); 4339 if (state.ls_status != DLADM_STATUS_OK) { 4340 die_dlerr(state.ls_status, 4341 "failed to show physical link %s", argv[optind]); 4342 } 4343 } 4344 ofmt_close(ofmt); 4345 } 4346 4347 static void 4348 do_show_vlan(int argc, char *argv[], const char *use) 4349 { 4350 int option; 4351 uint32_t flags = DLADM_OPT_ACTIVE; 4352 boolean_t p_arg = B_FALSE; 4353 datalink_id_t linkid = DATALINK_ALL_LINKID; 4354 show_state_t state; 4355 dladm_status_t status; 4356 boolean_t o_arg = B_FALSE; 4357 char *fields_str = NULL; 4358 ofmt_handle_t ofmt; 4359 ofmt_status_t oferr; 4360 uint_t ofmtflags = 0; 4361 4362 bzero(&state, sizeof (state)); 4363 4364 opterr = 0; 4365 while ((option = getopt_long(argc, argv, ":pPo:", 4366 show_lopts, NULL)) != -1) { 4367 switch (option) { 4368 case 'p': 4369 if (p_arg) 4370 die_optdup(option); 4371 4372 p_arg = B_TRUE; 4373 break; 4374 case 'P': 4375 if (flags != DLADM_OPT_ACTIVE) 4376 die_optdup(option); 4377 4378 flags = DLADM_OPT_PERSIST; 4379 break; 4380 case 'o': 4381 o_arg = B_TRUE; 4382 fields_str = optarg; 4383 break; 4384 default: 4385 die_opterr(optopt, option, use); 4386 break; 4387 } 4388 } 4389 4390 /* get link name (optional last argument) */ 4391 if (optind == (argc-1)) { 4392 if ((status = dladm_name2info(handle, argv[optind], &linkid, 4393 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 4394 die_dlerr(status, "link %s is not valid", argv[optind]); 4395 } 4396 } else if (optind != argc) { 4397 usage(); 4398 } 4399 4400 state.ls_parsable = p_arg; 4401 state.ls_flags = flags; 4402 state.ls_donefirst = B_FALSE; 4403 4404 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 4405 fields_str = NULL; 4406 4407 if (state.ls_parsable) 4408 ofmtflags |= OFMT_PARSABLE; 4409 oferr = ofmt_open(fields_str, vlan_fields, ofmtflags, 0, &ofmt); 4410 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 4411 state.ls_ofmt = ofmt; 4412 4413 if (linkid == DATALINK_ALL_LINKID) { 4414 (void) dladm_walk_datalink_id(show_vlan, handle, &state, 4415 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags); 4416 } else { 4417 (void) show_vlan(handle, linkid, &state); 4418 if (state.ls_status != DLADM_STATUS_OK) { 4419 die_dlerr(state.ls_status, "failed to show vlan %s", 4420 argv[optind]); 4421 } 4422 } 4423 ofmt_close(ofmt); 4424 } 4425 4426 static void 4427 do_create_vnic(int argc, char *argv[], const char *use) 4428 { 4429 datalink_id_t linkid, dev_linkid; 4430 char devname[MAXLINKNAMELEN]; 4431 char name[MAXLINKNAMELEN]; 4432 boolean_t l_arg = B_FALSE; 4433 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4434 char *altroot = NULL; 4435 int option; 4436 char *endp = NULL; 4437 dladm_status_t status; 4438 vnic_mac_addr_type_t mac_addr_type = VNIC_MAC_ADDR_TYPE_UNKNOWN; 4439 uchar_t *mac_addr = NULL; 4440 int mac_slot = -1; 4441 uint_t maclen = 0, mac_prefix_len = 0; 4442 char propstr[DLADM_STRSIZE]; 4443 dladm_arg_list_t *proplist = NULL; 4444 int vid = 0; 4445 int af = AF_UNSPEC; 4446 vrid_t vrid = VRRP_VRID_NONE; 4447 4448 opterr = 0; 4449 bzero(propstr, DLADM_STRSIZE); 4450 4451 while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:V:A:H", 4452 vnic_lopts, NULL)) != -1) { 4453 switch (option) { 4454 case 't': 4455 flags &= ~DLADM_OPT_PERSIST; 4456 break; 4457 case 'R': 4458 altroot = optarg; 4459 break; 4460 case 'l': 4461 if (strlcpy(devname, optarg, MAXLINKNAMELEN) >= 4462 MAXLINKNAMELEN) 4463 die("link name too long"); 4464 l_arg = B_TRUE; 4465 break; 4466 case 'm': 4467 if (mac_addr_type != VNIC_MAC_ADDR_TYPE_UNKNOWN) 4468 die("cannot specify -m option twice"); 4469 4470 if (strcmp(optarg, "fixed") == 0) { 4471 /* 4472 * A fixed MAC address must be specified 4473 * by its value, not by the keyword 'fixed'. 4474 */ 4475 die("'fixed' is not a valid MAC address"); 4476 } 4477 if (dladm_vnic_str2macaddrtype(optarg, 4478 &mac_addr_type) != DLADM_STATUS_OK) { 4479 mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED; 4480 /* MAC address specified by value */ 4481 mac_addr = _link_aton(optarg, (int *)&maclen); 4482 if (mac_addr == NULL) { 4483 if (maclen == (uint_t)-1) 4484 die("invalid MAC address"); 4485 else 4486 die("out of memory"); 4487 } 4488 } 4489 break; 4490 case 'n': 4491 errno = 0; 4492 mac_slot = (int)strtol(optarg, &endp, 10); 4493 if (errno != 0 || *endp != '\0') 4494 die("invalid slot number"); 4495 break; 4496 case 'p': 4497 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 4498 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 4499 DLADM_STRSIZE) 4500 die("property list too long '%s'", propstr); 4501 break; 4502 case 'r': 4503 mac_addr = _link_aton(optarg, (int *)&mac_prefix_len); 4504 if (mac_addr == NULL) { 4505 if (mac_prefix_len == (uint_t)-1) 4506 die("invalid MAC address"); 4507 else 4508 die("out of memory"); 4509 } 4510 break; 4511 case 'V': 4512 if (!str2int(optarg, (int *)&vrid) || 4513 vrid < VRRP_VRID_MIN || vrid > VRRP_VRID_MAX) { 4514 die("invalid VRRP identifier '%s'", optarg); 4515 } 4516 4517 break; 4518 case 'A': 4519 if (strcmp(optarg, "inet") == 0) 4520 af = AF_INET; 4521 else if (strcmp(optarg, "inet6") == 0) 4522 af = AF_INET6; 4523 else 4524 die("invalid address family '%s'", optarg); 4525 break; 4526 case 'v': 4527 if (vid != 0) 4528 die_optdup(option); 4529 4530 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 4531 die("invalid VLAN identifier '%s'", optarg); 4532 4533 break; 4534 case 'f': 4535 flags |= DLADM_OPT_FORCE; 4536 break; 4537 case 'H': 4538 flags |= DLADM_OPT_HWRINGS; 4539 break; 4540 default: 4541 die_opterr(optopt, option, use); 4542 } 4543 } 4544 4545 if (mac_addr_type == VNIC_MAC_ADDR_TYPE_UNKNOWN) 4546 mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO; 4547 4548 /* 4549 * 'f' - force, flag can be specified only with 'v' - vlan. 4550 */ 4551 if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0) 4552 die("-f option can only be used with -v"); 4553 4554 if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM && 4555 mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED) 4556 usage(); 4557 4558 if (mac_addr_type == VNIC_MAC_ADDR_TYPE_VRID) { 4559 if (vrid == VRRP_VRID_NONE || af == AF_UNSPEC || 4560 mac_addr != NULL || maclen != 0 || mac_slot != -1 || 4561 mac_prefix_len != 0) { 4562 usage(); 4563 } 4564 } else if ((af != AF_UNSPEC || vrid != VRRP_VRID_NONE)) { 4565 usage(); 4566 } 4567 4568 /* check required options */ 4569 if (!l_arg) 4570 usage(); 4571 4572 if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY) 4573 usage(); 4574 4575 /* the VNIC id is the required operand */ 4576 if (optind != (argc - 1)) 4577 usage(); 4578 4579 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 4580 die("link name too long '%s'", argv[optind]); 4581 4582 if (!dladm_valid_linkname(name)) 4583 die("invalid link name '%s'", argv[optind]); 4584 4585 if (altroot != NULL) 4586 altroot_cmd(altroot, argc, argv); 4587 4588 if (dladm_name2info(handle, devname, &dev_linkid, NULL, NULL, NULL) != 4589 DLADM_STATUS_OK) 4590 die("invalid link name '%s'", devname); 4591 4592 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 4593 != DLADM_STATUS_OK) 4594 die("invalid vnic property"); 4595 4596 status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type, 4597 mac_addr, maclen, &mac_slot, mac_prefix_len, vid, vrid, af, 4598 &linkid, proplist, flags); 4599 switch (status) { 4600 case DLADM_STATUS_OK: 4601 break; 4602 4603 case DLADM_STATUS_LINKBUSY: 4604 die("VLAN over '%s' may not use default_tag ID " 4605 "(see dladm(1M))", devname); 4606 break; 4607 4608 default: 4609 die_dlerr(status, "vnic creation over %s failed", devname); 4610 } 4611 4612 dladm_free_props(proplist); 4613 free(mac_addr); 4614 } 4615 4616 static void 4617 do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub, 4618 uint32_t flags) 4619 { 4620 boolean_t is_etherstub; 4621 dladm_vnic_attr_t attr; 4622 4623 if (dladm_vnic_info(handle, linkid, &attr, flags) != DLADM_STATUS_OK) { 4624 /* 4625 * Let the delete continue anyway. 4626 */ 4627 return; 4628 } 4629 is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID); 4630 if (is_etherstub != etherstub) { 4631 die("'%s' is not %s", name, 4632 (is_etherstub ? "a vnic" : "an etherstub")); 4633 } 4634 } 4635 4636 static void 4637 do_delete_vnic_common(int argc, char *argv[], const char *use, 4638 boolean_t etherstub) 4639 { 4640 int option; 4641 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4642 datalink_id_t linkid; 4643 char *altroot = NULL; 4644 dladm_status_t status; 4645 4646 opterr = 0; 4647 while ((option = getopt_long(argc, argv, ":R:t", lopts, 4648 NULL)) != -1) { 4649 switch (option) { 4650 case 't': 4651 flags &= ~DLADM_OPT_PERSIST; 4652 break; 4653 case 'R': 4654 altroot = optarg; 4655 break; 4656 default: 4657 die_opterr(optopt, option, use); 4658 } 4659 } 4660 4661 /* get vnic name (required last argument) */ 4662 if (optind != (argc - 1)) 4663 usage(); 4664 4665 if (altroot != NULL) 4666 altroot_cmd(altroot, argc, argv); 4667 4668 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 4669 NULL); 4670 if (status != DLADM_STATUS_OK) 4671 die("invalid link name '%s'", argv[optind]); 4672 4673 if ((flags & DLADM_OPT_ACTIVE) != 0) { 4674 do_etherstub_check(argv[optind], linkid, etherstub, 4675 DLADM_OPT_ACTIVE); 4676 } 4677 if ((flags & DLADM_OPT_PERSIST) != 0) { 4678 do_etherstub_check(argv[optind], linkid, etherstub, 4679 DLADM_OPT_PERSIST); 4680 } 4681 4682 status = dladm_vnic_delete(handle, linkid, flags); 4683 if (status != DLADM_STATUS_OK) 4684 die_dlerr(status, "vnic deletion failed"); 4685 } 4686 4687 static void 4688 do_delete_vnic(int argc, char *argv[], const char *use) 4689 { 4690 do_delete_vnic_common(argc, argv, use, B_FALSE); 4691 } 4692 4693 /* ARGSUSED */ 4694 static void 4695 do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan) 4696 { 4697 datalink_id_t linkid = DATALINK_ALL_LINKID; 4698 dladm_status_t status; 4699 char *type; 4700 4701 type = vlan ? "vlan" : "vnic"; 4702 4703 /* 4704 * get the id or the name of the vnic/vlan (optional last argument) 4705 */ 4706 if (argc == 2) { 4707 status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL, 4708 NULL); 4709 if (status != DLADM_STATUS_OK) 4710 goto done; 4711 4712 } else if (argc > 2) { 4713 usage(); 4714 } 4715 4716 if (vlan) 4717 status = dladm_vlan_up(handle, linkid); 4718 else 4719 status = dladm_vnic_up(handle, linkid, 0); 4720 4721 done: 4722 if (status != DLADM_STATUS_OK) { 4723 if (argc == 2) { 4724 die_dlerr(status, 4725 "could not bring up %s '%s'", type, argv[1]); 4726 } else { 4727 die_dlerr(status, "could not bring %ss up", type); 4728 } 4729 } 4730 } 4731 4732 static void 4733 do_up_vnic(int argc, char *argv[], const char *use) 4734 { 4735 do_up_vnic_common(argc, argv, use, B_FALSE); 4736 } 4737 4738 static void 4739 dump_vnics_head(const char *dev) 4740 { 4741 if (strlen(dev)) 4742 (void) printf("%s", dev); 4743 4744 (void) printf("\tipackets rbytes opackets obytes "); 4745 4746 if (strlen(dev)) 4747 (void) printf("%%ipkts %%opkts\n"); 4748 else 4749 (void) printf("\n"); 4750 } 4751 4752 static void 4753 dump_vnic_stat(const char *name, datalink_id_t vnic_id, 4754 show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats) 4755 { 4756 pktsum_t diff_stats; 4757 pktsum_t *old_stats = &state->vs_prevstats[vnic_id]; 4758 4759 dladm_stats_diff(&diff_stats, vnic_stats, old_stats); 4760 4761 (void) printf("%s", name); 4762 4763 (void) printf("\t%-10llu", diff_stats.ipackets); 4764 (void) printf("%-12llu", diff_stats.rbytes); 4765 (void) printf("%-10llu", diff_stats.opackets); 4766 (void) printf("%-12llu", diff_stats.obytes); 4767 4768 if (tot_stats) { 4769 if (tot_stats->ipackets == 0) { 4770 (void) printf("\t-"); 4771 } else { 4772 (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 4773 (double)tot_stats->ipackets * 100); 4774 } 4775 if (tot_stats->opackets == 0) { 4776 (void) printf("\t-"); 4777 } else { 4778 (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 4779 (double)tot_stats->opackets * 100); 4780 } 4781 } 4782 (void) printf("\n"); 4783 4784 *old_stats = *vnic_stats; 4785 } 4786 4787 /* 4788 * Called from the walker dladm_vnic_walk_sys() for each vnic to display 4789 * vnic information or statistics. 4790 */ 4791 static dladm_status_t 4792 print_vnic(show_vnic_state_t *state, datalink_id_t linkid) 4793 { 4794 dladm_vnic_attr_t attr, *vnic = &attr; 4795 dladm_status_t status; 4796 boolean_t is_etherstub; 4797 char devname[MAXLINKNAMELEN]; 4798 char vnic_name[MAXLINKNAMELEN]; 4799 char mstr[MAXMACADDRLEN * 3]; 4800 vnic_fields_buf_t vbuf; 4801 4802 if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) != 4803 DLADM_STATUS_OK) 4804 return (status); 4805 4806 is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID); 4807 if (state->vs_etherstub != is_etherstub) { 4808 /* 4809 * Want all etherstub but it's not one, or want 4810 * non-etherstub and it's one. 4811 */ 4812 return (DLADM_STATUS_OK); 4813 } 4814 4815 if (state->vs_link_id != DATALINK_ALL_LINKID) { 4816 if (state->vs_link_id != vnic->va_link_id) 4817 return (DLADM_STATUS_OK); 4818 } 4819 4820 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, 4821 NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK) 4822 return (DLADM_STATUS_BADARG); 4823 4824 bzero(devname, sizeof (devname)); 4825 if (!is_etherstub && 4826 dladm_datalink_id2info(handle, vnic->va_link_id, NULL, NULL, 4827 NULL, devname, sizeof (devname)) != DLADM_STATUS_OK) 4828 (void) sprintf(devname, "?"); 4829 4830 state->vs_found = B_TRUE; 4831 if (state->vs_stats) { 4832 /* print vnic statistics */ 4833 pktsum_t vnic_stats; 4834 4835 if (state->vs_firstonly) { 4836 if (state->vs_donefirst) 4837 return (0); 4838 state->vs_donefirst = B_TRUE; 4839 } 4840 4841 if (!state->vs_printstats) { 4842 /* 4843 * get vnic statistics and add to the sum for the 4844 * named device. 4845 */ 4846 get_link_stats(vnic_name, &vnic_stats); 4847 dladm_stats_total(&state->vs_totalstats, &vnic_stats, 4848 &state->vs_prevstats[vnic->va_vnic_id]); 4849 } else { 4850 /* get and print vnic statistics */ 4851 get_link_stats(vnic_name, &vnic_stats); 4852 dump_vnic_stat(vnic_name, linkid, state, &vnic_stats, 4853 &state->vs_totalstats); 4854 } 4855 return (DLADM_STATUS_OK); 4856 } else { 4857 (void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link), 4858 "%s", vnic_name); 4859 4860 if (!is_etherstub) { 4861 4862 (void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over), 4863 "%s", devname); 4864 (void) snprintf(vbuf.vnic_speed, 4865 sizeof (vbuf.vnic_speed), "%u", 4866 (uint_t)((get_ifspeed(vnic_name, B_TRUE)) 4867 / 1000000ull)); 4868 4869 switch (vnic->va_mac_addr_type) { 4870 case VNIC_MAC_ADDR_TYPE_FIXED: 4871 case VNIC_MAC_ADDR_TYPE_PRIMARY: 4872 (void) snprintf(vbuf.vnic_macaddrtype, 4873 sizeof (vbuf.vnic_macaddrtype), 4874 gettext("fixed")); 4875 break; 4876 case VNIC_MAC_ADDR_TYPE_RANDOM: 4877 (void) snprintf(vbuf.vnic_macaddrtype, 4878 sizeof (vbuf.vnic_macaddrtype), 4879 gettext("random")); 4880 break; 4881 case VNIC_MAC_ADDR_TYPE_FACTORY: 4882 (void) snprintf(vbuf.vnic_macaddrtype, 4883 sizeof (vbuf.vnic_macaddrtype), 4884 gettext("factory, slot %d"), 4885 vnic->va_mac_slot); 4886 break; 4887 case VNIC_MAC_ADDR_TYPE_VRID: 4888 (void) snprintf(vbuf.vnic_macaddrtype, 4889 sizeof (vbuf.vnic_macaddrtype), 4890 gettext("vrrp, %d/%s"), 4891 vnic->va_vrid, vnic->va_af == AF_INET ? 4892 "inet" : "inet6"); 4893 break; 4894 } 4895 4896 if (strlen(vbuf.vnic_macaddrtype) > 0) { 4897 (void) snprintf(vbuf.vnic_macaddr, 4898 sizeof (vbuf.vnic_macaddr), "%s", 4899 dladm_aggr_macaddr2str(vnic->va_mac_addr, 4900 mstr)); 4901 } 4902 4903 (void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid), 4904 "%d", vnic->va_vid); 4905 } 4906 4907 ofmt_print(state->vs_ofmt, &vbuf); 4908 4909 return (DLADM_STATUS_OK); 4910 } 4911 } 4912 4913 /* ARGSUSED */ 4914 static int 4915 show_vnic(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4916 { 4917 show_vnic_state_t *state = arg; 4918 4919 state->vs_status = print_vnic(state, linkid); 4920 return (DLADM_WALK_CONTINUE); 4921 } 4922 4923 static void 4924 do_show_vnic_common(int argc, char *argv[], const char *use, 4925 boolean_t etherstub) 4926 { 4927 int option; 4928 boolean_t s_arg = B_FALSE; 4929 boolean_t i_arg = B_FALSE; 4930 boolean_t l_arg = B_FALSE; 4931 uint32_t interval = 0, flags = DLADM_OPT_ACTIVE; 4932 datalink_id_t linkid = DATALINK_ALL_LINKID; 4933 datalink_id_t dev_linkid = DATALINK_ALL_LINKID; 4934 show_vnic_state_t state; 4935 dladm_status_t status; 4936 boolean_t o_arg = B_FALSE; 4937 char *fields_str = NULL; 4938 const ofmt_field_t *pf; 4939 char *all_e_fields = "link"; 4940 ofmt_handle_t ofmt; 4941 ofmt_status_t oferr; 4942 uint_t ofmtflags = 0; 4943 4944 bzero(&state, sizeof (state)); 4945 opterr = 0; 4946 while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts, 4947 NULL)) != -1) { 4948 switch (option) { 4949 case 'p': 4950 state.vs_parsable = B_TRUE; 4951 break; 4952 case 'P': 4953 flags = DLADM_OPT_PERSIST; 4954 break; 4955 case 'l': 4956 if (etherstub) 4957 die("option not supported for this command"); 4958 4959 if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >= 4960 MAXLINKNAMELEN) 4961 die("link name too long"); 4962 4963 l_arg = B_TRUE; 4964 break; 4965 case 's': 4966 if (s_arg) { 4967 die("the option -s cannot be specified " 4968 "more than once"); 4969 } 4970 s_arg = B_TRUE; 4971 break; 4972 case 'i': 4973 if (i_arg) { 4974 die("the option -i cannot be specified " 4975 "more than once"); 4976 } 4977 i_arg = B_TRUE; 4978 if (!dladm_str2interval(optarg, &interval)) 4979 die("invalid interval value '%s'", optarg); 4980 break; 4981 case 'o': 4982 o_arg = B_TRUE; 4983 fields_str = optarg; 4984 break; 4985 default: 4986 die_opterr(optopt, option, use); 4987 } 4988 } 4989 4990 if (i_arg && !s_arg) 4991 die("the option -i can be used only with -s"); 4992 4993 /* get vnic ID (optional last argument) */ 4994 if (optind == (argc - 1)) { 4995 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 4996 NULL, NULL); 4997 if (status != DLADM_STATUS_OK) { 4998 die_dlerr(status, "invalid vnic name '%s'", 4999 argv[optind]); 5000 } 5001 (void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN); 5002 } else if (optind != argc) { 5003 usage(); 5004 } 5005 5006 if (l_arg) { 5007 status = dladm_name2info(handle, state.vs_link, &dev_linkid, 5008 NULL, NULL, NULL); 5009 if (status != DLADM_STATUS_OK) { 5010 die_dlerr(status, "invalid link name '%s'", 5011 state.vs_link); 5012 } 5013 } 5014 5015 state.vs_vnic_id = linkid; 5016 state.vs_link_id = dev_linkid; 5017 state.vs_etherstub = etherstub; 5018 state.vs_found = B_FALSE; 5019 state.vs_flags = flags; 5020 5021 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 5022 if (etherstub) 5023 fields_str = all_e_fields; 5024 } 5025 pf = vnic_fields; 5026 5027 if (state.vs_parsable) 5028 ofmtflags |= OFMT_PARSABLE; 5029 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 5030 dladm_ofmt_check(oferr, state.vs_parsable, ofmt); 5031 state.vs_ofmt = ofmt; 5032 5033 if (s_arg) { 5034 /* Display vnic statistics */ 5035 vnic_stats(&state, interval); 5036 ofmt_close(ofmt); 5037 return; 5038 } 5039 5040 /* Display vnic information */ 5041 state.vs_donefirst = B_FALSE; 5042 5043 if (linkid == DATALINK_ALL_LINKID) { 5044 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 5045 DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB, 5046 DATALINK_ANY_MEDIATYPE, flags); 5047 } else { 5048 (void) show_vnic(handle, linkid, &state); 5049 if (state.vs_status != DLADM_STATUS_OK) { 5050 ofmt_close(ofmt); 5051 die_dlerr(state.vs_status, "failed to show vnic '%s'", 5052 state.vs_vnic); 5053 } 5054 } 5055 ofmt_close(ofmt); 5056 } 5057 5058 static void 5059 do_show_vnic(int argc, char *argv[], const char *use) 5060 { 5061 do_show_vnic_common(argc, argv, use, B_FALSE); 5062 } 5063 5064 static void 5065 do_create_etherstub(int argc, char *argv[], const char *use) 5066 { 5067 uint32_t flags; 5068 char *altroot = NULL; 5069 int option; 5070 dladm_status_t status; 5071 char name[MAXLINKNAMELEN]; 5072 uchar_t mac_addr[ETHERADDRL]; 5073 5074 name[0] = '\0'; 5075 bzero(mac_addr, sizeof (mac_addr)); 5076 flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5077 5078 opterr = 0; 5079 while ((option = getopt_long(argc, argv, "tR:", 5080 etherstub_lopts, NULL)) != -1) { 5081 switch (option) { 5082 case 't': 5083 flags &= ~DLADM_OPT_PERSIST; 5084 break; 5085 case 'R': 5086 altroot = optarg; 5087 break; 5088 default: 5089 die_opterr(optopt, option, use); 5090 } 5091 } 5092 5093 /* the etherstub id is the required operand */ 5094 if (optind != (argc - 1)) 5095 usage(); 5096 5097 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 5098 die("link name too long '%s'", argv[optind]); 5099 5100 if (!dladm_valid_linkname(name)) 5101 die("invalid link name '%s'", argv[optind]); 5102 5103 if (altroot != NULL) 5104 altroot_cmd(altroot, argc, argv); 5105 5106 status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID, 5107 VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, 5108 VRRP_VRID_NONE, AF_UNSPEC, NULL, NULL, flags); 5109 if (status != DLADM_STATUS_OK) 5110 die_dlerr(status, "etherstub creation failed"); 5111 } 5112 5113 static void 5114 do_delete_etherstub(int argc, char *argv[], const char *use) 5115 { 5116 do_delete_vnic_common(argc, argv, use, B_TRUE); 5117 } 5118 5119 /* ARGSUSED */ 5120 static void 5121 do_show_etherstub(int argc, char *argv[], const char *use) 5122 { 5123 do_show_vnic_common(argc, argv, use, B_TRUE); 5124 } 5125 5126 /* ARGSUSED */ 5127 static void 5128 do_up_simnet(int argc, char *argv[], const char *use) 5129 { 5130 (void) dladm_simnet_up(handle, DATALINK_ALL_LINKID, 0); 5131 } 5132 5133 static void 5134 do_create_simnet(int argc, char *argv[], const char *use) 5135 { 5136 uint32_t flags; 5137 char *altroot = NULL; 5138 char *media = NULL; 5139 uint32_t mtype = DL_ETHER; 5140 int option; 5141 dladm_status_t status; 5142 char name[MAXLINKNAMELEN]; 5143 5144 name[0] = '\0'; 5145 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5146 5147 opterr = 0; 5148 while ((option = getopt_long(argc, argv, ":tR:m:", 5149 simnet_lopts, NULL)) != -1) { 5150 switch (option) { 5151 case 't': 5152 flags &= ~DLADM_OPT_PERSIST; 5153 break; 5154 case 'R': 5155 altroot = optarg; 5156 break; 5157 case 'm': 5158 media = optarg; 5159 break; 5160 default: 5161 die_opterr(optopt, option, use); 5162 } 5163 } 5164 5165 /* the simnet id is the required operand */ 5166 if (optind != (argc - 1)) 5167 usage(); 5168 5169 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 5170 die("link name too long '%s'", argv[optind]); 5171 5172 if (!dladm_valid_linkname(name)) 5173 die("invalid link name '%s'", name); 5174 5175 if (media != NULL) { 5176 mtype = dladm_str2media(media); 5177 if (mtype != DL_ETHER && mtype != DL_WIFI) 5178 die("media type '%s' is not supported", media); 5179 } 5180 5181 if (altroot != NULL) 5182 altroot_cmd(altroot, argc, argv); 5183 5184 status = dladm_simnet_create(handle, name, mtype, flags); 5185 if (status != DLADM_STATUS_OK) 5186 die_dlerr(status, "simnet creation failed"); 5187 } 5188 5189 static void 5190 do_delete_simnet(int argc, char *argv[], const char *use) 5191 { 5192 int option; 5193 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5194 datalink_id_t linkid; 5195 char *altroot = NULL; 5196 dladm_status_t status; 5197 dladm_simnet_attr_t slinfo; 5198 5199 opterr = 0; 5200 while ((option = getopt_long(argc, argv, ":tR:", simnet_lopts, 5201 NULL)) != -1) { 5202 switch (option) { 5203 case 't': 5204 flags &= ~DLADM_OPT_PERSIST; 5205 break; 5206 case 'R': 5207 altroot = optarg; 5208 break; 5209 default: 5210 die_opterr(optopt, option, use); 5211 } 5212 } 5213 5214 /* get simnet name (required last argument) */ 5215 if (optind != (argc - 1)) 5216 usage(); 5217 5218 if (!dladm_valid_linkname(argv[optind])) 5219 die("invalid link name '%s'", argv[optind]); 5220 5221 if (altroot != NULL) 5222 altroot_cmd(altroot, argc, argv); 5223 5224 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 5225 NULL); 5226 if (status != DLADM_STATUS_OK) 5227 die("simnet '%s' not found", argv[optind]); 5228 5229 if ((status = dladm_simnet_info(handle, linkid, &slinfo, 5230 flags)) != DLADM_STATUS_OK) 5231 die_dlerr(status, "failed to retrieve simnet information"); 5232 5233 status = dladm_simnet_delete(handle, linkid, flags); 5234 if (status != DLADM_STATUS_OK) 5235 die_dlerr(status, "simnet deletion failed"); 5236 } 5237 5238 static void 5239 do_modify_simnet(int argc, char *argv[], const char *use) 5240 { 5241 int option; 5242 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5243 datalink_id_t linkid; 5244 datalink_id_t peer_linkid; 5245 char *altroot = NULL; 5246 dladm_status_t status; 5247 boolean_t p_arg = B_FALSE; 5248 5249 opterr = 0; 5250 while ((option = getopt_long(argc, argv, ":tR:p:", simnet_lopts, 5251 NULL)) != -1) { 5252 switch (option) { 5253 case 't': 5254 flags &= ~DLADM_OPT_PERSIST; 5255 break; 5256 case 'R': 5257 altroot = optarg; 5258 break; 5259 case 'p': 5260 if (p_arg) 5261 die_optdup(option); 5262 p_arg = B_TRUE; 5263 if (strcasecmp(optarg, "none") == 0) 5264 peer_linkid = DATALINK_INVALID_LINKID; 5265 else if (dladm_name2info(handle, optarg, &peer_linkid, 5266 NULL, NULL, NULL) != DLADM_STATUS_OK) 5267 die("invalid peer link name '%s'", optarg); 5268 break; 5269 default: 5270 die_opterr(optopt, option, use); 5271 } 5272 } 5273 5274 /* get simnet name (required last argument) */ 5275 if (optind != (argc - 1)) 5276 usage(); 5277 5278 /* Nothing to do if no peer link argument */ 5279 if (!p_arg) 5280 return; 5281 5282 if (altroot != NULL) 5283 altroot_cmd(altroot, argc, argv); 5284 5285 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 5286 NULL); 5287 if (status != DLADM_STATUS_OK) 5288 die("invalid link name '%s'", argv[optind]); 5289 5290 status = dladm_simnet_modify(handle, linkid, peer_linkid, flags); 5291 if (status != DLADM_STATUS_OK) 5292 die_dlerr(status, "simnet modification failed"); 5293 } 5294 5295 static dladm_status_t 5296 print_simnet(show_state_t *state, datalink_id_t linkid) 5297 { 5298 dladm_simnet_attr_t slinfo; 5299 uint32_t flags; 5300 dladm_status_t status; 5301 simnet_fields_buf_t slbuf; 5302 char mstr[ETHERADDRL * 3]; 5303 5304 bzero(&slbuf, sizeof (slbuf)); 5305 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL, 5306 slbuf.simnet_name, sizeof (slbuf.simnet_name))) 5307 != DLADM_STATUS_OK) 5308 return (status); 5309 5310 if (!(state->ls_flags & flags)) 5311 return (DLADM_STATUS_NOTFOUND); 5312 5313 if ((status = dladm_simnet_info(handle, linkid, &slinfo, 5314 state->ls_flags)) != DLADM_STATUS_OK) 5315 return (status); 5316 5317 if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID && 5318 (status = dladm_datalink_id2info(handle, slinfo.sna_peer_link_id, 5319 NULL, NULL, NULL, slbuf.simnet_otherlink, 5320 sizeof (slbuf.simnet_otherlink))) != 5321 DLADM_STATUS_OK) 5322 return (status); 5323 5324 if (slinfo.sna_mac_len > sizeof (slbuf.simnet_macaddr)) 5325 return (DLADM_STATUS_BADVAL); 5326 5327 (void) strlcpy(slbuf.simnet_macaddr, 5328 dladm_aggr_macaddr2str(slinfo.sna_mac_addr, mstr), 5329 sizeof (slbuf.simnet_macaddr)); 5330 (void) dladm_media2str(slinfo.sna_type, slbuf.simnet_media); 5331 5332 ofmt_print(state->ls_ofmt, &slbuf); 5333 return (status); 5334 } 5335 5336 /* ARGSUSED */ 5337 static int 5338 show_simnet(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5339 { 5340 show_state_t *state = arg; 5341 5342 state->ls_status = print_simnet(state, linkid); 5343 return (DLADM_WALK_CONTINUE); 5344 } 5345 5346 static void 5347 do_show_simnet(int argc, char *argv[], const char *use) 5348 { 5349 int option; 5350 uint32_t flags = DLADM_OPT_ACTIVE; 5351 boolean_t p_arg = B_FALSE; 5352 datalink_id_t linkid = DATALINK_ALL_LINKID; 5353 show_state_t state; 5354 dladm_status_t status; 5355 boolean_t o_arg = B_FALSE; 5356 ofmt_handle_t ofmt; 5357 ofmt_status_t oferr; 5358 char *all_fields = "link,media,macaddress,otherlink"; 5359 char *fields_str = all_fields; 5360 uint_t ofmtflags = 0; 5361 5362 bzero(&state, sizeof (state)); 5363 5364 opterr = 0; 5365 while ((option = getopt_long(argc, argv, ":pPo:", 5366 show_lopts, NULL)) != -1) { 5367 switch (option) { 5368 case 'p': 5369 if (p_arg) 5370 die_optdup(option); 5371 5372 p_arg = B_TRUE; 5373 state.ls_parsable = p_arg; 5374 break; 5375 case 'P': 5376 if (flags != DLADM_OPT_ACTIVE) 5377 die_optdup(option); 5378 5379 flags = DLADM_OPT_PERSIST; 5380 break; 5381 case 'o': 5382 o_arg = B_TRUE; 5383 fields_str = optarg; 5384 break; 5385 default: 5386 die_opterr(optopt, option, use); 5387 break; 5388 } 5389 } 5390 5391 if (p_arg && !o_arg) 5392 die("-p requires -o"); 5393 5394 if (strcasecmp(fields_str, "all") == 0) { 5395 if (p_arg) 5396 die("\"-o all\" is invalid with -p"); 5397 fields_str = all_fields; 5398 } 5399 5400 /* get link name (optional last argument) */ 5401 if (optind == (argc-1)) { 5402 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5403 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5404 die_dlerr(status, "link %s is not valid", argv[optind]); 5405 } 5406 } else if (optind != argc) { 5407 usage(); 5408 } 5409 5410 state.ls_flags = flags; 5411 state.ls_donefirst = B_FALSE; 5412 if (state.ls_parsable) 5413 ofmtflags |= OFMT_PARSABLE; 5414 oferr = ofmt_open(fields_str, simnet_fields, ofmtflags, 0, &ofmt); 5415 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 5416 state.ls_ofmt = ofmt; 5417 5418 if (linkid == DATALINK_ALL_LINKID) { 5419 (void) dladm_walk_datalink_id(show_simnet, handle, &state, 5420 DATALINK_CLASS_SIMNET, DATALINK_ANY_MEDIATYPE, flags); 5421 } else { 5422 (void) show_simnet(handle, linkid, &state); 5423 if (state.ls_status != DLADM_STATUS_OK) { 5424 ofmt_close(ofmt); 5425 die_dlerr(state.ls_status, "failed to show simnet %s", 5426 argv[optind]); 5427 } 5428 } 5429 ofmt_close(ofmt); 5430 } 5431 5432 static void 5433 link_stats(datalink_id_t linkid, uint_t interval, char *fields_str, 5434 show_state_t *state) 5435 { 5436 ofmt_handle_t ofmt; 5437 ofmt_status_t oferr; 5438 uint_t ofmtflags = 0; 5439 5440 if (state->ls_parsable) 5441 ofmtflags |= OFMT_PARSABLE; 5442 oferr = ofmt_open(fields_str, link_s_fields, ofmtflags, 0, &ofmt); 5443 dladm_ofmt_check(oferr, state->ls_parsable, ofmt); 5444 state->ls_ofmt = ofmt; 5445 5446 /* 5447 * If an interval is specified, continuously show the stats 5448 * only for the first MAC port. 5449 */ 5450 state->ls_firstonly = (interval != 0); 5451 5452 for (;;) { 5453 state->ls_donefirst = B_FALSE; 5454 if (linkid == DATALINK_ALL_LINKID) { 5455 (void) dladm_walk_datalink_id(show_link_stats, handle, 5456 state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 5457 DLADM_OPT_ACTIVE); 5458 } else { 5459 (void) show_link_stats(handle, linkid, state); 5460 } 5461 5462 if (interval == 0) 5463 break; 5464 5465 (void) fflush(stdout); 5466 (void) sleep(interval); 5467 } 5468 ofmt_close(ofmt); 5469 } 5470 5471 static void 5472 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) 5473 { 5474 /* 5475 * If an interval is specified, continuously show the stats 5476 * only for the first group. 5477 */ 5478 state->gs_firstonly = (interval != 0); 5479 5480 for (;;) { 5481 state->gs_donefirst = B_FALSE; 5482 if (linkid == DATALINK_ALL_LINKID) 5483 (void) dladm_walk_datalink_id(show_aggr, handle, state, 5484 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 5485 DLADM_OPT_ACTIVE); 5486 else 5487 (void) show_aggr(handle, linkid, state); 5488 5489 if (interval == 0) 5490 break; 5491 5492 (void) fflush(stdout); 5493 (void) sleep(interval); 5494 } 5495 } 5496 5497 /* ARGSUSED */ 5498 static void 5499 vnic_stats(show_vnic_state_t *sp, uint32_t interval) 5500 { 5501 show_vnic_state_t state; 5502 boolean_t specific_link, specific_dev; 5503 5504 /* Display vnic statistics */ 5505 dump_vnics_head(sp->vs_link); 5506 5507 bzero(&state, sizeof (state)); 5508 state.vs_stats = B_TRUE; 5509 state.vs_vnic_id = sp->vs_vnic_id; 5510 state.vs_link_id = sp->vs_link_id; 5511 5512 /* 5513 * If an interval is specified, and a vnic ID is not specified, 5514 * continuously show the stats only for the first vnic. 5515 */ 5516 specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID); 5517 specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID); 5518 5519 for (;;) { 5520 /* Get stats for each vnic */ 5521 state.vs_found = B_FALSE; 5522 state.vs_donefirst = B_FALSE; 5523 state.vs_printstats = B_FALSE; 5524 state.vs_flags = DLADM_OPT_ACTIVE; 5525 5526 if (!specific_link) { 5527 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 5528 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 5529 DLADM_OPT_ACTIVE); 5530 } else { 5531 (void) show_vnic(handle, sp->vs_vnic_id, &state); 5532 if (state.vs_status != DLADM_STATUS_OK) { 5533 die_dlerr(state.vs_status, 5534 "failed to show vnic '%s'", sp->vs_vnic); 5535 } 5536 } 5537 5538 if (specific_link && !state.vs_found) 5539 die("non-existent vnic '%s'", sp->vs_vnic); 5540 if (specific_dev && !state.vs_found) 5541 die("device %s has no vnics", sp->vs_link); 5542 5543 /* Show totals */ 5544 if ((specific_link | specific_dev) && !interval) { 5545 (void) printf("Total"); 5546 (void) printf("\t%-10llu", 5547 state.vs_totalstats.ipackets); 5548 (void) printf("%-12llu", 5549 state.vs_totalstats.rbytes); 5550 (void) printf("%-10llu", 5551 state.vs_totalstats.opackets); 5552 (void) printf("%-12llu\n", 5553 state.vs_totalstats.obytes); 5554 } 5555 5556 /* Show stats for each vnic */ 5557 state.vs_donefirst = B_FALSE; 5558 state.vs_printstats = B_TRUE; 5559 5560 if (!specific_link) { 5561 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 5562 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 5563 DLADM_OPT_ACTIVE); 5564 } else { 5565 (void) show_vnic(handle, sp->vs_vnic_id, &state); 5566 if (state.vs_status != DLADM_STATUS_OK) { 5567 die_dlerr(state.vs_status, 5568 "failed to show vnic '%s'", sp->vs_vnic); 5569 } 5570 } 5571 5572 if (interval == 0) 5573 break; 5574 5575 (void) fflush(stdout); 5576 (void) sleep(interval); 5577 } 5578 } 5579 5580 static void 5581 get_mac_stats(const char *dev, pktsum_t *stats) 5582 { 5583 kstat_ctl_t *kcp; 5584 kstat_t *ksp; 5585 char module[DLPI_LINKNAME_MAX]; 5586 uint_t instance; 5587 5588 5589 bzero(stats, sizeof (*stats)); 5590 5591 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 5592 return; 5593 5594 if ((kcp = kstat_open()) == NULL) { 5595 warn("kstat open operation failed"); 5596 return; 5597 } 5598 5599 ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL); 5600 if (ksp != NULL) 5601 dladm_get_stats(kcp, ksp, stats); 5602 5603 (void) kstat_close(kcp); 5604 5605 } 5606 5607 static void 5608 get_link_stats(const char *link, pktsum_t *stats) 5609 { 5610 kstat_ctl_t *kcp; 5611 kstat_t *ksp; 5612 5613 bzero(stats, sizeof (*stats)); 5614 5615 if ((kcp = kstat_open()) == NULL) { 5616 warn("kstat_open operation failed"); 5617 return; 5618 } 5619 5620 ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL); 5621 5622 if (ksp != NULL) 5623 dladm_get_stats(kcp, ksp, stats); 5624 5625 (void) kstat_close(kcp); 5626 } 5627 5628 static int 5629 query_kstat(char *module, int instance, const char *name, const char *stat, 5630 uint8_t type, void *val) 5631 { 5632 kstat_ctl_t *kcp; 5633 kstat_t *ksp; 5634 5635 if ((kcp = kstat_open()) == NULL) { 5636 warn("kstat open operation failed"); 5637 return (-1); 5638 } 5639 5640 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 5641 /* 5642 * The kstat query could fail if the underlying MAC 5643 * driver was already detached. 5644 */ 5645 goto bail; 5646 } 5647 5648 if (kstat_read(kcp, ksp, NULL) == -1) { 5649 warn("kstat read failed"); 5650 goto bail; 5651 } 5652 5653 if (dladm_kstat_value(ksp, stat, type, val) < 0) 5654 goto bail; 5655 5656 (void) kstat_close(kcp); 5657 return (0); 5658 5659 bail: 5660 (void) kstat_close(kcp); 5661 return (-1); 5662 } 5663 5664 static int 5665 get_one_kstat(const char *name, const char *stat, uint8_t type, 5666 void *val, boolean_t islink) 5667 { 5668 char module[DLPI_LINKNAME_MAX]; 5669 uint_t instance; 5670 5671 if (islink) { 5672 return (query_kstat("link", 0, name, stat, type, val)); 5673 } else { 5674 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS) 5675 return (-1); 5676 5677 return (query_kstat(module, instance, "mac", stat, type, val)); 5678 } 5679 } 5680 5681 static uint64_t 5682 get_ifspeed(const char *name, boolean_t islink) 5683 { 5684 uint64_t ifspeed = 0; 5685 5686 (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64, 5687 &ifspeed, islink); 5688 5689 return (ifspeed); 5690 } 5691 5692 static const char * 5693 get_linkstate(const char *name, boolean_t islink, char *buf) 5694 { 5695 link_state_t linkstate; 5696 5697 if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32, 5698 &linkstate, islink) != 0) { 5699 (void) strlcpy(buf, "?", DLADM_STRSIZE); 5700 return (buf); 5701 } 5702 return (dladm_linkstate2str(linkstate, buf)); 5703 } 5704 5705 static const char * 5706 get_linkduplex(const char *name, boolean_t islink, char *buf) 5707 { 5708 link_duplex_t linkduplex; 5709 5710 if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32, 5711 &linkduplex, islink) != 0) { 5712 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 5713 return (buf); 5714 } 5715 5716 return (dladm_linkduplex2str(linkduplex, buf)); 5717 } 5718 5719 static int 5720 parse_wifi_fields(char *str, ofmt_handle_t *ofmt, uint_t cmdtype, 5721 boolean_t parsable) 5722 { 5723 ofmt_field_t *template, *of; 5724 ofmt_cb_t *fn; 5725 ofmt_status_t oferr; 5726 5727 if (cmdtype == WIFI_CMD_SCAN) { 5728 template = wifi_common_fields; 5729 if (str == NULL) 5730 str = def_scan_wifi_fields; 5731 if (strcasecmp(str, "all") == 0) 5732 str = all_scan_wifi_fields; 5733 fn = print_wlan_attr_cb; 5734 } else if (cmdtype == WIFI_CMD_SHOW) { 5735 bcopy(wifi_common_fields, &wifi_show_fields[2], 5736 sizeof (wifi_common_fields)); 5737 template = wifi_show_fields; 5738 if (str == NULL) 5739 str = def_show_wifi_fields; 5740 if (strcasecmp(str, "all") == 0) 5741 str = all_show_wifi_fields; 5742 fn = print_link_attr_cb; 5743 } else { 5744 return (-1); 5745 } 5746 5747 for (of = template; of->of_name != NULL; of++) { 5748 if (of->of_cb == NULL) 5749 of->of_cb = fn; 5750 } 5751 5752 oferr = ofmt_open(str, template, (parsable ? OFMT_PARSABLE : 0), 5753 0, ofmt); 5754 dladm_ofmt_check(oferr, parsable, *ofmt); 5755 return (0); 5756 } 5757 5758 typedef struct print_wifi_state { 5759 char *ws_link; 5760 boolean_t ws_parsable; 5761 boolean_t ws_header; 5762 ofmt_handle_t ws_ofmt; 5763 } print_wifi_state_t; 5764 5765 typedef struct wlan_scan_args_s { 5766 print_wifi_state_t *ws_state; 5767 void *ws_attr; 5768 } wlan_scan_args_t; 5769 5770 static boolean_t 5771 print_wlan_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 5772 { 5773 wlan_scan_args_t *w = ofarg->ofmt_cbarg; 5774 print_wifi_state_t *statep = w->ws_state; 5775 dladm_wlan_attr_t *attrp = w->ws_attr; 5776 char tmpbuf[DLADM_STRSIZE]; 5777 5778 if (ofarg->ofmt_id == 0) { 5779 (void) strlcpy(buf, (char *)statep->ws_link, bufsize); 5780 return (B_TRUE); 5781 } 5782 5783 if ((ofarg->ofmt_id & attrp->wa_valid) == 0) 5784 return (B_TRUE); 5785 5786 switch (ofarg->ofmt_id) { 5787 case DLADM_WLAN_ATTR_ESSID: 5788 (void) dladm_wlan_essid2str(&attrp->wa_essid, tmpbuf); 5789 break; 5790 case DLADM_WLAN_ATTR_BSSID: 5791 (void) dladm_wlan_bssid2str(&attrp->wa_bssid, tmpbuf); 5792 break; 5793 case DLADM_WLAN_ATTR_SECMODE: 5794 (void) dladm_wlan_secmode2str(&attrp->wa_secmode, tmpbuf); 5795 break; 5796 case DLADM_WLAN_ATTR_STRENGTH: 5797 (void) dladm_wlan_strength2str(&attrp->wa_strength, tmpbuf); 5798 break; 5799 case DLADM_WLAN_ATTR_MODE: 5800 (void) dladm_wlan_mode2str(&attrp->wa_mode, tmpbuf); 5801 break; 5802 case DLADM_WLAN_ATTR_SPEED: 5803 (void) dladm_wlan_speed2str(&attrp->wa_speed, tmpbuf); 5804 (void) strlcat(tmpbuf, "Mb", sizeof (tmpbuf)); 5805 break; 5806 case DLADM_WLAN_ATTR_AUTH: 5807 (void) dladm_wlan_auth2str(&attrp->wa_auth, tmpbuf); 5808 break; 5809 case DLADM_WLAN_ATTR_BSSTYPE: 5810 (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, tmpbuf); 5811 break; 5812 } 5813 (void) strlcpy(buf, tmpbuf, bufsize); 5814 5815 return (B_TRUE); 5816 } 5817 5818 static boolean_t 5819 print_scan_results(void *arg, dladm_wlan_attr_t *attrp) 5820 { 5821 print_wifi_state_t *statep = arg; 5822 wlan_scan_args_t warg; 5823 5824 bzero(&warg, sizeof (warg)); 5825 warg.ws_state = statep; 5826 warg.ws_attr = attrp; 5827 ofmt_print(statep->ws_ofmt, &warg); 5828 return (B_TRUE); 5829 } 5830 5831 static int 5832 scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5833 { 5834 print_wifi_state_t *statep = arg; 5835 dladm_status_t status; 5836 char link[MAXLINKNAMELEN]; 5837 5838 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 5839 sizeof (link))) != DLADM_STATUS_OK) { 5840 return (DLADM_WALK_CONTINUE); 5841 } 5842 5843 statep->ws_link = link; 5844 status = dladm_wlan_scan(dh, linkid, statep, print_scan_results); 5845 if (status != DLADM_STATUS_OK) 5846 die_dlerr(status, "cannot scan link '%s'", statep->ws_link); 5847 5848 return (DLADM_WALK_CONTINUE); 5849 } 5850 5851 static boolean_t 5852 print_wifi_status_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 5853 { 5854 static char tmpbuf[DLADM_STRSIZE]; 5855 wlan_scan_args_t *w = ofarg->ofmt_cbarg; 5856 dladm_wlan_linkattr_t *attrp = w->ws_attr; 5857 5858 if ((ofarg->ofmt_id & attrp->la_valid) != 0) { 5859 (void) dladm_wlan_linkstatus2str(&attrp->la_status, tmpbuf); 5860 (void) strlcpy(buf, tmpbuf, bufsize); 5861 } 5862 return (B_TRUE); 5863 } 5864 5865 static boolean_t 5866 print_link_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 5867 { 5868 wlan_scan_args_t *w = ofarg->ofmt_cbarg, w1; 5869 print_wifi_state_t *statep = w->ws_state; 5870 dladm_wlan_linkattr_t *attrp = w->ws_attr; 5871 5872 bzero(&w1, sizeof (w1)); 5873 w1.ws_state = statep; 5874 w1.ws_attr = &attrp->la_wlan_attr; 5875 ofarg->ofmt_cbarg = &w1; 5876 return (print_wlan_attr_cb(ofarg, buf, bufsize)); 5877 } 5878 5879 static int 5880 show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5881 { 5882 print_wifi_state_t *statep = arg; 5883 dladm_wlan_linkattr_t attr; 5884 dladm_status_t status; 5885 char link[MAXLINKNAMELEN]; 5886 wlan_scan_args_t warg; 5887 5888 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 5889 sizeof (link))) != DLADM_STATUS_OK) { 5890 return (DLADM_WALK_CONTINUE); 5891 } 5892 5893 /* dladm_wlan_get_linkattr() memsets attr with 0 */ 5894 status = dladm_wlan_get_linkattr(dh, linkid, &attr); 5895 if (status != DLADM_STATUS_OK) 5896 die_dlerr(status, "cannot get link attributes for %s", link); 5897 5898 statep->ws_link = link; 5899 5900 bzero(&warg, sizeof (warg)); 5901 warg.ws_state = statep; 5902 warg.ws_attr = &attr; 5903 ofmt_print(statep->ws_ofmt, &warg); 5904 return (DLADM_WALK_CONTINUE); 5905 } 5906 5907 static void 5908 do_display_wifi(int argc, char **argv, int cmd, const char *use) 5909 { 5910 int option; 5911 char *fields_str = NULL; 5912 int (*callback)(dladm_handle_t, datalink_id_t, void *); 5913 print_wifi_state_t state; 5914 datalink_id_t linkid = DATALINK_ALL_LINKID; 5915 dladm_status_t status; 5916 5917 if (cmd == WIFI_CMD_SCAN) 5918 callback = scan_wifi; 5919 else if (cmd == WIFI_CMD_SHOW) 5920 callback = show_wifi; 5921 else 5922 return; 5923 5924 state.ws_parsable = B_FALSE; 5925 state.ws_header = B_TRUE; 5926 opterr = 0; 5927 while ((option = getopt_long(argc, argv, ":o:p", 5928 wifi_longopts, NULL)) != -1) { 5929 switch (option) { 5930 case 'o': 5931 fields_str = optarg; 5932 break; 5933 case 'p': 5934 state.ws_parsable = B_TRUE; 5935 break; 5936 default: 5937 die_opterr(optopt, option, use); 5938 } 5939 } 5940 5941 if (state.ws_parsable && fields_str == NULL) 5942 die("-p requires -o"); 5943 5944 if (state.ws_parsable && strcasecmp(fields_str, "all") == 0) 5945 die("\"-o all\" is invalid with -p"); 5946 5947 if (optind == (argc - 1)) { 5948 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5949 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5950 die_dlerr(status, "link %s is not valid", argv[optind]); 5951 } 5952 } else if (optind != argc) { 5953 usage(); 5954 } 5955 5956 if (parse_wifi_fields(fields_str, &state.ws_ofmt, cmd, 5957 state.ws_parsable) < 0) 5958 die("invalid field(s) specified"); 5959 5960 if (linkid == DATALINK_ALL_LINKID) { 5961 (void) dladm_walk_datalink_id(callback, handle, &state, 5962 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 5963 DL_WIFI, DLADM_OPT_ACTIVE); 5964 } else { 5965 (void) (*callback)(handle, linkid, &state); 5966 } 5967 ofmt_close(state.ws_ofmt); 5968 } 5969 5970 static void 5971 do_scan_wifi(int argc, char **argv, const char *use) 5972 { 5973 do_display_wifi(argc, argv, WIFI_CMD_SCAN, use); 5974 } 5975 5976 static void 5977 do_show_wifi(int argc, char **argv, const char *use) 5978 { 5979 do_display_wifi(argc, argv, WIFI_CMD_SHOW, use); 5980 } 5981 5982 typedef struct wlan_count_attr { 5983 uint_t wc_count; 5984 datalink_id_t wc_linkid; 5985 } wlan_count_attr_t; 5986 5987 /* ARGSUSED */ 5988 static int 5989 do_count_wlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5990 { 5991 wlan_count_attr_t *cp = arg; 5992 5993 if (cp->wc_count == 0) 5994 cp->wc_linkid = linkid; 5995 cp->wc_count++; 5996 return (DLADM_WALK_CONTINUE); 5997 } 5998 5999 static int 6000 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) 6001 { 6002 uint_t i; 6003 dladm_wlan_key_t *wk; 6004 int nfields = 1; 6005 char *field, *token, *lasts = NULL, c; 6006 6007 token = str; 6008 while ((c = *token++) != NULL) { 6009 if (c == ',') 6010 nfields++; 6011 } 6012 token = strdup(str); 6013 if (token == NULL) 6014 return (-1); 6015 6016 wk = malloc(nfields * sizeof (dladm_wlan_key_t)); 6017 if (wk == NULL) 6018 goto fail; 6019 6020 token = str; 6021 for (i = 0; i < nfields; i++) { 6022 char *s; 6023 dladm_secobj_class_t class; 6024 dladm_status_t status; 6025 6026 field = strtok_r(token, ",", &lasts); 6027 token = NULL; 6028 6029 (void) strlcpy(wk[i].wk_name, field, 6030 DLADM_WLAN_MAX_KEYNAME_LEN); 6031 6032 wk[i].wk_idx = 1; 6033 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 6034 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 6035 goto fail; 6036 6037 wk[i].wk_idx = (uint_t)(s[1] - '0'); 6038 *s = '\0'; 6039 } 6040 wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN; 6041 6042 status = dladm_get_secobj(handle, wk[i].wk_name, &class, 6043 wk[i].wk_val, &wk[i].wk_len, 0); 6044 if (status != DLADM_STATUS_OK) { 6045 if (status == DLADM_STATUS_NOTFOUND) { 6046 status = dladm_get_secobj(handle, wk[i].wk_name, 6047 &class, wk[i].wk_val, &wk[i].wk_len, 6048 DLADM_OPT_PERSIST); 6049 } 6050 if (status != DLADM_STATUS_OK) 6051 goto fail; 6052 } 6053 wk[i].wk_class = class; 6054 } 6055 *keys = wk; 6056 *key_countp = i; 6057 free(token); 6058 return (0); 6059 fail: 6060 free(wk); 6061 free(token); 6062 return (-1); 6063 } 6064 6065 static void 6066 do_connect_wifi(int argc, char **argv, const char *use) 6067 { 6068 int option; 6069 dladm_wlan_attr_t attr, *attrp; 6070 dladm_status_t status = DLADM_STATUS_OK; 6071 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 6072 datalink_id_t linkid = DATALINK_ALL_LINKID; 6073 dladm_wlan_key_t *keys = NULL; 6074 uint_t key_count = 0; 6075 uint_t flags = 0; 6076 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 6077 char buf[DLADM_STRSIZE]; 6078 6079 opterr = 0; 6080 (void) memset(&attr, 0, sizeof (attr)); 6081 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 6082 wifi_longopts, NULL)) != -1) { 6083 switch (option) { 6084 case 'e': 6085 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 6086 if (status != DLADM_STATUS_OK) 6087 die("invalid ESSID '%s'", optarg); 6088 6089 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 6090 /* 6091 * Try to connect without doing a scan. 6092 */ 6093 flags |= DLADM_WLAN_CONNECT_NOSCAN; 6094 break; 6095 case 'i': 6096 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 6097 if (status != DLADM_STATUS_OK) 6098 die("invalid BSSID %s", optarg); 6099 6100 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 6101 break; 6102 case 'a': 6103 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 6104 if (status != DLADM_STATUS_OK) 6105 die("invalid authentication mode '%s'", optarg); 6106 6107 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 6108 break; 6109 case 'm': 6110 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 6111 if (status != DLADM_STATUS_OK) 6112 die("invalid mode '%s'", optarg); 6113 6114 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 6115 break; 6116 case 'b': 6117 if ((status = dladm_wlan_str2bsstype(optarg, 6118 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 6119 die("invalid bsstype '%s'", optarg); 6120 } 6121 6122 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 6123 break; 6124 case 's': 6125 if ((status = dladm_wlan_str2secmode(optarg, 6126 &attr.wa_secmode)) != DLADM_STATUS_OK) { 6127 die("invalid security mode '%s'", optarg); 6128 } 6129 6130 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 6131 break; 6132 case 'k': 6133 if (parse_wlan_keys(optarg, &keys, &key_count) < 0) 6134 die("invalid key(s) '%s'", optarg); 6135 6136 if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP) 6137 keysecmode = DLADM_WLAN_SECMODE_WEP; 6138 else 6139 keysecmode = DLADM_WLAN_SECMODE_WPA; 6140 break; 6141 case 'T': 6142 if (strcasecmp(optarg, "forever") == 0) { 6143 timeout = -1; 6144 break; 6145 } 6146 if (!str2int(optarg, &timeout) || timeout < 0) 6147 die("invalid timeout value '%s'", optarg); 6148 break; 6149 case 'c': 6150 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 6151 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 6152 break; 6153 default: 6154 die_opterr(optopt, option, use); 6155 break; 6156 } 6157 } 6158 6159 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 6160 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) { 6161 die("key required for security mode '%s'", 6162 dladm_wlan_secmode2str(&attr.wa_secmode, buf)); 6163 } 6164 } else { 6165 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 6166 attr.wa_secmode != keysecmode) 6167 die("incompatible -s and -k options"); 6168 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 6169 attr.wa_secmode = keysecmode; 6170 } 6171 6172 if (optind == (argc - 1)) { 6173 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6174 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 6175 die_dlerr(status, "link %s is not valid", argv[optind]); 6176 } 6177 } else if (optind != argc) { 6178 usage(); 6179 } 6180 6181 if (linkid == DATALINK_ALL_LINKID) { 6182 wlan_count_attr_t wcattr; 6183 6184 wcattr.wc_linkid = DATALINK_INVALID_LINKID; 6185 wcattr.wc_count = 0; 6186 (void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr, 6187 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 6188 DL_WIFI, DLADM_OPT_ACTIVE); 6189 if (wcattr.wc_count == 0) { 6190 die("no wifi links are available"); 6191 } else if (wcattr.wc_count > 1) { 6192 die("link name is required when more than one wifi " 6193 "link is available"); 6194 } 6195 linkid = wcattr.wc_linkid; 6196 } 6197 attrp = (attr.wa_valid == 0) ? NULL : &attr; 6198 again: 6199 if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys, 6200 key_count, flags)) != DLADM_STATUS_OK) { 6201 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 6202 /* 6203 * Try again with scanning and filtering. 6204 */ 6205 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 6206 goto again; 6207 } 6208 6209 if (status == DLADM_STATUS_NOTFOUND) { 6210 if (attr.wa_valid == 0) { 6211 die("no wifi networks are available"); 6212 } else { 6213 die("no wifi networks with the specified " 6214 "criteria are available"); 6215 } 6216 } 6217 die_dlerr(status, "cannot connect"); 6218 } 6219 free(keys); 6220 } 6221 6222 /* ARGSUSED */ 6223 static int 6224 do_all_disconnect_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6225 { 6226 dladm_status_t status; 6227 6228 status = dladm_wlan_disconnect(dh, linkid); 6229 if (status != DLADM_STATUS_OK) 6230 warn_dlerr(status, "cannot disconnect link"); 6231 6232 return (DLADM_WALK_CONTINUE); 6233 } 6234 6235 static void 6236 do_disconnect_wifi(int argc, char **argv, const char *use) 6237 { 6238 int option; 6239 datalink_id_t linkid = DATALINK_ALL_LINKID; 6240 boolean_t all_links = B_FALSE; 6241 dladm_status_t status; 6242 wlan_count_attr_t wcattr; 6243 6244 opterr = 0; 6245 while ((option = getopt_long(argc, argv, ":a", 6246 wifi_longopts, NULL)) != -1) { 6247 switch (option) { 6248 case 'a': 6249 all_links = B_TRUE; 6250 break; 6251 default: 6252 die_opterr(optopt, option, use); 6253 break; 6254 } 6255 } 6256 6257 if (optind == (argc - 1)) { 6258 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6259 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 6260 die_dlerr(status, "link %s is not valid", argv[optind]); 6261 } 6262 } else if (optind != argc) { 6263 usage(); 6264 } 6265 6266 if (linkid == DATALINK_ALL_LINKID) { 6267 if (!all_links) { 6268 wcattr.wc_linkid = linkid; 6269 wcattr.wc_count = 0; 6270 (void) dladm_walk_datalink_id(do_count_wlan, handle, 6271 &wcattr, 6272 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 6273 DL_WIFI, DLADM_OPT_ACTIVE); 6274 if (wcattr.wc_count == 0) { 6275 die("no wifi links are available"); 6276 } else if (wcattr.wc_count > 1) { 6277 die("link name is required when more than " 6278 "one wifi link is available"); 6279 } 6280 linkid = wcattr.wc_linkid; 6281 } else { 6282 (void) dladm_walk_datalink_id(do_all_disconnect_wifi, 6283 handle, NULL, 6284 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 6285 DL_WIFI, DLADM_OPT_ACTIVE); 6286 return; 6287 } 6288 } 6289 status = dladm_wlan_disconnect(handle, linkid); 6290 if (status != DLADM_STATUS_OK) 6291 die_dlerr(status, "cannot disconnect"); 6292 } 6293 6294 static void 6295 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, 6296 const char *propname, dladm_prop_type_t type, const char *format, 6297 char **pptr) 6298 { 6299 int i; 6300 char *ptr, *lim; 6301 char buf[DLADM_STRSIZE]; 6302 char *unknown = "--", *notsup = ""; 6303 char **propvals = statep->ls_propvals; 6304 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 6305 dladm_status_t status; 6306 6307 status = dladm_get_linkprop(handle, linkid, type, propname, propvals, 6308 &valcnt); 6309 if (status != DLADM_STATUS_OK) { 6310 if (status == DLADM_STATUS_TEMPONLY) { 6311 if (type == DLADM_PROP_VAL_MODIFIABLE && 6312 statep->ls_persist) { 6313 valcnt = 1; 6314 propvals = &unknown; 6315 } else { 6316 statep->ls_status = status; 6317 statep->ls_retstatus = status; 6318 return; 6319 } 6320 } else if (status == DLADM_STATUS_NOTSUP || 6321 statep->ls_persist) { 6322 valcnt = 1; 6323 if (type == DLADM_PROP_VAL_CURRENT || 6324 type == DLADM_PROP_VAL_PERM) 6325 propvals = &unknown; 6326 else 6327 propvals = ¬sup; 6328 } else if (status == DLADM_STATUS_NOTDEFINED) { 6329 propvals = ¬sup; /* STR_UNDEF_VAL */ 6330 } else { 6331 if (statep->ls_proplist && 6332 statep->ls_status == DLADM_STATUS_OK) { 6333 warn_dlerr(status, 6334 "cannot get link property '%s' for %s", 6335 propname, statep->ls_link); 6336 } 6337 statep->ls_status = status; 6338 statep->ls_retstatus = status; 6339 return; 6340 } 6341 } 6342 6343 statep->ls_status = DLADM_STATUS_OK; 6344 6345 buf[0] = '\0'; 6346 ptr = buf; 6347 lim = buf + DLADM_STRSIZE; 6348 for (i = 0; i < valcnt; i++) { 6349 if (propvals[i][0] == '\0' && !statep->ls_parsable) 6350 ptr += snprintf(ptr, lim - ptr, "--,"); 6351 else 6352 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 6353 if (ptr >= lim) 6354 break; 6355 } 6356 if (valcnt > 0) 6357 buf[strlen(buf) - 1] = '\0'; 6358 6359 lim = statep->ls_line + MAX_PROP_LINE; 6360 if (statep->ls_parsable) { 6361 *pptr += snprintf(*pptr, lim - *pptr, 6362 "%s", buf); 6363 } else { 6364 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 6365 } 6366 } 6367 6368 static boolean_t 6369 print_linkprop_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 6370 { 6371 linkprop_args_t *arg = ofarg->ofmt_cbarg; 6372 char *propname = arg->ls_propname; 6373 show_linkprop_state_t *statep = arg->ls_state; 6374 char *ptr = statep->ls_line; 6375 char *lim = ptr + MAX_PROP_LINE; 6376 datalink_id_t linkid = arg->ls_linkid; 6377 6378 switch (ofarg->ofmt_id) { 6379 case LINKPROP_LINK: 6380 (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); 6381 break; 6382 case LINKPROP_PROPERTY: 6383 (void) snprintf(ptr, lim - ptr, "%s", propname); 6384 break; 6385 case LINKPROP_VALUE: 6386 print_linkprop(linkid, statep, propname, 6387 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 6388 DLADM_PROP_VAL_CURRENT, "%s", &ptr); 6389 /* 6390 * If we failed to query the link property, for example, query 6391 * the persistent value of a non-persistable link property, 6392 * simply skip the output. 6393 */ 6394 if (statep->ls_status != DLADM_STATUS_OK) 6395 goto skip; 6396 ptr = statep->ls_line; 6397 break; 6398 case LINKPROP_PERM: 6399 print_linkprop(linkid, statep, propname, 6400 DLADM_PROP_VAL_PERM, "%s", &ptr); 6401 if (statep->ls_status != DLADM_STATUS_OK) 6402 goto skip; 6403 ptr = statep->ls_line; 6404 break; 6405 case LINKPROP_DEFAULT: 6406 print_linkprop(linkid, statep, propname, 6407 DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 6408 if (statep->ls_status != DLADM_STATUS_OK) 6409 goto skip; 6410 ptr = statep->ls_line; 6411 break; 6412 case LINKPROP_POSSIBLE: 6413 print_linkprop(linkid, statep, propname, 6414 DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 6415 if (statep->ls_status != DLADM_STATUS_OK) 6416 goto skip; 6417 ptr = statep->ls_line; 6418 break; 6419 default: 6420 die("invalid input"); 6421 break; 6422 } 6423 (void) strlcpy(buf, ptr, bufsize); 6424 return (B_TRUE); 6425 skip: 6426 return ((statep->ls_status == DLADM_STATUS_OK) ? 6427 B_TRUE : B_FALSE); 6428 } 6429 6430 static boolean_t 6431 linkprop_is_supported(datalink_id_t linkid, const char *propname, 6432 show_linkprop_state_t *statep) 6433 { 6434 dladm_status_t status; 6435 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 6436 6437 /* if used with -p flag, always print output */ 6438 if (statep->ls_proplist != NULL) 6439 return (B_TRUE); 6440 6441 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_DEFAULT, 6442 propname, statep->ls_propvals, &valcnt); 6443 6444 if (status == DLADM_STATUS_OK) 6445 return (B_TRUE); 6446 6447 /* 6448 * A system wide default value is not available for the 6449 * property. Check if current value can be retrieved. 6450 */ 6451 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT, 6452 propname, statep->ls_propvals, &valcnt); 6453 6454 return (status == DLADM_STATUS_OK); 6455 } 6456 6457 /* ARGSUSED */ 6458 static int 6459 show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname, 6460 void *arg) 6461 { 6462 show_linkprop_state_t *statep = arg; 6463 linkprop_args_t ls_arg; 6464 6465 bzero(&ls_arg, sizeof (ls_arg)); 6466 ls_arg.ls_state = statep; 6467 ls_arg.ls_propname = (char *)propname; 6468 ls_arg.ls_linkid = linkid; 6469 6470 /* 6471 * This will need to be fixed when kernel interfaces are added 6472 * to enable walking of all known private properties. For now, 6473 * we are limited to walking persistent private properties only. 6474 */ 6475 if ((propname[0] == '_') && !statep->ls_persist && 6476 (statep->ls_proplist == NULL)) 6477 return (DLADM_WALK_CONTINUE); 6478 if (!statep->ls_parsable && 6479 !linkprop_is_supported(linkid, propname, statep)) 6480 return (DLADM_WALK_CONTINUE); 6481 6482 ofmt_print(statep->ls_ofmt, &ls_arg); 6483 6484 return (DLADM_WALK_CONTINUE); 6485 } 6486 6487 static void 6488 do_show_linkprop(int argc, char **argv, const char *use) 6489 { 6490 int option; 6491 char propstr[DLADM_STRSIZE]; 6492 dladm_arg_list_t *proplist = NULL; 6493 datalink_id_t linkid = DATALINK_ALL_LINKID; 6494 show_linkprop_state_t state; 6495 uint32_t flags = DLADM_OPT_ACTIVE; 6496 dladm_status_t status; 6497 char *fields_str = NULL; 6498 ofmt_handle_t ofmt; 6499 ofmt_status_t oferr; 6500 uint_t ofmtflags = 0; 6501 6502 bzero(propstr, DLADM_STRSIZE); 6503 opterr = 0; 6504 state.ls_propvals = NULL; 6505 state.ls_line = NULL; 6506 state.ls_parsable = B_FALSE; 6507 state.ls_persist = B_FALSE; 6508 state.ls_header = B_TRUE; 6509 state.ls_retstatus = DLADM_STATUS_OK; 6510 6511 while ((option = getopt_long(argc, argv, ":p:cPo:", 6512 prop_longopts, NULL)) != -1) { 6513 switch (option) { 6514 case 'p': 6515 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 6516 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 6517 DLADM_STRSIZE) 6518 die("property list too long '%s'", propstr); 6519 break; 6520 case 'c': 6521 state.ls_parsable = B_TRUE; 6522 break; 6523 case 'P': 6524 state.ls_persist = B_TRUE; 6525 flags = DLADM_OPT_PERSIST; 6526 break; 6527 case 'o': 6528 fields_str = optarg; 6529 break; 6530 default: 6531 die_opterr(optopt, option, use); 6532 break; 6533 } 6534 } 6535 6536 if (optind == (argc - 1)) { 6537 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6538 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 6539 die_dlerr(status, "link %s is not valid", argv[optind]); 6540 } 6541 } else if (optind != argc) { 6542 usage(); 6543 } 6544 6545 if (dladm_parse_link_props(propstr, &proplist, B_TRUE) 6546 != DLADM_STATUS_OK) 6547 die("invalid link properties specified"); 6548 state.ls_proplist = proplist; 6549 state.ls_status = DLADM_STATUS_OK; 6550 6551 if (state.ls_parsable) 6552 ofmtflags |= OFMT_PARSABLE; 6553 else 6554 ofmtflags |= OFMT_WRAP; 6555 6556 oferr = ofmt_open(fields_str, linkprop_fields, ofmtflags, 0, &ofmt); 6557 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 6558 state.ls_ofmt = ofmt; 6559 6560 if (linkid == DATALINK_ALL_LINKID) { 6561 (void) dladm_walk_datalink_id(show_linkprop_onelink, handle, 6562 &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 6563 } else { 6564 (void) show_linkprop_onelink(handle, linkid, &state); 6565 } 6566 ofmt_close(ofmt); 6567 dladm_free_props(proplist); 6568 6569 if (state.ls_retstatus != DLADM_STATUS_OK) { 6570 dladm_close(handle); 6571 exit(EXIT_FAILURE); 6572 } 6573 } 6574 6575 static int 6576 show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg) 6577 { 6578 int i; 6579 char *buf; 6580 uint32_t flags; 6581 dladm_arg_list_t *proplist = NULL; 6582 show_linkprop_state_t *statep = arg; 6583 dlpi_handle_t dh = NULL; 6584 6585 statep->ls_status = DLADM_STATUS_OK; 6586 6587 if (dladm_datalink_id2info(hdl, linkid, &flags, NULL, NULL, 6588 statep->ls_link, MAXLINKNAMELEN) != DLADM_STATUS_OK) { 6589 statep->ls_status = DLADM_STATUS_NOTFOUND; 6590 return (DLADM_WALK_CONTINUE); 6591 } 6592 6593 if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) || 6594 (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) { 6595 statep->ls_status = DLADM_STATUS_BADARG; 6596 return (DLADM_WALK_CONTINUE); 6597 } 6598 6599 proplist = statep->ls_proplist; 6600 6601 /* 6602 * When some WiFi links are opened for the first time, their hardware 6603 * automatically scans for APs and does other slow operations. Thus, 6604 * if there are no open links, the retrieval of link properties 6605 * (below) will proceed slowly unless we hold the link open. 6606 * 6607 * Note that failure of dlpi_open() does not necessarily mean invalid 6608 * link properties, because dlpi_open() may fail because of incorrect 6609 * autopush configuration. Therefore, we ingore the return value of 6610 * dlpi_open(). 6611 */ 6612 if (!statep->ls_persist) 6613 (void) dlpi_open(statep->ls_link, &dh, 0); 6614 6615 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 6616 DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 6617 if (buf == NULL) 6618 die("insufficient memory"); 6619 6620 statep->ls_propvals = (char **)(void *)buf; 6621 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 6622 statep->ls_propvals[i] = buf + 6623 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 6624 i * DLADM_PROP_VAL_MAX; 6625 } 6626 statep->ls_line = buf + 6627 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 6628 6629 if (proplist != NULL) { 6630 for (i = 0; i < proplist->al_count; i++) { 6631 (void) show_linkprop(hdl, linkid, 6632 proplist->al_info[i].ai_name, statep); 6633 } 6634 } else { 6635 (void) dladm_walk_linkprop(hdl, linkid, statep, 6636 show_linkprop); 6637 } 6638 if (dh != NULL) 6639 dlpi_close(dh); 6640 free(buf); 6641 return (DLADM_WALK_CONTINUE); 6642 } 6643 6644 static int 6645 reset_one_linkprop(dladm_handle_t dh, datalink_id_t linkid, 6646 const char *propname, void *arg) 6647 { 6648 set_linkprop_state_t *statep = arg; 6649 dladm_status_t status; 6650 6651 status = dladm_set_linkprop(dh, linkid, propname, NULL, 0, 6652 DLADM_OPT_ACTIVE | (statep->ls_temp ? 0 : DLADM_OPT_PERSIST)); 6653 if (status != DLADM_STATUS_OK && 6654 status != DLADM_STATUS_PROPRDONLY && 6655 status != DLADM_STATUS_NOTSUP) { 6656 warn_dlerr(status, "cannot reset link property '%s' on '%s'", 6657 propname, statep->ls_name); 6658 statep->ls_status = status; 6659 } 6660 6661 return (DLADM_WALK_CONTINUE); 6662 } 6663 6664 static void 6665 set_linkprop(int argc, char **argv, boolean_t reset, const char *use) 6666 { 6667 int i, option; 6668 char errmsg[DLADM_STRSIZE]; 6669 char *altroot = NULL; 6670 datalink_id_t linkid; 6671 boolean_t temp = B_FALSE; 6672 dladm_status_t status = DLADM_STATUS_OK; 6673 char propstr[DLADM_STRSIZE]; 6674 dladm_arg_list_t *proplist = NULL; 6675 6676 opterr = 0; 6677 bzero(propstr, DLADM_STRSIZE); 6678 6679 while ((option = getopt_long(argc, argv, ":p:R:t", 6680 prop_longopts, NULL)) != -1) { 6681 switch (option) { 6682 case 'p': 6683 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 6684 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 6685 DLADM_STRSIZE) 6686 die("property list too long '%s'", propstr); 6687 break; 6688 case 't': 6689 temp = B_TRUE; 6690 break; 6691 case 'R': 6692 altroot = optarg; 6693 break; 6694 default: 6695 die_opterr(optopt, option, use); 6696 6697 } 6698 } 6699 6700 /* get link name (required last argument) */ 6701 if (optind != (argc - 1)) 6702 usage(); 6703 6704 if (dladm_parse_link_props(propstr, &proplist, reset) != 6705 DLADM_STATUS_OK) 6706 die("invalid link properties specified"); 6707 6708 if (proplist == NULL && !reset) 6709 die("link property must be specified"); 6710 6711 if (altroot != NULL) { 6712 dladm_free_props(proplist); 6713 altroot_cmd(altroot, argc, argv); 6714 } 6715 6716 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 6717 NULL); 6718 if (status != DLADM_STATUS_OK) 6719 die_dlerr(status, "link %s is not valid", argv[optind]); 6720 6721 if (proplist == NULL) { 6722 set_linkprop_state_t state; 6723 6724 state.ls_name = argv[optind]; 6725 state.ls_reset = reset; 6726 state.ls_temp = temp; 6727 state.ls_status = DLADM_STATUS_OK; 6728 6729 (void) dladm_walk_linkprop(handle, linkid, &state, 6730 reset_one_linkprop); 6731 6732 status = state.ls_status; 6733 goto done; 6734 } 6735 6736 for (i = 0; i < proplist->al_count; i++) { 6737 dladm_arg_info_t *aip = &proplist->al_info[i]; 6738 char **val; 6739 uint_t count; 6740 6741 if (reset) { 6742 val = NULL; 6743 count = 0; 6744 } else { 6745 val = aip->ai_val; 6746 count = aip->ai_count; 6747 if (count == 0) { 6748 warn("no value specified for '%s'", 6749 aip->ai_name); 6750 status = DLADM_STATUS_BADARG; 6751 continue; 6752 } 6753 } 6754 status = dladm_set_linkprop(handle, linkid, aip->ai_name, val, 6755 count, DLADM_OPT_ACTIVE | (temp ? 0 : DLADM_OPT_PERSIST)); 6756 switch (status) { 6757 case DLADM_STATUS_OK: 6758 break; 6759 case DLADM_STATUS_NOTFOUND: 6760 warn("invalid link property '%s'", aip->ai_name); 6761 break; 6762 case DLADM_STATUS_BADVAL: { 6763 int j; 6764 char *ptr, *lim; 6765 char **propvals = NULL; 6766 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 6767 dladm_status_t s; 6768 6769 ptr = malloc((sizeof (char *) + 6770 DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 6771 MAX_PROP_LINE); 6772 6773 propvals = (char **)(void *)ptr; 6774 if (propvals == NULL) 6775 die("insufficient memory"); 6776 6777 for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 6778 propvals[j] = ptr + sizeof (char *) * 6779 DLADM_MAX_PROP_VALCNT + 6780 j * DLADM_PROP_VAL_MAX; 6781 } 6782 s = dladm_get_linkprop(handle, linkid, 6783 DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals, 6784 &valcnt); 6785 6786 if (s != DLADM_STATUS_OK) { 6787 warn_dlerr(status, "cannot set link property " 6788 "'%s' on '%s'", aip->ai_name, argv[optind]); 6789 free(propvals); 6790 break; 6791 } 6792 6793 ptr = errmsg; 6794 lim = ptr + DLADM_STRSIZE; 6795 *ptr = '\0'; 6796 for (j = 0; j < valcnt; j++) { 6797 ptr += snprintf(ptr, lim - ptr, "%s,", 6798 propvals[j]); 6799 if (ptr >= lim) 6800 break; 6801 } 6802 if (ptr > errmsg) { 6803 *(ptr - 1) = '\0'; 6804 warn("link property '%s' must be one of: %s", 6805 aip->ai_name, errmsg); 6806 } else 6807 warn("invalid link property '%s'", *val); 6808 free(propvals); 6809 break; 6810 } 6811 default: 6812 if (reset) { 6813 warn_dlerr(status, "cannot reset link property " 6814 "'%s' on '%s'", aip->ai_name, argv[optind]); 6815 } else { 6816 warn_dlerr(status, "cannot set link property " 6817 "'%s' on '%s'", aip->ai_name, argv[optind]); 6818 } 6819 break; 6820 } 6821 } 6822 done: 6823 dladm_free_props(proplist); 6824 if (status != DLADM_STATUS_OK) { 6825 dladm_close(handle); 6826 exit(EXIT_FAILURE); 6827 } 6828 } 6829 6830 static void 6831 do_set_linkprop(int argc, char **argv, const char *use) 6832 { 6833 set_linkprop(argc, argv, B_FALSE, use); 6834 } 6835 6836 static void 6837 do_reset_linkprop(int argc, char **argv, const char *use) 6838 { 6839 set_linkprop(argc, argv, B_TRUE, use); 6840 } 6841 6842 static int 6843 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 6844 dladm_secobj_class_t class) 6845 { 6846 int error = 0; 6847 6848 if (class == DLADM_SECOBJ_CLASS_WPA) { 6849 if (len < 8 || len > 63) 6850 return (EINVAL); 6851 (void) memcpy(obj_val, buf, len); 6852 *obj_lenp = len; 6853 return (error); 6854 } 6855 6856 if (class == DLADM_SECOBJ_CLASS_WEP) { 6857 switch (len) { 6858 case 5: /* ASCII key sizes */ 6859 case 13: 6860 (void) memcpy(obj_val, buf, len); 6861 *obj_lenp = len; 6862 break; 6863 case 10: /* Hex key sizes, not preceded by 0x */ 6864 case 26: 6865 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 6866 break; 6867 case 12: /* Hex key sizes, preceded by 0x */ 6868 case 28: 6869 if (strncmp(buf, "0x", 2) != 0) 6870 return (EINVAL); 6871 error = hexascii_to_octet(buf + 2, len - 2, 6872 obj_val, obj_lenp); 6873 break; 6874 default: 6875 return (EINVAL); 6876 } 6877 return (error); 6878 } 6879 6880 return (ENOENT); 6881 } 6882 6883 static void 6884 defersig(int sig) 6885 { 6886 signalled = sig; 6887 } 6888 6889 static int 6890 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 6891 { 6892 uint_t len = 0; 6893 int c; 6894 struct termios stored, current; 6895 void (*sigfunc)(int); 6896 6897 /* 6898 * Turn off echo -- but before we do so, defer SIGINT handling 6899 * so that a ^C doesn't leave the terminal corrupted. 6900 */ 6901 sigfunc = signal(SIGINT, defersig); 6902 (void) fflush(stdin); 6903 (void) tcgetattr(0, &stored); 6904 current = stored; 6905 current.c_lflag &= ~(ICANON|ECHO); 6906 current.c_cc[VTIME] = 0; 6907 current.c_cc[VMIN] = 1; 6908 (void) tcsetattr(0, TCSANOW, ¤t); 6909 again: 6910 if (try == 1) 6911 (void) printf(gettext("provide value for '%s': "), objname); 6912 else 6913 (void) printf(gettext("confirm value for '%s': "), objname); 6914 6915 (void) fflush(stdout); 6916 while (signalled == 0) { 6917 c = getchar(); 6918 if (c == '\n' || c == '\r') { 6919 if (len != 0) 6920 break; 6921 (void) putchar('\n'); 6922 goto again; 6923 } 6924 6925 buf[len++] = c; 6926 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 6927 break; 6928 (void) putchar('*'); 6929 } 6930 6931 (void) putchar('\n'); 6932 (void) fflush(stdin); 6933 6934 /* 6935 * Restore terminal setting and handle deferred signals. 6936 */ 6937 (void) tcsetattr(0, TCSANOW, &stored); 6938 6939 (void) signal(SIGINT, sigfunc); 6940 if (signalled != 0) 6941 (void) kill(getpid(), signalled); 6942 6943 return (len); 6944 } 6945 6946 static int 6947 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 6948 dladm_secobj_class_t class, FILE *filep) 6949 { 6950 int rval; 6951 uint_t len, len2; 6952 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 6953 6954 if (filep == NULL) { 6955 len = get_secobj_from_tty(1, obj_name, buf); 6956 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 6957 if (rval == 0) { 6958 len2 = get_secobj_from_tty(2, obj_name, buf2); 6959 if (len != len2 || memcmp(buf, buf2, len) != 0) 6960 rval = ENOTSUP; 6961 } 6962 return (rval); 6963 } else { 6964 for (;;) { 6965 if (fgets(buf, sizeof (buf), filep) == NULL) 6966 break; 6967 if (isspace(buf[0])) 6968 continue; 6969 6970 len = strlen(buf); 6971 if (buf[len - 1] == '\n') { 6972 buf[len - 1] = '\0'; 6973 len--; 6974 } 6975 break; 6976 } 6977 (void) fclose(filep); 6978 } 6979 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 6980 } 6981 6982 static boolean_t 6983 check_auth(const char *auth) 6984 { 6985 struct passwd *pw; 6986 6987 if ((pw = getpwuid(getuid())) == NULL) 6988 return (B_FALSE); 6989 6990 return (chkauthattr(auth, pw->pw_name) != 0); 6991 } 6992 6993 static void 6994 audit_secobj(char *auth, char *class, char *obj, 6995 boolean_t success, boolean_t create) 6996 { 6997 adt_session_data_t *ah; 6998 adt_event_data_t *event; 6999 au_event_t flag; 7000 char *errstr; 7001 7002 if (create) { 7003 flag = ADT_dladm_create_secobj; 7004 errstr = "ADT_dladm_create_secobj"; 7005 } else { 7006 flag = ADT_dladm_delete_secobj; 7007 errstr = "ADT_dladm_delete_secobj"; 7008 } 7009 7010 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 7011 die("adt_start_session: %s", strerror(errno)); 7012 7013 if ((event = adt_alloc_event(ah, flag)) == NULL) 7014 die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 7015 7016 /* fill in audit info */ 7017 if (create) { 7018 event->adt_dladm_create_secobj.auth_used = auth; 7019 event->adt_dladm_create_secobj.obj_class = class; 7020 event->adt_dladm_create_secobj.obj_name = obj; 7021 } else { 7022 event->adt_dladm_delete_secobj.auth_used = auth; 7023 event->adt_dladm_delete_secobj.obj_class = class; 7024 event->adt_dladm_delete_secobj.obj_name = obj; 7025 } 7026 7027 if (success) { 7028 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 7029 die("adt_put_event (%s, success): %s", errstr, 7030 strerror(errno)); 7031 } 7032 } else { 7033 if (adt_put_event(event, ADT_FAILURE, 7034 ADT_FAIL_VALUE_AUTH) != 0) { 7035 die("adt_put_event: (%s, failure): %s", errstr, 7036 strerror(errno)); 7037 } 7038 } 7039 7040 adt_free_event(event); 7041 (void) adt_end_session(ah); 7042 } 7043 7044 #define MAX_SECOBJS 32 7045 #define MAX_SECOBJ_NAMELEN 32 7046 static void 7047 do_create_secobj(int argc, char **argv, const char *use) 7048 { 7049 int option, rval; 7050 FILE *filep = NULL; 7051 char *obj_name = NULL; 7052 char *class_name = NULL; 7053 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 7054 uint_t obj_len; 7055 boolean_t success, temp = B_FALSE; 7056 dladm_status_t status; 7057 dladm_secobj_class_t class = -1; 7058 uid_t euid; 7059 7060 opterr = 0; 7061 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 7062 while ((option = getopt_long(argc, argv, ":f:c:R:t", 7063 wifi_longopts, NULL)) != -1) { 7064 switch (option) { 7065 case 'f': 7066 euid = geteuid(); 7067 (void) seteuid(getuid()); 7068 filep = fopen(optarg, "r"); 7069 if (filep == NULL) { 7070 die("cannot open %s: %s", optarg, 7071 strerror(errno)); 7072 } 7073 (void) seteuid(euid); 7074 break; 7075 case 'c': 7076 class_name = optarg; 7077 status = dladm_str2secobjclass(optarg, &class); 7078 if (status != DLADM_STATUS_OK) { 7079 die("invalid secure object class '%s', " 7080 "valid values are: wep, wpa", optarg); 7081 } 7082 break; 7083 case 't': 7084 temp = B_TRUE; 7085 break; 7086 case 'R': 7087 status = dladm_set_rootdir(optarg); 7088 if (status != DLADM_STATUS_OK) { 7089 die_dlerr(status, "invalid directory " 7090 "specified"); 7091 } 7092 break; 7093 default: 7094 die_opterr(optopt, option, use); 7095 break; 7096 } 7097 } 7098 7099 if (optind == (argc - 1)) 7100 obj_name = argv[optind]; 7101 else if (optind != argc) 7102 usage(); 7103 7104 if (class == -1) 7105 die("secure object class required"); 7106 7107 if (obj_name == NULL) 7108 die("secure object name required"); 7109 7110 if (!dladm_valid_secobj_name(obj_name)) 7111 die("invalid secure object name '%s'", obj_name); 7112 7113 success = check_auth(LINK_SEC_AUTH); 7114 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 7115 if (!success) 7116 die("authorization '%s' is required", LINK_SEC_AUTH); 7117 7118 rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 7119 if (rval != 0) { 7120 switch (rval) { 7121 case ENOENT: 7122 die("invalid secure object class"); 7123 break; 7124 case EINVAL: 7125 die("invalid secure object value"); 7126 break; 7127 case ENOTSUP: 7128 die("verification failed"); 7129 break; 7130 default: 7131 die("invalid secure object: %s", strerror(rval)); 7132 break; 7133 } 7134 } 7135 7136 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 7137 DLADM_OPT_CREATE | DLADM_OPT_ACTIVE); 7138 if (status != DLADM_STATUS_OK) { 7139 die_dlerr(status, "could not create secure object '%s'", 7140 obj_name); 7141 } 7142 if (temp) 7143 return; 7144 7145 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 7146 DLADM_OPT_PERSIST); 7147 if (status != DLADM_STATUS_OK) { 7148 warn_dlerr(status, "could not persistently create secure " 7149 "object '%s'", obj_name); 7150 } 7151 } 7152 7153 static void 7154 do_delete_secobj(int argc, char **argv, const char *use) 7155 { 7156 int i, option; 7157 boolean_t temp = B_FALSE; 7158 boolean_t success; 7159 dladm_status_t status, pstatus; 7160 int nfields = 1; 7161 char *field, *token, *lasts = NULL, c; 7162 7163 opterr = 0; 7164 status = pstatus = DLADM_STATUS_OK; 7165 while ((option = getopt_long(argc, argv, ":R:t", 7166 wifi_longopts, NULL)) != -1) { 7167 switch (option) { 7168 case 't': 7169 temp = B_TRUE; 7170 break; 7171 case 'R': 7172 status = dladm_set_rootdir(optarg); 7173 if (status != DLADM_STATUS_OK) { 7174 die_dlerr(status, "invalid directory " 7175 "specified"); 7176 } 7177 break; 7178 default: 7179 die_opterr(optopt, option, use); 7180 break; 7181 } 7182 } 7183 7184 if (optind == (argc - 1)) { 7185 token = argv[optind]; 7186 if (token == NULL) 7187 die("secure object name required"); 7188 while ((c = *token++) != NULL) { 7189 if (c == ',') 7190 nfields++; 7191 } 7192 token = strdup(argv[optind]); 7193 if (token == NULL) 7194 die("no memory"); 7195 } else if (optind != argc) 7196 usage(); 7197 7198 success = check_auth(LINK_SEC_AUTH); 7199 audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE); 7200 if (!success) 7201 die("authorization '%s' is required", LINK_SEC_AUTH); 7202 7203 for (i = 0; i < nfields; i++) { 7204 7205 field = strtok_r(token, ",", &lasts); 7206 token = NULL; 7207 status = dladm_unset_secobj(handle, field, DLADM_OPT_ACTIVE); 7208 if (!temp) { 7209 pstatus = dladm_unset_secobj(handle, field, 7210 DLADM_OPT_PERSIST); 7211 } else { 7212 pstatus = DLADM_STATUS_OK; 7213 } 7214 7215 if (status != DLADM_STATUS_OK) { 7216 warn_dlerr(status, "could not delete secure object " 7217 "'%s'", field); 7218 } 7219 if (pstatus != DLADM_STATUS_OK) { 7220 warn_dlerr(pstatus, "could not persistently delete " 7221 "secure object '%s'", field); 7222 } 7223 } 7224 free(token); 7225 7226 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) { 7227 dladm_close(handle); 7228 exit(EXIT_FAILURE); 7229 } 7230 } 7231 7232 typedef struct show_secobj_state { 7233 boolean_t ss_persist; 7234 boolean_t ss_parsable; 7235 boolean_t ss_header; 7236 ofmt_handle_t ss_ofmt; 7237 } show_secobj_state_t; 7238 7239 7240 static boolean_t 7241 show_secobj(dladm_handle_t dh, void *arg, const char *obj_name) 7242 { 7243 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 7244 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 7245 char buf[DLADM_STRSIZE]; 7246 uint_t flags = 0; 7247 dladm_secobj_class_t class; 7248 show_secobj_state_t *statep = arg; 7249 dladm_status_t status; 7250 secobj_fields_buf_t sbuf; 7251 7252 bzero(&sbuf, sizeof (secobj_fields_buf_t)); 7253 if (statep->ss_persist) 7254 flags |= DLADM_OPT_PERSIST; 7255 7256 status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len, 7257 flags); 7258 if (status != DLADM_STATUS_OK) 7259 die_dlerr(status, "cannot get secure object '%s'", obj_name); 7260 7261 (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), 7262 obj_name); 7263 (void) dladm_secobjclass2str(class, buf); 7264 (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf); 7265 if (getuid() == 0) { 7266 char val[DLADM_SECOBJ_VAL_MAX * 2]; 7267 uint_t len = sizeof (val); 7268 7269 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) 7270 (void) snprintf(sbuf.ss_val, 7271 sizeof (sbuf.ss_val), "%s", val); 7272 } 7273 ofmt_print(statep->ss_ofmt, &sbuf); 7274 return (B_TRUE); 7275 } 7276 7277 static void 7278 do_show_secobj(int argc, char **argv, const char *use) 7279 { 7280 int option; 7281 show_secobj_state_t state; 7282 dladm_status_t status; 7283 boolean_t o_arg = B_FALSE; 7284 uint_t i; 7285 uint_t flags; 7286 char *fields_str = NULL; 7287 char *def_fields = "object,class"; 7288 char *all_fields = "object,class,value"; 7289 char *field, *token, *lasts = NULL, c; 7290 ofmt_handle_t ofmt; 7291 ofmt_status_t oferr; 7292 uint_t ofmtflags = 0; 7293 7294 opterr = 0; 7295 bzero(&state, sizeof (state)); 7296 state.ss_parsable = B_FALSE; 7297 fields_str = def_fields; 7298 state.ss_persist = B_FALSE; 7299 state.ss_parsable = B_FALSE; 7300 state.ss_header = B_TRUE; 7301 while ((option = getopt_long(argc, argv, ":pPo:", 7302 wifi_longopts, NULL)) != -1) { 7303 switch (option) { 7304 case 'p': 7305 state.ss_parsable = B_TRUE; 7306 break; 7307 case 'P': 7308 state.ss_persist = B_TRUE; 7309 break; 7310 case 'o': 7311 o_arg = B_TRUE; 7312 if (strcasecmp(optarg, "all") == 0) 7313 fields_str = all_fields; 7314 else 7315 fields_str = optarg; 7316 break; 7317 default: 7318 die_opterr(optopt, option, use); 7319 break; 7320 } 7321 } 7322 7323 if (state.ss_parsable && !o_arg) 7324 die("option -c requires -o"); 7325 7326 if (state.ss_parsable && fields_str == all_fields) 7327 die("\"-o all\" is invalid with -p"); 7328 7329 if (state.ss_parsable) 7330 ofmtflags |= OFMT_PARSABLE; 7331 oferr = ofmt_open(fields_str, secobj_fields, ofmtflags, 0, &ofmt); 7332 dladm_ofmt_check(oferr, state.ss_parsable, ofmt); 7333 state.ss_ofmt = ofmt; 7334 7335 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 7336 7337 if (optind == (argc - 1)) { 7338 uint_t obj_fields = 1; 7339 7340 token = argv[optind]; 7341 if (token == NULL) 7342 die("secure object name required"); 7343 while ((c = *token++) != NULL) { 7344 if (c == ',') 7345 obj_fields++; 7346 } 7347 token = strdup(argv[optind]); 7348 if (token == NULL) 7349 die("no memory"); 7350 for (i = 0; i < obj_fields; i++) { 7351 field = strtok_r(token, ",", &lasts); 7352 token = NULL; 7353 if (!show_secobj(handle, &state, field)) 7354 break; 7355 } 7356 free(token); 7357 ofmt_close(ofmt); 7358 return; 7359 } else if (optind != argc) 7360 usage(); 7361 7362 status = dladm_walk_secobj(handle, &state, show_secobj, flags); 7363 7364 if (status != DLADM_STATUS_OK) 7365 die_dlerr(status, "show-secobj"); 7366 ofmt_close(ofmt); 7367 } 7368 7369 /*ARGSUSED*/ 7370 static int 7371 i_dladm_init_linkprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 7372 { 7373 (void) dladm_init_linkprop(dh, linkid, B_TRUE); 7374 return (DLADM_WALK_CONTINUE); 7375 } 7376 7377 /*ARGSUSED*/ 7378 void 7379 do_init_linkprop(int argc, char **argv, const char *use) 7380 { 7381 int option; 7382 dladm_status_t status; 7383 datalink_id_t linkid = DATALINK_ALL_LINKID; 7384 datalink_media_t media = DATALINK_ANY_MEDIATYPE; 7385 uint_t any_media = B_TRUE; 7386 7387 opterr = 0; 7388 while ((option = getopt(argc, argv, ":w")) != -1) { 7389 switch (option) { 7390 case 'w': 7391 media = DL_WIFI; 7392 any_media = B_FALSE; 7393 break; 7394 default: 7395 /* 7396 * Because init-linkprop is not a public command, 7397 * print the usage instead. 7398 */ 7399 usage(); 7400 break; 7401 } 7402 } 7403 7404 if (optind == (argc - 1)) { 7405 if ((status = dladm_name2info(handle, argv[optind], &linkid, 7406 NULL, NULL, NULL)) != DLADM_STATUS_OK) 7407 die_dlerr(status, "link %s is not valid", argv[optind]); 7408 } else if (optind != argc) { 7409 usage(); 7410 } 7411 7412 if (linkid == DATALINK_ALL_LINKID) { 7413 /* 7414 * linkprops of links of other classes have been initialized as 7415 * part of the dladm up-xxx operation. 7416 */ 7417 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle, 7418 NULL, DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST); 7419 } else { 7420 (void) dladm_init_linkprop(handle, linkid, any_media); 7421 } 7422 } 7423 7424 static void 7425 do_show_ether(int argc, char **argv, const char *use) 7426 { 7427 int option; 7428 datalink_id_t linkid; 7429 print_ether_state_t state; 7430 char *fields_str = NULL; 7431 ofmt_handle_t ofmt; 7432 ofmt_status_t oferr; 7433 uint_t ofmtflags = 0; 7434 7435 bzero(&state, sizeof (state)); 7436 state.es_link = NULL; 7437 state.es_parsable = B_FALSE; 7438 7439 while ((option = getopt_long(argc, argv, "o:px", 7440 showeth_lopts, NULL)) != -1) { 7441 switch (option) { 7442 case 'x': 7443 state.es_extended = B_TRUE; 7444 break; 7445 case 'p': 7446 state.es_parsable = B_TRUE; 7447 break; 7448 case 'o': 7449 fields_str = optarg; 7450 break; 7451 default: 7452 die_opterr(optopt, option, use); 7453 break; 7454 } 7455 } 7456 7457 if (optind == (argc - 1)) 7458 state.es_link = argv[optind]; 7459 7460 if (state.es_parsable) 7461 ofmtflags |= OFMT_PARSABLE; 7462 oferr = ofmt_open(fields_str, ether_fields, ofmtflags, 7463 DLADM_DEFAULT_COL, &ofmt); 7464 dladm_ofmt_check(oferr, state.es_parsable, ofmt); 7465 state.es_ofmt = ofmt; 7466 7467 if (state.es_link == NULL) { 7468 (void) dladm_walk_datalink_id(show_etherprop, handle, &state, 7469 DATALINK_CLASS_PHYS, DL_ETHER, DLADM_OPT_ACTIVE); 7470 } else { 7471 if (!link_is_ether(state.es_link, &linkid)) 7472 die("invalid link specified"); 7473 (void) show_etherprop(handle, linkid, &state); 7474 } 7475 ofmt_close(ofmt); 7476 } 7477 7478 static int 7479 show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 7480 { 7481 print_ether_state_t *statep = arg; 7482 ether_fields_buf_t ebuf; 7483 dladm_ether_info_t eattr; 7484 dladm_status_t status; 7485 7486 bzero(&ebuf, sizeof (ether_fields_buf_t)); 7487 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, 7488 ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) { 7489 return (DLADM_WALK_CONTINUE); 7490 } 7491 7492 status = dladm_ether_info(dh, linkid, &eattr); 7493 if (status != DLADM_STATUS_OK) 7494 goto cleanup; 7495 7496 (void) strlcpy(ebuf.eth_ptype, "current", sizeof (ebuf.eth_ptype)); 7497 7498 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 7499 sizeof (ebuf.eth_autoneg), &eattr, CURRENT); 7500 (void) dladm_ether_pause2str(ebuf.eth_pause, 7501 sizeof (ebuf.eth_pause), &eattr, CURRENT); 7502 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 7503 sizeof (ebuf.eth_spdx), &eattr, CURRENT); 7504 (void) strlcpy(ebuf.eth_state, 7505 dladm_linkstate2str(eattr.lei_state, ebuf.eth_state), 7506 sizeof (ebuf.eth_state)); 7507 (void) strlcpy(ebuf.eth_rem_fault, 7508 (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"), 7509 sizeof (ebuf.eth_rem_fault)); 7510 7511 ofmt_print(statep->es_ofmt, &ebuf); 7512 7513 if (statep->es_extended) 7514 show_ether_xprop(arg, &eattr); 7515 7516 cleanup: 7517 dladm_ether_info_done(&eattr); 7518 return (DLADM_WALK_CONTINUE); 7519 } 7520 7521 /* ARGSUSED */ 7522 static void 7523 do_init_secobj(int argc, char **argv, const char *use) 7524 { 7525 dladm_status_t status; 7526 7527 status = dladm_init_secobj(handle); 7528 if (status != DLADM_STATUS_OK) 7529 die_dlerr(status, "secure object initialization failed"); 7530 } 7531 7532 enum bridge_func { 7533 brCreate, brAdd, brModify 7534 }; 7535 7536 static void 7537 create_modify_add_bridge(int argc, char **argv, const char *use, 7538 enum bridge_func func) 7539 { 7540 int option; 7541 uint_t n, i, nlink; 7542 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 7543 char *altroot = NULL; 7544 char *links[MAXPORT]; 7545 datalink_id_t linkids[MAXPORT]; 7546 dladm_status_t status; 7547 const char *bridge; 7548 UID_STP_CFG_T cfg, cfg_old; 7549 dladm_bridge_prot_t brprot = DLADM_BRIDGE_PROT_UNKNOWN; 7550 dladm_bridge_prot_t brprot_old; 7551 7552 /* Set up the default configuration values */ 7553 cfg.field_mask = 0; 7554 cfg.bridge_priority = DEF_BR_PRIO; 7555 cfg.max_age = DEF_BR_MAXAGE; 7556 cfg.hello_time = DEF_BR_HELLOT; 7557 cfg.forward_delay = DEF_BR_FWDELAY; 7558 cfg.force_version = DEF_FORCE_VERS; 7559 7560 nlink = opterr = 0; 7561 while ((option = getopt_long(argc, argv, ":P:R:d:f:h:l:m:p:", 7562 bridge_lopts, NULL)) != -1) { 7563 switch (option) { 7564 case 'P': 7565 if (func == brAdd) 7566 die_opterr(optopt, option, use); 7567 status = dladm_bridge_str2prot(optarg, &brprot); 7568 if (status != DLADM_STATUS_OK) 7569 die_dlerr(status, "protection %s", optarg); 7570 break; 7571 case 'R': 7572 altroot = optarg; 7573 break; 7574 case 'd': 7575 if (func == brAdd) 7576 die_opterr(optopt, option, use); 7577 if (cfg.field_mask & BR_CFG_DELAY) 7578 die("forwarding delay set more than once"); 7579 if (!str2int(optarg, &cfg.forward_delay) || 7580 cfg.forward_delay < MIN_BR_FWDELAY || 7581 cfg.forward_delay > MAX_BR_FWDELAY) 7582 die("incorrect forwarding delay"); 7583 cfg.field_mask |= BR_CFG_DELAY; 7584 break; 7585 case 'f': 7586 if (func == brAdd) 7587 die_opterr(optopt, option, use); 7588 if (cfg.field_mask & BR_CFG_FORCE_VER) 7589 die("force protocol set more than once"); 7590 if (!str2int(optarg, &cfg.force_version) || 7591 cfg.force_version < 0) 7592 die("incorrect force protocol"); 7593 cfg.field_mask |= BR_CFG_FORCE_VER; 7594 break; 7595 case 'h': 7596 if (func == brAdd) 7597 die_opterr(optopt, option, use); 7598 if (cfg.field_mask & BR_CFG_HELLO) 7599 die("hello time set more than once"); 7600 if (!str2int(optarg, &cfg.hello_time) || 7601 cfg.hello_time < MIN_BR_HELLOT || 7602 cfg.hello_time > MAX_BR_HELLOT) 7603 die("incorrect hello time"); 7604 cfg.field_mask |= BR_CFG_HELLO; 7605 break; 7606 case 'l': 7607 if (func == brModify) 7608 die_opterr(optopt, option, use); 7609 if (nlink >= MAXPORT) 7610 die("too many links specified"); 7611 links[nlink++] = optarg; 7612 break; 7613 case 'm': 7614 if (func == brAdd) 7615 die_opterr(optopt, option, use); 7616 if (cfg.field_mask & BR_CFG_AGE) 7617 die("max age set more than once"); 7618 if (!str2int(optarg, &cfg.max_age) || 7619 cfg.max_age < MIN_BR_MAXAGE || 7620 cfg.max_age > MAX_BR_MAXAGE) 7621 die("incorrect max age"); 7622 cfg.field_mask |= BR_CFG_AGE; 7623 break; 7624 case 'p': 7625 if (func == brAdd) 7626 die_opterr(optopt, option, use); 7627 if (cfg.field_mask & BR_CFG_PRIO) 7628 die("priority set more than once"); 7629 if (!str2int(optarg, &cfg.bridge_priority) || 7630 cfg.bridge_priority < MIN_BR_PRIO || 7631 cfg.bridge_priority > MAX_BR_PRIO) 7632 die("incorrect priority"); 7633 cfg.bridge_priority &= 0xF000; 7634 cfg.field_mask |= BR_CFG_PRIO; 7635 break; 7636 default: 7637 die_opterr(optopt, option, use); 7638 break; 7639 } 7640 } 7641 7642 /* get the bridge name (required last argument) */ 7643 if (optind != (argc-1)) 7644 usage(); 7645 7646 bridge = argv[optind]; 7647 if (!dladm_valid_bridgename(bridge)) 7648 die("invalid bridge name '%s'", bridge); 7649 7650 /* 7651 * Get the current properties, if any, and merge in with changes. This 7652 * is necessary (even with the field_mask feature) so that the 7653 * value-checking macros will produce the right results with proposed 7654 * changes to existing configuration. We only need it for those 7655 * parameters, though. 7656 */ 7657 (void) dladm_bridge_get_properties(bridge, &cfg_old, &brprot_old); 7658 if (brprot == DLADM_BRIDGE_PROT_UNKNOWN) 7659 brprot = brprot_old; 7660 if (!(cfg.field_mask & BR_CFG_AGE)) 7661 cfg.max_age = cfg_old.max_age; 7662 if (!(cfg.field_mask & BR_CFG_HELLO)) 7663 cfg.hello_time = cfg_old.hello_time; 7664 if (!(cfg.field_mask & BR_CFG_DELAY)) 7665 cfg.forward_delay = cfg_old.forward_delay; 7666 7667 if (!CHECK_BRIDGE_CONFIG(cfg)) { 7668 warn("illegal forward delay / max age / hello time " 7669 "combination"); 7670 if (NO_MAXAGE(cfg)) { 7671 die("no max age possible: need forward delay >= %d or " 7672 "hello time <= %d", MIN_FWDELAY_NOM(cfg), 7673 MAX_HELLOTIME_NOM(cfg)); 7674 } else if (SMALL_MAXAGE(cfg)) { 7675 if (CAPPED_MAXAGE(cfg)) 7676 die("max age too small: need age >= %d and " 7677 "<= %d or hello time <= %d", 7678 MIN_MAXAGE(cfg), MAX_MAXAGE(cfg), 7679 MAX_HELLOTIME(cfg)); 7680 else 7681 die("max age too small: need age >= %d or " 7682 "hello time <= %d", 7683 MIN_MAXAGE(cfg), MAX_HELLOTIME(cfg)); 7684 } else if (FLOORED_MAXAGE(cfg)) { 7685 die("max age too large: need age >= %d and <= %d or " 7686 "forward delay >= %d", 7687 MIN_MAXAGE(cfg), MAX_MAXAGE(cfg), 7688 MIN_FWDELAY(cfg)); 7689 } else { 7690 die("max age too large: need age <= %d or forward " 7691 "delay >= %d", 7692 MAX_MAXAGE(cfg), MIN_FWDELAY(cfg)); 7693 } 7694 } 7695 7696 if (altroot != NULL) 7697 altroot_cmd(altroot, argc, argv); 7698 7699 for (n = 0; n < nlink; n++) { 7700 datalink_class_t class; 7701 uint32_t media; 7702 char pointless[DLADM_STRSIZE]; 7703 7704 if (dladm_name2info(handle, links[n], &linkids[n], NULL, &class, 7705 &media) != DLADM_STATUS_OK) 7706 die("invalid link name '%s'", links[n]); 7707 if (class & ~(DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | 7708 DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET)) 7709 die("%s %s cannot be bridged", 7710 dladm_class2str(class, pointless), links[n]); 7711 if (media != DL_ETHER && media != DL_100VG && 7712 media != DL_ETH_CSMA && media != DL_100BT) 7713 die("%s interface %s cannot be bridged", 7714 dladm_media2str(media, pointless), links[n]); 7715 } 7716 7717 if (func == brCreate) 7718 flags |= DLADM_OPT_CREATE; 7719 7720 if (func != brAdd) { 7721 status = dladm_bridge_configure(handle, bridge, &cfg, brprot, 7722 flags); 7723 if (status != DLADM_STATUS_OK) 7724 die_dlerr(status, "create operation failed"); 7725 } 7726 7727 status = DLADM_STATUS_OK; 7728 for (n = 0; n < nlink; n++) { 7729 status = dladm_bridge_setlink(handle, linkids[n], bridge); 7730 if (status != DLADM_STATUS_OK) 7731 break; 7732 } 7733 7734 if (n >= nlink) { 7735 /* 7736 * We were successful. If we're creating a new bridge, then 7737 * there's just one more step: enabling. If we're modifying or 7738 * just adding links, then we're done. 7739 */ 7740 if (func != brCreate || 7741 (status = dladm_bridge_enable(bridge)) == DLADM_STATUS_OK) 7742 return; 7743 } 7744 7745 /* clean up the partial configuration */ 7746 for (i = 0; i < n; i++) 7747 (void) dladm_bridge_setlink(handle, linkids[i], ""); 7748 7749 /* if failure for brCreate, then delete the bridge */ 7750 if (func == brCreate) 7751 (void) dladm_bridge_delete(handle, bridge, flags); 7752 7753 if (n < nlink) 7754 die_dlerr(status, "unable to add link %s to bridge %s", 7755 links[n], bridge); 7756 else 7757 die_dlerr(status, "unable to enable bridge %s", bridge); 7758 } 7759 7760 static void 7761 do_create_bridge(int argc, char **argv, const char *use) 7762 { 7763 create_modify_add_bridge(argc, argv, use, brCreate); 7764 } 7765 7766 static void 7767 do_modify_bridge(int argc, char **argv, const char *use) 7768 { 7769 create_modify_add_bridge(argc, argv, use, brModify); 7770 } 7771 7772 static void 7773 do_add_bridge(int argc, char **argv, const char *use) 7774 { 7775 create_modify_add_bridge(argc, argv, use, brAdd); 7776 } 7777 7778 static void 7779 do_delete_bridge(int argc, char **argv, const char *use) 7780 { 7781 char option; 7782 char *altroot = NULL; 7783 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 7784 dladm_status_t status; 7785 7786 opterr = 0; 7787 while ((option = getopt_long(argc, argv, ":R:", bridge_lopts, NULL)) != 7788 -1) { 7789 switch (option) { 7790 case 'R': 7791 altroot = optarg; 7792 break; 7793 default: 7794 die_opterr(optopt, option, use); 7795 break; 7796 } 7797 } 7798 7799 /* get the bridge name (required last argument) */ 7800 if (optind != (argc-1)) 7801 usage(); 7802 7803 if (altroot != NULL) 7804 altroot_cmd(altroot, argc, argv); 7805 7806 status = dladm_bridge_delete(handle, argv[optind], flags); 7807 if (status != DLADM_STATUS_OK) 7808 die_dlerr(status, "delete operation failed"); 7809 } 7810 7811 static void 7812 do_remove_bridge(int argc, char **argv, const char *use) 7813 { 7814 char option; 7815 uint_t n, nlink; 7816 char *links[MAXPORT]; 7817 datalink_id_t linkids[MAXPORT]; 7818 char *altroot = NULL; 7819 dladm_status_t status; 7820 boolean_t removed_one; 7821 7822 nlink = opterr = 0; 7823 while ((option = getopt_long(argc, argv, ":R:l:", bridge_lopts, 7824 NULL)) != -1) { 7825 switch (option) { 7826 case 'R': 7827 altroot = optarg; 7828 break; 7829 case 'l': 7830 if (nlink >= MAXPORT) 7831 die("too many links specified"); 7832 links[nlink++] = optarg; 7833 break; 7834 default: 7835 die_opterr(optopt, option, use); 7836 break; 7837 } 7838 } 7839 7840 if (nlink == 0) 7841 usage(); 7842 7843 /* get the bridge name (required last argument) */ 7844 if (optind != (argc-1)) 7845 usage(); 7846 7847 if (altroot != NULL) 7848 altroot_cmd(altroot, argc, argv); 7849 7850 for (n = 0; n < nlink; n++) { 7851 char bridge[MAXLINKNAMELEN]; 7852 7853 if (dladm_name2info(handle, links[n], &linkids[n], NULL, NULL, 7854 NULL) != DLADM_STATUS_OK) 7855 die("invalid link name '%s'", links[n]); 7856 status = dladm_bridge_getlink(handle, linkids[n], bridge, 7857 sizeof (bridge)); 7858 if (status != DLADM_STATUS_OK && 7859 status != DLADM_STATUS_NOTFOUND) { 7860 die_dlerr(status, "cannot get bridge status on %s", 7861 links[n]); 7862 } 7863 if (status == DLADM_STATUS_NOTFOUND || 7864 strcmp(bridge, argv[optind]) != 0) 7865 die("link %s is not on bridge %s", links[n], 7866 argv[optind]); 7867 } 7868 7869 removed_one = B_FALSE; 7870 for (n = 0; n < nlink; n++) { 7871 status = dladm_bridge_setlink(handle, linkids[n], ""); 7872 if (status == DLADM_STATUS_OK) { 7873 removed_one = B_TRUE; 7874 } else { 7875 warn_dlerr(status, 7876 "cannot remove link %s from bridge %s", 7877 links[n], argv[optind]); 7878 } 7879 } 7880 if (!removed_one) 7881 die("unable to remove any links from bridge %s", argv[optind]); 7882 } 7883 7884 static void 7885 fmt_int(char *buf, size_t buflen, int value, int runvalue, 7886 boolean_t printstar) 7887 { 7888 (void) snprintf(buf, buflen, "%d", value); 7889 if (value != runvalue && printstar) 7890 (void) strlcat(buf, "*", buflen); 7891 } 7892 7893 static void 7894 fmt_bridge_id(char *buf, size_t buflen, UID_BRIDGE_ID_T *bid) 7895 { 7896 (void) snprintf(buf, buflen, "%u/%x:%x:%x:%x:%x:%x", bid->prio, 7897 bid->addr[0], bid->addr[1], bid->addr[2], bid->addr[3], 7898 bid->addr[4], bid->addr[5]); 7899 } 7900 7901 static dladm_status_t 7902 print_bridge(show_state_t *state, datalink_id_t linkid, 7903 bridge_fields_buf_t *bbuf) 7904 { 7905 char link[MAXLINKNAMELEN]; 7906 datalink_class_t class; 7907 uint32_t flags; 7908 dladm_status_t status; 7909 UID_STP_CFG_T smfcfg, runcfg; 7910 UID_STP_STATE_T stpstate; 7911 dladm_bridge_prot_t smfprot, runprot; 7912 7913 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 7914 NULL, link, sizeof (link))) != DLADM_STATUS_OK) 7915 return (status); 7916 7917 if (!(state->ls_flags & flags)) 7918 return (DLADM_STATUS_NOTFOUND); 7919 7920 /* Convert observability node name back to bridge name */ 7921 if (!dladm_observe_to_bridge(link)) 7922 return (DLADM_STATUS_NOTFOUND); 7923 (void) strlcpy(bbuf->bridge_name, link, sizeof (bbuf->bridge_name)); 7924 7925 /* 7926 * If the running value differs from the one in SMF, and parsable 7927 * output is not requested, then we show the running value with an 7928 * asterisk. 7929 */ 7930 (void) dladm_bridge_get_properties(bbuf->bridge_name, &smfcfg, 7931 &smfprot); 7932 (void) dladm_bridge_run_properties(bbuf->bridge_name, &runcfg, 7933 &runprot); 7934 (void) snprintf(bbuf->bridge_protect, sizeof (bbuf->bridge_protect), 7935 "%s%s", state->ls_parsable || smfprot == runprot ? "" : "*", 7936 dladm_bridge_prot2str(runprot)); 7937 fmt_int(bbuf->bridge_priority, sizeof (bbuf->bridge_priority), 7938 smfcfg.bridge_priority, runcfg.bridge_priority, 7939 !state->ls_parsable && (runcfg.field_mask & BR_CFG_AGE)); 7940 fmt_int(bbuf->bridge_bmaxage, sizeof (bbuf->bridge_bmaxage), 7941 smfcfg.max_age, runcfg.max_age, 7942 !state->ls_parsable && (runcfg.field_mask & BR_CFG_AGE)); 7943 fmt_int(bbuf->bridge_bhellotime, 7944 sizeof (bbuf->bridge_bhellotime), smfcfg.hello_time, 7945 runcfg.hello_time, 7946 !state->ls_parsable && (runcfg.field_mask & BR_CFG_HELLO)); 7947 fmt_int(bbuf->bridge_bfwddelay, sizeof (bbuf->bridge_bfwddelay), 7948 smfcfg.forward_delay, runcfg.forward_delay, 7949 !state->ls_parsable && (runcfg.field_mask & BR_CFG_DELAY)); 7950 fmt_int(bbuf->bridge_forceproto, sizeof (bbuf->bridge_forceproto), 7951 smfcfg.force_version, runcfg.force_version, 7952 !state->ls_parsable && (runcfg.field_mask & BR_CFG_FORCE_VER)); 7953 fmt_int(bbuf->bridge_holdtime, sizeof (bbuf->bridge_holdtime), 7954 smfcfg.hold_time, runcfg.hold_time, 7955 !state->ls_parsable && (runcfg.field_mask & BR_CFG_HOLD_TIME)); 7956 7957 if (dladm_bridge_state(bbuf->bridge_name, &stpstate) == 7958 DLADM_STATUS_OK) { 7959 fmt_bridge_id(bbuf->bridge_address, 7960 sizeof (bbuf->bridge_address), &stpstate.bridge_id); 7961 (void) snprintf(bbuf->bridge_tctime, 7962 sizeof (bbuf->bridge_tctime), "%lu", 7963 stpstate.timeSince_Topo_Change); 7964 (void) snprintf(bbuf->bridge_tccount, 7965 sizeof (bbuf->bridge_tccount), "%lu", 7966 stpstate.Topo_Change_Count); 7967 (void) snprintf(bbuf->bridge_tchange, 7968 sizeof (bbuf->bridge_tchange), "%u", stpstate.Topo_Change); 7969 fmt_bridge_id(bbuf->bridge_desroot, 7970 sizeof (bbuf->bridge_desroot), &stpstate.designated_root); 7971 (void) snprintf(bbuf->bridge_rootcost, 7972 sizeof (bbuf->bridge_rootcost), "%lu", 7973 stpstate.root_path_cost); 7974 (void) snprintf(bbuf->bridge_rootport, 7975 sizeof (bbuf->bridge_rootport), "%u", stpstate.root_port); 7976 (void) snprintf(bbuf->bridge_maxage, 7977 sizeof (bbuf->bridge_maxage), "%d", stpstate.max_age); 7978 (void) snprintf(bbuf->bridge_hellotime, 7979 sizeof (bbuf->bridge_hellotime), "%d", stpstate.hello_time); 7980 (void) snprintf(bbuf->bridge_fwddelay, 7981 sizeof (bbuf->bridge_fwddelay), "%d", 7982 stpstate.forward_delay); 7983 } 7984 return (DLADM_STATUS_OK); 7985 } 7986 7987 static dladm_status_t 7988 print_bridge_stats(show_state_t *state, datalink_id_t linkid, 7989 bridge_statfields_buf_t *bbuf) 7990 { 7991 char link[MAXLINKNAMELEN]; 7992 datalink_class_t class; 7993 uint32_t flags; 7994 dladm_status_t status; 7995 kstat_ctl_t *kcp; 7996 kstat_t *ksp; 7997 brsum_t *brsum = (brsum_t *)&state->ls_prevstats; 7998 brsum_t newval; 7999 8000 #ifndef lint 8001 /* This is a compile-time assertion; optimizer normally fixes this */ 8002 extern void brsum_t_is_too_large(void); 8003 8004 if (sizeof (*brsum) > sizeof (state->ls_prevstats)) 8005 brsum_t_is_too_large(); 8006 #endif 8007 8008 if (state->ls_firstonly) { 8009 if (state->ls_donefirst) 8010 return (DLADM_WALK_CONTINUE); 8011 state->ls_donefirst = B_TRUE; 8012 } else { 8013 bzero(brsum, sizeof (*brsum)); 8014 } 8015 bzero(&newval, sizeof (newval)); 8016 8017 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 8018 NULL, link, sizeof (link))) != DLADM_STATUS_OK) 8019 return (status); 8020 8021 if (!(state->ls_flags & flags)) 8022 return (DLADM_STATUS_NOTFOUND); 8023 8024 if ((kcp = kstat_open()) == NULL) { 8025 warn("kstat open operation failed"); 8026 return (DLADM_STATUS_OK); 8027 } 8028 if ((ksp = kstat_lookup(kcp, "bridge", 0, link)) != NULL && 8029 kstat_read(kcp, ksp, NULL) != -1) { 8030 if (dladm_kstat_value(ksp, "drops", KSTAT_DATA_UINT64, 8031 &newval.drops) == DLADM_STATUS_OK) { 8032 (void) snprintf(bbuf->bridges_drops, 8033 sizeof (bbuf->bridges_drops), "%llu", 8034 newval.drops - brsum->drops); 8035 } 8036 if (dladm_kstat_value(ksp, "forward_direct", KSTAT_DATA_UINT64, 8037 &newval.forward_dir) == DLADM_STATUS_OK) { 8038 (void) snprintf(bbuf->bridges_forwards, 8039 sizeof (bbuf->bridges_forwards), "%llu", 8040 newval.forward_dir - brsum->forward_dir); 8041 } 8042 if (dladm_kstat_value(ksp, "forward_mbcast", KSTAT_DATA_UINT64, 8043 &newval.forward_mb) == DLADM_STATUS_OK) { 8044 (void) snprintf(bbuf->bridges_mbcast, 8045 sizeof (bbuf->bridges_mbcast), "%llu", 8046 newval.forward_mb - brsum->forward_mb); 8047 } 8048 if (dladm_kstat_value(ksp, "forward_unknown", KSTAT_DATA_UINT64, 8049 &newval.forward_unk) == DLADM_STATUS_OK) { 8050 (void) snprintf(bbuf->bridges_unknown, 8051 sizeof (bbuf->bridges_unknown), "%llu", 8052 newval.forward_unk - brsum->forward_unk); 8053 } 8054 if (dladm_kstat_value(ksp, "recv", KSTAT_DATA_UINT64, 8055 &newval.recv) == DLADM_STATUS_OK) { 8056 (void) snprintf(bbuf->bridges_recv, 8057 sizeof (bbuf->bridges_recv), "%llu", 8058 newval.recv - brsum->recv); 8059 } 8060 if (dladm_kstat_value(ksp, "sent", KSTAT_DATA_UINT64, 8061 &newval.sent) == DLADM_STATUS_OK) { 8062 (void) snprintf(bbuf->bridges_sent, 8063 sizeof (bbuf->bridges_sent), "%llu", 8064 newval.sent - brsum->sent); 8065 } 8066 } 8067 (void) kstat_close(kcp); 8068 8069 /* Convert observability node name back to bridge name */ 8070 if (!dladm_observe_to_bridge(link)) 8071 return (DLADM_STATUS_NOTFOUND); 8072 (void) strlcpy(bbuf->bridges_name, link, sizeof (bbuf->bridges_name)); 8073 8074 *brsum = newval; 8075 8076 return (DLADM_STATUS_OK); 8077 } 8078 8079 /* 8080 * This structure carries around extra state information for the show-bridge 8081 * command and allows us to use common support functions. 8082 */ 8083 typedef struct { 8084 show_state_t state; 8085 boolean_t show_stats; 8086 const char *bridge; 8087 } show_brstate_t; 8088 8089 /* ARGSUSED */ 8090 static int 8091 show_bridge(dladm_handle_t handle, datalink_id_t linkid, void *arg) 8092 { 8093 show_brstate_t *brstate = arg; 8094 void *buf; 8095 8096 if (brstate->show_stats) { 8097 bridge_statfields_buf_t bbuf; 8098 8099 bzero(&bbuf, sizeof (bbuf)); 8100 brstate->state.ls_status = print_bridge_stats(&brstate->state, 8101 linkid, &bbuf); 8102 buf = &bbuf; 8103 } else { 8104 bridge_fields_buf_t bbuf; 8105 8106 bzero(&bbuf, sizeof (bbuf)); 8107 brstate->state.ls_status = print_bridge(&brstate->state, linkid, 8108 &bbuf); 8109 buf = &bbuf; 8110 } 8111 if (brstate->state.ls_status == DLADM_STATUS_OK) 8112 ofmt_print(brstate->state.ls_ofmt, buf); 8113 return (DLADM_WALK_CONTINUE); 8114 } 8115 8116 static void 8117 fmt_bool(char *buf, size_t buflen, int val) 8118 { 8119 (void) strlcpy(buf, val ? "yes" : "no", buflen); 8120 } 8121 8122 static dladm_status_t 8123 print_bridge_link(show_state_t *state, datalink_id_t linkid, 8124 bridge_link_fields_buf_t *bbuf) 8125 { 8126 datalink_class_t class; 8127 uint32_t flags; 8128 dladm_status_t status; 8129 UID_STP_PORT_STATE_T stpstate; 8130 8131 status = dladm_datalink_id2info(handle, linkid, &flags, &class, NULL, 8132 bbuf->bridgel_link, sizeof (bbuf->bridgel_link)); 8133 if (status != DLADM_STATUS_OK) 8134 return (status); 8135 8136 if (!(state->ls_flags & flags)) 8137 return (DLADM_STATUS_NOTFOUND); 8138 8139 if (dladm_bridge_link_state(handle, linkid, &stpstate) == 8140 DLADM_STATUS_OK) { 8141 (void) snprintf(bbuf->bridgel_index, 8142 sizeof (bbuf->bridgel_index), "%u", stpstate.port_no); 8143 if (dlsym(RTLD_PROBE, "STP_IN_state2str")) { 8144 (void) strlcpy(bbuf->bridgel_state, 8145 STP_IN_state2str(stpstate.state), 8146 sizeof (bbuf->bridgel_state)); 8147 } else { 8148 (void) snprintf(bbuf->bridgel_state, 8149 sizeof (bbuf->bridgel_state), "%u", 8150 stpstate.state); 8151 } 8152 (void) snprintf(bbuf->bridgel_uptime, 8153 sizeof (bbuf->bridgel_uptime), "%lu", stpstate.uptime); 8154 (void) snprintf(bbuf->bridgel_opercost, 8155 sizeof (bbuf->bridgel_opercost), "%lu", 8156 stpstate.oper_port_path_cost); 8157 fmt_bool(bbuf->bridgel_operp2p, sizeof (bbuf->bridgel_operp2p), 8158 stpstate.oper_point2point); 8159 fmt_bool(bbuf->bridgel_operedge, 8160 sizeof (bbuf->bridgel_operedge), stpstate.oper_edge); 8161 fmt_bridge_id(bbuf->bridgel_desroot, 8162 sizeof (bbuf->bridgel_desroot), &stpstate.designated_root); 8163 (void) snprintf(bbuf->bridgel_descost, 8164 sizeof (bbuf->bridgel_descost), "%lu", 8165 stpstate.designated_cost); 8166 fmt_bridge_id(bbuf->bridgel_desbridge, 8167 sizeof (bbuf->bridgel_desbridge), 8168 &stpstate.designated_bridge); 8169 (void) snprintf(bbuf->bridgel_desport, 8170 sizeof (bbuf->bridgel_desport), "%u", 8171 stpstate.designated_port); 8172 fmt_bool(bbuf->bridgel_tcack, sizeof (bbuf->bridgel_tcack), 8173 stpstate.top_change_ack); 8174 } 8175 return (DLADM_STATUS_OK); 8176 } 8177 8178 static dladm_status_t 8179 print_bridge_link_stats(show_state_t *state, datalink_id_t linkid, 8180 bridge_link_statfields_buf_t *bbuf) 8181 { 8182 datalink_class_t class; 8183 uint32_t flags; 8184 dladm_status_t status; 8185 UID_STP_PORT_STATE_T stpstate; 8186 kstat_ctl_t *kcp; 8187 kstat_t *ksp; 8188 char bridge[MAXLINKNAMELEN]; 8189 char kstatname[MAXLINKNAMELEN*2 + 1]; 8190 brlsum_t *brlsum = (brlsum_t *)&state->ls_prevstats; 8191 brlsum_t newval; 8192 8193 #ifndef lint 8194 /* This is a compile-time assertion; optimizer normally fixes this */ 8195 extern void brlsum_t_is_too_large(void); 8196 8197 if (sizeof (*brlsum) > sizeof (state->ls_prevstats)) 8198 brlsum_t_is_too_large(); 8199 #endif 8200 8201 if (state->ls_firstonly) { 8202 if (state->ls_donefirst) 8203 return (DLADM_WALK_CONTINUE); 8204 state->ls_donefirst = B_TRUE; 8205 } else { 8206 bzero(brlsum, sizeof (*brlsum)); 8207 } 8208 bzero(&newval, sizeof (newval)); 8209 8210 status = dladm_datalink_id2info(handle, linkid, &flags, &class, NULL, 8211 bbuf->bridgels_link, sizeof (bbuf->bridgels_link)); 8212 if (status != DLADM_STATUS_OK) 8213 return (status); 8214 8215 if (!(state->ls_flags & flags)) 8216 return (DLADM_STATUS_NOTFOUND); 8217 8218 if (dladm_bridge_link_state(handle, linkid, &stpstate) == 8219 DLADM_STATUS_OK) { 8220 newval.cfgbpdu = stpstate.rx_cfg_bpdu_cnt; 8221 newval.tcnbpdu = stpstate.rx_tcn_bpdu_cnt; 8222 newval.rstpbpdu = stpstate.rx_rstp_bpdu_cnt; 8223 newval.txbpdu = stpstate.txCount; 8224 8225 (void) snprintf(bbuf->bridgels_cfgbpdu, 8226 sizeof (bbuf->bridgels_cfgbpdu), "%lu", 8227 newval.cfgbpdu - brlsum->cfgbpdu); 8228 (void) snprintf(bbuf->bridgels_tcnbpdu, 8229 sizeof (bbuf->bridgels_tcnbpdu), "%lu", 8230 newval.tcnbpdu - brlsum->tcnbpdu); 8231 (void) snprintf(bbuf->bridgels_rstpbpdu, 8232 sizeof (bbuf->bridgels_rstpbpdu), "%lu", 8233 newval.rstpbpdu - brlsum->rstpbpdu); 8234 (void) snprintf(bbuf->bridgels_txbpdu, 8235 sizeof (bbuf->bridgels_txbpdu), "%lu", 8236 newval.txbpdu - brlsum->txbpdu); 8237 } 8238 8239 if ((status = dladm_bridge_getlink(handle, linkid, bridge, 8240 sizeof (bridge))) != DLADM_STATUS_OK) 8241 goto bls_out; 8242 (void) snprintf(kstatname, sizeof (kstatname), "%s0-%s", bridge, 8243 bbuf->bridgels_link); 8244 if ((kcp = kstat_open()) == NULL) { 8245 warn("kstat open operation failed"); 8246 goto bls_out; 8247 } 8248 if ((ksp = kstat_lookup(kcp, "bridge", 0, kstatname)) != NULL && 8249 kstat_read(kcp, ksp, NULL) != -1) { 8250 if (dladm_kstat_value(ksp, "drops", KSTAT_DATA_UINT64, 8251 &newval.drops) != -1) { 8252 (void) snprintf(bbuf->bridgels_drops, 8253 sizeof (bbuf->bridgels_drops), "%llu", 8254 newval.drops - brlsum->drops); 8255 } 8256 if (dladm_kstat_value(ksp, "recv", KSTAT_DATA_UINT64, 8257 &newval.recv) != -1) { 8258 (void) snprintf(bbuf->bridgels_recv, 8259 sizeof (bbuf->bridgels_recv), "%llu", 8260 newval.recv - brlsum->recv); 8261 } 8262 if (dladm_kstat_value(ksp, "xmit", KSTAT_DATA_UINT64, 8263 &newval.xmit) != -1) { 8264 (void) snprintf(bbuf->bridgels_xmit, 8265 sizeof (bbuf->bridgels_xmit), "%llu", 8266 newval.xmit - brlsum->xmit); 8267 } 8268 } 8269 (void) kstat_close(kcp); 8270 bls_out: 8271 *brlsum = newval; 8272 8273 return (status); 8274 } 8275 8276 static void 8277 show_bridge_link(datalink_id_t linkid, show_brstate_t *brstate) 8278 { 8279 void *buf; 8280 8281 if (brstate->show_stats) { 8282 bridge_link_statfields_buf_t bbuf; 8283 8284 bzero(&bbuf, sizeof (bbuf)); 8285 brstate->state.ls_status = print_bridge_link_stats( 8286 &brstate->state, linkid, &bbuf); 8287 buf = &bbuf; 8288 } else { 8289 bridge_link_fields_buf_t bbuf; 8290 8291 bzero(&bbuf, sizeof (bbuf)); 8292 brstate->state.ls_status = print_bridge_link(&brstate->state, 8293 linkid, &bbuf); 8294 buf = &bbuf; 8295 } 8296 if (brstate->state.ls_status == DLADM_STATUS_OK) 8297 ofmt_print(brstate->state.ls_ofmt, buf); 8298 } 8299 8300 /* ARGSUSED */ 8301 static int 8302 show_bridge_link_walk(dladm_handle_t handle, datalink_id_t linkid, void *arg) 8303 { 8304 show_brstate_t *brstate = arg; 8305 char bridge[MAXLINKNAMELEN]; 8306 8307 if (dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)) == 8308 DLADM_STATUS_OK && strcmp(bridge, brstate->bridge) == 0) { 8309 show_bridge_link(linkid, brstate); 8310 } 8311 return (DLADM_WALK_CONTINUE); 8312 } 8313 8314 static void 8315 show_bridge_fwd(dladm_handle_t handle, bridge_listfwd_t *blf, 8316 show_state_t *state) 8317 { 8318 bridge_fwd_fields_buf_t bbuf; 8319 8320 bzero(&bbuf, sizeof (bbuf)); 8321 (void) snprintf(bbuf.bridgef_dest, sizeof (bbuf.bridgef_dest), 8322 "%s", ether_ntoa((struct ether_addr *)blf->blf_dest)); 8323 if (blf->blf_is_local) { 8324 (void) strlcpy(bbuf.bridgef_flags, "L", 8325 sizeof (bbuf.bridgef_flags)); 8326 } else { 8327 (void) snprintf(bbuf.bridgef_age, sizeof (bbuf.bridgef_age), 8328 "%2d.%03d", blf->blf_ms_age / 1000, blf->blf_ms_age % 1000); 8329 if (blf->blf_trill_nick != 0) { 8330 (void) snprintf(bbuf.bridgef_output, 8331 sizeof (bbuf.bridgef_output), "%u", 8332 blf->blf_trill_nick); 8333 } 8334 } 8335 if (blf->blf_linkid != DATALINK_INVALID_LINKID && 8336 blf->blf_trill_nick == 0) { 8337 state->ls_status = dladm_datalink_id2info(handle, 8338 blf->blf_linkid, NULL, NULL, NULL, bbuf.bridgef_output, 8339 sizeof (bbuf.bridgef_output)); 8340 } 8341 if (state->ls_status == DLADM_STATUS_OK) 8342 ofmt_print(state->ls_ofmt, &bbuf); 8343 } 8344 8345 static void 8346 show_bridge_trillnick(trill_listnick_t *tln, show_state_t *state) 8347 { 8348 bridge_trill_fields_buf_t bbuf; 8349 8350 bzero(&bbuf, sizeof (bbuf)); 8351 (void) snprintf(bbuf.bridget_nick, sizeof (bbuf.bridget_nick), 8352 "%u", tln->tln_nick); 8353 if (tln->tln_ours) { 8354 (void) strlcpy(bbuf.bridget_flags, "L", 8355 sizeof (bbuf.bridget_flags)); 8356 } else { 8357 state->ls_status = dladm_datalink_id2info(handle, 8358 tln->tln_linkid, NULL, NULL, NULL, bbuf.bridget_link, 8359 sizeof (bbuf.bridget_link)); 8360 (void) snprintf(bbuf.bridget_nexthop, 8361 sizeof (bbuf.bridget_nexthop), "%s", 8362 ether_ntoa((struct ether_addr *)tln->tln_nexthop)); 8363 } 8364 if (state->ls_status == DLADM_STATUS_OK) 8365 ofmt_print(state->ls_ofmt, &bbuf); 8366 } 8367 8368 static void 8369 do_show_bridge(int argc, char **argv, const char *use) 8370 { 8371 int option; 8372 enum { 8373 bridgeMode, linkMode, fwdMode, trillMode 8374 } op_mode = bridgeMode; 8375 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 8376 boolean_t parsable = B_FALSE; 8377 datalink_id_t linkid = DATALINK_ALL_LINKID; 8378 int interval = 0; 8379 show_brstate_t brstate; 8380 dladm_status_t status; 8381 char *fields_str = NULL; 8382 /* default: bridge-related data */ 8383 char *all_fields = "bridge,protect,address,priority,bmaxage," 8384 "bhellotime,bfwddelay,forceproto,tctime,tccount,tchange," 8385 "desroot,rootcost,rootport,maxage,hellotime,fwddelay,holdtime"; 8386 char *default_fields = "bridge,protect,address,priority," 8387 "desroot"; 8388 char *all_statfields = "bridge,drops,forwards,mbcast," 8389 "unknown,recv,sent"; 8390 char *default_statfields = "bridge,drops,forwards,mbcast," 8391 "unknown"; 8392 /* -l: link-related data */ 8393 char *all_link_fields = "link,index,state,uptime,opercost," 8394 "operp2p,operedge,desroot,descost,desbridge,desport,tcack"; 8395 char *default_link_fields = "link,state,uptime,desroot"; 8396 char *all_link_statfields = "link,cfgbpdu,tcnbpdu,rstpbpdu," 8397 "txbpdu,drops,recv,xmit"; 8398 char *default_link_statfields = "link,drops,recv,xmit"; 8399 /* -f: bridge forwarding table related data */ 8400 char *default_fwd_fields = "dest,age,flags,output"; 8401 /* -t: TRILL nickname table related data */ 8402 char *default_trill_fields = "nick,flags,link,nexthop"; 8403 char *default_str; 8404 char *all_str; 8405 ofmt_field_t *field_arr; 8406 ofmt_handle_t ofmt; 8407 ofmt_status_t oferr; 8408 uint_t ofmtflags = 0; 8409 8410 bzero(&brstate, sizeof (brstate)); 8411 8412 opterr = 0; 8413 while ((option = getopt_long(argc, argv, ":fi:lo:pst", 8414 bridge_show_lopts, NULL)) != -1) { 8415 switch (option) { 8416 case 'f': 8417 if (op_mode != bridgeMode && op_mode != fwdMode) 8418 die("-f is incompatible with -l or -t"); 8419 op_mode = fwdMode; 8420 break; 8421 case 'i': 8422 if (interval != 0) 8423 die_optdup(option); 8424 if (!str2int(optarg, &interval) || interval == 0) 8425 die("invalid interval value '%s'", optarg); 8426 break; 8427 case 'l': 8428 if (op_mode != bridgeMode && op_mode != linkMode) 8429 die("-l is incompatible with -f or -t"); 8430 op_mode = linkMode; 8431 break; 8432 case 'o': 8433 fields_str = optarg; 8434 break; 8435 case 'p': 8436 if (parsable) 8437 die_optdup(option); 8438 parsable = B_TRUE; 8439 break; 8440 case 's': 8441 if (brstate.show_stats) 8442 die_optdup(option); 8443 brstate.show_stats = B_TRUE; 8444 break; 8445 case 't': 8446 if (op_mode != bridgeMode && op_mode != trillMode) 8447 die("-t is incompatible with -f or -l"); 8448 op_mode = trillMode; 8449 break; 8450 default: 8451 die_opterr(optopt, option, use); 8452 break; 8453 } 8454 } 8455 8456 if (interval != 0 && !brstate.show_stats) 8457 die("the -i option can be used only with -s"); 8458 8459 if ((op_mode == fwdMode || op_mode == trillMode) && brstate.show_stats) 8460 die("the -f/-t and -s options cannot be used together"); 8461 8462 /* get the bridge name (optional last argument) */ 8463 if (optind == (argc-1)) { 8464 char lname[MAXLINKNAMELEN]; 8465 uint32_t lnkflg; 8466 datalink_class_t class; 8467 8468 brstate.bridge = argv[optind]; 8469 (void) snprintf(lname, sizeof (lname), "%s0", brstate.bridge); 8470 if ((status = dladm_name2info(handle, lname, &linkid, &lnkflg, 8471 &class, NULL)) != DLADM_STATUS_OK) { 8472 die_dlerr(status, "bridge %s is not valid", 8473 brstate.bridge); 8474 } 8475 8476 if (class != DATALINK_CLASS_BRIDGE) 8477 die("%s is not a bridge", brstate.bridge); 8478 8479 if (!(lnkflg & flags)) { 8480 die_dlerr(DLADM_STATUS_BADARG, 8481 "bridge %s is temporarily removed", brstate.bridge); 8482 } 8483 } else if (optind != argc) { 8484 usage(); 8485 } else if (op_mode != bridgeMode) { 8486 die("bridge name required for -l, -f, or -t"); 8487 return; 8488 } 8489 8490 brstate.state.ls_parsable = parsable; 8491 brstate.state.ls_flags = flags; 8492 brstate.state.ls_firstonly = (interval != 0); 8493 8494 switch (op_mode) { 8495 case bridgeMode: 8496 if (brstate.show_stats) { 8497 default_str = default_statfields; 8498 all_str = all_statfields; 8499 field_arr = bridge_statfields; 8500 } else { 8501 default_str = default_fields; 8502 all_str = all_fields; 8503 field_arr = bridge_fields; 8504 } 8505 break; 8506 8507 case linkMode: 8508 if (brstate.show_stats) { 8509 default_str = default_link_statfields; 8510 all_str = all_link_statfields; 8511 field_arr = bridge_link_statfields; 8512 } else { 8513 default_str = default_link_fields; 8514 all_str = all_link_fields; 8515 field_arr = bridge_link_fields; 8516 } 8517 break; 8518 8519 case fwdMode: 8520 default_str = all_str = default_fwd_fields; 8521 field_arr = bridge_fwd_fields; 8522 break; 8523 8524 case trillMode: 8525 default_str = all_str = default_trill_fields; 8526 field_arr = bridge_trill_fields; 8527 break; 8528 } 8529 8530 if (fields_str == NULL) 8531 fields_str = default_str; 8532 else if (strcasecmp(fields_str, "all") == 0) 8533 fields_str = all_str; 8534 8535 if (parsable) 8536 ofmtflags |= OFMT_PARSABLE; 8537 oferr = ofmt_open(fields_str, field_arr, ofmtflags, 0, &ofmt); 8538 dladm_ofmt_check(oferr, brstate.state.ls_parsable, ofmt); 8539 brstate.state.ls_ofmt = ofmt; 8540 8541 for (;;) { 8542 brstate.state.ls_donefirst = B_FALSE; 8543 switch (op_mode) { 8544 case bridgeMode: 8545 if (linkid == DATALINK_ALL_LINKID) { 8546 (void) dladm_walk_datalink_id(show_bridge, 8547 handle, &brstate, DATALINK_CLASS_BRIDGE, 8548 DATALINK_ANY_MEDIATYPE, flags); 8549 } else { 8550 (void) show_bridge(handle, linkid, &brstate); 8551 if (brstate.state.ls_status != 8552 DLADM_STATUS_OK) { 8553 die_dlerr(brstate.state.ls_status, 8554 "failed to show bridge %s", 8555 brstate.bridge); 8556 } 8557 } 8558 break; 8559 8560 case linkMode: { 8561 datalink_id_t *dlp; 8562 uint_t i, nlinks; 8563 8564 dlp = dladm_bridge_get_portlist(brstate.bridge, 8565 &nlinks); 8566 if (dlp != NULL) { 8567 for (i = 0; i < nlinks; i++) 8568 show_bridge_link(dlp[i], &brstate); 8569 dladm_bridge_free_portlist(dlp); 8570 } else if (errno == ENOENT) { 8571 /* bridge not running; iterate on libdladm */ 8572 (void) dladm_walk_datalink_id( 8573 show_bridge_link_walk, handle, 8574 &brstate, DATALINK_CLASS_PHYS | 8575 DATALINK_CLASS_AGGR | 8576 DATALINK_CLASS_ETHERSTUB, 8577 DATALINK_ANY_MEDIATYPE, flags); 8578 } else { 8579 die("unable to get port list for bridge %s: %s", 8580 brstate.bridge, strerror(errno)); 8581 } 8582 break; 8583 } 8584 8585 case fwdMode: { 8586 bridge_listfwd_t *blf; 8587 uint_t i, nfwd; 8588 8589 blf = dladm_bridge_get_fwdtable(handle, brstate.bridge, 8590 &nfwd); 8591 if (blf == NULL) { 8592 die("unable to get forwarding entries for " 8593 "bridge %s", brstate.bridge); 8594 } else { 8595 for (i = 0; i < nfwd; i++) 8596 show_bridge_fwd(handle, blf + i, 8597 &brstate.state); 8598 dladm_bridge_free_fwdtable(blf); 8599 } 8600 break; 8601 } 8602 8603 case trillMode: { 8604 trill_listnick_t *tln; 8605 uint_t i, nnick; 8606 8607 tln = dladm_bridge_get_trillnick(brstate.bridge, 8608 &nnick); 8609 if (tln == NULL) { 8610 if (errno == ENOENT) 8611 die("bridge %s is not running TRILL", 8612 brstate.bridge); 8613 else 8614 die("unable to get TRILL nickname " 8615 "entries for bridge %s", 8616 brstate.bridge); 8617 } else { 8618 for (i = 0; i < nnick; i++) 8619 show_bridge_trillnick(tln + i, 8620 &brstate.state); 8621 dladm_bridge_free_trillnick(tln); 8622 } 8623 break; 8624 } 8625 } 8626 if (interval == 0) 8627 break; 8628 (void) sleep(interval); 8629 } 8630 } 8631 8632 /* 8633 * "-R" option support. It is used for live upgrading. Append dladm commands 8634 * to a upgrade script which will be run when the alternative root boots up: 8635 * 8636 * - If the /etc/dladm/datalink.conf file exists on the alternative root, 8637 * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink 8638 * script. This script will be run as part of the network/physical service. 8639 * We cannot defer this to /var/svc/profile/upgrade because then the 8640 * configuration will not be able to take effect before network/physical 8641 * plumbs various interfaces. 8642 * 8643 * - If the /etc/dladm/datalink.conf file does not exist on the alternative 8644 * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script, 8645 * which will be run in the manifest-import service. 8646 * 8647 * Note that the SMF team is considering to move the manifest-import service 8648 * to be run at the very begining of boot. Once that is done, the need for 8649 * the /var/svc/profile/upgrade_datalink script will not exist any more. 8650 */ 8651 static void 8652 altroot_cmd(char *altroot, int argc, char *argv[]) 8653 { 8654 char path[MAXPATHLEN]; 8655 struct stat stbuf; 8656 FILE *fp; 8657 int i; 8658 8659 /* 8660 * Check for the existence of the /etc/dladm/datalink.conf 8661 * configuration file, and determine the name of script file. 8662 */ 8663 (void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf", 8664 altroot); 8665 if (stat(path, &stbuf) < 0) { 8666 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 8667 SMF_UPGRADE_FILE); 8668 } else { 8669 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 8670 SMF_UPGRADEDATALINK_FILE); 8671 } 8672 8673 if ((fp = fopen(path, "a+")) == NULL) 8674 die("operation not supported on %s", altroot); 8675 8676 (void) fprintf(fp, "/sbin/dladm "); 8677 for (i = 0; i < argc; i++) { 8678 /* 8679 * Directly write to the file if it is not the "-R <altroot>" 8680 * option. In which case, skip it. 8681 */ 8682 if (strcmp(argv[i], "-R") != 0) 8683 (void) fprintf(fp, "%s ", argv[i]); 8684 else 8685 i ++; 8686 } 8687 (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG); 8688 (void) fclose(fp); 8689 dladm_close(handle); 8690 exit(EXIT_SUCCESS); 8691 } 8692 8693 /* 8694 * Convert the string to an integer. Note that the string must not have any 8695 * trailing non-integer characters. 8696 */ 8697 static boolean_t 8698 str2int(const char *str, int *valp) 8699 { 8700 int val; 8701 char *endp = NULL; 8702 8703 errno = 0; 8704 val = strtol(str, &endp, 10); 8705 if (errno != 0 || *endp != '\0') 8706 return (B_FALSE); 8707 8708 *valp = val; 8709 return (B_TRUE); 8710 } 8711 8712 /* PRINTFLIKE1 */ 8713 static void 8714 warn(const char *format, ...) 8715 { 8716 va_list alist; 8717 8718 format = gettext(format); 8719 (void) fprintf(stderr, "%s: warning: ", progname); 8720 8721 va_start(alist, format); 8722 (void) vfprintf(stderr, format, alist); 8723 va_end(alist); 8724 8725 (void) putchar('\n'); 8726 } 8727 8728 /* PRINTFLIKE2 */ 8729 static void 8730 warn_dlerr(dladm_status_t err, const char *format, ...) 8731 { 8732 va_list alist; 8733 char errmsg[DLADM_STRSIZE]; 8734 8735 format = gettext(format); 8736 (void) fprintf(stderr, gettext("%s: warning: "), progname); 8737 8738 va_start(alist, format); 8739 (void) vfprintf(stderr, format, alist); 8740 va_end(alist); 8741 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 8742 } 8743 8744 /* 8745 * Also closes the dladm handle if it is not NULL. 8746 */ 8747 /* PRINTFLIKE2 */ 8748 static void 8749 die_dlerr(dladm_status_t err, const char *format, ...) 8750 { 8751 va_list alist; 8752 char errmsg[DLADM_STRSIZE]; 8753 8754 format = gettext(format); 8755 (void) fprintf(stderr, "%s: ", progname); 8756 8757 va_start(alist, format); 8758 (void) vfprintf(stderr, format, alist); 8759 va_end(alist); 8760 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 8761 8762 /* close dladm handle if it was opened */ 8763 if (handle != NULL) 8764 dladm_close(handle); 8765 8766 exit(EXIT_FAILURE); 8767 } 8768 8769 /* PRINTFLIKE1 */ 8770 static void 8771 die(const char *format, ...) 8772 { 8773 va_list alist; 8774 8775 format = gettext(format); 8776 (void) fprintf(stderr, "%s: ", progname); 8777 8778 va_start(alist, format); 8779 (void) vfprintf(stderr, format, alist); 8780 va_end(alist); 8781 8782 (void) putchar('\n'); 8783 8784 /* close dladm handle if it was opened */ 8785 if (handle != NULL) 8786 dladm_close(handle); 8787 8788 exit(EXIT_FAILURE); 8789 } 8790 8791 static void 8792 die_optdup(int opt) 8793 { 8794 die("the option -%c cannot be specified more than once", opt); 8795 } 8796 8797 static void 8798 die_opterr(int opt, int opterr, const char *usage) 8799 { 8800 switch (opterr) { 8801 case ':': 8802 die("option '-%c' requires a value\nusage: %s", opt, 8803 gettext(usage)); 8804 break; 8805 case '?': 8806 default: 8807 die("unrecognized option '-%c'\nusage: %s", opt, 8808 gettext(usage)); 8809 break; 8810 } 8811 } 8812 8813 static void 8814 show_ether_xprop(void *arg, dladm_ether_info_t *eattr) 8815 { 8816 print_ether_state_t *statep = arg; 8817 ether_fields_buf_t ebuf; 8818 int i; 8819 8820 for (i = CAPABLE; i <= PEERADV; i++) { 8821 bzero(&ebuf, sizeof (ebuf)); 8822 (void) strlcpy(ebuf.eth_ptype, ptype[i], 8823 sizeof (ebuf.eth_ptype)); 8824 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 8825 sizeof (ebuf.eth_autoneg), eattr, i); 8826 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 8827 sizeof (ebuf.eth_spdx), eattr, i); 8828 (void) dladm_ether_pause2str(ebuf.eth_pause, 8829 sizeof (ebuf.eth_pause), eattr, i); 8830 (void) strlcpy(ebuf.eth_rem_fault, 8831 (eattr->lei_attr[i].le_fault ? "fault" : "none"), 8832 sizeof (ebuf.eth_rem_fault)); 8833 ofmt_print(statep->es_ofmt, &ebuf); 8834 } 8835 8836 } 8837 8838 static boolean_t 8839 link_is_ether(const char *link, datalink_id_t *linkid) 8840 { 8841 uint32_t media; 8842 datalink_class_t class; 8843 8844 if (dladm_name2info(handle, link, linkid, NULL, &class, &media) == 8845 DLADM_STATUS_OK) { 8846 if (class == DATALINK_CLASS_PHYS && media == DL_ETHER) 8847 return (B_TRUE); 8848 } 8849 return (B_FALSE); 8850 } 8851 8852 /* 8853 * default output callback function that, when invoked, 8854 * prints string which is offset by ofmt_arg->ofmt_id within buf. 8855 */ 8856 static boolean_t 8857 print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 8858 { 8859 char *value; 8860 8861 value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id; 8862 (void) strlcpy(buf, value, bufsize); 8863 return (B_TRUE); 8864 } 8865 8866 static void 8867 dladm_ofmt_check(ofmt_status_t oferr, boolean_t parsable, 8868 ofmt_handle_t ofmt) 8869 { 8870 char buf[OFMT_BUFSIZE]; 8871 8872 if (oferr == OFMT_SUCCESS) 8873 return; 8874 (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf)); 8875 /* 8876 * All errors are considered fatal in parsable mode. 8877 * NOMEM errors are always fatal, regardless of mode. 8878 * For other errors, we print diagnostics in human-readable 8879 * mode and processs what we can. 8880 */ 8881 if (parsable || oferr == OFMT_ENOFIELDS) { 8882 ofmt_close(ofmt); 8883 die(buf); 8884 } else { 8885 warn(buf); 8886 } 8887 } 8888