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