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