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 [-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_RINGTYPE, 814 PHYS_H_RINGS, 815 PHYS_H_CLIENTS 816 } phys_h_field_index_t; 817 818 #define RINGSTRLEN 21 819 820 static const ofmt_field_t phys_h_fields[] = { 821 { "LINK", 13, PHYS_H_LINK, print_phys_one_hwgrp_cb}, 822 { "RINGTYPE", 9, PHYS_H_RINGTYPE, print_phys_one_hwgrp_cb}, 823 { "RINGS", RINGSTRLEN, PHYS_H_RINGS, print_phys_one_hwgrp_cb}, 824 { "CLIENTS", 24, 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 int i; 3698 boolean_t first = B_TRUE; 3699 int start = -1; 3700 int end = -1; 3701 char ringstr[RINGSTRLEN]; 3702 char ringsubstr[RINGSTRLEN]; 3703 3704 print_phys_hwgrp_state_t *hg_state = ofarg->ofmt_cbarg; 3705 dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr; 3706 3707 switch (ofarg->ofmt_id) { 3708 case PHYS_H_LINK: 3709 (void) snprintf(buf, bufsize, "%s", attr->hg_link_name); 3710 break; 3711 case PHYS_H_RINGTYPE: 3712 (void) snprintf(buf, bufsize, "%s", 3713 attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX"); 3714 break; 3715 case PHYS_H_RINGS: 3716 ringstr[0] = '\0'; 3717 for (i = 0; i < attr->hg_n_rings; i++) { 3718 uint_t index = attr->hg_rings[i]; 3719 3720 if (start == -1) { 3721 start = index; 3722 end = index; 3723 } else if (index == end + 1) { 3724 end = index; 3725 } else { 3726 if (start == end) { 3727 if (first) { 3728 (void) snprintf( 3729 ringsubstr, 3730 RINGSTRLEN, "%d", 3731 start); 3732 first = B_FALSE; 3733 } else { 3734 (void) snprintf( 3735 ringsubstr, 3736 RINGSTRLEN, ",%d", 3737 start); 3738 } 3739 } else { 3740 if (first) { 3741 (void) snprintf( 3742 ringsubstr, 3743 RINGSTRLEN, 3744 "%d-%d", 3745 start, end); 3746 first = B_FALSE; 3747 } else { 3748 (void) snprintf( 3749 ringsubstr, 3750 RINGSTRLEN, 3751 ",%d-%d", 3752 start, end); 3753 } 3754 } 3755 (void) strlcat(ringstr, ringsubstr, 3756 RINGSTRLEN); 3757 start = index; 3758 end = index; 3759 } 3760 } 3761 /* The last one */ 3762 if (start != -1) { 3763 if (first) { 3764 if (start == end) { 3765 (void) snprintf(buf, bufsize, "%d", 3766 start); 3767 } else { 3768 (void) snprintf(buf, bufsize, "%d-%d", 3769 start, end); 3770 } 3771 } else { 3772 if (start == end) { 3773 (void) snprintf(ringsubstr, RINGSTRLEN, 3774 ",%d", start); 3775 } else { 3776 (void) snprintf(ringsubstr, RINGSTRLEN, 3777 ",%d-%d", start, end); 3778 } 3779 (void) strlcat(ringstr, ringsubstr, RINGSTRLEN); 3780 (void) snprintf(buf, bufsize, "%s", ringstr); 3781 } 3782 } 3783 break; 3784 case PHYS_H_CLIENTS: 3785 if (attr->hg_client_names[0] == '\0') { 3786 (void) snprintf(buf, bufsize, "--"); 3787 } else { 3788 (void) snprintf(buf, bufsize, "%s ", 3789 attr->hg_client_names); 3790 } 3791 break; 3792 } 3793 3794 return (B_TRUE); 3795 } 3796 3797 /* 3798 * callback for dladm_walk_macaddr, invoked for each MAC address slot 3799 */ 3800 static boolean_t 3801 print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr) 3802 { 3803 print_phys_mac_state_t *mac_state = arg; 3804 show_state_t *state = mac_state->ms_state; 3805 3806 mac_state->ms_mac_attr = attr; 3807 ofmt_print(state->ls_ofmt, mac_state); 3808 3809 return (B_TRUE); 3810 } 3811 3812 /* 3813 * invoked by show-phys -m for each physical data-link 3814 */ 3815 static dladm_status_t 3816 print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link) 3817 { 3818 print_phys_mac_state_t mac_state; 3819 3820 mac_state.ms_state = state; 3821 mac_state.ms_link = link; 3822 3823 return (dladm_walk_macaddr(handle, linkid, &mac_state, 3824 print_phys_mac_callback)); 3825 } 3826 3827 /* 3828 * callback for dladm_walk_hwgrp, invoked for each MAC hwgrp 3829 */ 3830 static boolean_t 3831 print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr) 3832 { 3833 print_phys_hwgrp_state_t *hwgrp_state = arg; 3834 show_state_t *state = hwgrp_state->hs_state; 3835 3836 hwgrp_state->hs_grp_attr = attr; 3837 ofmt_print(state->ls_ofmt, hwgrp_state); 3838 3839 return (B_TRUE); 3840 } 3841 3842 /* invoked by show-phys -H for each physical data-link */ 3843 static dladm_status_t 3844 print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link) 3845 { 3846 print_phys_hwgrp_state_t hwgrp_state; 3847 3848 hwgrp_state.hs_state = state; 3849 hwgrp_state.hs_link = link; 3850 return (dladm_walk_hwgrp(handle, linkid, &hwgrp_state, 3851 print_phys_hwgrp_callback)); 3852 } 3853 3854 /* 3855 * Parse the "local=<laddr>,remote=<raddr>" sub-options for the -a option of 3856 * *-iptun subcommands. 3857 */ 3858 static void 3859 iptun_process_addrarg(char *addrarg, iptun_params_t *params) 3860 { 3861 char *addrval; 3862 3863 while (*addrarg != '\0') { 3864 switch (getsubopt(&addrarg, iptun_addropts, &addrval)) { 3865 case IPTUN_LOCAL: 3866 params->iptun_param_flags |= IPTUN_PARAM_LADDR; 3867 if (strlcpy(params->iptun_param_laddr, addrval, 3868 sizeof (params->iptun_param_laddr)) >= 3869 sizeof (params->iptun_param_laddr)) 3870 die("tunnel source address is too long"); 3871 break; 3872 case IPTUN_REMOTE: 3873 params->iptun_param_flags |= IPTUN_PARAM_RADDR; 3874 if (strlcpy(params->iptun_param_raddr, addrval, 3875 sizeof (params->iptun_param_raddr)) >= 3876 sizeof (params->iptun_param_raddr)) 3877 die("tunnel destination address is too long"); 3878 break; 3879 default: 3880 die("invalid address type: %s", addrval); 3881 break; 3882 } 3883 } 3884 } 3885 3886 /* 3887 * Convenience routine to process iptun-create/modify/delete subcommand 3888 * arguments. 3889 */ 3890 static void 3891 iptun_process_args(int argc, char *argv[], const char *opts, 3892 iptun_params_t *params, uint32_t *flags, char *name, const char *use) 3893 { 3894 int option; 3895 char *altroot = NULL; 3896 3897 if (params != NULL) 3898 bzero(params, sizeof (*params)); 3899 *flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 3900 3901 opterr = 0; 3902 while ((option = getopt_long(argc, argv, opts, iptun_lopts, NULL)) != 3903 -1) { 3904 switch (option) { 3905 case 'a': 3906 iptun_process_addrarg(optarg, params); 3907 break; 3908 case 'R': 3909 altroot = optarg; 3910 break; 3911 case 't': 3912 *flags &= ~DLADM_OPT_PERSIST; 3913 break; 3914 case 'T': 3915 params->iptun_param_type = iptun_gettypebyname(optarg); 3916 if (params->iptun_param_type == IPTUN_TYPE_UNKNOWN) 3917 die("unknown tunnel type: %s", optarg); 3918 params->iptun_param_flags |= IPTUN_PARAM_TYPE; 3919 break; 3920 default: 3921 die_opterr(optopt, option, use); 3922 break; 3923 } 3924 } 3925 3926 /* Get the required tunnel name argument. */ 3927 if (argc - optind != 1) 3928 usage(); 3929 3930 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 3931 die("tunnel name is too long"); 3932 3933 if (altroot != NULL) 3934 altroot_cmd(altroot, argc, argv); 3935 } 3936 3937 static void 3938 do_create_iptun(int argc, char *argv[], const char *use) 3939 { 3940 iptun_params_t params; 3941 dladm_status_t status; 3942 uint32_t flags; 3943 char name[MAXLINKNAMELEN]; 3944 3945 iptun_process_args(argc, argv, ":a:R:tT:", ¶ms, &flags, name, 3946 use); 3947 3948 status = dladm_iptun_create(handle, name, ¶ms, flags); 3949 if (status != DLADM_STATUS_OK) 3950 die_dlerr(status, "could not create tunnel"); 3951 } 3952 3953 static void 3954 do_delete_iptun(int argc, char *argv[], const char *use) 3955 { 3956 uint32_t flags; 3957 datalink_id_t linkid; 3958 dladm_status_t status; 3959 char name[MAXLINKNAMELEN]; 3960 3961 iptun_process_args(argc, argv, ":R:t", NULL, &flags, name, use); 3962 3963 status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL); 3964 if (status != DLADM_STATUS_OK) 3965 die_dlerr(status, "could not delete tunnel"); 3966 status = dladm_iptun_delete(handle, linkid, flags); 3967 if (status != DLADM_STATUS_OK) 3968 die_dlerr(status, "could not delete tunnel"); 3969 } 3970 3971 static void 3972 do_modify_iptun(int argc, char *argv[], const char *use) 3973 { 3974 iptun_params_t params; 3975 uint32_t flags; 3976 dladm_status_t status; 3977 char name[MAXLINKNAMELEN]; 3978 3979 iptun_process_args(argc, argv, ":a:R:t", ¶ms, &flags, name, use); 3980 3981 if ((status = dladm_name2info(handle, name, ¶ms.iptun_param_linkid, 3982 NULL, NULL, NULL)) != DLADM_STATUS_OK) 3983 die_dlerr(status, "could not modify tunnel"); 3984 status = dladm_iptun_modify(handle, ¶ms, flags); 3985 if (status != DLADM_STATUS_OK) 3986 die_dlerr(status, "could not modify tunnel"); 3987 } 3988 3989 static void 3990 do_show_iptun(int argc, char *argv[], const char *use) 3991 { 3992 char option; 3993 datalink_id_t linkid; 3994 uint32_t flags = DLADM_OPT_ACTIVE; 3995 char *name = NULL; 3996 dladm_status_t status; 3997 const char *fields_str = NULL; 3998 show_state_t state; 3999 ofmt_handle_t ofmt; 4000 ofmt_status_t oferr; 4001 uint_t ofmtflags = 0; 4002 4003 bzero(&state, sizeof (state)); 4004 opterr = 0; 4005 while ((option = getopt_long(argc, argv, ":pPo:", 4006 iptun_lopts, NULL)) != -1) { 4007 switch (option) { 4008 case 'o': 4009 fields_str = optarg; 4010 break; 4011 case 'p': 4012 state.ls_parsable = B_TRUE; 4013 ofmtflags = OFMT_PARSABLE; 4014 break; 4015 case 'P': 4016 flags = DLADM_OPT_PERSIST; 4017 break; 4018 default: 4019 die_opterr(optopt, option, use); 4020 break; 4021 } 4022 } 4023 4024 /* 4025 * Get the optional tunnel name argument. If there is one, it must 4026 * be the last thing remaining on the command-line. 4027 */ 4028 if (argc - optind > 1) 4029 die(gettext(use)); 4030 if (argc - optind == 1) 4031 name = argv[optind]; 4032 4033 oferr = ofmt_open(fields_str, iptun_fields, ofmtflags, 4034 DLADM_DEFAULT_COL, &ofmt); 4035 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 4036 4037 state.ls_ofmt = ofmt; 4038 state.ls_flags = flags; 4039 4040 if (name == NULL) { 4041 (void) dladm_walk_datalink_id(print_iptun_walker, handle, 4042 &state, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE, 4043 flags); 4044 status = state.ls_status; 4045 } else { 4046 if ((status = dladm_name2info(handle, name, &linkid, NULL, NULL, 4047 NULL)) == DLADM_STATUS_OK) 4048 status = print_iptun(handle, linkid, &state); 4049 } 4050 4051 if (status != DLADM_STATUS_OK) 4052 die_dlerr(status, "unable to obtain tunnel status"); 4053 } 4054 4055 /* ARGSUSED */ 4056 static void 4057 do_up_iptun(int argc, char *argv[], const char *use) 4058 { 4059 datalink_id_t linkid = DATALINK_ALL_LINKID; 4060 dladm_status_t status = DLADM_STATUS_OK; 4061 4062 /* 4063 * Get the optional tunnel name argument. If there is one, it must 4064 * be the last thing remaining on the command-line. 4065 */ 4066 if (argc - optind > 1) 4067 usage(); 4068 if (argc - optind == 1) { 4069 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 4070 NULL, NULL); 4071 } 4072 if (status == DLADM_STATUS_OK) 4073 status = dladm_iptun_up(handle, linkid); 4074 if (status != DLADM_STATUS_OK) 4075 die_dlerr(status, "unable to configure IP tunnel links"); 4076 } 4077 4078 /* ARGSUSED */ 4079 static void 4080 do_down_iptun(int argc, char *argv[], const char *use) 4081 { 4082 datalink_id_t linkid = DATALINK_ALL_LINKID; 4083 dladm_status_t status = DLADM_STATUS_OK; 4084 4085 /* 4086 * Get the optional tunnel name argument. If there is one, it must 4087 * be the last thing remaining on the command-line. 4088 */ 4089 if (argc - optind > 1) 4090 usage(); 4091 if (argc - optind == 1) { 4092 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 4093 NULL, NULL); 4094 } 4095 if (status == DLADM_STATUS_OK) 4096 status = dladm_iptun_down(handle, linkid); 4097 if (status != DLADM_STATUS_OK) 4098 die_dlerr(status, "unable to bring down IP tunnel links"); 4099 } 4100 4101 static iptun_type_t 4102 iptun_gettypebyname(char *typestr) 4103 { 4104 int i; 4105 4106 for (i = 0; iptun_types[i].type_name != NULL; i++) { 4107 if (strncmp(iptun_types[i].type_name, typestr, 4108 strlen(iptun_types[i].type_name)) == 0) { 4109 return (iptun_types[i].type_value); 4110 } 4111 } 4112 return (IPTUN_TYPE_UNKNOWN); 4113 } 4114 4115 static const char * 4116 iptun_gettypebyvalue(iptun_type_t type) 4117 { 4118 int i; 4119 4120 for (i = 0; iptun_types[i].type_name != NULL; i++) { 4121 if (iptun_types[i].type_value == type) 4122 return (iptun_types[i].type_name); 4123 } 4124 return (NULL); 4125 } 4126 4127 static dladm_status_t 4128 print_iptun(dladm_handle_t dh, datalink_id_t linkid, show_state_t *state) 4129 { 4130 dladm_status_t status; 4131 iptun_params_t params; 4132 iptun_fields_buf_t lbuf; 4133 const char *laddr; 4134 const char *raddr; 4135 4136 params.iptun_param_linkid = linkid; 4137 status = dladm_iptun_getparams(dh, ¶ms, state->ls_flags); 4138 if (status != DLADM_STATUS_OK) 4139 return (status); 4140 4141 /* LINK */ 4142 status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, 4143 lbuf.iptun_name, sizeof (lbuf.iptun_name)); 4144 if (status != DLADM_STATUS_OK) 4145 return (status); 4146 4147 /* TYPE */ 4148 (void) strlcpy(lbuf.iptun_type, 4149 iptun_gettypebyvalue(params.iptun_param_type), 4150 sizeof (lbuf.iptun_type)); 4151 4152 /* FLAGS */ 4153 (void) memset(lbuf.iptun_flags, '-', IPTUN_NUM_FLAGS); 4154 lbuf.iptun_flags[IPTUN_NUM_FLAGS] = '\0'; 4155 if (params.iptun_param_flags & IPTUN_PARAM_IPSECPOL) 4156 lbuf.iptun_flags[IPTUN_SFLAG_INDEX] = 's'; 4157 if (params.iptun_param_flags & IPTUN_PARAM_IMPLICIT) 4158 lbuf.iptun_flags[IPTUN_IFLAG_INDEX] = 'i'; 4159 4160 /* LOCAL */ 4161 if (params.iptun_param_flags & IPTUN_PARAM_LADDR) 4162 laddr = params.iptun_param_laddr; 4163 else 4164 laddr = (state->ls_parsable) ? "" : "--"; 4165 (void) strlcpy(lbuf.iptun_laddr, laddr, sizeof (lbuf.iptun_laddr)); 4166 4167 /* REMOTE */ 4168 if (params.iptun_param_flags & IPTUN_PARAM_RADDR) 4169 raddr = params.iptun_param_raddr; 4170 else 4171 raddr = (state->ls_parsable) ? "" : "--"; 4172 (void) strlcpy(lbuf.iptun_raddr, raddr, sizeof (lbuf.iptun_raddr)); 4173 4174 ofmt_print(state->ls_ofmt, &lbuf); 4175 4176 return (DLADM_STATUS_OK); 4177 } 4178 4179 static int 4180 print_iptun_walker(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4181 { 4182 ((show_state_t *)arg)->ls_status = print_iptun(dh, linkid, arg); 4183 return (DLADM_WALK_CONTINUE); 4184 } 4185 4186 static dladm_status_t 4187 print_phys(show_state_t *state, datalink_id_t linkid) 4188 { 4189 char link[MAXLINKNAMELEN]; 4190 uint32_t flags; 4191 dladm_status_t status; 4192 datalink_class_t class; 4193 uint32_t media; 4194 4195 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 4196 &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 4197 goto done; 4198 } 4199 4200 if (class != DATALINK_CLASS_PHYS) { 4201 status = DLADM_STATUS_BADARG; 4202 goto done; 4203 } 4204 4205 if (!(state->ls_flags & flags)) { 4206 status = DLADM_STATUS_NOTFOUND; 4207 goto done; 4208 } 4209 4210 if (state->ls_mac) 4211 status = print_phys_mac(state, linkid, link); 4212 else if (state->ls_hwgrp) 4213 status = print_phys_hwgrp(state, linkid, link); 4214 else 4215 status = print_phys_default(state, linkid, link, flags, media); 4216 4217 done: 4218 return (status); 4219 } 4220 4221 /* ARGSUSED */ 4222 static int 4223 show_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4224 { 4225 show_state_t *state = arg; 4226 4227 state->ls_status = print_phys(state, linkid); 4228 return (DLADM_WALK_CONTINUE); 4229 } 4230 4231 /* 4232 * Print the active topology information. 4233 */ 4234 static dladm_status_t 4235 print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l) 4236 { 4237 dladm_vlan_attr_t vinfo; 4238 uint32_t flags; 4239 dladm_status_t status; 4240 4241 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL, 4242 l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) { 4243 goto done; 4244 } 4245 4246 if (!(state->ls_flags & flags)) { 4247 status = DLADM_STATUS_NOTFOUND; 4248 goto done; 4249 } 4250 4251 if ((status = dladm_vlan_info(handle, linkid, &vinfo, 4252 state->ls_flags)) != DLADM_STATUS_OK || 4253 (status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, 4254 NULL, NULL, l->link_over, sizeof (l->link_over))) != 4255 DLADM_STATUS_OK) { 4256 goto done; 4257 } 4258 4259 (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d", 4260 vinfo.dv_vid); 4261 (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----", 4262 vinfo.dv_force ? 'f' : '-'); 4263 4264 done: 4265 return (status); 4266 } 4267 4268 /* ARGSUSED */ 4269 static int 4270 show_vlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4271 { 4272 show_state_t *state = arg; 4273 dladm_status_t status; 4274 link_fields_buf_t lbuf; 4275 4276 bzero(&lbuf, sizeof (link_fields_buf_t)); 4277 status = print_vlan(state, linkid, &lbuf); 4278 if (status != DLADM_STATUS_OK) 4279 goto done; 4280 4281 ofmt_print(state->ls_ofmt, &lbuf); 4282 4283 done: 4284 state->ls_status = status; 4285 return (DLADM_WALK_CONTINUE); 4286 } 4287 4288 static void 4289 do_show_phys(int argc, char *argv[], const char *use) 4290 { 4291 int option; 4292 uint32_t flags = DLADM_OPT_ACTIVE; 4293 boolean_t p_arg = B_FALSE; 4294 boolean_t o_arg = B_FALSE; 4295 boolean_t m_arg = B_FALSE; 4296 boolean_t H_arg = B_FALSE; 4297 datalink_id_t linkid = DATALINK_ALL_LINKID; 4298 show_state_t state; 4299 dladm_status_t status; 4300 char *fields_str = NULL; 4301 char *all_active_fields = 4302 "link,media,state,speed,duplex,device"; 4303 char *all_inactive_fields = "link,device,media,flags"; 4304 char *all_mac_fields = "link,slot,address,inuse,client"; 4305 char *all_hwgrp_fields = "link,ringtype,rings,clients"; 4306 const ofmt_field_t *pf; 4307 ofmt_handle_t ofmt; 4308 ofmt_status_t oferr; 4309 uint_t ofmtflags = 0; 4310 4311 bzero(&state, sizeof (state)); 4312 opterr = 0; 4313 while ((option = getopt_long(argc, argv, ":pPo:mH", 4314 show_lopts, NULL)) != -1) { 4315 switch (option) { 4316 case 'p': 4317 if (p_arg) 4318 die_optdup(option); 4319 4320 p_arg = B_TRUE; 4321 break; 4322 case 'P': 4323 if (flags != DLADM_OPT_ACTIVE) 4324 die_optdup(option); 4325 4326 flags = DLADM_OPT_PERSIST; 4327 break; 4328 case 'o': 4329 o_arg = B_TRUE; 4330 fields_str = optarg; 4331 break; 4332 case 'm': 4333 m_arg = B_TRUE; 4334 break; 4335 case 'H': 4336 H_arg = B_TRUE; 4337 break; 4338 default: 4339 die_opterr(optopt, option, use); 4340 break; 4341 } 4342 } 4343 4344 if (p_arg && !o_arg) 4345 die("-p requires -o"); 4346 4347 if (m_arg && H_arg) 4348 die("-m cannot combine with -H"); 4349 4350 if (p_arg && strcasecmp(fields_str, "all") == 0) 4351 die("\"-o all\" is invalid with -p"); 4352 4353 /* get link name (optional last argument) */ 4354 if (optind == (argc-1)) { 4355 if ((status = dladm_name2info(handle, argv[optind], &linkid, 4356 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 4357 die_dlerr(status, "link %s is not valid", argv[optind]); 4358 } 4359 } else if (optind != argc) { 4360 usage(); 4361 } 4362 4363 state.ls_parsable = p_arg; 4364 state.ls_flags = flags; 4365 state.ls_donefirst = B_FALSE; 4366 state.ls_mac = m_arg; 4367 state.ls_hwgrp = H_arg; 4368 4369 if (m_arg && !(flags & DLADM_OPT_ACTIVE)) { 4370 /* 4371 * We can only display the factory MAC addresses of 4372 * active data-links. 4373 */ 4374 die("-m not compatible with -P"); 4375 } 4376 4377 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 4378 if (state.ls_mac) 4379 fields_str = all_mac_fields; 4380 else if (state.ls_hwgrp) 4381 fields_str = all_hwgrp_fields; 4382 else if (state.ls_flags & DLADM_OPT_ACTIVE) { 4383 fields_str = all_active_fields; 4384 } else { 4385 fields_str = all_inactive_fields; 4386 } 4387 } 4388 4389 if (state.ls_mac) { 4390 pf = phys_m_fields; 4391 } else if (state.ls_hwgrp) { 4392 pf = phys_h_fields; 4393 } else { 4394 pf = phys_fields; 4395 } 4396 4397 if (state.ls_parsable) 4398 ofmtflags |= OFMT_PARSABLE; 4399 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 4400 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 4401 state.ls_ofmt = ofmt; 4402 4403 if (linkid == DATALINK_ALL_LINKID) { 4404 (void) dladm_walk_datalink_id(show_phys, handle, &state, 4405 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags); 4406 } else { 4407 (void) show_phys(handle, linkid, &state); 4408 if (state.ls_status != DLADM_STATUS_OK) { 4409 die_dlerr(state.ls_status, 4410 "failed to show physical link %s", argv[optind]); 4411 } 4412 } 4413 ofmt_close(ofmt); 4414 } 4415 4416 static void 4417 do_show_vlan(int argc, char *argv[], const char *use) 4418 { 4419 int option; 4420 uint32_t flags = DLADM_OPT_ACTIVE; 4421 boolean_t p_arg = B_FALSE; 4422 datalink_id_t linkid = DATALINK_ALL_LINKID; 4423 show_state_t state; 4424 dladm_status_t status; 4425 boolean_t o_arg = B_FALSE; 4426 char *fields_str = NULL; 4427 ofmt_handle_t ofmt; 4428 ofmt_status_t oferr; 4429 uint_t ofmtflags = 0; 4430 4431 bzero(&state, sizeof (state)); 4432 4433 opterr = 0; 4434 while ((option = getopt_long(argc, argv, ":pPo:", 4435 show_lopts, NULL)) != -1) { 4436 switch (option) { 4437 case 'p': 4438 if (p_arg) 4439 die_optdup(option); 4440 4441 p_arg = B_TRUE; 4442 break; 4443 case 'P': 4444 if (flags != DLADM_OPT_ACTIVE) 4445 die_optdup(option); 4446 4447 flags = DLADM_OPT_PERSIST; 4448 break; 4449 case 'o': 4450 o_arg = B_TRUE; 4451 fields_str = optarg; 4452 break; 4453 default: 4454 die_opterr(optopt, option, use); 4455 break; 4456 } 4457 } 4458 4459 /* get link name (optional last argument) */ 4460 if (optind == (argc-1)) { 4461 if ((status = dladm_name2info(handle, argv[optind], &linkid, 4462 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 4463 die_dlerr(status, "link %s is not valid", argv[optind]); 4464 } 4465 } else if (optind != argc) { 4466 usage(); 4467 } 4468 4469 state.ls_parsable = p_arg; 4470 state.ls_flags = flags; 4471 state.ls_donefirst = B_FALSE; 4472 4473 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 4474 fields_str = NULL; 4475 4476 if (state.ls_parsable) 4477 ofmtflags |= OFMT_PARSABLE; 4478 oferr = ofmt_open(fields_str, vlan_fields, ofmtflags, 0, &ofmt); 4479 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 4480 state.ls_ofmt = ofmt; 4481 4482 if (linkid == DATALINK_ALL_LINKID) { 4483 (void) dladm_walk_datalink_id(show_vlan, handle, &state, 4484 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags); 4485 } else { 4486 (void) show_vlan(handle, linkid, &state); 4487 if (state.ls_status != DLADM_STATUS_OK) { 4488 die_dlerr(state.ls_status, "failed to show vlan %s", 4489 argv[optind]); 4490 } 4491 } 4492 ofmt_close(ofmt); 4493 } 4494 4495 static void 4496 do_create_vnic(int argc, char *argv[], const char *use) 4497 { 4498 datalink_id_t linkid, dev_linkid; 4499 char devname[MAXLINKNAMELEN]; 4500 char name[MAXLINKNAMELEN]; 4501 boolean_t l_arg = B_FALSE; 4502 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4503 char *altroot = NULL; 4504 int option; 4505 char *endp = NULL; 4506 dladm_status_t status; 4507 vnic_mac_addr_type_t mac_addr_type = VNIC_MAC_ADDR_TYPE_UNKNOWN; 4508 uchar_t *mac_addr = NULL; 4509 int mac_slot = -1; 4510 uint_t maclen = 0, mac_prefix_len = 0; 4511 char propstr[DLADM_STRSIZE]; 4512 dladm_arg_list_t *proplist = NULL; 4513 int vid = 0; 4514 int af = AF_UNSPEC; 4515 vrid_t vrid = VRRP_VRID_NONE; 4516 4517 opterr = 0; 4518 bzero(propstr, DLADM_STRSIZE); 4519 4520 while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:V:A:H", 4521 vnic_lopts, NULL)) != -1) { 4522 switch (option) { 4523 case 't': 4524 flags &= ~DLADM_OPT_PERSIST; 4525 break; 4526 case 'R': 4527 altroot = optarg; 4528 break; 4529 case 'l': 4530 if (strlcpy(devname, optarg, MAXLINKNAMELEN) >= 4531 MAXLINKNAMELEN) 4532 die("link name too long"); 4533 l_arg = B_TRUE; 4534 break; 4535 case 'm': 4536 if (mac_addr_type != VNIC_MAC_ADDR_TYPE_UNKNOWN) 4537 die("cannot specify -m option twice"); 4538 4539 if (strcmp(optarg, "fixed") == 0) { 4540 /* 4541 * A fixed MAC address must be specified 4542 * by its value, not by the keyword 'fixed'. 4543 */ 4544 die("'fixed' is not a valid MAC address"); 4545 } 4546 if (dladm_vnic_str2macaddrtype(optarg, 4547 &mac_addr_type) != DLADM_STATUS_OK) { 4548 mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED; 4549 /* MAC address specified by value */ 4550 mac_addr = _link_aton(optarg, (int *)&maclen); 4551 if (mac_addr == NULL) { 4552 if (maclen == (uint_t)-1) 4553 die("invalid MAC address"); 4554 else 4555 die("out of memory"); 4556 } 4557 } 4558 break; 4559 case 'n': 4560 errno = 0; 4561 mac_slot = (int)strtol(optarg, &endp, 10); 4562 if (errno != 0 || *endp != '\0') 4563 die("invalid slot number"); 4564 break; 4565 case 'p': 4566 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 4567 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 4568 DLADM_STRSIZE) 4569 die("property list too long '%s'", propstr); 4570 break; 4571 case 'r': 4572 mac_addr = _link_aton(optarg, (int *)&mac_prefix_len); 4573 if (mac_addr == NULL) { 4574 if (mac_prefix_len == (uint_t)-1) 4575 die("invalid MAC address"); 4576 else 4577 die("out of memory"); 4578 } 4579 break; 4580 case 'V': 4581 if (!str2int(optarg, (int *)&vrid) || 4582 vrid < VRRP_VRID_MIN || vrid > VRRP_VRID_MAX) { 4583 die("invalid VRRP identifier '%s'", optarg); 4584 } 4585 4586 break; 4587 case 'A': 4588 if (strcmp(optarg, "inet") == 0) 4589 af = AF_INET; 4590 else if (strcmp(optarg, "inet6") == 0) 4591 af = AF_INET6; 4592 else 4593 die("invalid address family '%s'", optarg); 4594 break; 4595 case 'v': 4596 if (vid != 0) 4597 die_optdup(option); 4598 4599 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 4600 die("invalid VLAN identifier '%s'", optarg); 4601 4602 break; 4603 case 'f': 4604 flags |= DLADM_OPT_FORCE; 4605 break; 4606 default: 4607 die_opterr(optopt, option, use); 4608 } 4609 } 4610 4611 if (mac_addr_type == VNIC_MAC_ADDR_TYPE_UNKNOWN) 4612 mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO; 4613 4614 /* 4615 * 'f' - force, flag can be specified only with 'v' - vlan. 4616 */ 4617 if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0) 4618 die("-f option can only be used with -v"); 4619 4620 if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM && 4621 mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED) 4622 usage(); 4623 4624 if (mac_addr_type == VNIC_MAC_ADDR_TYPE_VRID) { 4625 if (vrid == VRRP_VRID_NONE || af == AF_UNSPEC || 4626 mac_addr != NULL || maclen != 0 || mac_slot != -1 || 4627 mac_prefix_len != 0) { 4628 usage(); 4629 } 4630 } else if ((af != AF_UNSPEC || vrid != VRRP_VRID_NONE)) { 4631 usage(); 4632 } 4633 4634 /* check required options */ 4635 if (!l_arg) 4636 usage(); 4637 4638 if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY) 4639 usage(); 4640 4641 /* the VNIC id is the required operand */ 4642 if (optind != (argc - 1)) 4643 usage(); 4644 4645 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 4646 die("link name too long '%s'", argv[optind]); 4647 4648 if (!dladm_valid_linkname(name)) 4649 die("invalid link name '%s'", argv[optind]); 4650 4651 if (altroot != NULL) 4652 altroot_cmd(altroot, argc, argv); 4653 4654 if (dladm_name2info(handle, devname, &dev_linkid, NULL, NULL, NULL) != 4655 DLADM_STATUS_OK) 4656 die("invalid link name '%s'", devname); 4657 4658 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 4659 != DLADM_STATUS_OK) 4660 die("invalid vnic property"); 4661 4662 status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type, 4663 mac_addr, maclen, &mac_slot, mac_prefix_len, vid, vrid, af, 4664 &linkid, proplist, flags); 4665 switch (status) { 4666 case DLADM_STATUS_OK: 4667 break; 4668 4669 case DLADM_STATUS_LINKBUSY: 4670 die("VLAN over '%s' may not use default_tag ID " 4671 "(see dladm(1M))", devname); 4672 break; 4673 4674 default: 4675 die_dlerr(status, "vnic creation over %s failed", devname); 4676 } 4677 4678 dladm_free_props(proplist); 4679 free(mac_addr); 4680 } 4681 4682 static void 4683 do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub, 4684 uint32_t flags) 4685 { 4686 boolean_t is_etherstub; 4687 dladm_vnic_attr_t attr; 4688 4689 if (dladm_vnic_info(handle, linkid, &attr, flags) != DLADM_STATUS_OK) { 4690 /* 4691 * Let the delete continue anyway. 4692 */ 4693 return; 4694 } 4695 is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID); 4696 if (is_etherstub != etherstub) { 4697 die("'%s' is not %s", name, 4698 (is_etherstub ? "a vnic" : "an etherstub")); 4699 } 4700 } 4701 4702 static void 4703 do_delete_vnic_common(int argc, char *argv[], const char *use, 4704 boolean_t etherstub) 4705 { 4706 int option; 4707 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4708 datalink_id_t linkid; 4709 char *altroot = NULL; 4710 dladm_status_t status; 4711 4712 opterr = 0; 4713 while ((option = getopt_long(argc, argv, ":R:t", lopts, 4714 NULL)) != -1) { 4715 switch (option) { 4716 case 't': 4717 flags &= ~DLADM_OPT_PERSIST; 4718 break; 4719 case 'R': 4720 altroot = optarg; 4721 break; 4722 default: 4723 die_opterr(optopt, option, use); 4724 } 4725 } 4726 4727 /* get vnic name (required last argument) */ 4728 if (optind != (argc - 1)) 4729 usage(); 4730 4731 if (altroot != NULL) 4732 altroot_cmd(altroot, argc, argv); 4733 4734 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 4735 NULL); 4736 if (status != DLADM_STATUS_OK) 4737 die("invalid link name '%s'", argv[optind]); 4738 4739 if ((flags & DLADM_OPT_ACTIVE) != 0) { 4740 do_etherstub_check(argv[optind], linkid, etherstub, 4741 DLADM_OPT_ACTIVE); 4742 } 4743 if ((flags & DLADM_OPT_PERSIST) != 0) { 4744 do_etherstub_check(argv[optind], linkid, etherstub, 4745 DLADM_OPT_PERSIST); 4746 } 4747 4748 status = dladm_vnic_delete(handle, linkid, flags); 4749 if (status != DLADM_STATUS_OK) 4750 die_dlerr(status, "vnic deletion failed"); 4751 } 4752 4753 static void 4754 do_delete_vnic(int argc, char *argv[], const char *use) 4755 { 4756 do_delete_vnic_common(argc, argv, use, B_FALSE); 4757 } 4758 4759 /* ARGSUSED */ 4760 static void 4761 do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan) 4762 { 4763 datalink_id_t linkid = DATALINK_ALL_LINKID; 4764 dladm_status_t status; 4765 char *type; 4766 4767 type = vlan ? "vlan" : "vnic"; 4768 4769 /* 4770 * get the id or the name of the vnic/vlan (optional last argument) 4771 */ 4772 if (argc == 2) { 4773 status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL, 4774 NULL); 4775 if (status != DLADM_STATUS_OK) 4776 goto done; 4777 4778 } else if (argc > 2) { 4779 usage(); 4780 } 4781 4782 if (vlan) 4783 status = dladm_vlan_up(handle, linkid); 4784 else 4785 status = dladm_vnic_up(handle, linkid, 0); 4786 4787 done: 4788 if (status != DLADM_STATUS_OK) { 4789 if (argc == 2) { 4790 die_dlerr(status, 4791 "could not bring up %s '%s'", type, argv[1]); 4792 } else { 4793 die_dlerr(status, "could not bring %ss up", type); 4794 } 4795 } 4796 } 4797 4798 static void 4799 do_up_vnic(int argc, char *argv[], const char *use) 4800 { 4801 do_up_vnic_common(argc, argv, use, B_FALSE); 4802 } 4803 4804 static void 4805 dump_vnics_head(const char *dev) 4806 { 4807 if (strlen(dev)) 4808 (void) printf("%s", dev); 4809 4810 (void) printf("\tipackets rbytes opackets obytes "); 4811 4812 if (strlen(dev)) 4813 (void) printf("%%ipkts %%opkts\n"); 4814 else 4815 (void) printf("\n"); 4816 } 4817 4818 static void 4819 dump_vnic_stat(const char *name, datalink_id_t vnic_id, 4820 show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats) 4821 { 4822 pktsum_t diff_stats; 4823 pktsum_t *old_stats = &state->vs_prevstats[vnic_id]; 4824 4825 dladm_stats_diff(&diff_stats, vnic_stats, old_stats); 4826 4827 (void) printf("%s", name); 4828 4829 (void) printf("\t%-10llu", diff_stats.ipackets); 4830 (void) printf("%-12llu", diff_stats.rbytes); 4831 (void) printf("%-10llu", diff_stats.opackets); 4832 (void) printf("%-12llu", diff_stats.obytes); 4833 4834 if (tot_stats) { 4835 if (tot_stats->ipackets == 0) { 4836 (void) printf("\t-"); 4837 } else { 4838 (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 4839 (double)tot_stats->ipackets * 100); 4840 } 4841 if (tot_stats->opackets == 0) { 4842 (void) printf("\t-"); 4843 } else { 4844 (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 4845 (double)tot_stats->opackets * 100); 4846 } 4847 } 4848 (void) printf("\n"); 4849 4850 *old_stats = *vnic_stats; 4851 } 4852 4853 /* 4854 * Called from the walker dladm_vnic_walk_sys() for each vnic to display 4855 * vnic information or statistics. 4856 */ 4857 static dladm_status_t 4858 print_vnic(show_vnic_state_t *state, datalink_id_t linkid) 4859 { 4860 dladm_vnic_attr_t attr, *vnic = &attr; 4861 dladm_status_t status; 4862 boolean_t is_etherstub; 4863 char devname[MAXLINKNAMELEN]; 4864 char vnic_name[MAXLINKNAMELEN]; 4865 char mstr[MAXMACADDRLEN * 3]; 4866 vnic_fields_buf_t vbuf; 4867 4868 if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) != 4869 DLADM_STATUS_OK) 4870 return (status); 4871 4872 is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID); 4873 if (state->vs_etherstub != is_etherstub) { 4874 /* 4875 * Want all etherstub but it's not one, or want 4876 * non-etherstub and it's one. 4877 */ 4878 return (DLADM_STATUS_OK); 4879 } 4880 4881 if (state->vs_link_id != DATALINK_ALL_LINKID) { 4882 if (state->vs_link_id != vnic->va_link_id) 4883 return (DLADM_STATUS_OK); 4884 } 4885 4886 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, 4887 NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK) 4888 return (DLADM_STATUS_BADARG); 4889 4890 bzero(devname, sizeof (devname)); 4891 if (!is_etherstub && 4892 dladm_datalink_id2info(handle, vnic->va_link_id, NULL, NULL, 4893 NULL, devname, sizeof (devname)) != DLADM_STATUS_OK) 4894 (void) sprintf(devname, "?"); 4895 4896 state->vs_found = B_TRUE; 4897 if (state->vs_stats) { 4898 /* print vnic statistics */ 4899 pktsum_t vnic_stats; 4900 4901 if (state->vs_firstonly) { 4902 if (state->vs_donefirst) 4903 return (0); 4904 state->vs_donefirst = B_TRUE; 4905 } 4906 4907 if (!state->vs_printstats) { 4908 /* 4909 * get vnic statistics and add to the sum for the 4910 * named device. 4911 */ 4912 get_link_stats(vnic_name, &vnic_stats); 4913 dladm_stats_total(&state->vs_totalstats, &vnic_stats, 4914 &state->vs_prevstats[vnic->va_vnic_id]); 4915 } else { 4916 /* get and print vnic statistics */ 4917 get_link_stats(vnic_name, &vnic_stats); 4918 dump_vnic_stat(vnic_name, linkid, state, &vnic_stats, 4919 &state->vs_totalstats); 4920 } 4921 return (DLADM_STATUS_OK); 4922 } else { 4923 (void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link), 4924 "%s", vnic_name); 4925 4926 if (!is_etherstub) { 4927 4928 (void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over), 4929 "%s", devname); 4930 (void) snprintf(vbuf.vnic_speed, 4931 sizeof (vbuf.vnic_speed), "%u", 4932 (uint_t)((get_ifspeed(vnic_name, B_TRUE)) 4933 / 1000000ull)); 4934 4935 switch (vnic->va_mac_addr_type) { 4936 case VNIC_MAC_ADDR_TYPE_FIXED: 4937 case VNIC_MAC_ADDR_TYPE_PRIMARY: 4938 (void) snprintf(vbuf.vnic_macaddrtype, 4939 sizeof (vbuf.vnic_macaddrtype), 4940 gettext("fixed")); 4941 break; 4942 case VNIC_MAC_ADDR_TYPE_RANDOM: 4943 (void) snprintf(vbuf.vnic_macaddrtype, 4944 sizeof (vbuf.vnic_macaddrtype), 4945 gettext("random")); 4946 break; 4947 case VNIC_MAC_ADDR_TYPE_FACTORY: 4948 (void) snprintf(vbuf.vnic_macaddrtype, 4949 sizeof (vbuf.vnic_macaddrtype), 4950 gettext("factory, slot %d"), 4951 vnic->va_mac_slot); 4952 break; 4953 case VNIC_MAC_ADDR_TYPE_VRID: 4954 (void) snprintf(vbuf.vnic_macaddrtype, 4955 sizeof (vbuf.vnic_macaddrtype), 4956 gettext("vrrp, %d/%s"), 4957 vnic->va_vrid, vnic->va_af == AF_INET ? 4958 "inet" : "inet6"); 4959 break; 4960 } 4961 4962 if (strlen(vbuf.vnic_macaddrtype) > 0) { 4963 (void) snprintf(vbuf.vnic_macaddr, 4964 sizeof (vbuf.vnic_macaddr), "%s", 4965 dladm_aggr_macaddr2str(vnic->va_mac_addr, 4966 mstr)); 4967 } 4968 4969 (void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid), 4970 "%d", vnic->va_vid); 4971 } 4972 4973 ofmt_print(state->vs_ofmt, &vbuf); 4974 4975 return (DLADM_STATUS_OK); 4976 } 4977 } 4978 4979 /* ARGSUSED */ 4980 static int 4981 show_vnic(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4982 { 4983 show_vnic_state_t *state = arg; 4984 4985 state->vs_status = print_vnic(state, linkid); 4986 return (DLADM_WALK_CONTINUE); 4987 } 4988 4989 static void 4990 do_show_vnic_common(int argc, char *argv[], const char *use, 4991 boolean_t etherstub) 4992 { 4993 int option; 4994 boolean_t s_arg = B_FALSE; 4995 boolean_t i_arg = B_FALSE; 4996 boolean_t l_arg = B_FALSE; 4997 uint32_t interval = 0, flags = DLADM_OPT_ACTIVE; 4998 datalink_id_t linkid = DATALINK_ALL_LINKID; 4999 datalink_id_t dev_linkid = DATALINK_ALL_LINKID; 5000 show_vnic_state_t state; 5001 dladm_status_t status; 5002 boolean_t o_arg = B_FALSE; 5003 char *fields_str = NULL; 5004 const ofmt_field_t *pf; 5005 char *all_e_fields = "link"; 5006 ofmt_handle_t ofmt; 5007 ofmt_status_t oferr; 5008 uint_t ofmtflags = 0; 5009 5010 bzero(&state, sizeof (state)); 5011 opterr = 0; 5012 while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts, 5013 NULL)) != -1) { 5014 switch (option) { 5015 case 'p': 5016 state.vs_parsable = B_TRUE; 5017 break; 5018 case 'P': 5019 flags = DLADM_OPT_PERSIST; 5020 break; 5021 case 'l': 5022 if (etherstub) 5023 die("option not supported for this command"); 5024 5025 if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >= 5026 MAXLINKNAMELEN) 5027 die("link name too long"); 5028 5029 l_arg = B_TRUE; 5030 break; 5031 case 's': 5032 if (s_arg) { 5033 die("the option -s cannot be specified " 5034 "more than once"); 5035 } 5036 s_arg = B_TRUE; 5037 break; 5038 case 'i': 5039 if (i_arg) { 5040 die("the option -i cannot be specified " 5041 "more than once"); 5042 } 5043 i_arg = B_TRUE; 5044 if (!dladm_str2interval(optarg, &interval)) 5045 die("invalid interval value '%s'", optarg); 5046 break; 5047 case 'o': 5048 o_arg = B_TRUE; 5049 fields_str = optarg; 5050 break; 5051 default: 5052 die_opterr(optopt, option, use); 5053 } 5054 } 5055 5056 if (i_arg && !s_arg) 5057 die("the option -i can be used only with -s"); 5058 5059 /* get vnic ID (optional last argument) */ 5060 if (optind == (argc - 1)) { 5061 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 5062 NULL, NULL); 5063 if (status != DLADM_STATUS_OK) { 5064 die_dlerr(status, "invalid vnic name '%s'", 5065 argv[optind]); 5066 } 5067 (void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN); 5068 } else if (optind != argc) { 5069 usage(); 5070 } 5071 5072 if (l_arg) { 5073 status = dladm_name2info(handle, state.vs_link, &dev_linkid, 5074 NULL, NULL, NULL); 5075 if (status != DLADM_STATUS_OK) { 5076 die_dlerr(status, "invalid link name '%s'", 5077 state.vs_link); 5078 } 5079 } 5080 5081 state.vs_vnic_id = linkid; 5082 state.vs_link_id = dev_linkid; 5083 state.vs_etherstub = etherstub; 5084 state.vs_found = B_FALSE; 5085 state.vs_flags = flags; 5086 5087 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 5088 if (etherstub) 5089 fields_str = all_e_fields; 5090 } 5091 pf = vnic_fields; 5092 5093 if (state.vs_parsable) 5094 ofmtflags |= OFMT_PARSABLE; 5095 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 5096 dladm_ofmt_check(oferr, state.vs_parsable, ofmt); 5097 state.vs_ofmt = ofmt; 5098 5099 if (s_arg) { 5100 /* Display vnic statistics */ 5101 vnic_stats(&state, interval); 5102 ofmt_close(ofmt); 5103 return; 5104 } 5105 5106 /* Display vnic information */ 5107 state.vs_donefirst = B_FALSE; 5108 5109 if (linkid == DATALINK_ALL_LINKID) { 5110 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 5111 DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB, 5112 DATALINK_ANY_MEDIATYPE, flags); 5113 } else { 5114 (void) show_vnic(handle, linkid, &state); 5115 if (state.vs_status != DLADM_STATUS_OK) { 5116 ofmt_close(ofmt); 5117 die_dlerr(state.vs_status, "failed to show vnic '%s'", 5118 state.vs_vnic); 5119 } 5120 } 5121 ofmt_close(ofmt); 5122 } 5123 5124 static void 5125 do_show_vnic(int argc, char *argv[], const char *use) 5126 { 5127 do_show_vnic_common(argc, argv, use, B_FALSE); 5128 } 5129 5130 static void 5131 do_create_etherstub(int argc, char *argv[], const char *use) 5132 { 5133 uint32_t flags; 5134 char *altroot = NULL; 5135 int option; 5136 dladm_status_t status; 5137 char name[MAXLINKNAMELEN]; 5138 uchar_t mac_addr[ETHERADDRL]; 5139 5140 name[0] = '\0'; 5141 bzero(mac_addr, sizeof (mac_addr)); 5142 flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5143 5144 opterr = 0; 5145 while ((option = getopt_long(argc, argv, "tR:", 5146 etherstub_lopts, NULL)) != -1) { 5147 switch (option) { 5148 case 't': 5149 flags &= ~DLADM_OPT_PERSIST; 5150 break; 5151 case 'R': 5152 altroot = optarg; 5153 break; 5154 default: 5155 die_opterr(optopt, option, use); 5156 } 5157 } 5158 5159 /* the etherstub id is the required operand */ 5160 if (optind != (argc - 1)) 5161 usage(); 5162 5163 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 5164 die("link name too long '%s'", argv[optind]); 5165 5166 if (!dladm_valid_linkname(name)) 5167 die("invalid link name '%s'", argv[optind]); 5168 5169 if (altroot != NULL) 5170 altroot_cmd(altroot, argc, argv); 5171 5172 status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID, 5173 VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, 5174 VRRP_VRID_NONE, AF_UNSPEC, NULL, NULL, flags); 5175 if (status != DLADM_STATUS_OK) 5176 die_dlerr(status, "etherstub creation failed"); 5177 } 5178 5179 static void 5180 do_delete_etherstub(int argc, char *argv[], const char *use) 5181 { 5182 do_delete_vnic_common(argc, argv, use, B_TRUE); 5183 } 5184 5185 /* ARGSUSED */ 5186 static void 5187 do_show_etherstub(int argc, char *argv[], const char *use) 5188 { 5189 do_show_vnic_common(argc, argv, use, B_TRUE); 5190 } 5191 5192 /* ARGSUSED */ 5193 static void 5194 do_up_simnet(int argc, char *argv[], const char *use) 5195 { 5196 (void) dladm_simnet_up(handle, DATALINK_ALL_LINKID, 0); 5197 } 5198 5199 static void 5200 do_create_simnet(int argc, char *argv[], const char *use) 5201 { 5202 uint32_t flags; 5203 char *altroot = NULL; 5204 char *media = NULL; 5205 uint32_t mtype = DL_ETHER; 5206 int option; 5207 dladm_status_t status; 5208 char name[MAXLINKNAMELEN]; 5209 5210 name[0] = '\0'; 5211 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5212 5213 opterr = 0; 5214 while ((option = getopt_long(argc, argv, ":tR:m:", 5215 simnet_lopts, NULL)) != -1) { 5216 switch (option) { 5217 case 't': 5218 flags &= ~DLADM_OPT_PERSIST; 5219 break; 5220 case 'R': 5221 altroot = optarg; 5222 break; 5223 case 'm': 5224 media = optarg; 5225 break; 5226 default: 5227 die_opterr(optopt, option, use); 5228 } 5229 } 5230 5231 /* the simnet id is the required operand */ 5232 if (optind != (argc - 1)) 5233 usage(); 5234 5235 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 5236 die("link name too long '%s'", argv[optind]); 5237 5238 if (!dladm_valid_linkname(name)) 5239 die("invalid link name '%s'", name); 5240 5241 if (media != NULL) { 5242 mtype = dladm_str2media(media); 5243 if (mtype != DL_ETHER && mtype != DL_WIFI) 5244 die("media type '%s' is not supported", media); 5245 } 5246 5247 if (altroot != NULL) 5248 altroot_cmd(altroot, argc, argv); 5249 5250 status = dladm_simnet_create(handle, name, mtype, flags); 5251 if (status != DLADM_STATUS_OK) 5252 die_dlerr(status, "simnet creation failed"); 5253 } 5254 5255 static void 5256 do_delete_simnet(int argc, char *argv[], const char *use) 5257 { 5258 int option; 5259 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5260 datalink_id_t linkid; 5261 char *altroot = NULL; 5262 dladm_status_t status; 5263 dladm_simnet_attr_t slinfo; 5264 5265 opterr = 0; 5266 while ((option = getopt_long(argc, argv, ":tR:", simnet_lopts, 5267 NULL)) != -1) { 5268 switch (option) { 5269 case 't': 5270 flags &= ~DLADM_OPT_PERSIST; 5271 break; 5272 case 'R': 5273 altroot = optarg; 5274 break; 5275 default: 5276 die_opterr(optopt, option, use); 5277 } 5278 } 5279 5280 /* get simnet name (required last argument) */ 5281 if (optind != (argc - 1)) 5282 usage(); 5283 5284 if (!dladm_valid_linkname(argv[optind])) 5285 die("invalid link name '%s'", argv[optind]); 5286 5287 if (altroot != NULL) 5288 altroot_cmd(altroot, argc, argv); 5289 5290 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 5291 NULL); 5292 if (status != DLADM_STATUS_OK) 5293 die("simnet '%s' not found", argv[optind]); 5294 5295 if ((status = dladm_simnet_info(handle, linkid, &slinfo, 5296 flags)) != DLADM_STATUS_OK) 5297 die_dlerr(status, "failed to retrieve simnet information"); 5298 5299 status = dladm_simnet_delete(handle, linkid, flags); 5300 if (status != DLADM_STATUS_OK) 5301 die_dlerr(status, "simnet deletion failed"); 5302 } 5303 5304 static void 5305 do_modify_simnet(int argc, char *argv[], const char *use) 5306 { 5307 int option; 5308 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5309 datalink_id_t linkid; 5310 datalink_id_t peer_linkid; 5311 char *altroot = NULL; 5312 dladm_status_t status; 5313 boolean_t p_arg = B_FALSE; 5314 5315 opterr = 0; 5316 while ((option = getopt_long(argc, argv, ":tR:p:", simnet_lopts, 5317 NULL)) != -1) { 5318 switch (option) { 5319 case 't': 5320 flags &= ~DLADM_OPT_PERSIST; 5321 break; 5322 case 'R': 5323 altroot = optarg; 5324 break; 5325 case 'p': 5326 if (p_arg) 5327 die_optdup(option); 5328 p_arg = B_TRUE; 5329 if (strcasecmp(optarg, "none") == 0) 5330 peer_linkid = DATALINK_INVALID_LINKID; 5331 else if (dladm_name2info(handle, optarg, &peer_linkid, 5332 NULL, NULL, NULL) != DLADM_STATUS_OK) 5333 die("invalid peer link name '%s'", optarg); 5334 break; 5335 default: 5336 die_opterr(optopt, option, use); 5337 } 5338 } 5339 5340 /* get simnet name (required last argument) */ 5341 if (optind != (argc - 1)) 5342 usage(); 5343 5344 /* Nothing to do if no peer link argument */ 5345 if (!p_arg) 5346 return; 5347 5348 if (altroot != NULL) 5349 altroot_cmd(altroot, argc, argv); 5350 5351 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 5352 NULL); 5353 if (status != DLADM_STATUS_OK) 5354 die("invalid link name '%s'", argv[optind]); 5355 5356 status = dladm_simnet_modify(handle, linkid, peer_linkid, flags); 5357 if (status != DLADM_STATUS_OK) 5358 die_dlerr(status, "simnet modification failed"); 5359 } 5360 5361 static dladm_status_t 5362 print_simnet(show_state_t *state, datalink_id_t linkid) 5363 { 5364 dladm_simnet_attr_t slinfo; 5365 uint32_t flags; 5366 dladm_status_t status; 5367 simnet_fields_buf_t slbuf; 5368 char mstr[ETHERADDRL * 3]; 5369 5370 bzero(&slbuf, sizeof (slbuf)); 5371 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL, 5372 slbuf.simnet_name, sizeof (slbuf.simnet_name))) 5373 != DLADM_STATUS_OK) 5374 return (status); 5375 5376 if (!(state->ls_flags & flags)) 5377 return (DLADM_STATUS_NOTFOUND); 5378 5379 if ((status = dladm_simnet_info(handle, linkid, &slinfo, 5380 state->ls_flags)) != DLADM_STATUS_OK) 5381 return (status); 5382 5383 if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID && 5384 (status = dladm_datalink_id2info(handle, slinfo.sna_peer_link_id, 5385 NULL, NULL, NULL, slbuf.simnet_otherlink, 5386 sizeof (slbuf.simnet_otherlink))) != 5387 DLADM_STATUS_OK) 5388 return (status); 5389 5390 if (slinfo.sna_mac_len > sizeof (slbuf.simnet_macaddr)) 5391 return (DLADM_STATUS_BADVAL); 5392 5393 (void) strlcpy(slbuf.simnet_macaddr, 5394 dladm_aggr_macaddr2str(slinfo.sna_mac_addr, mstr), 5395 sizeof (slbuf.simnet_macaddr)); 5396 (void) dladm_media2str(slinfo.sna_type, slbuf.simnet_media); 5397 5398 ofmt_print(state->ls_ofmt, &slbuf); 5399 return (status); 5400 } 5401 5402 /* ARGSUSED */ 5403 static int 5404 show_simnet(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5405 { 5406 show_state_t *state = arg; 5407 5408 state->ls_status = print_simnet(state, linkid); 5409 return (DLADM_WALK_CONTINUE); 5410 } 5411 5412 static void 5413 do_show_simnet(int argc, char *argv[], const char *use) 5414 { 5415 int option; 5416 uint32_t flags = DLADM_OPT_ACTIVE; 5417 boolean_t p_arg = B_FALSE; 5418 datalink_id_t linkid = DATALINK_ALL_LINKID; 5419 show_state_t state; 5420 dladm_status_t status; 5421 boolean_t o_arg = B_FALSE; 5422 ofmt_handle_t ofmt; 5423 ofmt_status_t oferr; 5424 char *all_fields = "link,media,macaddress,otherlink"; 5425 char *fields_str = all_fields; 5426 uint_t ofmtflags = 0; 5427 5428 bzero(&state, sizeof (state)); 5429 5430 opterr = 0; 5431 while ((option = getopt_long(argc, argv, ":pPo:", 5432 show_lopts, NULL)) != -1) { 5433 switch (option) { 5434 case 'p': 5435 if (p_arg) 5436 die_optdup(option); 5437 5438 p_arg = B_TRUE; 5439 state.ls_parsable = p_arg; 5440 break; 5441 case 'P': 5442 if (flags != DLADM_OPT_ACTIVE) 5443 die_optdup(option); 5444 5445 flags = DLADM_OPT_PERSIST; 5446 break; 5447 case 'o': 5448 o_arg = B_TRUE; 5449 fields_str = optarg; 5450 break; 5451 default: 5452 die_opterr(optopt, option, use); 5453 break; 5454 } 5455 } 5456 5457 if (p_arg && !o_arg) 5458 die("-p requires -o"); 5459 5460 if (strcasecmp(fields_str, "all") == 0) { 5461 if (p_arg) 5462 die("\"-o all\" is invalid with -p"); 5463 fields_str = all_fields; 5464 } 5465 5466 /* get link name (optional last argument) */ 5467 if (optind == (argc-1)) { 5468 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5469 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5470 die_dlerr(status, "link %s is not valid", argv[optind]); 5471 } 5472 } else if (optind != argc) { 5473 usage(); 5474 } 5475 5476 state.ls_flags = flags; 5477 state.ls_donefirst = B_FALSE; 5478 if (state.ls_parsable) 5479 ofmtflags |= OFMT_PARSABLE; 5480 oferr = ofmt_open(fields_str, simnet_fields, ofmtflags, 0, &ofmt); 5481 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 5482 state.ls_ofmt = ofmt; 5483 5484 if (linkid == DATALINK_ALL_LINKID) { 5485 (void) dladm_walk_datalink_id(show_simnet, handle, &state, 5486 DATALINK_CLASS_SIMNET, DATALINK_ANY_MEDIATYPE, flags); 5487 } else { 5488 (void) show_simnet(handle, linkid, &state); 5489 if (state.ls_status != DLADM_STATUS_OK) { 5490 ofmt_close(ofmt); 5491 die_dlerr(state.ls_status, "failed to show simnet %s", 5492 argv[optind]); 5493 } 5494 } 5495 ofmt_close(ofmt); 5496 } 5497 5498 static void 5499 link_stats(datalink_id_t linkid, uint_t interval, char *fields_str, 5500 show_state_t *state) 5501 { 5502 ofmt_handle_t ofmt; 5503 ofmt_status_t oferr; 5504 uint_t ofmtflags = 0; 5505 5506 if (state->ls_parsable) 5507 ofmtflags |= OFMT_PARSABLE; 5508 oferr = ofmt_open(fields_str, link_s_fields, ofmtflags, 0, &ofmt); 5509 dladm_ofmt_check(oferr, state->ls_parsable, ofmt); 5510 state->ls_ofmt = ofmt; 5511 5512 /* 5513 * If an interval is specified, continuously show the stats 5514 * only for the first MAC port. 5515 */ 5516 state->ls_firstonly = (interval != 0); 5517 5518 for (;;) { 5519 state->ls_donefirst = B_FALSE; 5520 if (linkid == DATALINK_ALL_LINKID) { 5521 (void) dladm_walk_datalink_id(show_link_stats, handle, 5522 state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 5523 DLADM_OPT_ACTIVE); 5524 } else { 5525 (void) show_link_stats(handle, linkid, state); 5526 } 5527 5528 if (interval == 0) 5529 break; 5530 5531 (void) fflush(stdout); 5532 (void) sleep(interval); 5533 } 5534 ofmt_close(ofmt); 5535 } 5536 5537 static void 5538 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) 5539 { 5540 /* 5541 * If an interval is specified, continuously show the stats 5542 * only for the first group. 5543 */ 5544 state->gs_firstonly = (interval != 0); 5545 5546 for (;;) { 5547 state->gs_donefirst = B_FALSE; 5548 if (linkid == DATALINK_ALL_LINKID) 5549 (void) dladm_walk_datalink_id(show_aggr, handle, state, 5550 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 5551 DLADM_OPT_ACTIVE); 5552 else 5553 (void) show_aggr(handle, linkid, state); 5554 5555 if (interval == 0) 5556 break; 5557 5558 (void) fflush(stdout); 5559 (void) sleep(interval); 5560 } 5561 } 5562 5563 /* ARGSUSED */ 5564 static void 5565 vnic_stats(show_vnic_state_t *sp, uint32_t interval) 5566 { 5567 show_vnic_state_t state; 5568 boolean_t specific_link, specific_dev; 5569 5570 /* Display vnic statistics */ 5571 dump_vnics_head(sp->vs_link); 5572 5573 bzero(&state, sizeof (state)); 5574 state.vs_stats = B_TRUE; 5575 state.vs_vnic_id = sp->vs_vnic_id; 5576 state.vs_link_id = sp->vs_link_id; 5577 5578 /* 5579 * If an interval is specified, and a vnic ID is not specified, 5580 * continuously show the stats only for the first vnic. 5581 */ 5582 specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID); 5583 specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID); 5584 5585 for (;;) { 5586 /* Get stats for each vnic */ 5587 state.vs_found = B_FALSE; 5588 state.vs_donefirst = B_FALSE; 5589 state.vs_printstats = B_FALSE; 5590 state.vs_flags = DLADM_OPT_ACTIVE; 5591 5592 if (!specific_link) { 5593 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 5594 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 5595 DLADM_OPT_ACTIVE); 5596 } else { 5597 (void) show_vnic(handle, sp->vs_vnic_id, &state); 5598 if (state.vs_status != DLADM_STATUS_OK) { 5599 die_dlerr(state.vs_status, 5600 "failed to show vnic '%s'", sp->vs_vnic); 5601 } 5602 } 5603 5604 if (specific_link && !state.vs_found) 5605 die("non-existent vnic '%s'", sp->vs_vnic); 5606 if (specific_dev && !state.vs_found) 5607 die("device %s has no vnics", sp->vs_link); 5608 5609 /* Show totals */ 5610 if ((specific_link | specific_dev) && !interval) { 5611 (void) printf("Total"); 5612 (void) printf("\t%-10llu", 5613 state.vs_totalstats.ipackets); 5614 (void) printf("%-12llu", 5615 state.vs_totalstats.rbytes); 5616 (void) printf("%-10llu", 5617 state.vs_totalstats.opackets); 5618 (void) printf("%-12llu\n", 5619 state.vs_totalstats.obytes); 5620 } 5621 5622 /* Show stats for each vnic */ 5623 state.vs_donefirst = B_FALSE; 5624 state.vs_printstats = B_TRUE; 5625 5626 if (!specific_link) { 5627 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 5628 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 5629 DLADM_OPT_ACTIVE); 5630 } else { 5631 (void) show_vnic(handle, sp->vs_vnic_id, &state); 5632 if (state.vs_status != DLADM_STATUS_OK) { 5633 die_dlerr(state.vs_status, 5634 "failed to show vnic '%s'", sp->vs_vnic); 5635 } 5636 } 5637 5638 if (interval == 0) 5639 break; 5640 5641 (void) fflush(stdout); 5642 (void) sleep(interval); 5643 } 5644 } 5645 5646 static void 5647 get_mac_stats(const char *dev, pktsum_t *stats) 5648 { 5649 kstat_ctl_t *kcp; 5650 kstat_t *ksp; 5651 char module[DLPI_LINKNAME_MAX]; 5652 uint_t instance; 5653 5654 5655 bzero(stats, sizeof (*stats)); 5656 5657 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 5658 return; 5659 5660 if ((kcp = kstat_open()) == NULL) { 5661 warn("kstat open operation failed"); 5662 return; 5663 } 5664 5665 ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL); 5666 if (ksp != NULL) 5667 dladm_get_stats(kcp, ksp, stats); 5668 5669 (void) kstat_close(kcp); 5670 5671 } 5672 5673 static void 5674 get_link_stats(const char *link, pktsum_t *stats) 5675 { 5676 kstat_ctl_t *kcp; 5677 kstat_t *ksp; 5678 5679 bzero(stats, sizeof (*stats)); 5680 5681 if ((kcp = kstat_open()) == NULL) { 5682 warn("kstat_open operation failed"); 5683 return; 5684 } 5685 5686 ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL); 5687 5688 if (ksp != NULL) 5689 dladm_get_stats(kcp, ksp, stats); 5690 5691 (void) kstat_close(kcp); 5692 } 5693 5694 static int 5695 query_kstat(char *module, int instance, const char *name, const char *stat, 5696 uint8_t type, void *val) 5697 { 5698 kstat_ctl_t *kcp; 5699 kstat_t *ksp; 5700 5701 if ((kcp = kstat_open()) == NULL) { 5702 warn("kstat open operation failed"); 5703 return (-1); 5704 } 5705 5706 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 5707 /* 5708 * The kstat query could fail if the underlying MAC 5709 * driver was already detached. 5710 */ 5711 goto bail; 5712 } 5713 5714 if (kstat_read(kcp, ksp, NULL) == -1) { 5715 warn("kstat read failed"); 5716 goto bail; 5717 } 5718 5719 if (dladm_kstat_value(ksp, stat, type, val) < 0) 5720 goto bail; 5721 5722 (void) kstat_close(kcp); 5723 return (0); 5724 5725 bail: 5726 (void) kstat_close(kcp); 5727 return (-1); 5728 } 5729 5730 static int 5731 get_one_kstat(const char *name, const char *stat, uint8_t type, 5732 void *val, boolean_t islink) 5733 { 5734 char module[DLPI_LINKNAME_MAX]; 5735 uint_t instance; 5736 5737 if (islink) { 5738 return (query_kstat("link", 0, name, stat, type, val)); 5739 } else { 5740 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS) 5741 return (-1); 5742 5743 return (query_kstat(module, instance, "mac", stat, type, val)); 5744 } 5745 } 5746 5747 static uint64_t 5748 get_ifspeed(const char *name, boolean_t islink) 5749 { 5750 uint64_t ifspeed = 0; 5751 5752 (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64, 5753 &ifspeed, islink); 5754 5755 return (ifspeed); 5756 } 5757 5758 static const char * 5759 get_linkstate(const char *name, boolean_t islink, char *buf) 5760 { 5761 link_state_t linkstate; 5762 5763 if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32, 5764 &linkstate, islink) != 0) { 5765 (void) strlcpy(buf, "?", DLADM_STRSIZE); 5766 return (buf); 5767 } 5768 return (dladm_linkstate2str(linkstate, buf)); 5769 } 5770 5771 static const char * 5772 get_linkduplex(const char *name, boolean_t islink, char *buf) 5773 { 5774 link_duplex_t linkduplex; 5775 5776 if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32, 5777 &linkduplex, islink) != 0) { 5778 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 5779 return (buf); 5780 } 5781 5782 return (dladm_linkduplex2str(linkduplex, buf)); 5783 } 5784 5785 static int 5786 parse_wifi_fields(char *str, ofmt_handle_t *ofmt, uint_t cmdtype, 5787 boolean_t parsable) 5788 { 5789 ofmt_field_t *template, *of; 5790 ofmt_cb_t *fn; 5791 ofmt_status_t oferr; 5792 5793 if (cmdtype == WIFI_CMD_SCAN) { 5794 template = wifi_common_fields; 5795 if (str == NULL) 5796 str = def_scan_wifi_fields; 5797 if (strcasecmp(str, "all") == 0) 5798 str = all_scan_wifi_fields; 5799 fn = print_wlan_attr_cb; 5800 } else if (cmdtype == WIFI_CMD_SHOW) { 5801 bcopy(wifi_common_fields, &wifi_show_fields[2], 5802 sizeof (wifi_common_fields)); 5803 template = wifi_show_fields; 5804 if (str == NULL) 5805 str = def_show_wifi_fields; 5806 if (strcasecmp(str, "all") == 0) 5807 str = all_show_wifi_fields; 5808 fn = print_link_attr_cb; 5809 } else { 5810 return (-1); 5811 } 5812 5813 for (of = template; of->of_name != NULL; of++) { 5814 if (of->of_cb == NULL) 5815 of->of_cb = fn; 5816 } 5817 5818 oferr = ofmt_open(str, template, (parsable ? OFMT_PARSABLE : 0), 5819 0, ofmt); 5820 dladm_ofmt_check(oferr, parsable, *ofmt); 5821 return (0); 5822 } 5823 5824 typedef struct print_wifi_state { 5825 char *ws_link; 5826 boolean_t ws_parsable; 5827 boolean_t ws_header; 5828 ofmt_handle_t ws_ofmt; 5829 } print_wifi_state_t; 5830 5831 typedef struct wlan_scan_args_s { 5832 print_wifi_state_t *ws_state; 5833 void *ws_attr; 5834 } wlan_scan_args_t; 5835 5836 static boolean_t 5837 print_wlan_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 5838 { 5839 wlan_scan_args_t *w = ofarg->ofmt_cbarg; 5840 print_wifi_state_t *statep = w->ws_state; 5841 dladm_wlan_attr_t *attrp = w->ws_attr; 5842 char tmpbuf[DLADM_STRSIZE]; 5843 5844 if (ofarg->ofmt_id == 0) { 5845 (void) strlcpy(buf, (char *)statep->ws_link, bufsize); 5846 return (B_TRUE); 5847 } 5848 5849 if ((ofarg->ofmt_id & attrp->wa_valid) == 0) 5850 return (B_TRUE); 5851 5852 switch (ofarg->ofmt_id) { 5853 case DLADM_WLAN_ATTR_ESSID: 5854 (void) dladm_wlan_essid2str(&attrp->wa_essid, tmpbuf); 5855 break; 5856 case DLADM_WLAN_ATTR_BSSID: 5857 (void) dladm_wlan_bssid2str(&attrp->wa_bssid, tmpbuf); 5858 break; 5859 case DLADM_WLAN_ATTR_SECMODE: 5860 (void) dladm_wlan_secmode2str(&attrp->wa_secmode, tmpbuf); 5861 break; 5862 case DLADM_WLAN_ATTR_STRENGTH: 5863 (void) dladm_wlan_strength2str(&attrp->wa_strength, tmpbuf); 5864 break; 5865 case DLADM_WLAN_ATTR_MODE: 5866 (void) dladm_wlan_mode2str(&attrp->wa_mode, tmpbuf); 5867 break; 5868 case DLADM_WLAN_ATTR_SPEED: 5869 (void) dladm_wlan_speed2str(&attrp->wa_speed, tmpbuf); 5870 (void) strlcat(tmpbuf, "Mb", sizeof (tmpbuf)); 5871 break; 5872 case DLADM_WLAN_ATTR_AUTH: 5873 (void) dladm_wlan_auth2str(&attrp->wa_auth, tmpbuf); 5874 break; 5875 case DLADM_WLAN_ATTR_BSSTYPE: 5876 (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, tmpbuf); 5877 break; 5878 } 5879 (void) strlcpy(buf, tmpbuf, bufsize); 5880 5881 return (B_TRUE); 5882 } 5883 5884 static boolean_t 5885 print_scan_results(void *arg, dladm_wlan_attr_t *attrp) 5886 { 5887 print_wifi_state_t *statep = arg; 5888 wlan_scan_args_t warg; 5889 5890 bzero(&warg, sizeof (warg)); 5891 warg.ws_state = statep; 5892 warg.ws_attr = attrp; 5893 ofmt_print(statep->ws_ofmt, &warg); 5894 return (B_TRUE); 5895 } 5896 5897 static int 5898 scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5899 { 5900 print_wifi_state_t *statep = arg; 5901 dladm_status_t status; 5902 char link[MAXLINKNAMELEN]; 5903 5904 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 5905 sizeof (link))) != DLADM_STATUS_OK) { 5906 return (DLADM_WALK_CONTINUE); 5907 } 5908 5909 statep->ws_link = link; 5910 status = dladm_wlan_scan(dh, linkid, statep, print_scan_results); 5911 if (status != DLADM_STATUS_OK) 5912 die_dlerr(status, "cannot scan link '%s'", statep->ws_link); 5913 5914 return (DLADM_WALK_CONTINUE); 5915 } 5916 5917 static boolean_t 5918 print_wifi_status_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 5919 { 5920 static char tmpbuf[DLADM_STRSIZE]; 5921 wlan_scan_args_t *w = ofarg->ofmt_cbarg; 5922 dladm_wlan_linkattr_t *attrp = w->ws_attr; 5923 5924 if ((ofarg->ofmt_id & attrp->la_valid) != 0) { 5925 (void) dladm_wlan_linkstatus2str(&attrp->la_status, tmpbuf); 5926 (void) strlcpy(buf, tmpbuf, bufsize); 5927 } 5928 return (B_TRUE); 5929 } 5930 5931 static boolean_t 5932 print_link_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 5933 { 5934 wlan_scan_args_t *w = ofarg->ofmt_cbarg, w1; 5935 print_wifi_state_t *statep = w->ws_state; 5936 dladm_wlan_linkattr_t *attrp = w->ws_attr; 5937 5938 bzero(&w1, sizeof (w1)); 5939 w1.ws_state = statep; 5940 w1.ws_attr = &attrp->la_wlan_attr; 5941 ofarg->ofmt_cbarg = &w1; 5942 return (print_wlan_attr_cb(ofarg, buf, bufsize)); 5943 } 5944 5945 static int 5946 show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5947 { 5948 print_wifi_state_t *statep = arg; 5949 dladm_wlan_linkattr_t attr; 5950 dladm_status_t status; 5951 char link[MAXLINKNAMELEN]; 5952 wlan_scan_args_t warg; 5953 5954 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 5955 sizeof (link))) != DLADM_STATUS_OK) { 5956 return (DLADM_WALK_CONTINUE); 5957 } 5958 5959 /* dladm_wlan_get_linkattr() memsets attr with 0 */ 5960 status = dladm_wlan_get_linkattr(dh, linkid, &attr); 5961 if (status != DLADM_STATUS_OK) 5962 die_dlerr(status, "cannot get link attributes for %s", link); 5963 5964 statep->ws_link = link; 5965 5966 bzero(&warg, sizeof (warg)); 5967 warg.ws_state = statep; 5968 warg.ws_attr = &attr; 5969 ofmt_print(statep->ws_ofmt, &warg); 5970 return (DLADM_WALK_CONTINUE); 5971 } 5972 5973 static void 5974 do_display_wifi(int argc, char **argv, int cmd, const char *use) 5975 { 5976 int option; 5977 char *fields_str = NULL; 5978 int (*callback)(dladm_handle_t, datalink_id_t, void *); 5979 print_wifi_state_t state; 5980 datalink_id_t linkid = DATALINK_ALL_LINKID; 5981 dladm_status_t status; 5982 5983 if (cmd == WIFI_CMD_SCAN) 5984 callback = scan_wifi; 5985 else if (cmd == WIFI_CMD_SHOW) 5986 callback = show_wifi; 5987 else 5988 return; 5989 5990 state.ws_parsable = B_FALSE; 5991 state.ws_header = B_TRUE; 5992 opterr = 0; 5993 while ((option = getopt_long(argc, argv, ":o:p", 5994 wifi_longopts, NULL)) != -1) { 5995 switch (option) { 5996 case 'o': 5997 fields_str = optarg; 5998 break; 5999 case 'p': 6000 state.ws_parsable = B_TRUE; 6001 break; 6002 default: 6003 die_opterr(optopt, option, use); 6004 } 6005 } 6006 6007 if (state.ws_parsable && fields_str == NULL) 6008 die("-p requires -o"); 6009 6010 if (state.ws_parsable && strcasecmp(fields_str, "all") == 0) 6011 die("\"-o all\" is invalid with -p"); 6012 6013 if (optind == (argc - 1)) { 6014 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6015 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 6016 die_dlerr(status, "link %s is not valid", argv[optind]); 6017 } 6018 } else if (optind != argc) { 6019 usage(); 6020 } 6021 6022 if (parse_wifi_fields(fields_str, &state.ws_ofmt, cmd, 6023 state.ws_parsable) < 0) 6024 die("invalid field(s) specified"); 6025 6026 if (linkid == DATALINK_ALL_LINKID) { 6027 (void) dladm_walk_datalink_id(callback, handle, &state, 6028 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 6029 DL_WIFI, DLADM_OPT_ACTIVE); 6030 } else { 6031 (void) (*callback)(handle, linkid, &state); 6032 } 6033 ofmt_close(state.ws_ofmt); 6034 } 6035 6036 static void 6037 do_scan_wifi(int argc, char **argv, const char *use) 6038 { 6039 do_display_wifi(argc, argv, WIFI_CMD_SCAN, use); 6040 } 6041 6042 static void 6043 do_show_wifi(int argc, char **argv, const char *use) 6044 { 6045 do_display_wifi(argc, argv, WIFI_CMD_SHOW, use); 6046 } 6047 6048 typedef struct wlan_count_attr { 6049 uint_t wc_count; 6050 datalink_id_t wc_linkid; 6051 } wlan_count_attr_t; 6052 6053 /* ARGSUSED */ 6054 static int 6055 do_count_wlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6056 { 6057 wlan_count_attr_t *cp = arg; 6058 6059 if (cp->wc_count == 0) 6060 cp->wc_linkid = linkid; 6061 cp->wc_count++; 6062 return (DLADM_WALK_CONTINUE); 6063 } 6064 6065 static int 6066 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) 6067 { 6068 uint_t i; 6069 dladm_wlan_key_t *wk; 6070 int nfields = 1; 6071 char *field, *token, *lasts = NULL, c; 6072 6073 token = str; 6074 while ((c = *token++) != NULL) { 6075 if (c == ',') 6076 nfields++; 6077 } 6078 token = strdup(str); 6079 if (token == NULL) 6080 return (-1); 6081 6082 wk = malloc(nfields * sizeof (dladm_wlan_key_t)); 6083 if (wk == NULL) 6084 goto fail; 6085 6086 token = str; 6087 for (i = 0; i < nfields; i++) { 6088 char *s; 6089 dladm_secobj_class_t class; 6090 dladm_status_t status; 6091 6092 field = strtok_r(token, ",", &lasts); 6093 token = NULL; 6094 6095 (void) strlcpy(wk[i].wk_name, field, 6096 DLADM_WLAN_MAX_KEYNAME_LEN); 6097 6098 wk[i].wk_idx = 1; 6099 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 6100 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 6101 goto fail; 6102 6103 wk[i].wk_idx = (uint_t)(s[1] - '0'); 6104 *s = '\0'; 6105 } 6106 wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN; 6107 6108 status = dladm_get_secobj(handle, wk[i].wk_name, &class, 6109 wk[i].wk_val, &wk[i].wk_len, 0); 6110 if (status != DLADM_STATUS_OK) { 6111 if (status == DLADM_STATUS_NOTFOUND) { 6112 status = dladm_get_secobj(handle, wk[i].wk_name, 6113 &class, wk[i].wk_val, &wk[i].wk_len, 6114 DLADM_OPT_PERSIST); 6115 } 6116 if (status != DLADM_STATUS_OK) 6117 goto fail; 6118 } 6119 wk[i].wk_class = class; 6120 } 6121 *keys = wk; 6122 *key_countp = i; 6123 free(token); 6124 return (0); 6125 fail: 6126 free(wk); 6127 free(token); 6128 return (-1); 6129 } 6130 6131 static void 6132 do_connect_wifi(int argc, char **argv, const char *use) 6133 { 6134 int option; 6135 dladm_wlan_attr_t attr, *attrp; 6136 dladm_status_t status = DLADM_STATUS_OK; 6137 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 6138 datalink_id_t linkid = DATALINK_ALL_LINKID; 6139 dladm_wlan_key_t *keys = NULL; 6140 uint_t key_count = 0; 6141 uint_t flags = 0; 6142 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 6143 char buf[DLADM_STRSIZE]; 6144 6145 opterr = 0; 6146 (void) memset(&attr, 0, sizeof (attr)); 6147 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 6148 wifi_longopts, NULL)) != -1) { 6149 switch (option) { 6150 case 'e': 6151 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 6152 if (status != DLADM_STATUS_OK) 6153 die("invalid ESSID '%s'", optarg); 6154 6155 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 6156 /* 6157 * Try to connect without doing a scan. 6158 */ 6159 flags |= DLADM_WLAN_CONNECT_NOSCAN; 6160 break; 6161 case 'i': 6162 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 6163 if (status != DLADM_STATUS_OK) 6164 die("invalid BSSID %s", optarg); 6165 6166 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 6167 break; 6168 case 'a': 6169 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 6170 if (status != DLADM_STATUS_OK) 6171 die("invalid authentication mode '%s'", optarg); 6172 6173 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 6174 break; 6175 case 'm': 6176 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 6177 if (status != DLADM_STATUS_OK) 6178 die("invalid mode '%s'", optarg); 6179 6180 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 6181 break; 6182 case 'b': 6183 if ((status = dladm_wlan_str2bsstype(optarg, 6184 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 6185 die("invalid bsstype '%s'", optarg); 6186 } 6187 6188 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 6189 break; 6190 case 's': 6191 if ((status = dladm_wlan_str2secmode(optarg, 6192 &attr.wa_secmode)) != DLADM_STATUS_OK) { 6193 die("invalid security mode '%s'", optarg); 6194 } 6195 6196 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 6197 break; 6198 case 'k': 6199 if (parse_wlan_keys(optarg, &keys, &key_count) < 0) 6200 die("invalid key(s) '%s'", optarg); 6201 6202 if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP) 6203 keysecmode = DLADM_WLAN_SECMODE_WEP; 6204 else 6205 keysecmode = DLADM_WLAN_SECMODE_WPA; 6206 break; 6207 case 'T': 6208 if (strcasecmp(optarg, "forever") == 0) { 6209 timeout = -1; 6210 break; 6211 } 6212 if (!str2int(optarg, &timeout) || timeout < 0) 6213 die("invalid timeout value '%s'", optarg); 6214 break; 6215 case 'c': 6216 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 6217 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 6218 break; 6219 default: 6220 die_opterr(optopt, option, use); 6221 break; 6222 } 6223 } 6224 6225 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 6226 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) { 6227 die("key required for security mode '%s'", 6228 dladm_wlan_secmode2str(&attr.wa_secmode, buf)); 6229 } 6230 } else { 6231 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 6232 attr.wa_secmode != keysecmode) 6233 die("incompatible -s and -k options"); 6234 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 6235 attr.wa_secmode = keysecmode; 6236 } 6237 6238 if (optind == (argc - 1)) { 6239 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6240 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 6241 die_dlerr(status, "link %s is not valid", argv[optind]); 6242 } 6243 } else if (optind != argc) { 6244 usage(); 6245 } 6246 6247 if (linkid == DATALINK_ALL_LINKID) { 6248 wlan_count_attr_t wcattr; 6249 6250 wcattr.wc_linkid = DATALINK_INVALID_LINKID; 6251 wcattr.wc_count = 0; 6252 (void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr, 6253 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 6254 DL_WIFI, DLADM_OPT_ACTIVE); 6255 if (wcattr.wc_count == 0) { 6256 die("no wifi links are available"); 6257 } else if (wcattr.wc_count > 1) { 6258 die("link name is required when more than one wifi " 6259 "link is available"); 6260 } 6261 linkid = wcattr.wc_linkid; 6262 } 6263 attrp = (attr.wa_valid == 0) ? NULL : &attr; 6264 again: 6265 if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys, 6266 key_count, flags)) != DLADM_STATUS_OK) { 6267 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 6268 /* 6269 * Try again with scanning and filtering. 6270 */ 6271 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 6272 goto again; 6273 } 6274 6275 if (status == DLADM_STATUS_NOTFOUND) { 6276 if (attr.wa_valid == 0) { 6277 die("no wifi networks are available"); 6278 } else { 6279 die("no wifi networks with the specified " 6280 "criteria are available"); 6281 } 6282 } 6283 die_dlerr(status, "cannot connect"); 6284 } 6285 free(keys); 6286 } 6287 6288 /* ARGSUSED */ 6289 static int 6290 do_all_disconnect_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6291 { 6292 dladm_status_t status; 6293 6294 status = dladm_wlan_disconnect(dh, linkid); 6295 if (status != DLADM_STATUS_OK) 6296 warn_dlerr(status, "cannot disconnect link"); 6297 6298 return (DLADM_WALK_CONTINUE); 6299 } 6300 6301 static void 6302 do_disconnect_wifi(int argc, char **argv, const char *use) 6303 { 6304 int option; 6305 datalink_id_t linkid = DATALINK_ALL_LINKID; 6306 boolean_t all_links = B_FALSE; 6307 dladm_status_t status; 6308 wlan_count_attr_t wcattr; 6309 6310 opterr = 0; 6311 while ((option = getopt_long(argc, argv, ":a", 6312 wifi_longopts, NULL)) != -1) { 6313 switch (option) { 6314 case 'a': 6315 all_links = B_TRUE; 6316 break; 6317 default: 6318 die_opterr(optopt, option, use); 6319 break; 6320 } 6321 } 6322 6323 if (optind == (argc - 1)) { 6324 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6325 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 6326 die_dlerr(status, "link %s is not valid", argv[optind]); 6327 } 6328 } else if (optind != argc) { 6329 usage(); 6330 } 6331 6332 if (linkid == DATALINK_ALL_LINKID) { 6333 if (!all_links) { 6334 wcattr.wc_linkid = linkid; 6335 wcattr.wc_count = 0; 6336 (void) dladm_walk_datalink_id(do_count_wlan, handle, 6337 &wcattr, 6338 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 6339 DL_WIFI, DLADM_OPT_ACTIVE); 6340 if (wcattr.wc_count == 0) { 6341 die("no wifi links are available"); 6342 } else if (wcattr.wc_count > 1) { 6343 die("link name is required when more than " 6344 "one wifi link is available"); 6345 } 6346 linkid = wcattr.wc_linkid; 6347 } else { 6348 (void) dladm_walk_datalink_id(do_all_disconnect_wifi, 6349 handle, NULL, 6350 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 6351 DL_WIFI, DLADM_OPT_ACTIVE); 6352 return; 6353 } 6354 } 6355 status = dladm_wlan_disconnect(handle, linkid); 6356 if (status != DLADM_STATUS_OK) 6357 die_dlerr(status, "cannot disconnect"); 6358 } 6359 6360 static void 6361 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, 6362 const char *propname, dladm_prop_type_t type, const char *format, 6363 char **pptr) 6364 { 6365 int i; 6366 char *ptr, *lim; 6367 char buf[DLADM_STRSIZE]; 6368 char *unknown = "--", *notsup = ""; 6369 char **propvals = statep->ls_propvals; 6370 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 6371 dladm_status_t status; 6372 6373 status = dladm_get_linkprop(handle, linkid, type, propname, propvals, 6374 &valcnt); 6375 if (status != DLADM_STATUS_OK) { 6376 if (status == DLADM_STATUS_TEMPONLY) { 6377 if (type == DLADM_PROP_VAL_MODIFIABLE && 6378 statep->ls_persist) { 6379 valcnt = 1; 6380 propvals = &unknown; 6381 } else { 6382 statep->ls_status = status; 6383 statep->ls_retstatus = status; 6384 return; 6385 } 6386 } else if (status == DLADM_STATUS_NOTSUP || 6387 statep->ls_persist) { 6388 valcnt = 1; 6389 if (type == DLADM_PROP_VAL_CURRENT || 6390 type == DLADM_PROP_VAL_PERM) 6391 propvals = &unknown; 6392 else 6393 propvals = ¬sup; 6394 } else if (status == DLADM_STATUS_NOTDEFINED) { 6395 propvals = ¬sup; /* STR_UNDEF_VAL */ 6396 } else { 6397 if (statep->ls_proplist && 6398 statep->ls_status == DLADM_STATUS_OK) { 6399 warn_dlerr(status, 6400 "cannot get link property '%s' for %s", 6401 propname, statep->ls_link); 6402 } 6403 statep->ls_status = status; 6404 statep->ls_retstatus = status; 6405 return; 6406 } 6407 } 6408 6409 statep->ls_status = DLADM_STATUS_OK; 6410 6411 buf[0] = '\0'; 6412 ptr = buf; 6413 lim = buf + DLADM_STRSIZE; 6414 for (i = 0; i < valcnt; i++) { 6415 if (propvals[i][0] == '\0' && !statep->ls_parsable) 6416 ptr += snprintf(ptr, lim - ptr, "--,"); 6417 else 6418 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 6419 if (ptr >= lim) 6420 break; 6421 } 6422 if (valcnt > 0) 6423 buf[strlen(buf) - 1] = '\0'; 6424 6425 lim = statep->ls_line + MAX_PROP_LINE; 6426 if (statep->ls_parsable) { 6427 *pptr += snprintf(*pptr, lim - *pptr, 6428 "%s", buf); 6429 } else { 6430 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 6431 } 6432 } 6433 6434 static boolean_t 6435 print_linkprop_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 6436 { 6437 linkprop_args_t *arg = ofarg->ofmt_cbarg; 6438 char *propname = arg->ls_propname; 6439 show_linkprop_state_t *statep = arg->ls_state; 6440 char *ptr = statep->ls_line; 6441 char *lim = ptr + MAX_PROP_LINE; 6442 datalink_id_t linkid = arg->ls_linkid; 6443 6444 switch (ofarg->ofmt_id) { 6445 case LINKPROP_LINK: 6446 (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); 6447 break; 6448 case LINKPROP_PROPERTY: 6449 (void) snprintf(ptr, lim - ptr, "%s", propname); 6450 break; 6451 case LINKPROP_VALUE: 6452 print_linkprop(linkid, statep, propname, 6453 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 6454 DLADM_PROP_VAL_CURRENT, "%s", &ptr); 6455 /* 6456 * If we failed to query the link property, for example, query 6457 * the persistent value of a non-persistable link property, 6458 * simply skip the output. 6459 */ 6460 if (statep->ls_status != DLADM_STATUS_OK) 6461 goto skip; 6462 ptr = statep->ls_line; 6463 break; 6464 case LINKPROP_PERM: 6465 print_linkprop(linkid, statep, propname, 6466 DLADM_PROP_VAL_PERM, "%s", &ptr); 6467 if (statep->ls_status != DLADM_STATUS_OK) 6468 goto skip; 6469 ptr = statep->ls_line; 6470 break; 6471 case LINKPROP_DEFAULT: 6472 print_linkprop(linkid, statep, propname, 6473 DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 6474 if (statep->ls_status != DLADM_STATUS_OK) 6475 goto skip; 6476 ptr = statep->ls_line; 6477 break; 6478 case LINKPROP_POSSIBLE: 6479 print_linkprop(linkid, statep, propname, 6480 DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 6481 if (statep->ls_status != DLADM_STATUS_OK) 6482 goto skip; 6483 ptr = statep->ls_line; 6484 break; 6485 default: 6486 die("invalid input"); 6487 break; 6488 } 6489 (void) strlcpy(buf, ptr, bufsize); 6490 return (B_TRUE); 6491 skip: 6492 return ((statep->ls_status == DLADM_STATUS_OK) ? 6493 B_TRUE : B_FALSE); 6494 } 6495 6496 static boolean_t 6497 linkprop_is_supported(datalink_id_t linkid, const char *propname, 6498 show_linkprop_state_t *statep) 6499 { 6500 dladm_status_t status; 6501 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 6502 6503 /* if used with -p flag, always print output */ 6504 if (statep->ls_proplist != NULL) 6505 return (B_TRUE); 6506 6507 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_DEFAULT, 6508 propname, statep->ls_propvals, &valcnt); 6509 6510 if (status == DLADM_STATUS_OK) 6511 return (B_TRUE); 6512 6513 /* 6514 * A system wide default value is not available for the 6515 * property. Check if current value can be retrieved. 6516 */ 6517 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT, 6518 propname, statep->ls_propvals, &valcnt); 6519 6520 return (status == DLADM_STATUS_OK); 6521 } 6522 6523 /* ARGSUSED */ 6524 static int 6525 show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname, 6526 void *arg) 6527 { 6528 show_linkprop_state_t *statep = arg; 6529 linkprop_args_t ls_arg; 6530 6531 bzero(&ls_arg, sizeof (ls_arg)); 6532 ls_arg.ls_state = statep; 6533 ls_arg.ls_propname = (char *)propname; 6534 ls_arg.ls_linkid = linkid; 6535 6536 /* 6537 * This will need to be fixed when kernel interfaces are added 6538 * to enable walking of all known private properties. For now, 6539 * we are limited to walking persistent private properties only. 6540 */ 6541 if ((propname[0] == '_') && !statep->ls_persist && 6542 (statep->ls_proplist == NULL)) 6543 return (DLADM_WALK_CONTINUE); 6544 if (!statep->ls_parsable && 6545 !linkprop_is_supported(linkid, propname, statep)) 6546 return (DLADM_WALK_CONTINUE); 6547 6548 ofmt_print(statep->ls_ofmt, &ls_arg); 6549 6550 return (DLADM_WALK_CONTINUE); 6551 } 6552 6553 static void 6554 do_show_linkprop(int argc, char **argv, const char *use) 6555 { 6556 int option; 6557 char propstr[DLADM_STRSIZE]; 6558 dladm_arg_list_t *proplist = NULL; 6559 datalink_id_t linkid = DATALINK_ALL_LINKID; 6560 show_linkprop_state_t state; 6561 uint32_t flags = DLADM_OPT_ACTIVE; 6562 dladm_status_t status; 6563 char *fields_str = NULL; 6564 ofmt_handle_t ofmt; 6565 ofmt_status_t oferr; 6566 uint_t ofmtflags = 0; 6567 6568 bzero(propstr, DLADM_STRSIZE); 6569 opterr = 0; 6570 state.ls_propvals = NULL; 6571 state.ls_line = NULL; 6572 state.ls_parsable = B_FALSE; 6573 state.ls_persist = B_FALSE; 6574 state.ls_header = B_TRUE; 6575 state.ls_retstatus = DLADM_STATUS_OK; 6576 6577 while ((option = getopt_long(argc, argv, ":p:cPo:", 6578 prop_longopts, NULL)) != -1) { 6579 switch (option) { 6580 case 'p': 6581 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 6582 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 6583 DLADM_STRSIZE) 6584 die("property list too long '%s'", propstr); 6585 break; 6586 case 'c': 6587 state.ls_parsable = B_TRUE; 6588 break; 6589 case 'P': 6590 state.ls_persist = B_TRUE; 6591 flags = DLADM_OPT_PERSIST; 6592 break; 6593 case 'o': 6594 fields_str = optarg; 6595 break; 6596 default: 6597 die_opterr(optopt, option, use); 6598 break; 6599 } 6600 } 6601 6602 if (optind == (argc - 1)) { 6603 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6604 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 6605 die_dlerr(status, "link %s is not valid", argv[optind]); 6606 } 6607 } else if (optind != argc) { 6608 usage(); 6609 } 6610 6611 if (dladm_parse_link_props(propstr, &proplist, B_TRUE) 6612 != DLADM_STATUS_OK) 6613 die("invalid link properties specified"); 6614 state.ls_proplist = proplist; 6615 state.ls_status = DLADM_STATUS_OK; 6616 6617 if (state.ls_parsable) 6618 ofmtflags |= OFMT_PARSABLE; 6619 else 6620 ofmtflags |= OFMT_WRAP; 6621 6622 oferr = ofmt_open(fields_str, linkprop_fields, ofmtflags, 0, &ofmt); 6623 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 6624 state.ls_ofmt = ofmt; 6625 6626 if (linkid == DATALINK_ALL_LINKID) { 6627 (void) dladm_walk_datalink_id(show_linkprop_onelink, handle, 6628 &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 6629 } else { 6630 (void) show_linkprop_onelink(handle, linkid, &state); 6631 } 6632 ofmt_close(ofmt); 6633 dladm_free_props(proplist); 6634 6635 if (state.ls_retstatus != DLADM_STATUS_OK) { 6636 dladm_close(handle); 6637 exit(EXIT_FAILURE); 6638 } 6639 } 6640 6641 static int 6642 show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg) 6643 { 6644 int i; 6645 char *buf; 6646 uint32_t flags; 6647 dladm_arg_list_t *proplist = NULL; 6648 show_linkprop_state_t *statep = arg; 6649 dlpi_handle_t dh = NULL; 6650 6651 statep->ls_status = DLADM_STATUS_OK; 6652 6653 if (dladm_datalink_id2info(hdl, linkid, &flags, NULL, NULL, 6654 statep->ls_link, MAXLINKNAMELEN) != DLADM_STATUS_OK) { 6655 statep->ls_status = DLADM_STATUS_NOTFOUND; 6656 return (DLADM_WALK_CONTINUE); 6657 } 6658 6659 if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) || 6660 (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) { 6661 statep->ls_status = DLADM_STATUS_BADARG; 6662 return (DLADM_WALK_CONTINUE); 6663 } 6664 6665 proplist = statep->ls_proplist; 6666 6667 /* 6668 * When some WiFi links are opened for the first time, their hardware 6669 * automatically scans for APs and does other slow operations. Thus, 6670 * if there are no open links, the retrieval of link properties 6671 * (below) will proceed slowly unless we hold the link open. 6672 * 6673 * Note that failure of dlpi_open() does not necessarily mean invalid 6674 * link properties, because dlpi_open() may fail because of incorrect 6675 * autopush configuration. Therefore, we ingore the return value of 6676 * dlpi_open(). 6677 */ 6678 if (!statep->ls_persist) 6679 (void) dlpi_open(statep->ls_link, &dh, 0); 6680 6681 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 6682 DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 6683 if (buf == NULL) 6684 die("insufficient memory"); 6685 6686 statep->ls_propvals = (char **)(void *)buf; 6687 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 6688 statep->ls_propvals[i] = buf + 6689 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 6690 i * DLADM_PROP_VAL_MAX; 6691 } 6692 statep->ls_line = buf + 6693 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 6694 6695 if (proplist != NULL) { 6696 for (i = 0; i < proplist->al_count; i++) { 6697 (void) show_linkprop(hdl, linkid, 6698 proplist->al_info[i].ai_name, statep); 6699 } 6700 } else { 6701 (void) dladm_walk_linkprop(hdl, linkid, statep, 6702 show_linkprop); 6703 } 6704 if (dh != NULL) 6705 dlpi_close(dh); 6706 free(buf); 6707 return (DLADM_WALK_CONTINUE); 6708 } 6709 6710 static int 6711 reset_one_linkprop(dladm_handle_t dh, datalink_id_t linkid, 6712 const char *propname, void *arg) 6713 { 6714 set_linkprop_state_t *statep = arg; 6715 dladm_status_t status; 6716 6717 status = dladm_set_linkprop(dh, linkid, propname, NULL, 0, 6718 DLADM_OPT_ACTIVE | (statep->ls_temp ? 0 : DLADM_OPT_PERSIST)); 6719 if (status != DLADM_STATUS_OK && 6720 status != DLADM_STATUS_PROPRDONLY && 6721 status != DLADM_STATUS_NOTSUP) { 6722 warn_dlerr(status, "cannot reset link property '%s' on '%s'", 6723 propname, statep->ls_name); 6724 statep->ls_status = status; 6725 } 6726 6727 return (DLADM_WALK_CONTINUE); 6728 } 6729 6730 static void 6731 set_linkprop(int argc, char **argv, boolean_t reset, const char *use) 6732 { 6733 int i, option; 6734 char errmsg[DLADM_STRSIZE]; 6735 char *altroot = NULL; 6736 datalink_id_t linkid; 6737 boolean_t temp = B_FALSE; 6738 dladm_status_t status = DLADM_STATUS_OK; 6739 char propstr[DLADM_STRSIZE]; 6740 dladm_arg_list_t *proplist = NULL; 6741 6742 opterr = 0; 6743 bzero(propstr, DLADM_STRSIZE); 6744 6745 while ((option = getopt_long(argc, argv, ":p:R:t", 6746 prop_longopts, NULL)) != -1) { 6747 switch (option) { 6748 case 'p': 6749 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 6750 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 6751 DLADM_STRSIZE) 6752 die("property list too long '%s'", propstr); 6753 break; 6754 case 't': 6755 temp = B_TRUE; 6756 break; 6757 case 'R': 6758 altroot = optarg; 6759 break; 6760 default: 6761 die_opterr(optopt, option, use); 6762 6763 } 6764 } 6765 6766 /* get link name (required last argument) */ 6767 if (optind != (argc - 1)) 6768 usage(); 6769 6770 if (dladm_parse_link_props(propstr, &proplist, reset) != 6771 DLADM_STATUS_OK) 6772 die("invalid link properties specified"); 6773 6774 if (proplist == NULL && !reset) 6775 die("link property must be specified"); 6776 6777 if (altroot != NULL) { 6778 dladm_free_props(proplist); 6779 altroot_cmd(altroot, argc, argv); 6780 } 6781 6782 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 6783 NULL); 6784 if (status != DLADM_STATUS_OK) 6785 die_dlerr(status, "link %s is not valid", argv[optind]); 6786 6787 if (proplist == NULL) { 6788 set_linkprop_state_t state; 6789 6790 state.ls_name = argv[optind]; 6791 state.ls_reset = reset; 6792 state.ls_temp = temp; 6793 state.ls_status = DLADM_STATUS_OK; 6794 6795 (void) dladm_walk_linkprop(handle, linkid, &state, 6796 reset_one_linkprop); 6797 6798 status = state.ls_status; 6799 goto done; 6800 } 6801 6802 for (i = 0; i < proplist->al_count; i++) { 6803 dladm_arg_info_t *aip = &proplist->al_info[i]; 6804 char **val; 6805 uint_t count; 6806 6807 if (reset) { 6808 val = NULL; 6809 count = 0; 6810 } else { 6811 val = aip->ai_val; 6812 count = aip->ai_count; 6813 if (count == 0) { 6814 warn("no value specified for '%s'", 6815 aip->ai_name); 6816 status = DLADM_STATUS_BADARG; 6817 continue; 6818 } 6819 } 6820 status = dladm_set_linkprop(handle, linkid, aip->ai_name, val, 6821 count, DLADM_OPT_ACTIVE | (temp ? 0 : DLADM_OPT_PERSIST)); 6822 switch (status) { 6823 case DLADM_STATUS_OK: 6824 break; 6825 case DLADM_STATUS_NOTFOUND: 6826 warn("invalid link property '%s'", aip->ai_name); 6827 break; 6828 case DLADM_STATUS_BADVAL: { 6829 int j; 6830 char *ptr, *lim; 6831 char **propvals = NULL; 6832 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 6833 dladm_status_t s; 6834 6835 ptr = malloc((sizeof (char *) + 6836 DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 6837 MAX_PROP_LINE); 6838 6839 propvals = (char **)(void *)ptr; 6840 if (propvals == NULL) 6841 die("insufficient memory"); 6842 6843 for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 6844 propvals[j] = ptr + sizeof (char *) * 6845 DLADM_MAX_PROP_VALCNT + 6846 j * DLADM_PROP_VAL_MAX; 6847 } 6848 s = dladm_get_linkprop(handle, linkid, 6849 DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals, 6850 &valcnt); 6851 6852 if (s != DLADM_STATUS_OK) { 6853 warn_dlerr(status, "cannot set link property " 6854 "'%s' on '%s'", aip->ai_name, argv[optind]); 6855 free(propvals); 6856 break; 6857 } 6858 6859 ptr = errmsg; 6860 lim = ptr + DLADM_STRSIZE; 6861 *ptr = '\0'; 6862 for (j = 0; j < valcnt; j++) { 6863 ptr += snprintf(ptr, lim - ptr, "%s,", 6864 propvals[j]); 6865 if (ptr >= lim) 6866 break; 6867 } 6868 if (ptr > errmsg) { 6869 *(ptr - 1) = '\0'; 6870 warn("link property '%s' must be one of: %s", 6871 aip->ai_name, errmsg); 6872 } else 6873 warn("invalid link property '%s'", *val); 6874 free(propvals); 6875 break; 6876 } 6877 default: 6878 if (reset) { 6879 warn_dlerr(status, "cannot reset link property " 6880 "'%s' on '%s'", aip->ai_name, argv[optind]); 6881 } else { 6882 warn_dlerr(status, "cannot set link property " 6883 "'%s' on '%s'", aip->ai_name, argv[optind]); 6884 } 6885 break; 6886 } 6887 } 6888 done: 6889 dladm_free_props(proplist); 6890 if (status != DLADM_STATUS_OK) { 6891 dladm_close(handle); 6892 exit(EXIT_FAILURE); 6893 } 6894 } 6895 6896 static void 6897 do_set_linkprop(int argc, char **argv, const char *use) 6898 { 6899 set_linkprop(argc, argv, B_FALSE, use); 6900 } 6901 6902 static void 6903 do_reset_linkprop(int argc, char **argv, const char *use) 6904 { 6905 set_linkprop(argc, argv, B_TRUE, use); 6906 } 6907 6908 static int 6909 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 6910 dladm_secobj_class_t class) 6911 { 6912 int error = 0; 6913 6914 if (class == DLADM_SECOBJ_CLASS_WPA) { 6915 if (len < 8 || len > 63) 6916 return (EINVAL); 6917 (void) memcpy(obj_val, buf, len); 6918 *obj_lenp = len; 6919 return (error); 6920 } 6921 6922 if (class == DLADM_SECOBJ_CLASS_WEP) { 6923 switch (len) { 6924 case 5: /* ASCII key sizes */ 6925 case 13: 6926 (void) memcpy(obj_val, buf, len); 6927 *obj_lenp = len; 6928 break; 6929 case 10: /* Hex key sizes, not preceded by 0x */ 6930 case 26: 6931 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 6932 break; 6933 case 12: /* Hex key sizes, preceded by 0x */ 6934 case 28: 6935 if (strncmp(buf, "0x", 2) != 0) 6936 return (EINVAL); 6937 error = hexascii_to_octet(buf + 2, len - 2, 6938 obj_val, obj_lenp); 6939 break; 6940 default: 6941 return (EINVAL); 6942 } 6943 return (error); 6944 } 6945 6946 return (ENOENT); 6947 } 6948 6949 static void 6950 defersig(int sig) 6951 { 6952 signalled = sig; 6953 } 6954 6955 static int 6956 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 6957 { 6958 uint_t len = 0; 6959 int c; 6960 struct termios stored, current; 6961 void (*sigfunc)(int); 6962 6963 /* 6964 * Turn off echo -- but before we do so, defer SIGINT handling 6965 * so that a ^C doesn't leave the terminal corrupted. 6966 */ 6967 sigfunc = signal(SIGINT, defersig); 6968 (void) fflush(stdin); 6969 (void) tcgetattr(0, &stored); 6970 current = stored; 6971 current.c_lflag &= ~(ICANON|ECHO); 6972 current.c_cc[VTIME] = 0; 6973 current.c_cc[VMIN] = 1; 6974 (void) tcsetattr(0, TCSANOW, ¤t); 6975 again: 6976 if (try == 1) 6977 (void) printf(gettext("provide value for '%s': "), objname); 6978 else 6979 (void) printf(gettext("confirm value for '%s': "), objname); 6980 6981 (void) fflush(stdout); 6982 while (signalled == 0) { 6983 c = getchar(); 6984 if (c == '\n' || c == '\r') { 6985 if (len != 0) 6986 break; 6987 (void) putchar('\n'); 6988 goto again; 6989 } 6990 6991 buf[len++] = c; 6992 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 6993 break; 6994 (void) putchar('*'); 6995 } 6996 6997 (void) putchar('\n'); 6998 (void) fflush(stdin); 6999 7000 /* 7001 * Restore terminal setting and handle deferred signals. 7002 */ 7003 (void) tcsetattr(0, TCSANOW, &stored); 7004 7005 (void) signal(SIGINT, sigfunc); 7006 if (signalled != 0) 7007 (void) kill(getpid(), signalled); 7008 7009 return (len); 7010 } 7011 7012 static int 7013 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 7014 dladm_secobj_class_t class, FILE *filep) 7015 { 7016 int rval; 7017 uint_t len, len2; 7018 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 7019 7020 if (filep == NULL) { 7021 len = get_secobj_from_tty(1, obj_name, buf); 7022 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 7023 if (rval == 0) { 7024 len2 = get_secobj_from_tty(2, obj_name, buf2); 7025 if (len != len2 || memcmp(buf, buf2, len) != 0) 7026 rval = ENOTSUP; 7027 } 7028 return (rval); 7029 } else { 7030 for (;;) { 7031 if (fgets(buf, sizeof (buf), filep) == NULL) 7032 break; 7033 if (isspace(buf[0])) 7034 continue; 7035 7036 len = strlen(buf); 7037 if (buf[len - 1] == '\n') { 7038 buf[len - 1] = '\0'; 7039 len--; 7040 } 7041 break; 7042 } 7043 (void) fclose(filep); 7044 } 7045 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 7046 } 7047 7048 static boolean_t 7049 check_auth(const char *auth) 7050 { 7051 struct passwd *pw; 7052 7053 if ((pw = getpwuid(getuid())) == NULL) 7054 return (B_FALSE); 7055 7056 return (chkauthattr(auth, pw->pw_name) != 0); 7057 } 7058 7059 static void 7060 audit_secobj(char *auth, char *class, char *obj, 7061 boolean_t success, boolean_t create) 7062 { 7063 adt_session_data_t *ah; 7064 adt_event_data_t *event; 7065 au_event_t flag; 7066 char *errstr; 7067 7068 if (create) { 7069 flag = ADT_dladm_create_secobj; 7070 errstr = "ADT_dladm_create_secobj"; 7071 } else { 7072 flag = ADT_dladm_delete_secobj; 7073 errstr = "ADT_dladm_delete_secobj"; 7074 } 7075 7076 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 7077 die("adt_start_session: %s", strerror(errno)); 7078 7079 if ((event = adt_alloc_event(ah, flag)) == NULL) 7080 die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 7081 7082 /* fill in audit info */ 7083 if (create) { 7084 event->adt_dladm_create_secobj.auth_used = auth; 7085 event->adt_dladm_create_secobj.obj_class = class; 7086 event->adt_dladm_create_secobj.obj_name = obj; 7087 } else { 7088 event->adt_dladm_delete_secobj.auth_used = auth; 7089 event->adt_dladm_delete_secobj.obj_class = class; 7090 event->adt_dladm_delete_secobj.obj_name = obj; 7091 } 7092 7093 if (success) { 7094 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 7095 die("adt_put_event (%s, success): %s", errstr, 7096 strerror(errno)); 7097 } 7098 } else { 7099 if (adt_put_event(event, ADT_FAILURE, 7100 ADT_FAIL_VALUE_AUTH) != 0) { 7101 die("adt_put_event: (%s, failure): %s", errstr, 7102 strerror(errno)); 7103 } 7104 } 7105 7106 adt_free_event(event); 7107 (void) adt_end_session(ah); 7108 } 7109 7110 #define MAX_SECOBJS 32 7111 #define MAX_SECOBJ_NAMELEN 32 7112 static void 7113 do_create_secobj(int argc, char **argv, const char *use) 7114 { 7115 int option, rval; 7116 FILE *filep = NULL; 7117 char *obj_name = NULL; 7118 char *class_name = NULL; 7119 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 7120 uint_t obj_len; 7121 boolean_t success, temp = B_FALSE; 7122 dladm_status_t status; 7123 dladm_secobj_class_t class = -1; 7124 uid_t euid; 7125 7126 opterr = 0; 7127 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 7128 while ((option = getopt_long(argc, argv, ":f:c:R:t", 7129 wifi_longopts, NULL)) != -1) { 7130 switch (option) { 7131 case 'f': 7132 euid = geteuid(); 7133 (void) seteuid(getuid()); 7134 filep = fopen(optarg, "r"); 7135 if (filep == NULL) { 7136 die("cannot open %s: %s", optarg, 7137 strerror(errno)); 7138 } 7139 (void) seteuid(euid); 7140 break; 7141 case 'c': 7142 class_name = optarg; 7143 status = dladm_str2secobjclass(optarg, &class); 7144 if (status != DLADM_STATUS_OK) { 7145 die("invalid secure object class '%s', " 7146 "valid values are: wep, wpa", optarg); 7147 } 7148 break; 7149 case 't': 7150 temp = B_TRUE; 7151 break; 7152 case 'R': 7153 status = dladm_set_rootdir(optarg); 7154 if (status != DLADM_STATUS_OK) { 7155 die_dlerr(status, "invalid directory " 7156 "specified"); 7157 } 7158 break; 7159 default: 7160 die_opterr(optopt, option, use); 7161 break; 7162 } 7163 } 7164 7165 if (optind == (argc - 1)) 7166 obj_name = argv[optind]; 7167 else if (optind != argc) 7168 usage(); 7169 7170 if (class == -1) 7171 die("secure object class required"); 7172 7173 if (obj_name == NULL) 7174 die("secure object name required"); 7175 7176 if (!dladm_valid_secobj_name(obj_name)) 7177 die("invalid secure object name '%s'", obj_name); 7178 7179 success = check_auth(LINK_SEC_AUTH); 7180 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 7181 if (!success) 7182 die("authorization '%s' is required", LINK_SEC_AUTH); 7183 7184 rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 7185 if (rval != 0) { 7186 switch (rval) { 7187 case ENOENT: 7188 die("invalid secure object class"); 7189 break; 7190 case EINVAL: 7191 die("invalid secure object value"); 7192 break; 7193 case ENOTSUP: 7194 die("verification failed"); 7195 break; 7196 default: 7197 die("invalid secure object: %s", strerror(rval)); 7198 break; 7199 } 7200 } 7201 7202 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 7203 DLADM_OPT_CREATE | DLADM_OPT_ACTIVE); 7204 if (status != DLADM_STATUS_OK) { 7205 die_dlerr(status, "could not create secure object '%s'", 7206 obj_name); 7207 } 7208 if (temp) 7209 return; 7210 7211 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 7212 DLADM_OPT_PERSIST); 7213 if (status != DLADM_STATUS_OK) { 7214 warn_dlerr(status, "could not persistently create secure " 7215 "object '%s'", obj_name); 7216 } 7217 } 7218 7219 static void 7220 do_delete_secobj(int argc, char **argv, const char *use) 7221 { 7222 int i, option; 7223 boolean_t temp = B_FALSE; 7224 boolean_t success; 7225 dladm_status_t status, pstatus; 7226 int nfields = 1; 7227 char *field, *token, *lasts = NULL, c; 7228 7229 opterr = 0; 7230 status = pstatus = DLADM_STATUS_OK; 7231 while ((option = getopt_long(argc, argv, ":R:t", 7232 wifi_longopts, NULL)) != -1) { 7233 switch (option) { 7234 case 't': 7235 temp = B_TRUE; 7236 break; 7237 case 'R': 7238 status = dladm_set_rootdir(optarg); 7239 if (status != DLADM_STATUS_OK) { 7240 die_dlerr(status, "invalid directory " 7241 "specified"); 7242 } 7243 break; 7244 default: 7245 die_opterr(optopt, option, use); 7246 break; 7247 } 7248 } 7249 7250 if (optind == (argc - 1)) { 7251 token = argv[optind]; 7252 if (token == NULL) 7253 die("secure object name required"); 7254 while ((c = *token++) != NULL) { 7255 if (c == ',') 7256 nfields++; 7257 } 7258 token = strdup(argv[optind]); 7259 if (token == NULL) 7260 die("no memory"); 7261 } else if (optind != argc) 7262 usage(); 7263 7264 success = check_auth(LINK_SEC_AUTH); 7265 audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE); 7266 if (!success) 7267 die("authorization '%s' is required", LINK_SEC_AUTH); 7268 7269 for (i = 0; i < nfields; i++) { 7270 7271 field = strtok_r(token, ",", &lasts); 7272 token = NULL; 7273 status = dladm_unset_secobj(handle, field, DLADM_OPT_ACTIVE); 7274 if (!temp) { 7275 pstatus = dladm_unset_secobj(handle, field, 7276 DLADM_OPT_PERSIST); 7277 } else { 7278 pstatus = DLADM_STATUS_OK; 7279 } 7280 7281 if (status != DLADM_STATUS_OK) { 7282 warn_dlerr(status, "could not delete secure object " 7283 "'%s'", field); 7284 } 7285 if (pstatus != DLADM_STATUS_OK) { 7286 warn_dlerr(pstatus, "could not persistently delete " 7287 "secure object '%s'", field); 7288 } 7289 } 7290 free(token); 7291 7292 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) { 7293 dladm_close(handle); 7294 exit(EXIT_FAILURE); 7295 } 7296 } 7297 7298 typedef struct show_secobj_state { 7299 boolean_t ss_persist; 7300 boolean_t ss_parsable; 7301 boolean_t ss_header; 7302 ofmt_handle_t ss_ofmt; 7303 } show_secobj_state_t; 7304 7305 7306 static boolean_t 7307 show_secobj(dladm_handle_t dh, void *arg, const char *obj_name) 7308 { 7309 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 7310 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 7311 char buf[DLADM_STRSIZE]; 7312 uint_t flags = 0; 7313 dladm_secobj_class_t class; 7314 show_secobj_state_t *statep = arg; 7315 dladm_status_t status; 7316 secobj_fields_buf_t sbuf; 7317 7318 bzero(&sbuf, sizeof (secobj_fields_buf_t)); 7319 if (statep->ss_persist) 7320 flags |= DLADM_OPT_PERSIST; 7321 7322 status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len, 7323 flags); 7324 if (status != DLADM_STATUS_OK) 7325 die_dlerr(status, "cannot get secure object '%s'", obj_name); 7326 7327 (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), 7328 obj_name); 7329 (void) dladm_secobjclass2str(class, buf); 7330 (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf); 7331 if (getuid() == 0) { 7332 char val[DLADM_SECOBJ_VAL_MAX * 2]; 7333 uint_t len = sizeof (val); 7334 7335 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) 7336 (void) snprintf(sbuf.ss_val, 7337 sizeof (sbuf.ss_val), "%s", val); 7338 } 7339 ofmt_print(statep->ss_ofmt, &sbuf); 7340 return (B_TRUE); 7341 } 7342 7343 static void 7344 do_show_secobj(int argc, char **argv, const char *use) 7345 { 7346 int option; 7347 show_secobj_state_t state; 7348 dladm_status_t status; 7349 boolean_t o_arg = B_FALSE; 7350 uint_t i; 7351 uint_t flags; 7352 char *fields_str = NULL; 7353 char *def_fields = "object,class"; 7354 char *all_fields = "object,class,value"; 7355 char *field, *token, *lasts = NULL, c; 7356 ofmt_handle_t ofmt; 7357 ofmt_status_t oferr; 7358 uint_t ofmtflags = 0; 7359 7360 opterr = 0; 7361 bzero(&state, sizeof (state)); 7362 state.ss_parsable = B_FALSE; 7363 fields_str = def_fields; 7364 state.ss_persist = B_FALSE; 7365 state.ss_parsable = B_FALSE; 7366 state.ss_header = B_TRUE; 7367 while ((option = getopt_long(argc, argv, ":pPo:", 7368 wifi_longopts, NULL)) != -1) { 7369 switch (option) { 7370 case 'p': 7371 state.ss_parsable = B_TRUE; 7372 break; 7373 case 'P': 7374 state.ss_persist = B_TRUE; 7375 break; 7376 case 'o': 7377 o_arg = B_TRUE; 7378 if (strcasecmp(optarg, "all") == 0) 7379 fields_str = all_fields; 7380 else 7381 fields_str = optarg; 7382 break; 7383 default: 7384 die_opterr(optopt, option, use); 7385 break; 7386 } 7387 } 7388 7389 if (state.ss_parsable && !o_arg) 7390 die("option -c requires -o"); 7391 7392 if (state.ss_parsable && fields_str == all_fields) 7393 die("\"-o all\" is invalid with -p"); 7394 7395 if (state.ss_parsable) 7396 ofmtflags |= OFMT_PARSABLE; 7397 oferr = ofmt_open(fields_str, secobj_fields, ofmtflags, 0, &ofmt); 7398 dladm_ofmt_check(oferr, state.ss_parsable, ofmt); 7399 state.ss_ofmt = ofmt; 7400 7401 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 7402 7403 if (optind == (argc - 1)) { 7404 uint_t obj_fields = 1; 7405 7406 token = argv[optind]; 7407 if (token == NULL) 7408 die("secure object name required"); 7409 while ((c = *token++) != NULL) { 7410 if (c == ',') 7411 obj_fields++; 7412 } 7413 token = strdup(argv[optind]); 7414 if (token == NULL) 7415 die("no memory"); 7416 for (i = 0; i < obj_fields; i++) { 7417 field = strtok_r(token, ",", &lasts); 7418 token = NULL; 7419 if (!show_secobj(handle, &state, field)) 7420 break; 7421 } 7422 free(token); 7423 ofmt_close(ofmt); 7424 return; 7425 } else if (optind != argc) 7426 usage(); 7427 7428 status = dladm_walk_secobj(handle, &state, show_secobj, flags); 7429 7430 if (status != DLADM_STATUS_OK) 7431 die_dlerr(status, "show-secobj"); 7432 ofmt_close(ofmt); 7433 } 7434 7435 /*ARGSUSED*/ 7436 static int 7437 i_dladm_init_linkprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 7438 { 7439 (void) dladm_init_linkprop(dh, linkid, B_TRUE); 7440 return (DLADM_WALK_CONTINUE); 7441 } 7442 7443 /*ARGSUSED*/ 7444 void 7445 do_init_linkprop(int argc, char **argv, const char *use) 7446 { 7447 int option; 7448 dladm_status_t status; 7449 datalink_id_t linkid = DATALINK_ALL_LINKID; 7450 datalink_media_t media = DATALINK_ANY_MEDIATYPE; 7451 uint_t any_media = B_TRUE; 7452 7453 opterr = 0; 7454 while ((option = getopt(argc, argv, ":w")) != -1) { 7455 switch (option) { 7456 case 'w': 7457 media = DL_WIFI; 7458 any_media = B_FALSE; 7459 break; 7460 default: 7461 /* 7462 * Because init-linkprop is not a public command, 7463 * print the usage instead. 7464 */ 7465 usage(); 7466 break; 7467 } 7468 } 7469 7470 if (optind == (argc - 1)) { 7471 if ((status = dladm_name2info(handle, argv[optind], &linkid, 7472 NULL, NULL, NULL)) != DLADM_STATUS_OK) 7473 die_dlerr(status, "link %s is not valid", argv[optind]); 7474 } else if (optind != argc) { 7475 usage(); 7476 } 7477 7478 if (linkid == DATALINK_ALL_LINKID) { 7479 /* 7480 * linkprops of links of other classes have been initialized as 7481 * part of the dladm up-xxx operation. 7482 */ 7483 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle, 7484 NULL, DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST); 7485 } else { 7486 (void) dladm_init_linkprop(handle, linkid, any_media); 7487 } 7488 } 7489 7490 static void 7491 do_show_ether(int argc, char **argv, const char *use) 7492 { 7493 int option; 7494 datalink_id_t linkid; 7495 print_ether_state_t state; 7496 char *fields_str = NULL; 7497 ofmt_handle_t ofmt; 7498 ofmt_status_t oferr; 7499 uint_t ofmtflags = 0; 7500 7501 bzero(&state, sizeof (state)); 7502 state.es_link = NULL; 7503 state.es_parsable = B_FALSE; 7504 7505 while ((option = getopt_long(argc, argv, "o:px", 7506 showeth_lopts, NULL)) != -1) { 7507 switch (option) { 7508 case 'x': 7509 state.es_extended = B_TRUE; 7510 break; 7511 case 'p': 7512 state.es_parsable = B_TRUE; 7513 break; 7514 case 'o': 7515 fields_str = optarg; 7516 break; 7517 default: 7518 die_opterr(optopt, option, use); 7519 break; 7520 } 7521 } 7522 7523 if (optind == (argc - 1)) 7524 state.es_link = argv[optind]; 7525 7526 if (state.es_parsable) 7527 ofmtflags |= OFMT_PARSABLE; 7528 oferr = ofmt_open(fields_str, ether_fields, ofmtflags, 7529 DLADM_DEFAULT_COL, &ofmt); 7530 dladm_ofmt_check(oferr, state.es_parsable, ofmt); 7531 state.es_ofmt = ofmt; 7532 7533 if (state.es_link == NULL) { 7534 (void) dladm_walk_datalink_id(show_etherprop, handle, &state, 7535 DATALINK_CLASS_PHYS, DL_ETHER, DLADM_OPT_ACTIVE); 7536 } else { 7537 if (!link_is_ether(state.es_link, &linkid)) 7538 die("invalid link specified"); 7539 (void) show_etherprop(handle, linkid, &state); 7540 } 7541 ofmt_close(ofmt); 7542 } 7543 7544 static int 7545 show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 7546 { 7547 print_ether_state_t *statep = arg; 7548 ether_fields_buf_t ebuf; 7549 dladm_ether_info_t eattr; 7550 dladm_status_t status; 7551 7552 bzero(&ebuf, sizeof (ether_fields_buf_t)); 7553 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, 7554 ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) { 7555 return (DLADM_WALK_CONTINUE); 7556 } 7557 7558 status = dladm_ether_info(dh, linkid, &eattr); 7559 if (status != DLADM_STATUS_OK) 7560 goto cleanup; 7561 7562 (void) strlcpy(ebuf.eth_ptype, "current", sizeof (ebuf.eth_ptype)); 7563 7564 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 7565 sizeof (ebuf.eth_autoneg), &eattr, CURRENT); 7566 (void) dladm_ether_pause2str(ebuf.eth_pause, 7567 sizeof (ebuf.eth_pause), &eattr, CURRENT); 7568 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 7569 sizeof (ebuf.eth_spdx), &eattr, CURRENT); 7570 (void) strlcpy(ebuf.eth_state, 7571 dladm_linkstate2str(eattr.lei_state, ebuf.eth_state), 7572 sizeof (ebuf.eth_state)); 7573 (void) strlcpy(ebuf.eth_rem_fault, 7574 (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"), 7575 sizeof (ebuf.eth_rem_fault)); 7576 7577 ofmt_print(statep->es_ofmt, &ebuf); 7578 7579 if (statep->es_extended) 7580 show_ether_xprop(arg, &eattr); 7581 7582 cleanup: 7583 dladm_ether_info_done(&eattr); 7584 return (DLADM_WALK_CONTINUE); 7585 } 7586 7587 /* ARGSUSED */ 7588 static void 7589 do_init_secobj(int argc, char **argv, const char *use) 7590 { 7591 dladm_status_t status; 7592 7593 status = dladm_init_secobj(handle); 7594 if (status != DLADM_STATUS_OK) 7595 die_dlerr(status, "secure object initialization failed"); 7596 } 7597 7598 enum bridge_func { 7599 brCreate, brAdd, brModify 7600 }; 7601 7602 static void 7603 create_modify_add_bridge(int argc, char **argv, const char *use, 7604 enum bridge_func func) 7605 { 7606 int option; 7607 uint_t n, i, nlink; 7608 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 7609 char *altroot = NULL; 7610 char *links[MAXPORT]; 7611 datalink_id_t linkids[MAXPORT]; 7612 dladm_status_t status; 7613 const char *bridge; 7614 UID_STP_CFG_T cfg, cfg_old; 7615 dladm_bridge_prot_t brprot = DLADM_BRIDGE_PROT_UNKNOWN; 7616 dladm_bridge_prot_t brprot_old; 7617 7618 /* Set up the default configuration values */ 7619 cfg.field_mask = 0; 7620 cfg.bridge_priority = DEF_BR_PRIO; 7621 cfg.max_age = DEF_BR_MAXAGE; 7622 cfg.hello_time = DEF_BR_HELLOT; 7623 cfg.forward_delay = DEF_BR_FWDELAY; 7624 cfg.force_version = DEF_FORCE_VERS; 7625 7626 nlink = opterr = 0; 7627 while ((option = getopt_long(argc, argv, ":P:R:d:f:h:l:m:p:", 7628 bridge_lopts, NULL)) != -1) { 7629 switch (option) { 7630 case 'P': 7631 if (func == brAdd) 7632 die_opterr(optopt, option, use); 7633 status = dladm_bridge_str2prot(optarg, &brprot); 7634 if (status != DLADM_STATUS_OK) 7635 die_dlerr(status, "protection %s", optarg); 7636 break; 7637 case 'R': 7638 altroot = optarg; 7639 break; 7640 case 'd': 7641 if (func == brAdd) 7642 die_opterr(optopt, option, use); 7643 if (cfg.field_mask & BR_CFG_DELAY) 7644 die("forwarding delay set more than once"); 7645 if (!str2int(optarg, &cfg.forward_delay) || 7646 cfg.forward_delay < MIN_BR_FWDELAY || 7647 cfg.forward_delay > MAX_BR_FWDELAY) 7648 die("incorrect forwarding delay"); 7649 cfg.field_mask |= BR_CFG_DELAY; 7650 break; 7651 case 'f': 7652 if (func == brAdd) 7653 die_opterr(optopt, option, use); 7654 if (cfg.field_mask & BR_CFG_FORCE_VER) 7655 die("force protocol set more than once"); 7656 if (!str2int(optarg, &cfg.force_version) || 7657 cfg.force_version < 0) 7658 die("incorrect force protocol"); 7659 cfg.field_mask |= BR_CFG_FORCE_VER; 7660 break; 7661 case 'h': 7662 if (func == brAdd) 7663 die_opterr(optopt, option, use); 7664 if (cfg.field_mask & BR_CFG_HELLO) 7665 die("hello time set more than once"); 7666 if (!str2int(optarg, &cfg.hello_time) || 7667 cfg.hello_time < MIN_BR_HELLOT || 7668 cfg.hello_time > MAX_BR_HELLOT) 7669 die("incorrect hello time"); 7670 cfg.field_mask |= BR_CFG_HELLO; 7671 break; 7672 case 'l': 7673 if (func == brModify) 7674 die_opterr(optopt, option, use); 7675 if (nlink >= MAXPORT) 7676 die("too many links specified"); 7677 links[nlink++] = optarg; 7678 break; 7679 case 'm': 7680 if (func == brAdd) 7681 die_opterr(optopt, option, use); 7682 if (cfg.field_mask & BR_CFG_AGE) 7683 die("max age set more than once"); 7684 if (!str2int(optarg, &cfg.max_age) || 7685 cfg.max_age < MIN_BR_MAXAGE || 7686 cfg.max_age > MAX_BR_MAXAGE) 7687 die("incorrect max age"); 7688 cfg.field_mask |= BR_CFG_AGE; 7689 break; 7690 case 'p': 7691 if (func == brAdd) 7692 die_opterr(optopt, option, use); 7693 if (cfg.field_mask & BR_CFG_PRIO) 7694 die("priority set more than once"); 7695 if (!str2int(optarg, &cfg.bridge_priority) || 7696 cfg.bridge_priority < MIN_BR_PRIO || 7697 cfg.bridge_priority > MAX_BR_PRIO) 7698 die("incorrect priority"); 7699 cfg.bridge_priority &= 0xF000; 7700 cfg.field_mask |= BR_CFG_PRIO; 7701 break; 7702 default: 7703 die_opterr(optopt, option, use); 7704 break; 7705 } 7706 } 7707 7708 /* get the bridge name (required last argument) */ 7709 if (optind != (argc-1)) 7710 usage(); 7711 7712 bridge = argv[optind]; 7713 if (!dladm_valid_bridgename(bridge)) 7714 die("invalid bridge name '%s'", bridge); 7715 7716 /* 7717 * Get the current properties, if any, and merge in with changes. This 7718 * is necessary (even with the field_mask feature) so that the 7719 * value-checking macros will produce the right results with proposed 7720 * changes to existing configuration. We only need it for those 7721 * parameters, though. 7722 */ 7723 (void) dladm_bridge_get_properties(bridge, &cfg_old, &brprot_old); 7724 if (brprot == DLADM_BRIDGE_PROT_UNKNOWN) 7725 brprot = brprot_old; 7726 if (!(cfg.field_mask & BR_CFG_AGE)) 7727 cfg.max_age = cfg_old.max_age; 7728 if (!(cfg.field_mask & BR_CFG_HELLO)) 7729 cfg.hello_time = cfg_old.hello_time; 7730 if (!(cfg.field_mask & BR_CFG_DELAY)) 7731 cfg.forward_delay = cfg_old.forward_delay; 7732 7733 if (!CHECK_BRIDGE_CONFIG(cfg)) { 7734 warn("illegal forward delay / max age / hello time " 7735 "combination"); 7736 if (NO_MAXAGE(cfg)) { 7737 die("no max age possible: need forward delay >= %d or " 7738 "hello time <= %d", MIN_FWDELAY_NOM(cfg), 7739 MAX_HELLOTIME_NOM(cfg)); 7740 } else if (SMALL_MAXAGE(cfg)) { 7741 if (CAPPED_MAXAGE(cfg)) 7742 die("max age too small: need age >= %d and " 7743 "<= %d or hello time <= %d", 7744 MIN_MAXAGE(cfg), MAX_MAXAGE(cfg), 7745 MAX_HELLOTIME(cfg)); 7746 else 7747 die("max age too small: need age >= %d or " 7748 "hello time <= %d", 7749 MIN_MAXAGE(cfg), MAX_HELLOTIME(cfg)); 7750 } else if (FLOORED_MAXAGE(cfg)) { 7751 die("max age too large: need age >= %d and <= %d or " 7752 "forward delay >= %d", 7753 MIN_MAXAGE(cfg), MAX_MAXAGE(cfg), 7754 MIN_FWDELAY(cfg)); 7755 } else { 7756 die("max age too large: need age <= %d or forward " 7757 "delay >= %d", 7758 MAX_MAXAGE(cfg), MIN_FWDELAY(cfg)); 7759 } 7760 } 7761 7762 if (altroot != NULL) 7763 altroot_cmd(altroot, argc, argv); 7764 7765 for (n = 0; n < nlink; n++) { 7766 datalink_class_t class; 7767 uint32_t media; 7768 char pointless[DLADM_STRSIZE]; 7769 7770 if (dladm_name2info(handle, links[n], &linkids[n], NULL, &class, 7771 &media) != DLADM_STATUS_OK) 7772 die("invalid link name '%s'", links[n]); 7773 if (class & ~(DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | 7774 DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET)) 7775 die("%s %s cannot be bridged", 7776 dladm_class2str(class, pointless), links[n]); 7777 if (media != DL_ETHER && media != DL_100VG && 7778 media != DL_ETH_CSMA && media != DL_100BT) 7779 die("%s interface %s cannot be bridged", 7780 dladm_media2str(media, pointless), links[n]); 7781 } 7782 7783 if (func == brCreate) 7784 flags |= DLADM_OPT_CREATE; 7785 7786 if (func != brAdd) { 7787 status = dladm_bridge_configure(handle, bridge, &cfg, brprot, 7788 flags); 7789 if (status != DLADM_STATUS_OK) 7790 die_dlerr(status, "create operation failed"); 7791 } 7792 7793 status = DLADM_STATUS_OK; 7794 for (n = 0; n < nlink; n++) { 7795 status = dladm_bridge_setlink(handle, linkids[n], bridge); 7796 if (status != DLADM_STATUS_OK) 7797 break; 7798 } 7799 7800 if (n >= nlink) { 7801 /* 7802 * We were successful. If we're creating a new bridge, then 7803 * there's just one more step: enabling. If we're modifying or 7804 * just adding links, then we're done. 7805 */ 7806 if (func != brCreate || 7807 (status = dladm_bridge_enable(bridge)) == DLADM_STATUS_OK) 7808 return; 7809 } 7810 7811 /* clean up the partial configuration */ 7812 for (i = 0; i < n; i++) 7813 (void) dladm_bridge_setlink(handle, linkids[i], ""); 7814 7815 /* if failure for brCreate, then delete the bridge */ 7816 if (func == brCreate) 7817 (void) dladm_bridge_delete(handle, bridge, flags); 7818 7819 if (n < nlink) 7820 die_dlerr(status, "unable to add link %s to bridge %s", 7821 links[n], bridge); 7822 else 7823 die_dlerr(status, "unable to enable bridge %s", bridge); 7824 } 7825 7826 static void 7827 do_create_bridge(int argc, char **argv, const char *use) 7828 { 7829 create_modify_add_bridge(argc, argv, use, brCreate); 7830 } 7831 7832 static void 7833 do_modify_bridge(int argc, char **argv, const char *use) 7834 { 7835 create_modify_add_bridge(argc, argv, use, brModify); 7836 } 7837 7838 static void 7839 do_add_bridge(int argc, char **argv, const char *use) 7840 { 7841 create_modify_add_bridge(argc, argv, use, brAdd); 7842 } 7843 7844 static void 7845 do_delete_bridge(int argc, char **argv, const char *use) 7846 { 7847 char option; 7848 char *altroot = NULL; 7849 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 7850 dladm_status_t status; 7851 7852 opterr = 0; 7853 while ((option = getopt_long(argc, argv, ":R:", bridge_lopts, NULL)) != 7854 -1) { 7855 switch (option) { 7856 case 'R': 7857 altroot = optarg; 7858 break; 7859 default: 7860 die_opterr(optopt, option, use); 7861 break; 7862 } 7863 } 7864 7865 /* get the bridge name (required last argument) */ 7866 if (optind != (argc-1)) 7867 usage(); 7868 7869 if (altroot != NULL) 7870 altroot_cmd(altroot, argc, argv); 7871 7872 status = dladm_bridge_delete(handle, argv[optind], flags); 7873 if (status != DLADM_STATUS_OK) 7874 die_dlerr(status, "delete operation failed"); 7875 } 7876 7877 static void 7878 do_remove_bridge(int argc, char **argv, const char *use) 7879 { 7880 char option; 7881 uint_t n, nlink; 7882 char *links[MAXPORT]; 7883 datalink_id_t linkids[MAXPORT]; 7884 char *altroot = NULL; 7885 dladm_status_t status; 7886 boolean_t removed_one; 7887 7888 nlink = opterr = 0; 7889 while ((option = getopt_long(argc, argv, ":R:l:", bridge_lopts, 7890 NULL)) != -1) { 7891 switch (option) { 7892 case 'R': 7893 altroot = optarg; 7894 break; 7895 case 'l': 7896 if (nlink >= MAXPORT) 7897 die("too many links specified"); 7898 links[nlink++] = optarg; 7899 break; 7900 default: 7901 die_opterr(optopt, option, use); 7902 break; 7903 } 7904 } 7905 7906 if (nlink == 0) 7907 usage(); 7908 7909 /* get the bridge name (required last argument) */ 7910 if (optind != (argc-1)) 7911 usage(); 7912 7913 if (altroot != NULL) 7914 altroot_cmd(altroot, argc, argv); 7915 7916 for (n = 0; n < nlink; n++) { 7917 char bridge[MAXLINKNAMELEN]; 7918 7919 if (dladm_name2info(handle, links[n], &linkids[n], NULL, NULL, 7920 NULL) != DLADM_STATUS_OK) 7921 die("invalid link name '%s'", links[n]); 7922 status = dladm_bridge_getlink(handle, linkids[n], bridge, 7923 sizeof (bridge)); 7924 if (status != DLADM_STATUS_OK && 7925 status != DLADM_STATUS_NOTFOUND) { 7926 die_dlerr(status, "cannot get bridge status on %s", 7927 links[n]); 7928 } 7929 if (status == DLADM_STATUS_NOTFOUND || 7930 strcmp(bridge, argv[optind]) != 0) 7931 die("link %s is not on bridge %s", links[n], 7932 argv[optind]); 7933 } 7934 7935 removed_one = B_FALSE; 7936 for (n = 0; n < nlink; n++) { 7937 status = dladm_bridge_setlink(handle, linkids[n], ""); 7938 if (status == DLADM_STATUS_OK) { 7939 removed_one = B_TRUE; 7940 } else { 7941 warn_dlerr(status, 7942 "cannot remove link %s from bridge %s", 7943 links[n], argv[optind]); 7944 } 7945 } 7946 if (!removed_one) 7947 die("unable to remove any links from bridge %s", argv[optind]); 7948 } 7949 7950 static void 7951 fmt_int(char *buf, size_t buflen, int value, int runvalue, 7952 boolean_t printstar) 7953 { 7954 (void) snprintf(buf, buflen, "%d", value); 7955 if (value != runvalue && printstar) 7956 (void) strlcat(buf, "*", buflen); 7957 } 7958 7959 static void 7960 fmt_bridge_id(char *buf, size_t buflen, UID_BRIDGE_ID_T *bid) 7961 { 7962 (void) snprintf(buf, buflen, "%u/%x:%x:%x:%x:%x:%x", bid->prio, 7963 bid->addr[0], bid->addr[1], bid->addr[2], bid->addr[3], 7964 bid->addr[4], bid->addr[5]); 7965 } 7966 7967 static dladm_status_t 7968 print_bridge(show_state_t *state, datalink_id_t linkid, 7969 bridge_fields_buf_t *bbuf) 7970 { 7971 char link[MAXLINKNAMELEN]; 7972 datalink_class_t class; 7973 uint32_t flags; 7974 dladm_status_t status; 7975 UID_STP_CFG_T smfcfg, runcfg; 7976 UID_STP_STATE_T stpstate; 7977 dladm_bridge_prot_t smfprot, runprot; 7978 7979 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 7980 NULL, link, sizeof (link))) != DLADM_STATUS_OK) 7981 return (status); 7982 7983 if (!(state->ls_flags & flags)) 7984 return (DLADM_STATUS_NOTFOUND); 7985 7986 /* Convert observability node name back to bridge name */ 7987 if (!dladm_observe_to_bridge(link)) 7988 return (DLADM_STATUS_NOTFOUND); 7989 (void) strlcpy(bbuf->bridge_name, link, sizeof (bbuf->bridge_name)); 7990 7991 /* 7992 * If the running value differs from the one in SMF, and parsable 7993 * output is not requested, then we show the running value with an 7994 * asterisk. 7995 */ 7996 (void) dladm_bridge_get_properties(bbuf->bridge_name, &smfcfg, 7997 &smfprot); 7998 (void) dladm_bridge_run_properties(bbuf->bridge_name, &runcfg, 7999 &runprot); 8000 (void) snprintf(bbuf->bridge_protect, sizeof (bbuf->bridge_protect), 8001 "%s%s", state->ls_parsable || smfprot == runprot ? "" : "*", 8002 dladm_bridge_prot2str(runprot)); 8003 fmt_int(bbuf->bridge_priority, sizeof (bbuf->bridge_priority), 8004 smfcfg.bridge_priority, runcfg.bridge_priority, 8005 !state->ls_parsable && (runcfg.field_mask & BR_CFG_AGE)); 8006 fmt_int(bbuf->bridge_bmaxage, sizeof (bbuf->bridge_bmaxage), 8007 smfcfg.max_age, runcfg.max_age, 8008 !state->ls_parsable && (runcfg.field_mask & BR_CFG_AGE)); 8009 fmt_int(bbuf->bridge_bhellotime, 8010 sizeof (bbuf->bridge_bhellotime), smfcfg.hello_time, 8011 runcfg.hello_time, 8012 !state->ls_parsable && (runcfg.field_mask & BR_CFG_HELLO)); 8013 fmt_int(bbuf->bridge_bfwddelay, sizeof (bbuf->bridge_bfwddelay), 8014 smfcfg.forward_delay, runcfg.forward_delay, 8015 !state->ls_parsable && (runcfg.field_mask & BR_CFG_DELAY)); 8016 fmt_int(bbuf->bridge_forceproto, sizeof (bbuf->bridge_forceproto), 8017 smfcfg.force_version, runcfg.force_version, 8018 !state->ls_parsable && (runcfg.field_mask & BR_CFG_FORCE_VER)); 8019 fmt_int(bbuf->bridge_holdtime, sizeof (bbuf->bridge_holdtime), 8020 smfcfg.hold_time, runcfg.hold_time, 8021 !state->ls_parsable && (runcfg.field_mask & BR_CFG_HOLD_TIME)); 8022 8023 if (dladm_bridge_state(bbuf->bridge_name, &stpstate) == 8024 DLADM_STATUS_OK) { 8025 fmt_bridge_id(bbuf->bridge_address, 8026 sizeof (bbuf->bridge_address), &stpstate.bridge_id); 8027 (void) snprintf(bbuf->bridge_tctime, 8028 sizeof (bbuf->bridge_tctime), "%lu", 8029 stpstate.timeSince_Topo_Change); 8030 (void) snprintf(bbuf->bridge_tccount, 8031 sizeof (bbuf->bridge_tccount), "%lu", 8032 stpstate.Topo_Change_Count); 8033 (void) snprintf(bbuf->bridge_tchange, 8034 sizeof (bbuf->bridge_tchange), "%u", stpstate.Topo_Change); 8035 fmt_bridge_id(bbuf->bridge_desroot, 8036 sizeof (bbuf->bridge_desroot), &stpstate.designated_root); 8037 (void) snprintf(bbuf->bridge_rootcost, 8038 sizeof (bbuf->bridge_rootcost), "%lu", 8039 stpstate.root_path_cost); 8040 (void) snprintf(bbuf->bridge_rootport, 8041 sizeof (bbuf->bridge_rootport), "%u", stpstate.root_port); 8042 (void) snprintf(bbuf->bridge_maxage, 8043 sizeof (bbuf->bridge_maxage), "%d", stpstate.max_age); 8044 (void) snprintf(bbuf->bridge_hellotime, 8045 sizeof (bbuf->bridge_hellotime), "%d", stpstate.hello_time); 8046 (void) snprintf(bbuf->bridge_fwddelay, 8047 sizeof (bbuf->bridge_fwddelay), "%d", 8048 stpstate.forward_delay); 8049 } 8050 return (DLADM_STATUS_OK); 8051 } 8052 8053 static dladm_status_t 8054 print_bridge_stats(show_state_t *state, datalink_id_t linkid, 8055 bridge_statfields_buf_t *bbuf) 8056 { 8057 char link[MAXLINKNAMELEN]; 8058 datalink_class_t class; 8059 uint32_t flags; 8060 dladm_status_t status; 8061 kstat_ctl_t *kcp; 8062 kstat_t *ksp; 8063 brsum_t *brsum = (brsum_t *)&state->ls_prevstats; 8064 brsum_t newval; 8065 8066 #ifndef lint 8067 /* This is a compile-time assertion; optimizer normally fixes this */ 8068 extern void brsum_t_is_too_large(void); 8069 8070 if (sizeof (*brsum) > sizeof (state->ls_prevstats)) 8071 brsum_t_is_too_large(); 8072 #endif 8073 8074 if (state->ls_firstonly) { 8075 if (state->ls_donefirst) 8076 return (DLADM_WALK_CONTINUE); 8077 state->ls_donefirst = B_TRUE; 8078 } else { 8079 bzero(brsum, sizeof (*brsum)); 8080 } 8081 bzero(&newval, sizeof (newval)); 8082 8083 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 8084 NULL, link, sizeof (link))) != DLADM_STATUS_OK) 8085 return (status); 8086 8087 if (!(state->ls_flags & flags)) 8088 return (DLADM_STATUS_NOTFOUND); 8089 8090 if ((kcp = kstat_open()) == NULL) { 8091 warn("kstat open operation failed"); 8092 return (DLADM_STATUS_OK); 8093 } 8094 if ((ksp = kstat_lookup(kcp, "bridge", 0, link)) != NULL && 8095 kstat_read(kcp, ksp, NULL) != -1) { 8096 if (dladm_kstat_value(ksp, "drops", KSTAT_DATA_UINT64, 8097 &newval.drops) == DLADM_STATUS_OK) { 8098 (void) snprintf(bbuf->bridges_drops, 8099 sizeof (bbuf->bridges_drops), "%llu", 8100 newval.drops - brsum->drops); 8101 } 8102 if (dladm_kstat_value(ksp, "forward_direct", KSTAT_DATA_UINT64, 8103 &newval.forward_dir) == DLADM_STATUS_OK) { 8104 (void) snprintf(bbuf->bridges_forwards, 8105 sizeof (bbuf->bridges_forwards), "%llu", 8106 newval.forward_dir - brsum->forward_dir); 8107 } 8108 if (dladm_kstat_value(ksp, "forward_mbcast", KSTAT_DATA_UINT64, 8109 &newval.forward_mb) == DLADM_STATUS_OK) { 8110 (void) snprintf(bbuf->bridges_mbcast, 8111 sizeof (bbuf->bridges_mbcast), "%llu", 8112 newval.forward_mb - brsum->forward_mb); 8113 } 8114 if (dladm_kstat_value(ksp, "forward_unknown", KSTAT_DATA_UINT64, 8115 &newval.forward_unk) == DLADM_STATUS_OK) { 8116 (void) snprintf(bbuf->bridges_unknown, 8117 sizeof (bbuf->bridges_unknown), "%llu", 8118 newval.forward_unk - brsum->forward_unk); 8119 } 8120 if (dladm_kstat_value(ksp, "recv", KSTAT_DATA_UINT64, 8121 &newval.recv) == DLADM_STATUS_OK) { 8122 (void) snprintf(bbuf->bridges_recv, 8123 sizeof (bbuf->bridges_recv), "%llu", 8124 newval.recv - brsum->recv); 8125 } 8126 if (dladm_kstat_value(ksp, "sent", KSTAT_DATA_UINT64, 8127 &newval.sent) == DLADM_STATUS_OK) { 8128 (void) snprintf(bbuf->bridges_sent, 8129 sizeof (bbuf->bridges_sent), "%llu", 8130 newval.sent - brsum->sent); 8131 } 8132 } 8133 (void) kstat_close(kcp); 8134 8135 /* Convert observability node name back to bridge name */ 8136 if (!dladm_observe_to_bridge(link)) 8137 return (DLADM_STATUS_NOTFOUND); 8138 (void) strlcpy(bbuf->bridges_name, link, sizeof (bbuf->bridges_name)); 8139 8140 *brsum = newval; 8141 8142 return (DLADM_STATUS_OK); 8143 } 8144 8145 /* 8146 * This structure carries around extra state information for the show-bridge 8147 * command and allows us to use common support functions. 8148 */ 8149 typedef struct { 8150 show_state_t state; 8151 boolean_t show_stats; 8152 const char *bridge; 8153 } show_brstate_t; 8154 8155 /* ARGSUSED */ 8156 static int 8157 show_bridge(dladm_handle_t handle, datalink_id_t linkid, void *arg) 8158 { 8159 show_brstate_t *brstate = arg; 8160 void *buf; 8161 8162 if (brstate->show_stats) { 8163 bridge_statfields_buf_t bbuf; 8164 8165 bzero(&bbuf, sizeof (bbuf)); 8166 brstate->state.ls_status = print_bridge_stats(&brstate->state, 8167 linkid, &bbuf); 8168 buf = &bbuf; 8169 } else { 8170 bridge_fields_buf_t bbuf; 8171 8172 bzero(&bbuf, sizeof (bbuf)); 8173 brstate->state.ls_status = print_bridge(&brstate->state, linkid, 8174 &bbuf); 8175 buf = &bbuf; 8176 } 8177 if (brstate->state.ls_status == DLADM_STATUS_OK) 8178 ofmt_print(brstate->state.ls_ofmt, buf); 8179 return (DLADM_WALK_CONTINUE); 8180 } 8181 8182 static void 8183 fmt_bool(char *buf, size_t buflen, int val) 8184 { 8185 (void) strlcpy(buf, val ? "yes" : "no", buflen); 8186 } 8187 8188 static dladm_status_t 8189 print_bridge_link(show_state_t *state, datalink_id_t linkid, 8190 bridge_link_fields_buf_t *bbuf) 8191 { 8192 datalink_class_t class; 8193 uint32_t flags; 8194 dladm_status_t status; 8195 UID_STP_PORT_STATE_T stpstate; 8196 8197 status = dladm_datalink_id2info(handle, linkid, &flags, &class, NULL, 8198 bbuf->bridgel_link, sizeof (bbuf->bridgel_link)); 8199 if (status != DLADM_STATUS_OK) 8200 return (status); 8201 8202 if (!(state->ls_flags & flags)) 8203 return (DLADM_STATUS_NOTFOUND); 8204 8205 if (dladm_bridge_link_state(handle, linkid, &stpstate) == 8206 DLADM_STATUS_OK) { 8207 (void) snprintf(bbuf->bridgel_index, 8208 sizeof (bbuf->bridgel_index), "%u", stpstate.port_no); 8209 if (dlsym(RTLD_PROBE, "STP_IN_state2str")) { 8210 (void) strlcpy(bbuf->bridgel_state, 8211 STP_IN_state2str(stpstate.state), 8212 sizeof (bbuf->bridgel_state)); 8213 } else { 8214 (void) snprintf(bbuf->bridgel_state, 8215 sizeof (bbuf->bridgel_state), "%u", 8216 stpstate.state); 8217 } 8218 (void) snprintf(bbuf->bridgel_uptime, 8219 sizeof (bbuf->bridgel_uptime), "%lu", stpstate.uptime); 8220 (void) snprintf(bbuf->bridgel_opercost, 8221 sizeof (bbuf->bridgel_opercost), "%lu", 8222 stpstate.oper_port_path_cost); 8223 fmt_bool(bbuf->bridgel_operp2p, sizeof (bbuf->bridgel_operp2p), 8224 stpstate.oper_point2point); 8225 fmt_bool(bbuf->bridgel_operedge, 8226 sizeof (bbuf->bridgel_operedge), stpstate.oper_edge); 8227 fmt_bridge_id(bbuf->bridgel_desroot, 8228 sizeof (bbuf->bridgel_desroot), &stpstate.designated_root); 8229 (void) snprintf(bbuf->bridgel_descost, 8230 sizeof (bbuf->bridgel_descost), "%lu", 8231 stpstate.designated_cost); 8232 fmt_bridge_id(bbuf->bridgel_desbridge, 8233 sizeof (bbuf->bridgel_desbridge), 8234 &stpstate.designated_bridge); 8235 (void) snprintf(bbuf->bridgel_desport, 8236 sizeof (bbuf->bridgel_desport), "%u", 8237 stpstate.designated_port); 8238 fmt_bool(bbuf->bridgel_tcack, sizeof (bbuf->bridgel_tcack), 8239 stpstate.top_change_ack); 8240 } 8241 return (DLADM_STATUS_OK); 8242 } 8243 8244 static dladm_status_t 8245 print_bridge_link_stats(show_state_t *state, datalink_id_t linkid, 8246 bridge_link_statfields_buf_t *bbuf) 8247 { 8248 datalink_class_t class; 8249 uint32_t flags; 8250 dladm_status_t status; 8251 UID_STP_PORT_STATE_T stpstate; 8252 kstat_ctl_t *kcp; 8253 kstat_t *ksp; 8254 char bridge[MAXLINKNAMELEN]; 8255 char kstatname[MAXLINKNAMELEN*2 + 1]; 8256 brlsum_t *brlsum = (brlsum_t *)&state->ls_prevstats; 8257 brlsum_t newval; 8258 8259 #ifndef lint 8260 /* This is a compile-time assertion; optimizer normally fixes this */ 8261 extern void brlsum_t_is_too_large(void); 8262 8263 if (sizeof (*brlsum) > sizeof (state->ls_prevstats)) 8264 brlsum_t_is_too_large(); 8265 #endif 8266 8267 if (state->ls_firstonly) { 8268 if (state->ls_donefirst) 8269 return (DLADM_WALK_CONTINUE); 8270 state->ls_donefirst = B_TRUE; 8271 } else { 8272 bzero(brlsum, sizeof (*brlsum)); 8273 } 8274 bzero(&newval, sizeof (newval)); 8275 8276 status = dladm_datalink_id2info(handle, linkid, &flags, &class, NULL, 8277 bbuf->bridgels_link, sizeof (bbuf->bridgels_link)); 8278 if (status != DLADM_STATUS_OK) 8279 return (status); 8280 8281 if (!(state->ls_flags & flags)) 8282 return (DLADM_STATUS_NOTFOUND); 8283 8284 if (dladm_bridge_link_state(handle, linkid, &stpstate) == 8285 DLADM_STATUS_OK) { 8286 newval.cfgbpdu = stpstate.rx_cfg_bpdu_cnt; 8287 newval.tcnbpdu = stpstate.rx_tcn_bpdu_cnt; 8288 newval.rstpbpdu = stpstate.rx_rstp_bpdu_cnt; 8289 newval.txbpdu = stpstate.txCount; 8290 8291 (void) snprintf(bbuf->bridgels_cfgbpdu, 8292 sizeof (bbuf->bridgels_cfgbpdu), "%lu", 8293 newval.cfgbpdu - brlsum->cfgbpdu); 8294 (void) snprintf(bbuf->bridgels_tcnbpdu, 8295 sizeof (bbuf->bridgels_tcnbpdu), "%lu", 8296 newval.tcnbpdu - brlsum->tcnbpdu); 8297 (void) snprintf(bbuf->bridgels_rstpbpdu, 8298 sizeof (bbuf->bridgels_rstpbpdu), "%lu", 8299 newval.rstpbpdu - brlsum->rstpbpdu); 8300 (void) snprintf(bbuf->bridgels_txbpdu, 8301 sizeof (bbuf->bridgels_txbpdu), "%lu", 8302 newval.txbpdu - brlsum->txbpdu); 8303 } 8304 8305 if ((status = dladm_bridge_getlink(handle, linkid, bridge, 8306 sizeof (bridge))) != DLADM_STATUS_OK) 8307 goto bls_out; 8308 (void) snprintf(kstatname, sizeof (kstatname), "%s0-%s", bridge, 8309 bbuf->bridgels_link); 8310 if ((kcp = kstat_open()) == NULL) { 8311 warn("kstat open operation failed"); 8312 goto bls_out; 8313 } 8314 if ((ksp = kstat_lookup(kcp, "bridge", 0, kstatname)) != NULL && 8315 kstat_read(kcp, ksp, NULL) != -1) { 8316 if (dladm_kstat_value(ksp, "drops", KSTAT_DATA_UINT64, 8317 &newval.drops) != -1) { 8318 (void) snprintf(bbuf->bridgels_drops, 8319 sizeof (bbuf->bridgels_drops), "%llu", 8320 newval.drops - brlsum->drops); 8321 } 8322 if (dladm_kstat_value(ksp, "recv", KSTAT_DATA_UINT64, 8323 &newval.recv) != -1) { 8324 (void) snprintf(bbuf->bridgels_recv, 8325 sizeof (bbuf->bridgels_recv), "%llu", 8326 newval.recv - brlsum->recv); 8327 } 8328 if (dladm_kstat_value(ksp, "xmit", KSTAT_DATA_UINT64, 8329 &newval.xmit) != -1) { 8330 (void) snprintf(bbuf->bridgels_xmit, 8331 sizeof (bbuf->bridgels_xmit), "%llu", 8332 newval.xmit - brlsum->xmit); 8333 } 8334 } 8335 (void) kstat_close(kcp); 8336 bls_out: 8337 *brlsum = newval; 8338 8339 return (status); 8340 } 8341 8342 static void 8343 show_bridge_link(datalink_id_t linkid, show_brstate_t *brstate) 8344 { 8345 void *buf; 8346 8347 if (brstate->show_stats) { 8348 bridge_link_statfields_buf_t bbuf; 8349 8350 bzero(&bbuf, sizeof (bbuf)); 8351 brstate->state.ls_status = print_bridge_link_stats( 8352 &brstate->state, linkid, &bbuf); 8353 buf = &bbuf; 8354 } else { 8355 bridge_link_fields_buf_t bbuf; 8356 8357 bzero(&bbuf, sizeof (bbuf)); 8358 brstate->state.ls_status = print_bridge_link(&brstate->state, 8359 linkid, &bbuf); 8360 buf = &bbuf; 8361 } 8362 if (brstate->state.ls_status == DLADM_STATUS_OK) 8363 ofmt_print(brstate->state.ls_ofmt, buf); 8364 } 8365 8366 /* ARGSUSED */ 8367 static int 8368 show_bridge_link_walk(dladm_handle_t handle, datalink_id_t linkid, void *arg) 8369 { 8370 show_brstate_t *brstate = arg; 8371 char bridge[MAXLINKNAMELEN]; 8372 8373 if (dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)) == 8374 DLADM_STATUS_OK && strcmp(bridge, brstate->bridge) == 0) { 8375 show_bridge_link(linkid, brstate); 8376 } 8377 return (DLADM_WALK_CONTINUE); 8378 } 8379 8380 static void 8381 show_bridge_fwd(dladm_handle_t handle, bridge_listfwd_t *blf, 8382 show_state_t *state) 8383 { 8384 bridge_fwd_fields_buf_t bbuf; 8385 8386 bzero(&bbuf, sizeof (bbuf)); 8387 (void) snprintf(bbuf.bridgef_dest, sizeof (bbuf.bridgef_dest), 8388 "%s", ether_ntoa((struct ether_addr *)blf->blf_dest)); 8389 if (blf->blf_is_local) { 8390 (void) strlcpy(bbuf.bridgef_flags, "L", 8391 sizeof (bbuf.bridgef_flags)); 8392 } else { 8393 (void) snprintf(bbuf.bridgef_age, sizeof (bbuf.bridgef_age), 8394 "%2d.%03d", blf->blf_ms_age / 1000, blf->blf_ms_age % 1000); 8395 if (blf->blf_trill_nick != 0) { 8396 (void) snprintf(bbuf.bridgef_output, 8397 sizeof (bbuf.bridgef_output), "%u", 8398 blf->blf_trill_nick); 8399 } 8400 } 8401 if (blf->blf_linkid != DATALINK_INVALID_LINKID && 8402 blf->blf_trill_nick == 0) { 8403 state->ls_status = dladm_datalink_id2info(handle, 8404 blf->blf_linkid, NULL, NULL, NULL, bbuf.bridgef_output, 8405 sizeof (bbuf.bridgef_output)); 8406 } 8407 if (state->ls_status == DLADM_STATUS_OK) 8408 ofmt_print(state->ls_ofmt, &bbuf); 8409 } 8410 8411 static void 8412 show_bridge_trillnick(trill_listnick_t *tln, show_state_t *state) 8413 { 8414 bridge_trill_fields_buf_t bbuf; 8415 8416 bzero(&bbuf, sizeof (bbuf)); 8417 (void) snprintf(bbuf.bridget_nick, sizeof (bbuf.bridget_nick), 8418 "%u", tln->tln_nick); 8419 if (tln->tln_ours) { 8420 (void) strlcpy(bbuf.bridget_flags, "L", 8421 sizeof (bbuf.bridget_flags)); 8422 } else { 8423 state->ls_status = dladm_datalink_id2info(handle, 8424 tln->tln_linkid, NULL, NULL, NULL, bbuf.bridget_link, 8425 sizeof (bbuf.bridget_link)); 8426 (void) snprintf(bbuf.bridget_nexthop, 8427 sizeof (bbuf.bridget_nexthop), "%s", 8428 ether_ntoa((struct ether_addr *)tln->tln_nexthop)); 8429 } 8430 if (state->ls_status == DLADM_STATUS_OK) 8431 ofmt_print(state->ls_ofmt, &bbuf); 8432 } 8433 8434 static void 8435 do_show_bridge(int argc, char **argv, const char *use) 8436 { 8437 int option; 8438 enum { 8439 bridgeMode, linkMode, fwdMode, trillMode 8440 } op_mode = bridgeMode; 8441 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 8442 boolean_t parsable = B_FALSE; 8443 datalink_id_t linkid = DATALINK_ALL_LINKID; 8444 int interval = 0; 8445 show_brstate_t brstate; 8446 dladm_status_t status; 8447 char *fields_str = NULL; 8448 /* default: bridge-related data */ 8449 char *all_fields = "bridge,protect,address,priority,bmaxage," 8450 "bhellotime,bfwddelay,forceproto,tctime,tccount,tchange," 8451 "desroot,rootcost,rootport,maxage,hellotime,fwddelay,holdtime"; 8452 char *default_fields = "bridge,protect,address,priority," 8453 "desroot"; 8454 char *all_statfields = "bridge,drops,forwards,mbcast," 8455 "unknown,recv,sent"; 8456 char *default_statfields = "bridge,drops,forwards,mbcast," 8457 "unknown"; 8458 /* -l: link-related data */ 8459 char *all_link_fields = "link,index,state,uptime,opercost," 8460 "operp2p,operedge,desroot,descost,desbridge,desport,tcack"; 8461 char *default_link_fields = "link,state,uptime,desroot"; 8462 char *all_link_statfields = "link,cfgbpdu,tcnbpdu,rstpbpdu," 8463 "txbpdu,drops,recv,xmit"; 8464 char *default_link_statfields = "link,drops,recv,xmit"; 8465 /* -f: bridge forwarding table related data */ 8466 char *default_fwd_fields = "dest,age,flags,output"; 8467 /* -t: TRILL nickname table related data */ 8468 char *default_trill_fields = "nick,flags,link,nexthop"; 8469 char *default_str; 8470 char *all_str; 8471 ofmt_field_t *field_arr; 8472 ofmt_handle_t ofmt; 8473 ofmt_status_t oferr; 8474 uint_t ofmtflags = 0; 8475 8476 bzero(&brstate, sizeof (brstate)); 8477 8478 opterr = 0; 8479 while ((option = getopt_long(argc, argv, ":fi:lo:pst", 8480 bridge_show_lopts, NULL)) != -1) { 8481 switch (option) { 8482 case 'f': 8483 if (op_mode != bridgeMode && op_mode != fwdMode) 8484 die("-f is incompatible with -l or -t"); 8485 op_mode = fwdMode; 8486 break; 8487 case 'i': 8488 if (interval != 0) 8489 die_optdup(option); 8490 if (!str2int(optarg, &interval) || interval == 0) 8491 die("invalid interval value '%s'", optarg); 8492 break; 8493 case 'l': 8494 if (op_mode != bridgeMode && op_mode != linkMode) 8495 die("-l is incompatible with -f or -t"); 8496 op_mode = linkMode; 8497 break; 8498 case 'o': 8499 fields_str = optarg; 8500 break; 8501 case 'p': 8502 if (parsable) 8503 die_optdup(option); 8504 parsable = B_TRUE; 8505 break; 8506 case 's': 8507 if (brstate.show_stats) 8508 die_optdup(option); 8509 brstate.show_stats = B_TRUE; 8510 break; 8511 case 't': 8512 if (op_mode != bridgeMode && op_mode != trillMode) 8513 die("-t is incompatible with -f or -l"); 8514 op_mode = trillMode; 8515 break; 8516 default: 8517 die_opterr(optopt, option, use); 8518 break; 8519 } 8520 } 8521 8522 if (interval != 0 && !brstate.show_stats) 8523 die("the -i option can be used only with -s"); 8524 8525 if ((op_mode == fwdMode || op_mode == trillMode) && brstate.show_stats) 8526 die("the -f/-t and -s options cannot be used together"); 8527 8528 /* get the bridge name (optional last argument) */ 8529 if (optind == (argc-1)) { 8530 char lname[MAXLINKNAMELEN]; 8531 uint32_t lnkflg; 8532 datalink_class_t class; 8533 8534 brstate.bridge = argv[optind]; 8535 (void) snprintf(lname, sizeof (lname), "%s0", brstate.bridge); 8536 if ((status = dladm_name2info(handle, lname, &linkid, &lnkflg, 8537 &class, NULL)) != DLADM_STATUS_OK) { 8538 die_dlerr(status, "bridge %s is not valid", 8539 brstate.bridge); 8540 } 8541 8542 if (class != DATALINK_CLASS_BRIDGE) 8543 die("%s is not a bridge", brstate.bridge); 8544 8545 if (!(lnkflg & flags)) { 8546 die_dlerr(DLADM_STATUS_BADARG, 8547 "bridge %s is temporarily removed", brstate.bridge); 8548 } 8549 } else if (optind != argc) { 8550 usage(); 8551 } else if (op_mode != bridgeMode) { 8552 die("bridge name required for -l, -f, or -t"); 8553 return; 8554 } 8555 8556 brstate.state.ls_parsable = parsable; 8557 brstate.state.ls_flags = flags; 8558 brstate.state.ls_firstonly = (interval != 0); 8559 8560 switch (op_mode) { 8561 case bridgeMode: 8562 if (brstate.show_stats) { 8563 default_str = default_statfields; 8564 all_str = all_statfields; 8565 field_arr = bridge_statfields; 8566 } else { 8567 default_str = default_fields; 8568 all_str = all_fields; 8569 field_arr = bridge_fields; 8570 } 8571 break; 8572 8573 case linkMode: 8574 if (brstate.show_stats) { 8575 default_str = default_link_statfields; 8576 all_str = all_link_statfields; 8577 field_arr = bridge_link_statfields; 8578 } else { 8579 default_str = default_link_fields; 8580 all_str = all_link_fields; 8581 field_arr = bridge_link_fields; 8582 } 8583 break; 8584 8585 case fwdMode: 8586 default_str = all_str = default_fwd_fields; 8587 field_arr = bridge_fwd_fields; 8588 break; 8589 8590 case trillMode: 8591 default_str = all_str = default_trill_fields; 8592 field_arr = bridge_trill_fields; 8593 break; 8594 } 8595 8596 if (fields_str == NULL) 8597 fields_str = default_str; 8598 else if (strcasecmp(fields_str, "all") == 0) 8599 fields_str = all_str; 8600 8601 if (parsable) 8602 ofmtflags |= OFMT_PARSABLE; 8603 oferr = ofmt_open(fields_str, field_arr, ofmtflags, 0, &ofmt); 8604 dladm_ofmt_check(oferr, brstate.state.ls_parsable, ofmt); 8605 brstate.state.ls_ofmt = ofmt; 8606 8607 for (;;) { 8608 brstate.state.ls_donefirst = B_FALSE; 8609 switch (op_mode) { 8610 case bridgeMode: 8611 if (linkid == DATALINK_ALL_LINKID) { 8612 (void) dladm_walk_datalink_id(show_bridge, 8613 handle, &brstate, DATALINK_CLASS_BRIDGE, 8614 DATALINK_ANY_MEDIATYPE, flags); 8615 } else { 8616 (void) show_bridge(handle, linkid, &brstate); 8617 if (brstate.state.ls_status != 8618 DLADM_STATUS_OK) { 8619 die_dlerr(brstate.state.ls_status, 8620 "failed to show bridge %s", 8621 brstate.bridge); 8622 } 8623 } 8624 break; 8625 8626 case linkMode: { 8627 datalink_id_t *dlp; 8628 uint_t i, nlinks; 8629 8630 dlp = dladm_bridge_get_portlist(brstate.bridge, 8631 &nlinks); 8632 if (dlp != NULL) { 8633 for (i = 0; i < nlinks; i++) 8634 show_bridge_link(dlp[i], &brstate); 8635 dladm_bridge_free_portlist(dlp); 8636 } else if (errno == ENOENT) { 8637 /* bridge not running; iterate on libdladm */ 8638 (void) dladm_walk_datalink_id( 8639 show_bridge_link_walk, handle, 8640 &brstate, DATALINK_CLASS_PHYS | 8641 DATALINK_CLASS_AGGR | 8642 DATALINK_CLASS_ETHERSTUB, 8643 DATALINK_ANY_MEDIATYPE, flags); 8644 } else { 8645 die("unable to get port list for bridge %s: %s", 8646 brstate.bridge, strerror(errno)); 8647 } 8648 break; 8649 } 8650 8651 case fwdMode: { 8652 bridge_listfwd_t *blf; 8653 uint_t i, nfwd; 8654 8655 blf = dladm_bridge_get_fwdtable(handle, brstate.bridge, 8656 &nfwd); 8657 if (blf == NULL) { 8658 die("unable to get forwarding entries for " 8659 "bridge %s", brstate.bridge); 8660 } else { 8661 for (i = 0; i < nfwd; i++) 8662 show_bridge_fwd(handle, blf + i, 8663 &brstate.state); 8664 dladm_bridge_free_fwdtable(blf); 8665 } 8666 break; 8667 } 8668 8669 case trillMode: { 8670 trill_listnick_t *tln; 8671 uint_t i, nnick; 8672 8673 tln = dladm_bridge_get_trillnick(brstate.bridge, 8674 &nnick); 8675 if (tln == NULL) { 8676 if (errno == ENOENT) 8677 die("bridge %s is not running TRILL", 8678 brstate.bridge); 8679 else 8680 die("unable to get TRILL nickname " 8681 "entries for bridge %s", 8682 brstate.bridge); 8683 } else { 8684 for (i = 0; i < nnick; i++) 8685 show_bridge_trillnick(tln + i, 8686 &brstate.state); 8687 dladm_bridge_free_trillnick(tln); 8688 } 8689 break; 8690 } 8691 } 8692 if (interval == 0) 8693 break; 8694 (void) sleep(interval); 8695 } 8696 } 8697 8698 /* 8699 * "-R" option support. It is used for live upgrading. Append dladm commands 8700 * to a upgrade script which will be run when the alternative root boots up: 8701 * 8702 * - If the /etc/dladm/datalink.conf file exists on the alternative root, 8703 * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink 8704 * script. This script will be run as part of the network/physical service. 8705 * We cannot defer this to /var/svc/profile/upgrade because then the 8706 * configuration will not be able to take effect before network/physical 8707 * plumbs various interfaces. 8708 * 8709 * - If the /etc/dladm/datalink.conf file does not exist on the alternative 8710 * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script, 8711 * which will be run in the manifest-import service. 8712 * 8713 * Note that the SMF team is considering to move the manifest-import service 8714 * to be run at the very begining of boot. Once that is done, the need for 8715 * the /var/svc/profile/upgrade_datalink script will not exist any more. 8716 */ 8717 static void 8718 altroot_cmd(char *altroot, int argc, char *argv[]) 8719 { 8720 char path[MAXPATHLEN]; 8721 struct stat stbuf; 8722 FILE *fp; 8723 int i; 8724 8725 /* 8726 * Check for the existence of the /etc/dladm/datalink.conf 8727 * configuration file, and determine the name of script file. 8728 */ 8729 (void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf", 8730 altroot); 8731 if (stat(path, &stbuf) < 0) { 8732 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 8733 SMF_UPGRADE_FILE); 8734 } else { 8735 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 8736 SMF_UPGRADEDATALINK_FILE); 8737 } 8738 8739 if ((fp = fopen(path, "a+")) == NULL) 8740 die("operation not supported on %s", altroot); 8741 8742 (void) fprintf(fp, "/sbin/dladm "); 8743 for (i = 0; i < argc; i++) { 8744 /* 8745 * Directly write to the file if it is not the "-R <altroot>" 8746 * option. In which case, skip it. 8747 */ 8748 if (strcmp(argv[i], "-R") != 0) 8749 (void) fprintf(fp, "%s ", argv[i]); 8750 else 8751 i ++; 8752 } 8753 (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG); 8754 (void) fclose(fp); 8755 dladm_close(handle); 8756 exit(EXIT_SUCCESS); 8757 } 8758 8759 /* 8760 * Convert the string to an integer. Note that the string must not have any 8761 * trailing non-integer characters. 8762 */ 8763 static boolean_t 8764 str2int(const char *str, int *valp) 8765 { 8766 int val; 8767 char *endp = NULL; 8768 8769 errno = 0; 8770 val = strtol(str, &endp, 10); 8771 if (errno != 0 || *endp != '\0') 8772 return (B_FALSE); 8773 8774 *valp = val; 8775 return (B_TRUE); 8776 } 8777 8778 /* PRINTFLIKE1 */ 8779 static void 8780 warn(const char *format, ...) 8781 { 8782 va_list alist; 8783 8784 format = gettext(format); 8785 (void) fprintf(stderr, "%s: warning: ", progname); 8786 8787 va_start(alist, format); 8788 (void) vfprintf(stderr, format, alist); 8789 va_end(alist); 8790 8791 (void) putc('\n', stderr); 8792 } 8793 8794 /* PRINTFLIKE2 */ 8795 static void 8796 warn_dlerr(dladm_status_t err, const char *format, ...) 8797 { 8798 va_list alist; 8799 char errmsg[DLADM_STRSIZE]; 8800 8801 format = gettext(format); 8802 (void) fprintf(stderr, gettext("%s: warning: "), progname); 8803 8804 va_start(alist, format); 8805 (void) vfprintf(stderr, format, alist); 8806 va_end(alist); 8807 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 8808 } 8809 8810 /* 8811 * Also closes the dladm handle if it is not NULL. 8812 */ 8813 /* PRINTFLIKE2 */ 8814 static void 8815 die_dlerr(dladm_status_t err, const char *format, ...) 8816 { 8817 va_list alist; 8818 char errmsg[DLADM_STRSIZE]; 8819 8820 format = gettext(format); 8821 (void) fprintf(stderr, "%s: ", progname); 8822 8823 va_start(alist, format); 8824 (void) vfprintf(stderr, format, alist); 8825 va_end(alist); 8826 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 8827 8828 /* close dladm handle if it was opened */ 8829 if (handle != NULL) 8830 dladm_close(handle); 8831 8832 exit(EXIT_FAILURE); 8833 } 8834 8835 /* PRINTFLIKE1 */ 8836 static void 8837 die(const char *format, ...) 8838 { 8839 va_list alist; 8840 8841 format = gettext(format); 8842 (void) fprintf(stderr, "%s: ", progname); 8843 8844 va_start(alist, format); 8845 (void) vfprintf(stderr, format, alist); 8846 va_end(alist); 8847 8848 (void) putc('\n', stderr); 8849 8850 /* close dladm handle if it was opened */ 8851 if (handle != NULL) 8852 dladm_close(handle); 8853 8854 exit(EXIT_FAILURE); 8855 } 8856 8857 static void 8858 die_optdup(int opt) 8859 { 8860 die("the option -%c cannot be specified more than once", opt); 8861 } 8862 8863 static void 8864 die_opterr(int opt, int opterr, const char *usage) 8865 { 8866 switch (opterr) { 8867 case ':': 8868 die("option '-%c' requires a value\nusage: %s", opt, 8869 gettext(usage)); 8870 break; 8871 case '?': 8872 default: 8873 die("unrecognized option '-%c'\nusage: %s", opt, 8874 gettext(usage)); 8875 break; 8876 } 8877 } 8878 8879 static void 8880 show_ether_xprop(void *arg, dladm_ether_info_t *eattr) 8881 { 8882 print_ether_state_t *statep = arg; 8883 ether_fields_buf_t ebuf; 8884 int i; 8885 8886 for (i = CAPABLE; i <= PEERADV; i++) { 8887 bzero(&ebuf, sizeof (ebuf)); 8888 (void) strlcpy(ebuf.eth_ptype, ptype[i], 8889 sizeof (ebuf.eth_ptype)); 8890 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 8891 sizeof (ebuf.eth_autoneg), eattr, i); 8892 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 8893 sizeof (ebuf.eth_spdx), eattr, i); 8894 (void) dladm_ether_pause2str(ebuf.eth_pause, 8895 sizeof (ebuf.eth_pause), eattr, i); 8896 (void) strlcpy(ebuf.eth_rem_fault, 8897 (eattr->lei_attr[i].le_fault ? "fault" : "none"), 8898 sizeof (ebuf.eth_rem_fault)); 8899 ofmt_print(statep->es_ofmt, &ebuf); 8900 } 8901 8902 } 8903 8904 static boolean_t 8905 link_is_ether(const char *link, datalink_id_t *linkid) 8906 { 8907 uint32_t media; 8908 datalink_class_t class; 8909 8910 if (dladm_name2info(handle, link, linkid, NULL, &class, &media) == 8911 DLADM_STATUS_OK) { 8912 if (class == DATALINK_CLASS_PHYS && media == DL_ETHER) 8913 return (B_TRUE); 8914 } 8915 return (B_FALSE); 8916 } 8917 8918 /* 8919 * default output callback function that, when invoked, 8920 * prints string which is offset by ofmt_arg->ofmt_id within buf. 8921 */ 8922 static boolean_t 8923 print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 8924 { 8925 char *value; 8926 8927 value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id; 8928 (void) strlcpy(buf, value, bufsize); 8929 return (B_TRUE); 8930 } 8931 8932 static void 8933 dladm_ofmt_check(ofmt_status_t oferr, boolean_t parsable, 8934 ofmt_handle_t ofmt) 8935 { 8936 char buf[OFMT_BUFSIZE]; 8937 8938 if (oferr == OFMT_SUCCESS) 8939 return; 8940 (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf)); 8941 /* 8942 * All errors are considered fatal in parsable mode. 8943 * NOMEM errors are always fatal, regardless of mode. 8944 * For other errors, we print diagnostics in human-readable 8945 * mode and processs what we can. 8946 */ 8947 if (parsable || oferr == OFMT_ENOFIELDS) { 8948 ofmt_close(ofmt); 8949 die(buf); 8950 } else { 8951 warn(buf); 8952 } 8953 } 8954