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