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