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