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