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 ; 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 (void) snprintf(pattr.link_phys_device, 3710 sizeof (pattr.link_phys_device), "%s", dpa.dp_dev); 3711 (void) dladm_media2str(media, pattr.link_phys_media); 3712 if (state->ls_flags == DLADM_OPT_ACTIVE) { 3713 boolean_t islink; 3714 3715 if (!dpa.dp_novanity) { 3716 (void) strlcpy(pattr.link_name, link, 3717 sizeof (pattr.link_name)); 3718 islink = B_TRUE; 3719 } else { 3720 /* 3721 * This is a physical link that does not have 3722 * vanity naming support. 3723 */ 3724 (void) strlcpy(pattr.link_name, dpa.dp_dev, 3725 sizeof (pattr.link_name)); 3726 islink = B_FALSE; 3727 } 3728 3729 (void) get_linkstate(pattr.link_name, islink, 3730 pattr.link_phys_state); 3731 (void) snprintf(pattr.link_phys_speed, 3732 sizeof (pattr.link_phys_speed), "%u", 3733 (uint_t)((get_ifspeed(pattr.link_name, 3734 islink)) / 1000000ull)); 3735 (void) get_linkduplex(pattr.link_name, islink, 3736 pattr.link_phys_duplex); 3737 } else { 3738 (void) snprintf(pattr.link_name, sizeof (pattr.link_name), 3739 "%s", link); 3740 (void) snprintf(pattr.link_flags, sizeof (pattr.link_flags), 3741 "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r'); 3742 } 3743 3744 ofmt_print(state->ls_ofmt, &pattr); 3745 3746 done: 3747 return (status); 3748 } 3749 3750 typedef struct { 3751 show_state_t *ms_state; 3752 char *ms_link; 3753 dladm_macaddr_attr_t *ms_mac_attr; 3754 } print_phys_mac_state_t; 3755 3756 /* 3757 * callback for ofmt_print() 3758 */ 3759 static boolean_t 3760 print_phys_one_mac_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3761 { 3762 print_phys_mac_state_t *mac_state = ofarg->ofmt_cbarg; 3763 dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr; 3764 boolean_t is_primary = (attr->ma_slot == 0); 3765 boolean_t is_parsable = mac_state->ms_state->ls_parsable; 3766 3767 switch (ofarg->ofmt_id) { 3768 case PHYS_M_LINK: 3769 (void) snprintf(buf, bufsize, "%s", 3770 (is_primary || is_parsable) ? mac_state->ms_link : " "); 3771 break; 3772 case PHYS_M_SLOT: 3773 if (is_primary) 3774 (void) snprintf(buf, bufsize, gettext("primary")); 3775 else 3776 (void) snprintf(buf, bufsize, "%d", attr->ma_slot); 3777 break; 3778 case PHYS_M_ADDRESS: 3779 (void) dladm_aggr_macaddr2str(attr->ma_addr, buf); 3780 break; 3781 case PHYS_M_INUSE: 3782 (void) snprintf(buf, bufsize, "%s", 3783 attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") : 3784 gettext("no")); 3785 break; 3786 case PHYS_M_CLIENT: 3787 /* 3788 * CR 6678526: resolve link id to actual link name if 3789 * it is valid. 3790 */ 3791 (void) snprintf(buf, bufsize, "%s", attr->ma_client_name); 3792 break; 3793 } 3794 3795 return (B_TRUE); 3796 } 3797 3798 typedef struct { 3799 show_state_t *hs_state; 3800 char *hs_link; 3801 dladm_hwgrp_attr_t *hs_grp_attr; 3802 } print_phys_hwgrp_state_t; 3803 3804 static boolean_t 3805 print_phys_one_hwgrp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3806 { 3807 int i; 3808 boolean_t first = B_TRUE; 3809 int start = -1; 3810 int end = -1; 3811 char ringstr[RINGSTRLEN]; 3812 char ringsubstr[RINGSTRLEN]; 3813 3814 print_phys_hwgrp_state_t *hg_state = ofarg->ofmt_cbarg; 3815 dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr; 3816 3817 switch (ofarg->ofmt_id) { 3818 case PHYS_H_LINK: 3819 (void) snprintf(buf, bufsize, "%s", attr->hg_link_name); 3820 break; 3821 case PHYS_H_RINGTYPE: 3822 (void) snprintf(buf, bufsize, "%s", 3823 attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX"); 3824 break; 3825 case PHYS_H_RINGS: 3826 ringstr[0] = '\0'; 3827 for (i = 0; i < attr->hg_n_rings; i++) { 3828 uint_t index = attr->hg_rings[i]; 3829 3830 if (start == -1) { 3831 start = index; 3832 end = index; 3833 } else if (index == end + 1) { 3834 end = index; 3835 } else { 3836 if (start == end) { 3837 if (first) { 3838 (void) snprintf( 3839 ringsubstr, 3840 RINGSTRLEN, "%d", 3841 start); 3842 first = B_FALSE; 3843 } else { 3844 (void) snprintf( 3845 ringsubstr, 3846 RINGSTRLEN, ",%d", 3847 start); 3848 } 3849 } else { 3850 if (first) { 3851 (void) snprintf( 3852 ringsubstr, 3853 RINGSTRLEN, 3854 "%d-%d", 3855 start, end); 3856 first = B_FALSE; 3857 } else { 3858 (void) snprintf( 3859 ringsubstr, 3860 RINGSTRLEN, 3861 ",%d-%d", 3862 start, end); 3863 } 3864 } 3865 (void) strlcat(ringstr, ringsubstr, 3866 RINGSTRLEN); 3867 start = index; 3868 end = index; 3869 } 3870 } 3871 /* The last one */ 3872 if (start != -1) { 3873 if (first) { 3874 if (start == end) { 3875 (void) snprintf(buf, bufsize, "%d", 3876 start); 3877 } else { 3878 (void) snprintf(buf, bufsize, "%d-%d", 3879 start, end); 3880 } 3881 } else { 3882 if (start == end) { 3883 (void) snprintf(ringsubstr, RINGSTRLEN, 3884 ",%d", start); 3885 } else { 3886 (void) snprintf(ringsubstr, RINGSTRLEN, 3887 ",%d-%d", start, end); 3888 } 3889 (void) strlcat(ringstr, ringsubstr, RINGSTRLEN); 3890 (void) snprintf(buf, bufsize, "%s", ringstr); 3891 } 3892 } 3893 break; 3894 case PHYS_H_CLIENTS: 3895 if (attr->hg_client_names[0] == '\0') { 3896 (void) snprintf(buf, bufsize, "--"); 3897 } else { 3898 (void) snprintf(buf, bufsize, "%s ", 3899 attr->hg_client_names); 3900 } 3901 break; 3902 } 3903 3904 return (B_TRUE); 3905 } 3906 3907 /* 3908 * callback for dladm_walk_macaddr, invoked for each MAC address slot 3909 */ 3910 static boolean_t 3911 print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr) 3912 { 3913 print_phys_mac_state_t *mac_state = arg; 3914 show_state_t *state = mac_state->ms_state; 3915 3916 mac_state->ms_mac_attr = attr; 3917 ofmt_print(state->ls_ofmt, mac_state); 3918 3919 return (B_TRUE); 3920 } 3921 3922 /* 3923 * invoked by show-phys -m for each physical data-link 3924 */ 3925 static dladm_status_t 3926 print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link) 3927 { 3928 print_phys_mac_state_t mac_state; 3929 3930 mac_state.ms_state = state; 3931 mac_state.ms_link = link; 3932 3933 return (dladm_walk_macaddr(handle, linkid, &mac_state, 3934 print_phys_mac_callback)); 3935 } 3936 3937 /* 3938 * callback for dladm_walk_hwgrp, invoked for each MAC hwgrp 3939 */ 3940 static boolean_t 3941 print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr) 3942 { 3943 print_phys_hwgrp_state_t *hwgrp_state = arg; 3944 show_state_t *state = hwgrp_state->hs_state; 3945 3946 hwgrp_state->hs_grp_attr = attr; 3947 ofmt_print(state->ls_ofmt, hwgrp_state); 3948 3949 return (B_TRUE); 3950 } 3951 3952 /* invoked by show-phys -H for each physical data-link */ 3953 static dladm_status_t 3954 print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link) 3955 { 3956 print_phys_hwgrp_state_t hwgrp_state; 3957 3958 hwgrp_state.hs_state = state; 3959 hwgrp_state.hs_link = link; 3960 return (dladm_walk_hwgrp(handle, linkid, &hwgrp_state, 3961 print_phys_hwgrp_callback)); 3962 } 3963 3964 /* 3965 * Parse the "local=<laddr>,remote=<raddr>" sub-options for the -a option of 3966 * *-iptun subcommands. 3967 */ 3968 static void 3969 iptun_process_addrarg(char *addrarg, iptun_params_t *params) 3970 { 3971 char *addrval; 3972 3973 while (*addrarg != '\0') { 3974 switch (getsubopt(&addrarg, iptun_addropts, &addrval)) { 3975 case IPTUN_LOCAL: 3976 params->iptun_param_flags |= IPTUN_PARAM_LADDR; 3977 if (strlcpy(params->iptun_param_laddr, addrval, 3978 sizeof (params->iptun_param_laddr)) >= 3979 sizeof (params->iptun_param_laddr)) 3980 die("tunnel source address is too long"); 3981 break; 3982 case IPTUN_REMOTE: 3983 params->iptun_param_flags |= IPTUN_PARAM_RADDR; 3984 if (strlcpy(params->iptun_param_raddr, addrval, 3985 sizeof (params->iptun_param_raddr)) >= 3986 sizeof (params->iptun_param_raddr)) 3987 die("tunnel destination address is too long"); 3988 break; 3989 default: 3990 die("invalid address type: %s", addrval); 3991 break; 3992 } 3993 } 3994 } 3995 3996 /* 3997 * Convenience routine to process iptun-create/modify/delete subcommand 3998 * arguments. 3999 */ 4000 static void 4001 iptun_process_args(int argc, char *argv[], const char *opts, 4002 iptun_params_t *params, uint32_t *flags, char *name, const char *use) 4003 { 4004 int option; 4005 char *altroot = NULL; 4006 4007 if (params != NULL) 4008 bzero(params, sizeof (*params)); 4009 *flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4010 4011 opterr = 0; 4012 while ((option = getopt_long(argc, argv, opts, iptun_lopts, NULL)) != 4013 -1) { 4014 switch (option) { 4015 case 'a': 4016 iptun_process_addrarg(optarg, params); 4017 break; 4018 case 'R': 4019 altroot = optarg; 4020 break; 4021 case 't': 4022 *flags &= ~DLADM_OPT_PERSIST; 4023 break; 4024 case 'T': 4025 params->iptun_param_type = iptun_gettypebyname(optarg); 4026 if (params->iptun_param_type == IPTUN_TYPE_UNKNOWN) 4027 die("unknown tunnel type: %s", optarg); 4028 params->iptun_param_flags |= IPTUN_PARAM_TYPE; 4029 break; 4030 default: 4031 die_opterr(optopt, option, use); 4032 break; 4033 } 4034 } 4035 4036 /* Get the required tunnel name argument. */ 4037 if (argc - optind != 1) 4038 usage(); 4039 4040 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 4041 die("tunnel name is too long"); 4042 4043 if (altroot != NULL) 4044 altroot_cmd(altroot, argc, argv); 4045 } 4046 4047 static void 4048 do_create_iptun(int argc, char *argv[], const char *use) 4049 { 4050 iptun_params_t params; 4051 dladm_status_t status; 4052 uint32_t flags; 4053 char name[MAXLINKNAMELEN]; 4054 4055 iptun_process_args(argc, argv, ":a:R:tT:", ¶ms, &flags, name, 4056 use); 4057 4058 status = dladm_iptun_create(handle, name, ¶ms, flags); 4059 if (status != DLADM_STATUS_OK) 4060 die_dlerr(status, "could not create tunnel"); 4061 } 4062 4063 static void 4064 do_delete_iptun(int argc, char *argv[], const char *use) 4065 { 4066 uint32_t flags; 4067 datalink_id_t linkid; 4068 dladm_status_t status; 4069 char name[MAXLINKNAMELEN]; 4070 4071 iptun_process_args(argc, argv, ":R:t", NULL, &flags, name, use); 4072 4073 status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL); 4074 if (status != DLADM_STATUS_OK) 4075 die_dlerr(status, "could not delete tunnel"); 4076 status = dladm_iptun_delete(handle, linkid, flags); 4077 if (status != DLADM_STATUS_OK) 4078 die_dlerr(status, "could not delete tunnel"); 4079 } 4080 4081 static void 4082 do_modify_iptun(int argc, char *argv[], const char *use) 4083 { 4084 iptun_params_t params; 4085 uint32_t flags; 4086 dladm_status_t status; 4087 char name[MAXLINKNAMELEN]; 4088 4089 iptun_process_args(argc, argv, ":a:R:t", ¶ms, &flags, name, use); 4090 4091 if ((status = dladm_name2info(handle, name, ¶ms.iptun_param_linkid, 4092 NULL, NULL, NULL)) != DLADM_STATUS_OK) 4093 die_dlerr(status, "could not modify tunnel"); 4094 status = dladm_iptun_modify(handle, ¶ms, flags); 4095 if (status != DLADM_STATUS_OK) 4096 die_dlerr(status, "could not modify tunnel"); 4097 } 4098 4099 static void 4100 do_show_iptun(int argc, char *argv[], const char *use) 4101 { 4102 char option; 4103 datalink_id_t linkid; 4104 uint32_t flags = DLADM_OPT_ACTIVE; 4105 char *name = NULL; 4106 dladm_status_t status; 4107 const char *fields_str = NULL; 4108 show_state_t state; 4109 ofmt_handle_t ofmt; 4110 ofmt_status_t oferr; 4111 uint_t ofmtflags = 0; 4112 4113 bzero(&state, sizeof (state)); 4114 opterr = 0; 4115 while ((option = getopt_long(argc, argv, ":pPo:", 4116 iptun_lopts, NULL)) != -1) { 4117 switch (option) { 4118 case 'o': 4119 fields_str = optarg; 4120 break; 4121 case 'p': 4122 state.ls_parsable = B_TRUE; 4123 ofmtflags = OFMT_PARSABLE; 4124 break; 4125 case 'P': 4126 flags = DLADM_OPT_PERSIST; 4127 break; 4128 default: 4129 die_opterr(optopt, option, use); 4130 break; 4131 } 4132 } 4133 4134 /* 4135 * Get the optional tunnel name argument. If there is one, it must 4136 * be the last thing remaining on the command-line. 4137 */ 4138 if (argc - optind > 1) 4139 die(gettext(use)); 4140 if (argc - optind == 1) 4141 name = argv[optind]; 4142 4143 oferr = ofmt_open(fields_str, iptun_fields, ofmtflags, 4144 DLADM_DEFAULT_COL, &ofmt); 4145 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 4146 4147 state.ls_ofmt = ofmt; 4148 state.ls_flags = flags; 4149 4150 if (name == NULL) { 4151 (void) dladm_walk_datalink_id(print_iptun_walker, handle, 4152 &state, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE, 4153 flags); 4154 status = state.ls_status; 4155 } else { 4156 if ((status = dladm_name2info(handle, name, &linkid, NULL, NULL, 4157 NULL)) == DLADM_STATUS_OK) 4158 status = print_iptun(handle, linkid, &state); 4159 } 4160 4161 if (status != DLADM_STATUS_OK) 4162 die_dlerr(status, "unable to obtain tunnel status"); 4163 } 4164 4165 /* ARGSUSED */ 4166 static void 4167 do_up_iptun(int argc, char *argv[], const char *use) 4168 { 4169 datalink_id_t linkid = DATALINK_ALL_LINKID; 4170 dladm_status_t status = DLADM_STATUS_OK; 4171 4172 /* 4173 * Get the optional tunnel name argument. If there is one, it must 4174 * be the last thing remaining on the command-line. 4175 */ 4176 if (argc - optind > 1) 4177 usage(); 4178 if (argc - optind == 1) { 4179 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 4180 NULL, NULL); 4181 } 4182 if (status == DLADM_STATUS_OK) 4183 status = dladm_iptun_up(handle, linkid); 4184 if (status != DLADM_STATUS_OK) 4185 die_dlerr(status, "unable to configure IP tunnel links"); 4186 } 4187 4188 /* ARGSUSED */ 4189 static void 4190 do_down_iptun(int argc, char *argv[], const char *use) 4191 { 4192 datalink_id_t linkid = DATALINK_ALL_LINKID; 4193 dladm_status_t status = DLADM_STATUS_OK; 4194 4195 /* 4196 * Get the optional tunnel name argument. If there is one, it must 4197 * be the last thing remaining on the command-line. 4198 */ 4199 if (argc - optind > 1) 4200 usage(); 4201 if (argc - optind == 1) { 4202 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 4203 NULL, NULL); 4204 } 4205 if (status == DLADM_STATUS_OK) 4206 status = dladm_iptun_down(handle, linkid); 4207 if (status != DLADM_STATUS_OK) 4208 die_dlerr(status, "unable to bring down IP tunnel links"); 4209 } 4210 4211 static iptun_type_t 4212 iptun_gettypebyname(char *typestr) 4213 { 4214 int i; 4215 4216 for (i = 0; iptun_types[i].type_name != NULL; i++) { 4217 if (strncmp(iptun_types[i].type_name, typestr, 4218 strlen(iptun_types[i].type_name)) == 0) { 4219 return (iptun_types[i].type_value); 4220 } 4221 } 4222 return (IPTUN_TYPE_UNKNOWN); 4223 } 4224 4225 static const char * 4226 iptun_gettypebyvalue(iptun_type_t type) 4227 { 4228 int i; 4229 4230 for (i = 0; iptun_types[i].type_name != NULL; i++) { 4231 if (iptun_types[i].type_value == type) 4232 return (iptun_types[i].type_name); 4233 } 4234 return (NULL); 4235 } 4236 4237 static dladm_status_t 4238 print_iptun(dladm_handle_t dh, datalink_id_t linkid, show_state_t *state) 4239 { 4240 dladm_status_t status; 4241 iptun_params_t params; 4242 iptun_fields_buf_t lbuf; 4243 const char *laddr; 4244 const char *raddr; 4245 4246 params.iptun_param_linkid = linkid; 4247 status = dladm_iptun_getparams(dh, ¶ms, state->ls_flags); 4248 if (status != DLADM_STATUS_OK) 4249 return (status); 4250 4251 /* LINK */ 4252 status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, 4253 lbuf.iptun_name, sizeof (lbuf.iptun_name)); 4254 if (status != DLADM_STATUS_OK) 4255 return (status); 4256 4257 /* TYPE */ 4258 (void) strlcpy(lbuf.iptun_type, 4259 iptun_gettypebyvalue(params.iptun_param_type), 4260 sizeof (lbuf.iptun_type)); 4261 4262 /* FLAGS */ 4263 (void) memset(lbuf.iptun_flags, '-', IPTUN_NUM_FLAGS); 4264 lbuf.iptun_flags[IPTUN_NUM_FLAGS] = '\0'; 4265 if (params.iptun_param_flags & IPTUN_PARAM_IPSECPOL) 4266 lbuf.iptun_flags[IPTUN_SFLAG_INDEX] = 's'; 4267 if (params.iptun_param_flags & IPTUN_PARAM_IMPLICIT) 4268 lbuf.iptun_flags[IPTUN_IFLAG_INDEX] = 'i'; 4269 4270 /* LOCAL */ 4271 if (params.iptun_param_flags & IPTUN_PARAM_LADDR) 4272 laddr = params.iptun_param_laddr; 4273 else 4274 laddr = (state->ls_parsable) ? "" : "--"; 4275 (void) strlcpy(lbuf.iptun_laddr, laddr, sizeof (lbuf.iptun_laddr)); 4276 4277 /* REMOTE */ 4278 if (params.iptun_param_flags & IPTUN_PARAM_RADDR) 4279 raddr = params.iptun_param_raddr; 4280 else 4281 raddr = (state->ls_parsable) ? "" : "--"; 4282 (void) strlcpy(lbuf.iptun_raddr, raddr, sizeof (lbuf.iptun_raddr)); 4283 4284 ofmt_print(state->ls_ofmt, &lbuf); 4285 4286 return (DLADM_STATUS_OK); 4287 } 4288 4289 static int 4290 print_iptun_walker(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4291 { 4292 ((show_state_t *)arg)->ls_status = print_iptun(dh, linkid, arg); 4293 return (DLADM_WALK_CONTINUE); 4294 } 4295 4296 static dladm_status_t 4297 print_phys(show_state_t *state, datalink_id_t linkid) 4298 { 4299 char link[MAXLINKNAMELEN]; 4300 uint32_t flags; 4301 dladm_status_t status; 4302 datalink_class_t class; 4303 uint32_t media; 4304 4305 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 4306 &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 4307 goto done; 4308 } 4309 4310 if (class != DATALINK_CLASS_PHYS) { 4311 status = DLADM_STATUS_BADARG; 4312 goto done; 4313 } 4314 4315 if (!(state->ls_flags & flags)) { 4316 status = DLADM_STATUS_NOTFOUND; 4317 goto done; 4318 } 4319 4320 if (state->ls_mac) 4321 status = print_phys_mac(state, linkid, link); 4322 else if (state->ls_hwgrp) 4323 status = print_phys_hwgrp(state, linkid, link); 4324 else 4325 status = print_phys_default(state, linkid, link, flags, media); 4326 4327 done: 4328 return (status); 4329 } 4330 4331 /* ARGSUSED */ 4332 static int 4333 show_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4334 { 4335 show_state_t *state = arg; 4336 4337 state->ls_status = print_phys(state, linkid); 4338 return (DLADM_WALK_CONTINUE); 4339 } 4340 4341 /* 4342 * Print the active topology information. 4343 */ 4344 static dladm_status_t 4345 print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l) 4346 { 4347 dladm_vlan_attr_t vinfo; 4348 uint32_t flags; 4349 dladm_status_t status; 4350 4351 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL, 4352 l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) { 4353 goto done; 4354 } 4355 4356 if (!(state->ls_flags & flags)) { 4357 status = DLADM_STATUS_NOTFOUND; 4358 goto done; 4359 } 4360 4361 if ((status = dladm_vlan_info(handle, linkid, &vinfo, 4362 state->ls_flags)) != DLADM_STATUS_OK || 4363 (status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, 4364 NULL, NULL, l->link_over, sizeof (l->link_over))) != 4365 DLADM_STATUS_OK) { 4366 goto done; 4367 } 4368 4369 (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d", 4370 vinfo.dv_vid); 4371 (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----", 4372 vinfo.dv_force ? 'f' : '-'); 4373 4374 done: 4375 return (status); 4376 } 4377 4378 /* ARGSUSED */ 4379 static int 4380 show_vlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4381 { 4382 show_state_t *state = arg; 4383 dladm_status_t status; 4384 link_fields_buf_t lbuf; 4385 4386 bzero(&lbuf, sizeof (link_fields_buf_t)); 4387 status = print_vlan(state, linkid, &lbuf); 4388 if (status != DLADM_STATUS_OK) 4389 goto done; 4390 4391 ofmt_print(state->ls_ofmt, &lbuf); 4392 4393 done: 4394 state->ls_status = status; 4395 return (DLADM_WALK_CONTINUE); 4396 } 4397 4398 static void 4399 do_show_phys(int argc, char *argv[], const char *use) 4400 { 4401 int option; 4402 uint32_t flags = DLADM_OPT_ACTIVE; 4403 boolean_t p_arg = B_FALSE; 4404 boolean_t o_arg = B_FALSE; 4405 boolean_t m_arg = B_FALSE; 4406 boolean_t H_arg = B_FALSE; 4407 datalink_id_t linkid = DATALINK_ALL_LINKID; 4408 show_state_t state; 4409 dladm_status_t status; 4410 char *fields_str = NULL; 4411 char *all_active_fields = 4412 "link,media,state,speed,duplex,device"; 4413 char *all_inactive_fields = "link,device,media,flags"; 4414 char *all_mac_fields = "link,slot,address,inuse,client"; 4415 char *all_hwgrp_fields = "link,ringtype,rings,clients"; 4416 const ofmt_field_t *pf; 4417 ofmt_handle_t ofmt; 4418 ofmt_status_t oferr; 4419 uint_t ofmtflags = 0; 4420 4421 bzero(&state, sizeof (state)); 4422 opterr = 0; 4423 while ((option = getopt_long(argc, argv, ":pPo:mH", 4424 show_lopts, NULL)) != -1) { 4425 switch (option) { 4426 case 'p': 4427 if (p_arg) 4428 die_optdup(option); 4429 4430 p_arg = B_TRUE; 4431 break; 4432 case 'P': 4433 if (flags != DLADM_OPT_ACTIVE) 4434 die_optdup(option); 4435 4436 flags = DLADM_OPT_PERSIST; 4437 break; 4438 case 'o': 4439 o_arg = B_TRUE; 4440 fields_str = optarg; 4441 break; 4442 case 'm': 4443 m_arg = B_TRUE; 4444 break; 4445 case 'H': 4446 H_arg = B_TRUE; 4447 break; 4448 default: 4449 die_opterr(optopt, option, use); 4450 break; 4451 } 4452 } 4453 4454 if (p_arg && !o_arg) 4455 die("-p requires -o"); 4456 4457 if (m_arg && H_arg) 4458 die("-m cannot combine with -H"); 4459 4460 if (p_arg && strcasecmp(fields_str, "all") == 0) 4461 die("\"-o all\" is invalid with -p"); 4462 4463 /* get link name (optional last argument) */ 4464 if (optind == (argc-1)) { 4465 if ((status = dladm_name2info(handle, argv[optind], &linkid, 4466 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 4467 die_dlerr(status, "link %s is not valid", argv[optind]); 4468 } 4469 } else if (optind != argc) { 4470 usage(); 4471 } 4472 4473 state.ls_parsable = p_arg; 4474 state.ls_flags = flags; 4475 state.ls_donefirst = B_FALSE; 4476 state.ls_mac = m_arg; 4477 state.ls_hwgrp = H_arg; 4478 4479 if (m_arg && !(flags & DLADM_OPT_ACTIVE)) { 4480 /* 4481 * We can only display the factory MAC addresses of 4482 * active data-links. 4483 */ 4484 die("-m not compatible with -P"); 4485 } 4486 4487 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 4488 if (state.ls_mac) 4489 fields_str = all_mac_fields; 4490 else if (state.ls_hwgrp) 4491 fields_str = all_hwgrp_fields; 4492 else if (state.ls_flags & DLADM_OPT_ACTIVE) { 4493 fields_str = all_active_fields; 4494 } else { 4495 fields_str = all_inactive_fields; 4496 } 4497 } 4498 4499 if (state.ls_mac) { 4500 pf = phys_m_fields; 4501 } else if (state.ls_hwgrp) { 4502 pf = phys_h_fields; 4503 } else { 4504 pf = phys_fields; 4505 } 4506 4507 if (state.ls_parsable) 4508 ofmtflags |= OFMT_PARSABLE; 4509 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 4510 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 4511 state.ls_ofmt = ofmt; 4512 4513 if (linkid == DATALINK_ALL_LINKID) { 4514 (void) dladm_walk_datalink_id(show_phys, handle, &state, 4515 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags); 4516 } else { 4517 (void) show_phys(handle, linkid, &state); 4518 if (state.ls_status != DLADM_STATUS_OK) { 4519 die_dlerr(state.ls_status, 4520 "failed to show physical link %s", argv[optind]); 4521 } 4522 } 4523 ofmt_close(ofmt); 4524 } 4525 4526 static void 4527 do_show_vlan(int argc, char *argv[], const char *use) 4528 { 4529 int option; 4530 uint32_t flags = DLADM_OPT_ACTIVE; 4531 boolean_t p_arg = B_FALSE; 4532 datalink_id_t linkid = DATALINK_ALL_LINKID; 4533 show_state_t state; 4534 dladm_status_t status; 4535 boolean_t o_arg = B_FALSE; 4536 char *fields_str = NULL; 4537 ofmt_handle_t ofmt; 4538 ofmt_status_t oferr; 4539 uint_t ofmtflags = 0; 4540 4541 bzero(&state, sizeof (state)); 4542 4543 opterr = 0; 4544 while ((option = getopt_long(argc, argv, ":pPo:", 4545 show_lopts, NULL)) != -1) { 4546 switch (option) { 4547 case 'p': 4548 if (p_arg) 4549 die_optdup(option); 4550 4551 p_arg = B_TRUE; 4552 break; 4553 case 'P': 4554 if (flags != DLADM_OPT_ACTIVE) 4555 die_optdup(option); 4556 4557 flags = DLADM_OPT_PERSIST; 4558 break; 4559 case 'o': 4560 o_arg = B_TRUE; 4561 fields_str = optarg; 4562 break; 4563 default: 4564 die_opterr(optopt, option, use); 4565 break; 4566 } 4567 } 4568 4569 /* get link name (optional last argument) */ 4570 if (optind == (argc-1)) { 4571 if ((status = dladm_name2info(handle, argv[optind], &linkid, 4572 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 4573 die_dlerr(status, "link %s is not valid", argv[optind]); 4574 } 4575 } else if (optind != argc) { 4576 usage(); 4577 } 4578 4579 state.ls_parsable = p_arg; 4580 state.ls_flags = flags; 4581 state.ls_donefirst = B_FALSE; 4582 4583 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 4584 fields_str = NULL; 4585 4586 if (state.ls_parsable) 4587 ofmtflags |= OFMT_PARSABLE; 4588 oferr = ofmt_open(fields_str, vlan_fields, ofmtflags, 0, &ofmt); 4589 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 4590 state.ls_ofmt = ofmt; 4591 4592 if (linkid == DATALINK_ALL_LINKID) { 4593 (void) dladm_walk_datalink_id(show_vlan, handle, &state, 4594 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags); 4595 } else { 4596 (void) show_vlan(handle, linkid, &state); 4597 if (state.ls_status != DLADM_STATUS_OK) { 4598 die_dlerr(state.ls_status, "failed to show vlan %s", 4599 argv[optind]); 4600 } 4601 } 4602 ofmt_close(ofmt); 4603 } 4604 4605 static void 4606 do_create_vnic(int argc, char *argv[], const char *use) 4607 { 4608 datalink_id_t linkid, dev_linkid; 4609 char devname[MAXLINKNAMELEN]; 4610 char name[MAXLINKNAMELEN]; 4611 boolean_t l_arg = B_FALSE; 4612 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4613 char *altroot = NULL; 4614 int option; 4615 char *endp = NULL; 4616 dladm_status_t status; 4617 vnic_mac_addr_type_t mac_addr_type = VNIC_MAC_ADDR_TYPE_UNKNOWN; 4618 uchar_t *mac_addr = NULL; 4619 int mac_slot = -1; 4620 uint_t maclen = 0, mac_prefix_len = 0; 4621 char propstr[DLADM_STRSIZE]; 4622 dladm_arg_list_t *proplist = NULL; 4623 int vid = 0; 4624 int af = AF_UNSPEC; 4625 vrid_t vrid = VRRP_VRID_NONE; 4626 4627 opterr = 0; 4628 bzero(propstr, DLADM_STRSIZE); 4629 4630 while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:V:A:H", 4631 vnic_lopts, NULL)) != -1) { 4632 switch (option) { 4633 case 't': 4634 flags &= ~DLADM_OPT_PERSIST; 4635 break; 4636 case 'R': 4637 altroot = optarg; 4638 break; 4639 case 'l': 4640 if (strlcpy(devname, optarg, MAXLINKNAMELEN) >= 4641 MAXLINKNAMELEN) 4642 die("link name too long"); 4643 l_arg = B_TRUE; 4644 break; 4645 case 'm': 4646 if (mac_addr_type != VNIC_MAC_ADDR_TYPE_UNKNOWN) 4647 die("cannot specify -m option twice"); 4648 4649 if (strcmp(optarg, "fixed") == 0) { 4650 /* 4651 * A fixed MAC address must be specified 4652 * by its value, not by the keyword 'fixed'. 4653 */ 4654 die("'fixed' is not a valid MAC address"); 4655 } 4656 if (dladm_vnic_str2macaddrtype(optarg, 4657 &mac_addr_type) != DLADM_STATUS_OK) { 4658 mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED; 4659 /* MAC address specified by value */ 4660 mac_addr = _link_aton(optarg, (int *)&maclen); 4661 if (mac_addr == NULL) { 4662 if (maclen == (uint_t)-1) 4663 die("invalid MAC address"); 4664 else 4665 die("out of memory"); 4666 } 4667 } 4668 break; 4669 case 'n': 4670 errno = 0; 4671 mac_slot = (int)strtol(optarg, &endp, 10); 4672 if (errno != 0 || *endp != '\0') 4673 die("invalid slot number"); 4674 break; 4675 case 'p': 4676 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 4677 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 4678 DLADM_STRSIZE) 4679 die("property list too long '%s'", propstr); 4680 break; 4681 case 'r': 4682 mac_addr = _link_aton(optarg, (int *)&mac_prefix_len); 4683 if (mac_addr == NULL) { 4684 if (mac_prefix_len == (uint_t)-1) 4685 die("invalid MAC address"); 4686 else 4687 die("out of memory"); 4688 } 4689 break; 4690 case 'V': 4691 if (!str2int(optarg, (int *)&vrid) || 4692 vrid < VRRP_VRID_MIN || vrid > VRRP_VRID_MAX) { 4693 die("invalid VRRP identifier '%s'", optarg); 4694 } 4695 4696 break; 4697 case 'A': 4698 if (strcmp(optarg, "inet") == 0) 4699 af = AF_INET; 4700 else if (strcmp(optarg, "inet6") == 0) 4701 af = AF_INET6; 4702 else 4703 die("invalid address family '%s'", optarg); 4704 break; 4705 case 'v': 4706 if (vid != 0) 4707 die_optdup(option); 4708 4709 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 4710 die("invalid VLAN identifier '%s'", optarg); 4711 4712 break; 4713 case 'f': 4714 flags |= DLADM_OPT_FORCE; 4715 break; 4716 default: 4717 die_opterr(optopt, option, use); 4718 } 4719 } 4720 4721 if (mac_addr_type == VNIC_MAC_ADDR_TYPE_UNKNOWN) 4722 mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO; 4723 4724 /* 4725 * 'f' - force, flag can be specified only with 'v' - vlan. 4726 */ 4727 if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0) 4728 die("-f option can only be used with -v"); 4729 4730 if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM && 4731 mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED) 4732 usage(); 4733 4734 if (mac_addr_type == VNIC_MAC_ADDR_TYPE_VRID) { 4735 if (vrid == VRRP_VRID_NONE || af == AF_UNSPEC || 4736 mac_addr != NULL || maclen != 0 || mac_slot != -1 || 4737 mac_prefix_len != 0) { 4738 usage(); 4739 } 4740 } else if ((af != AF_UNSPEC || vrid != VRRP_VRID_NONE)) { 4741 usage(); 4742 } 4743 4744 /* check required options */ 4745 if (!l_arg) 4746 usage(); 4747 4748 if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY) 4749 usage(); 4750 4751 /* the VNIC id is the required operand */ 4752 if (optind != (argc - 1)) 4753 usage(); 4754 4755 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 4756 die("link name too long '%s'", argv[optind]); 4757 4758 if (!dladm_valid_linkname(name)) 4759 die("invalid link name '%s'", argv[optind]); 4760 4761 if (altroot != NULL) 4762 altroot_cmd(altroot, argc, argv); 4763 4764 if (dladm_name2info(handle, devname, &dev_linkid, NULL, NULL, NULL) != 4765 DLADM_STATUS_OK) 4766 die("invalid link name '%s'", devname); 4767 4768 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 4769 != DLADM_STATUS_OK) 4770 die("invalid vnic property"); 4771 4772 status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type, 4773 mac_addr, maclen, &mac_slot, mac_prefix_len, vid, vrid, af, 4774 &linkid, proplist, flags); 4775 switch (status) { 4776 case DLADM_STATUS_OK: 4777 break; 4778 4779 case DLADM_STATUS_LINKBUSY: 4780 die("VLAN over '%s' may not use default_tag ID " 4781 "(see dladm(1M))", devname); 4782 break; 4783 4784 default: 4785 die_dlerr(status, "vnic creation over %s failed", devname); 4786 } 4787 4788 dladm_free_props(proplist); 4789 free(mac_addr); 4790 } 4791 4792 static void 4793 do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub, 4794 uint32_t flags) 4795 { 4796 boolean_t is_etherstub; 4797 dladm_vnic_attr_t attr; 4798 4799 if (dladm_vnic_info(handle, linkid, &attr, flags) != DLADM_STATUS_OK) { 4800 /* 4801 * Let the delete continue anyway. 4802 */ 4803 return; 4804 } 4805 is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID); 4806 if (is_etherstub != etherstub) { 4807 die("'%s' is not %s", name, 4808 (is_etherstub ? "a vnic" : "an etherstub")); 4809 } 4810 } 4811 4812 static void 4813 do_delete_vnic_common(int argc, char *argv[], const char *use, 4814 boolean_t etherstub) 4815 { 4816 int option; 4817 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4818 datalink_id_t linkid; 4819 char *altroot = NULL; 4820 dladm_status_t status; 4821 4822 opterr = 0; 4823 while ((option = getopt_long(argc, argv, ":R:t", lopts, 4824 NULL)) != -1) { 4825 switch (option) { 4826 case 't': 4827 flags &= ~DLADM_OPT_PERSIST; 4828 break; 4829 case 'R': 4830 altroot = optarg; 4831 break; 4832 default: 4833 die_opterr(optopt, option, use); 4834 } 4835 } 4836 4837 /* get vnic name (required last argument) */ 4838 if (optind != (argc - 1)) 4839 usage(); 4840 4841 if (altroot != NULL) 4842 altroot_cmd(altroot, argc, argv); 4843 4844 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 4845 NULL); 4846 if (status != DLADM_STATUS_OK) 4847 die("invalid link name '%s'", argv[optind]); 4848 4849 if ((flags & DLADM_OPT_ACTIVE) != 0) { 4850 do_etherstub_check(argv[optind], linkid, etherstub, 4851 DLADM_OPT_ACTIVE); 4852 } 4853 if ((flags & DLADM_OPT_PERSIST) != 0) { 4854 do_etherstub_check(argv[optind], linkid, etherstub, 4855 DLADM_OPT_PERSIST); 4856 } 4857 4858 status = dladm_vnic_delete(handle, linkid, flags); 4859 if (status != DLADM_STATUS_OK) 4860 die_dlerr(status, "vnic deletion failed"); 4861 } 4862 4863 static void 4864 do_delete_vnic(int argc, char *argv[], const char *use) 4865 { 4866 do_delete_vnic_common(argc, argv, use, B_FALSE); 4867 } 4868 4869 /* ARGSUSED */ 4870 static void 4871 do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan) 4872 { 4873 datalink_id_t linkid = DATALINK_ALL_LINKID; 4874 dladm_status_t status; 4875 char *type; 4876 4877 type = vlan ? "vlan" : "vnic"; 4878 4879 /* 4880 * get the id or the name of the vnic/vlan (optional last argument) 4881 */ 4882 if (argc == 2) { 4883 status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL, 4884 NULL); 4885 if (status != DLADM_STATUS_OK) 4886 goto done; 4887 4888 } else if (argc > 2) { 4889 usage(); 4890 } 4891 4892 if (vlan) 4893 status = dladm_vlan_up(handle, linkid); 4894 else 4895 status = dladm_vnic_up(handle, linkid, 0); 4896 4897 done: 4898 if (status != DLADM_STATUS_OK) { 4899 if (argc == 2) { 4900 die_dlerr(status, 4901 "could not bring up %s '%s'", type, argv[1]); 4902 } else { 4903 die_dlerr(status, "could not bring %ss up", type); 4904 } 4905 } 4906 } 4907 4908 static void 4909 do_up_vnic(int argc, char *argv[], const char *use) 4910 { 4911 do_up_vnic_common(argc, argv, use, B_FALSE); 4912 } 4913 4914 static void 4915 dump_vnics_head(const char *dev) 4916 { 4917 if (strlen(dev)) 4918 (void) printf("%s", dev); 4919 4920 (void) printf("\tipackets rbytes opackets obytes "); 4921 4922 if (strlen(dev)) 4923 (void) printf("%%ipkts %%opkts\n"); 4924 else 4925 (void) printf("\n"); 4926 } 4927 4928 static void 4929 dump_vnic_stat(const char *name, datalink_id_t vnic_id, 4930 show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats) 4931 { 4932 pktsum_t diff_stats; 4933 pktsum_t *old_stats = &state->vs_prevstats[vnic_id]; 4934 4935 dladm_stats_diff(&diff_stats, vnic_stats, old_stats); 4936 4937 (void) printf("%s", name); 4938 4939 (void) printf("\t%-10llu", diff_stats.ipackets); 4940 (void) printf("%-12llu", diff_stats.rbytes); 4941 (void) printf("%-10llu", diff_stats.opackets); 4942 (void) printf("%-12llu", diff_stats.obytes); 4943 4944 if (tot_stats) { 4945 if (tot_stats->ipackets == 0) { 4946 (void) printf("\t-"); 4947 } else { 4948 (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 4949 (double)tot_stats->ipackets * 100); 4950 } 4951 if (tot_stats->opackets == 0) { 4952 (void) printf("\t-"); 4953 } else { 4954 (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 4955 (double)tot_stats->opackets * 100); 4956 } 4957 } 4958 (void) printf("\n"); 4959 4960 *old_stats = *vnic_stats; 4961 } 4962 4963 /* 4964 * Called from the walker dladm_vnic_walk_sys() for each vnic to display 4965 * vnic information or statistics. 4966 */ 4967 static dladm_status_t 4968 print_vnic(show_vnic_state_t *state, datalink_id_t linkid) 4969 { 4970 dladm_vnic_attr_t attr, *vnic = &attr; 4971 dladm_status_t status; 4972 boolean_t is_etherstub; 4973 char devname[MAXLINKNAMELEN]; 4974 char vnic_name[MAXLINKNAMELEN]; 4975 char mstr[MAXMACADDRLEN * 3]; 4976 vnic_fields_buf_t vbuf; 4977 4978 if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) != 4979 DLADM_STATUS_OK) 4980 return (status); 4981 4982 is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID); 4983 if (state->vs_etherstub != is_etherstub) { 4984 /* 4985 * Want all etherstub but it's not one, or want 4986 * non-etherstub and it's one. 4987 */ 4988 return (DLADM_STATUS_OK); 4989 } 4990 4991 if (state->vs_link_id != DATALINK_ALL_LINKID) { 4992 if (state->vs_link_id != vnic->va_link_id) 4993 return (DLADM_STATUS_OK); 4994 } 4995 4996 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, 4997 NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK) 4998 return (DLADM_STATUS_BADARG); 4999 5000 bzero(devname, sizeof (devname)); 5001 if (!is_etherstub && 5002 dladm_datalink_id2info(handle, vnic->va_link_id, NULL, NULL, 5003 NULL, devname, sizeof (devname)) != DLADM_STATUS_OK) 5004 (void) sprintf(devname, "?"); 5005 5006 state->vs_found = B_TRUE; 5007 if (state->vs_stats) { 5008 /* print vnic statistics */ 5009 pktsum_t vnic_stats; 5010 5011 if (state->vs_firstonly) { 5012 if (state->vs_donefirst) 5013 return (0); 5014 state->vs_donefirst = B_TRUE; 5015 } 5016 5017 if (!state->vs_printstats) { 5018 /* 5019 * get vnic statistics and add to the sum for the 5020 * named device. 5021 */ 5022 get_link_stats(vnic_name, &vnic_stats); 5023 dladm_stats_total(&state->vs_totalstats, &vnic_stats, 5024 &state->vs_prevstats[vnic->va_vnic_id]); 5025 } else { 5026 /* get and print vnic statistics */ 5027 get_link_stats(vnic_name, &vnic_stats); 5028 dump_vnic_stat(vnic_name, linkid, state, &vnic_stats, 5029 &state->vs_totalstats); 5030 } 5031 return (DLADM_STATUS_OK); 5032 } else { 5033 (void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link), 5034 "%s", vnic_name); 5035 5036 if (!is_etherstub) { 5037 5038 (void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over), 5039 "%s", devname); 5040 (void) snprintf(vbuf.vnic_speed, 5041 sizeof (vbuf.vnic_speed), "%u", 5042 (uint_t)((get_ifspeed(vnic_name, B_TRUE)) 5043 / 1000000ull)); 5044 5045 switch (vnic->va_mac_addr_type) { 5046 case VNIC_MAC_ADDR_TYPE_FIXED: 5047 case VNIC_MAC_ADDR_TYPE_PRIMARY: 5048 (void) snprintf(vbuf.vnic_macaddrtype, 5049 sizeof (vbuf.vnic_macaddrtype), 5050 gettext("fixed")); 5051 break; 5052 case VNIC_MAC_ADDR_TYPE_RANDOM: 5053 (void) snprintf(vbuf.vnic_macaddrtype, 5054 sizeof (vbuf.vnic_macaddrtype), 5055 gettext("random")); 5056 break; 5057 case VNIC_MAC_ADDR_TYPE_FACTORY: 5058 (void) snprintf(vbuf.vnic_macaddrtype, 5059 sizeof (vbuf.vnic_macaddrtype), 5060 gettext("factory, slot %d"), 5061 vnic->va_mac_slot); 5062 break; 5063 case VNIC_MAC_ADDR_TYPE_VRID: 5064 (void) snprintf(vbuf.vnic_macaddrtype, 5065 sizeof (vbuf.vnic_macaddrtype), 5066 gettext("vrrp, %d/%s"), 5067 vnic->va_vrid, vnic->va_af == AF_INET ? 5068 "inet" : "inet6"); 5069 break; 5070 } 5071 5072 if (strlen(vbuf.vnic_macaddrtype) > 0) { 5073 (void) snprintf(vbuf.vnic_macaddr, 5074 sizeof (vbuf.vnic_macaddr), "%s", 5075 dladm_aggr_macaddr2str(vnic->va_mac_addr, 5076 mstr)); 5077 } 5078 5079 (void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid), 5080 "%d", vnic->va_vid); 5081 } 5082 5083 ofmt_print(state->vs_ofmt, &vbuf); 5084 5085 return (DLADM_STATUS_OK); 5086 } 5087 } 5088 5089 /* ARGSUSED */ 5090 static int 5091 show_vnic(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5092 { 5093 show_vnic_state_t *state = arg; 5094 5095 state->vs_status = print_vnic(state, linkid); 5096 return (DLADM_WALK_CONTINUE); 5097 } 5098 5099 static void 5100 do_show_vnic_common(int argc, char *argv[], const char *use, 5101 boolean_t etherstub) 5102 { 5103 int option; 5104 boolean_t s_arg = B_FALSE; 5105 boolean_t i_arg = B_FALSE; 5106 boolean_t l_arg = B_FALSE; 5107 uint32_t interval = 0, flags = DLADM_OPT_ACTIVE; 5108 datalink_id_t linkid = DATALINK_ALL_LINKID; 5109 datalink_id_t dev_linkid = DATALINK_ALL_LINKID; 5110 show_vnic_state_t state; 5111 dladm_status_t status; 5112 boolean_t o_arg = B_FALSE; 5113 char *fields_str = NULL; 5114 const ofmt_field_t *pf; 5115 char *all_e_fields = "link"; 5116 ofmt_handle_t ofmt; 5117 ofmt_status_t oferr; 5118 uint_t ofmtflags = 0; 5119 5120 bzero(&state, sizeof (state)); 5121 opterr = 0; 5122 while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts, 5123 NULL)) != -1) { 5124 switch (option) { 5125 case 'p': 5126 state.vs_parsable = B_TRUE; 5127 break; 5128 case 'P': 5129 flags = DLADM_OPT_PERSIST; 5130 break; 5131 case 'l': 5132 if (etherstub) 5133 die("option not supported for this command"); 5134 5135 if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >= 5136 MAXLINKNAMELEN) 5137 die("link name too long"); 5138 5139 l_arg = B_TRUE; 5140 break; 5141 case 's': 5142 if (s_arg) { 5143 die("the option -s cannot be specified " 5144 "more than once"); 5145 } 5146 s_arg = B_TRUE; 5147 break; 5148 case 'i': 5149 if (i_arg) { 5150 die("the option -i cannot be specified " 5151 "more than once"); 5152 } 5153 i_arg = B_TRUE; 5154 if (!dladm_str2interval(optarg, &interval)) 5155 die("invalid interval value '%s'", optarg); 5156 break; 5157 case 'o': 5158 o_arg = B_TRUE; 5159 fields_str = optarg; 5160 break; 5161 default: 5162 die_opterr(optopt, option, use); 5163 } 5164 } 5165 5166 if (i_arg && !s_arg) 5167 die("the option -i can be used only with -s"); 5168 5169 /* get vnic ID (optional last argument) */ 5170 if (optind == (argc - 1)) { 5171 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 5172 NULL, NULL); 5173 if (status != DLADM_STATUS_OK) { 5174 die_dlerr(status, "invalid vnic name '%s'", 5175 argv[optind]); 5176 } 5177 (void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN); 5178 } else if (optind != argc) { 5179 usage(); 5180 } 5181 5182 if (l_arg) { 5183 status = dladm_name2info(handle, state.vs_link, &dev_linkid, 5184 NULL, NULL, NULL); 5185 if (status != DLADM_STATUS_OK) { 5186 die_dlerr(status, "invalid link name '%s'", 5187 state.vs_link); 5188 } 5189 } 5190 5191 state.vs_vnic_id = linkid; 5192 state.vs_link_id = dev_linkid; 5193 state.vs_etherstub = etherstub; 5194 state.vs_found = B_FALSE; 5195 state.vs_flags = flags; 5196 5197 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 5198 if (etherstub) 5199 fields_str = all_e_fields; 5200 } 5201 pf = vnic_fields; 5202 5203 if (state.vs_parsable) 5204 ofmtflags |= OFMT_PARSABLE; 5205 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 5206 ofmt_check(oferr, state.vs_parsable, ofmt, die, warn); 5207 state.vs_ofmt = ofmt; 5208 5209 if (s_arg) { 5210 /* Display vnic statistics */ 5211 vnic_stats(&state, interval); 5212 ofmt_close(ofmt); 5213 return; 5214 } 5215 5216 /* Display vnic information */ 5217 state.vs_donefirst = B_FALSE; 5218 5219 if (linkid == DATALINK_ALL_LINKID) { 5220 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 5221 DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB, 5222 DATALINK_ANY_MEDIATYPE, flags); 5223 } else { 5224 (void) show_vnic(handle, linkid, &state); 5225 if (state.vs_status != DLADM_STATUS_OK) { 5226 ofmt_close(ofmt); 5227 die_dlerr(state.vs_status, "failed to show vnic '%s'", 5228 state.vs_vnic); 5229 } 5230 } 5231 ofmt_close(ofmt); 5232 } 5233 5234 static void 5235 do_show_vnic(int argc, char *argv[], const char *use) 5236 { 5237 do_show_vnic_common(argc, argv, use, B_FALSE); 5238 } 5239 5240 static void 5241 do_create_etherstub(int argc, char *argv[], const char *use) 5242 { 5243 uint32_t flags; 5244 char *altroot = NULL; 5245 int option; 5246 dladm_status_t status; 5247 char name[MAXLINKNAMELEN]; 5248 uchar_t mac_addr[ETHERADDRL]; 5249 5250 name[0] = '\0'; 5251 bzero(mac_addr, sizeof (mac_addr)); 5252 flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5253 5254 opterr = 0; 5255 while ((option = getopt_long(argc, argv, "tR:", 5256 etherstub_lopts, NULL)) != -1) { 5257 switch (option) { 5258 case 't': 5259 flags &= ~DLADM_OPT_PERSIST; 5260 break; 5261 case 'R': 5262 altroot = optarg; 5263 break; 5264 default: 5265 die_opterr(optopt, option, use); 5266 } 5267 } 5268 5269 /* the etherstub id is the required operand */ 5270 if (optind != (argc - 1)) 5271 usage(); 5272 5273 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 5274 die("link name too long '%s'", argv[optind]); 5275 5276 if (!dladm_valid_linkname(name)) 5277 die("invalid link name '%s'", argv[optind]); 5278 5279 if (altroot != NULL) 5280 altroot_cmd(altroot, argc, argv); 5281 5282 status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID, 5283 VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, 5284 VRRP_VRID_NONE, AF_UNSPEC, NULL, NULL, flags); 5285 if (status != DLADM_STATUS_OK) 5286 die_dlerr(status, "etherstub creation failed"); 5287 } 5288 5289 static void 5290 do_delete_etherstub(int argc, char *argv[], const char *use) 5291 { 5292 do_delete_vnic_common(argc, argv, use, B_TRUE); 5293 } 5294 5295 /* ARGSUSED */ 5296 static void 5297 do_show_etherstub(int argc, char *argv[], const char *use) 5298 { 5299 do_show_vnic_common(argc, argv, use, B_TRUE); 5300 } 5301 5302 /* ARGSUSED */ 5303 static void 5304 do_up_simnet(int argc, char *argv[], const char *use) 5305 { 5306 (void) dladm_simnet_up(handle, DATALINK_ALL_LINKID, 0); 5307 } 5308 5309 static void 5310 do_create_simnet(int argc, char *argv[], const char *use) 5311 { 5312 uint32_t flags; 5313 char *altroot = NULL; 5314 char *media = NULL; 5315 uint32_t mtype = DL_ETHER; 5316 int option; 5317 dladm_status_t status; 5318 char name[MAXLINKNAMELEN]; 5319 5320 name[0] = '\0'; 5321 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5322 5323 opterr = 0; 5324 while ((option = getopt_long(argc, argv, ":tR:m:", 5325 simnet_lopts, NULL)) != -1) { 5326 switch (option) { 5327 case 't': 5328 flags &= ~DLADM_OPT_PERSIST; 5329 break; 5330 case 'R': 5331 altroot = optarg; 5332 break; 5333 case 'm': 5334 media = optarg; 5335 break; 5336 default: 5337 die_opterr(optopt, option, use); 5338 } 5339 } 5340 5341 /* the simnet id is the required operand */ 5342 if (optind != (argc - 1)) 5343 usage(); 5344 5345 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 5346 die("link name too long '%s'", argv[optind]); 5347 5348 if (!dladm_valid_linkname(name)) 5349 die("invalid link name '%s'", name); 5350 5351 if (media != NULL) { 5352 mtype = dladm_str2media(media); 5353 if (mtype != DL_ETHER && mtype != DL_WIFI) 5354 die("media type '%s' is not supported", media); 5355 } 5356 5357 if (altroot != NULL) 5358 altroot_cmd(altroot, argc, argv); 5359 5360 status = dladm_simnet_create(handle, name, mtype, flags); 5361 if (status != DLADM_STATUS_OK) 5362 die_dlerr(status, "simnet creation failed"); 5363 } 5364 5365 static void 5366 do_delete_simnet(int argc, char *argv[], const char *use) 5367 { 5368 int option; 5369 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5370 datalink_id_t linkid; 5371 char *altroot = NULL; 5372 dladm_status_t status; 5373 dladm_simnet_attr_t slinfo; 5374 5375 opterr = 0; 5376 while ((option = getopt_long(argc, argv, ":tR:", simnet_lopts, 5377 NULL)) != -1) { 5378 switch (option) { 5379 case 't': 5380 flags &= ~DLADM_OPT_PERSIST; 5381 break; 5382 case 'R': 5383 altroot = optarg; 5384 break; 5385 default: 5386 die_opterr(optopt, option, use); 5387 } 5388 } 5389 5390 /* get simnet name (required last argument) */ 5391 if (optind != (argc - 1)) 5392 usage(); 5393 5394 if (!dladm_valid_linkname(argv[optind])) 5395 die("invalid link name '%s'", argv[optind]); 5396 5397 if (altroot != NULL) 5398 altroot_cmd(altroot, argc, argv); 5399 5400 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 5401 NULL); 5402 if (status != DLADM_STATUS_OK) 5403 die("simnet '%s' not found", argv[optind]); 5404 5405 if ((status = dladm_simnet_info(handle, linkid, &slinfo, 5406 flags)) != DLADM_STATUS_OK) 5407 die_dlerr(status, "failed to retrieve simnet information"); 5408 5409 status = dladm_simnet_delete(handle, linkid, flags); 5410 if (status != DLADM_STATUS_OK) 5411 die_dlerr(status, "simnet deletion failed"); 5412 } 5413 5414 static void 5415 do_modify_simnet(int argc, char *argv[], const char *use) 5416 { 5417 int option; 5418 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5419 datalink_id_t linkid; 5420 datalink_id_t peer_linkid; 5421 char *altroot = NULL; 5422 dladm_status_t status; 5423 boolean_t p_arg = B_FALSE; 5424 5425 opterr = 0; 5426 while ((option = getopt_long(argc, argv, ":tR:p:", simnet_lopts, 5427 NULL)) != -1) { 5428 switch (option) { 5429 case 't': 5430 flags &= ~DLADM_OPT_PERSIST; 5431 break; 5432 case 'R': 5433 altroot = optarg; 5434 break; 5435 case 'p': 5436 if (p_arg) 5437 die_optdup(option); 5438 p_arg = B_TRUE; 5439 if (strcasecmp(optarg, "none") == 0) 5440 peer_linkid = DATALINK_INVALID_LINKID; 5441 else if (dladm_name2info(handle, optarg, &peer_linkid, 5442 NULL, NULL, NULL) != DLADM_STATUS_OK) 5443 die("invalid peer link name '%s'", optarg); 5444 break; 5445 default: 5446 die_opterr(optopt, option, use); 5447 } 5448 } 5449 5450 /* get simnet name (required last argument) */ 5451 if (optind != (argc - 1)) 5452 usage(); 5453 5454 /* Nothing to do if no peer link argument */ 5455 if (!p_arg) 5456 return; 5457 5458 if (altroot != NULL) 5459 altroot_cmd(altroot, argc, argv); 5460 5461 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 5462 NULL); 5463 if (status != DLADM_STATUS_OK) 5464 die("invalid link name '%s'", argv[optind]); 5465 5466 status = dladm_simnet_modify(handle, linkid, peer_linkid, flags); 5467 if (status != DLADM_STATUS_OK) 5468 die_dlerr(status, "simnet modification failed"); 5469 } 5470 5471 static dladm_status_t 5472 print_simnet(show_state_t *state, datalink_id_t linkid) 5473 { 5474 dladm_simnet_attr_t slinfo; 5475 uint32_t flags; 5476 dladm_status_t status; 5477 simnet_fields_buf_t slbuf; 5478 char mstr[ETHERADDRL * 3]; 5479 5480 bzero(&slbuf, sizeof (slbuf)); 5481 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL, 5482 slbuf.simnet_name, sizeof (slbuf.simnet_name))) 5483 != DLADM_STATUS_OK) 5484 return (status); 5485 5486 if (!(state->ls_flags & flags)) 5487 return (DLADM_STATUS_NOTFOUND); 5488 5489 if ((status = dladm_simnet_info(handle, linkid, &slinfo, 5490 state->ls_flags)) != DLADM_STATUS_OK) 5491 return (status); 5492 5493 if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID && 5494 (status = dladm_datalink_id2info(handle, slinfo.sna_peer_link_id, 5495 NULL, NULL, NULL, slbuf.simnet_otherlink, 5496 sizeof (slbuf.simnet_otherlink))) != 5497 DLADM_STATUS_OK) 5498 return (status); 5499 5500 if (slinfo.sna_mac_len > sizeof (slbuf.simnet_macaddr)) 5501 return (DLADM_STATUS_BADVAL); 5502 5503 (void) strlcpy(slbuf.simnet_macaddr, 5504 dladm_aggr_macaddr2str(slinfo.sna_mac_addr, mstr), 5505 sizeof (slbuf.simnet_macaddr)); 5506 (void) dladm_media2str(slinfo.sna_type, slbuf.simnet_media); 5507 5508 ofmt_print(state->ls_ofmt, &slbuf); 5509 return (status); 5510 } 5511 5512 /* ARGSUSED */ 5513 static int 5514 show_simnet(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5515 { 5516 show_state_t *state = arg; 5517 5518 state->ls_status = print_simnet(state, linkid); 5519 return (DLADM_WALK_CONTINUE); 5520 } 5521 5522 static void 5523 do_show_simnet(int argc, char *argv[], const char *use) 5524 { 5525 int option; 5526 uint32_t flags = DLADM_OPT_ACTIVE; 5527 boolean_t p_arg = B_FALSE; 5528 datalink_id_t linkid = DATALINK_ALL_LINKID; 5529 show_state_t state; 5530 dladm_status_t status; 5531 boolean_t o_arg = B_FALSE; 5532 ofmt_handle_t ofmt; 5533 ofmt_status_t oferr; 5534 char *all_fields = "link,media,macaddress,otherlink"; 5535 char *fields_str = all_fields; 5536 uint_t ofmtflags = 0; 5537 5538 bzero(&state, sizeof (state)); 5539 5540 opterr = 0; 5541 while ((option = getopt_long(argc, argv, ":pPo:", 5542 show_lopts, NULL)) != -1) { 5543 switch (option) { 5544 case 'p': 5545 if (p_arg) 5546 die_optdup(option); 5547 5548 p_arg = B_TRUE; 5549 state.ls_parsable = p_arg; 5550 break; 5551 case 'P': 5552 if (flags != DLADM_OPT_ACTIVE) 5553 die_optdup(option); 5554 5555 flags = DLADM_OPT_PERSIST; 5556 break; 5557 case 'o': 5558 o_arg = B_TRUE; 5559 fields_str = optarg; 5560 break; 5561 default: 5562 die_opterr(optopt, option, use); 5563 break; 5564 } 5565 } 5566 5567 if (p_arg && !o_arg) 5568 die("-p requires -o"); 5569 5570 if (strcasecmp(fields_str, "all") == 0) { 5571 if (p_arg) 5572 die("\"-o all\" is invalid with -p"); 5573 fields_str = all_fields; 5574 } 5575 5576 /* get link name (optional last argument) */ 5577 if (optind == (argc-1)) { 5578 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5579 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5580 die_dlerr(status, "link %s is not valid", argv[optind]); 5581 } 5582 } else if (optind != argc) { 5583 usage(); 5584 } 5585 5586 state.ls_flags = flags; 5587 state.ls_donefirst = B_FALSE; 5588 if (state.ls_parsable) 5589 ofmtflags |= OFMT_PARSABLE; 5590 oferr = ofmt_open(fields_str, simnet_fields, ofmtflags, 0, &ofmt); 5591 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 5592 state.ls_ofmt = ofmt; 5593 5594 if (linkid == DATALINK_ALL_LINKID) { 5595 (void) dladm_walk_datalink_id(show_simnet, handle, &state, 5596 DATALINK_CLASS_SIMNET, DATALINK_ANY_MEDIATYPE, flags); 5597 } else { 5598 (void) show_simnet(handle, linkid, &state); 5599 if (state.ls_status != DLADM_STATUS_OK) { 5600 ofmt_close(ofmt); 5601 die_dlerr(state.ls_status, "failed to show simnet %s", 5602 argv[optind]); 5603 } 5604 } 5605 ofmt_close(ofmt); 5606 } 5607 5608 static void 5609 link_stats(datalink_id_t linkid, uint_t interval, char *fields_str, 5610 show_state_t *state) 5611 { 5612 ofmt_handle_t ofmt; 5613 ofmt_status_t oferr; 5614 uint_t ofmtflags = 0; 5615 5616 if (state->ls_parsable) 5617 ofmtflags |= OFMT_PARSABLE; 5618 oferr = ofmt_open(fields_str, link_s_fields, ofmtflags, 0, &ofmt); 5619 ofmt_check(oferr, state->ls_parsable, ofmt, die, warn); 5620 state->ls_ofmt = ofmt; 5621 5622 /* 5623 * If an interval is specified, continuously show the stats 5624 * only for the first MAC port. 5625 */ 5626 state->ls_firstonly = (interval != 0); 5627 5628 for (;;) { 5629 state->ls_donefirst = B_FALSE; 5630 if (linkid == DATALINK_ALL_LINKID) { 5631 (void) dladm_walk_datalink_id(show_link_stats, handle, 5632 state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 5633 DLADM_OPT_ACTIVE); 5634 } else { 5635 (void) show_link_stats(handle, linkid, state); 5636 } 5637 5638 if (interval == 0) 5639 break; 5640 5641 (void) fflush(stdout); 5642 (void) sleep(interval); 5643 } 5644 ofmt_close(ofmt); 5645 } 5646 5647 static void 5648 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) 5649 { 5650 /* 5651 * If an interval is specified, continuously show the stats 5652 * only for the first group. 5653 */ 5654 state->gs_firstonly = (interval != 0); 5655 5656 for (;;) { 5657 state->gs_donefirst = B_FALSE; 5658 if (linkid == DATALINK_ALL_LINKID) 5659 (void) dladm_walk_datalink_id(show_aggr, handle, state, 5660 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 5661 DLADM_OPT_ACTIVE); 5662 else 5663 (void) show_aggr(handle, linkid, state); 5664 5665 if (interval == 0) 5666 break; 5667 5668 (void) fflush(stdout); 5669 (void) sleep(interval); 5670 } 5671 } 5672 5673 /* ARGSUSED */ 5674 static void 5675 vnic_stats(show_vnic_state_t *sp, uint32_t interval) 5676 { 5677 show_vnic_state_t state; 5678 boolean_t specific_link, specific_dev; 5679 5680 /* Display vnic statistics */ 5681 dump_vnics_head(sp->vs_link); 5682 5683 bzero(&state, sizeof (state)); 5684 state.vs_stats = B_TRUE; 5685 state.vs_vnic_id = sp->vs_vnic_id; 5686 state.vs_link_id = sp->vs_link_id; 5687 5688 /* 5689 * If an interval is specified, and a vnic ID is not specified, 5690 * continuously show the stats only for the first vnic. 5691 */ 5692 specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID); 5693 specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID); 5694 5695 for (;;) { 5696 /* Get stats for each vnic */ 5697 state.vs_found = B_FALSE; 5698 state.vs_donefirst = B_FALSE; 5699 state.vs_printstats = B_FALSE; 5700 state.vs_flags = DLADM_OPT_ACTIVE; 5701 5702 if (!specific_link) { 5703 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 5704 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 5705 DLADM_OPT_ACTIVE); 5706 } else { 5707 (void) show_vnic(handle, sp->vs_vnic_id, &state); 5708 if (state.vs_status != DLADM_STATUS_OK) { 5709 die_dlerr(state.vs_status, 5710 "failed to show vnic '%s'", sp->vs_vnic); 5711 } 5712 } 5713 5714 if (specific_link && !state.vs_found) 5715 die("non-existent vnic '%s'", sp->vs_vnic); 5716 if (specific_dev && !state.vs_found) 5717 die("device %s has no vnics", sp->vs_link); 5718 5719 /* Show totals */ 5720 if ((specific_link | specific_dev) && !interval) { 5721 (void) printf("Total"); 5722 (void) printf("\t%-10llu", 5723 state.vs_totalstats.ipackets); 5724 (void) printf("%-12llu", 5725 state.vs_totalstats.rbytes); 5726 (void) printf("%-10llu", 5727 state.vs_totalstats.opackets); 5728 (void) printf("%-12llu\n", 5729 state.vs_totalstats.obytes); 5730 } 5731 5732 /* Show stats for each vnic */ 5733 state.vs_donefirst = B_FALSE; 5734 state.vs_printstats = B_TRUE; 5735 5736 if (!specific_link) { 5737 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 5738 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 5739 DLADM_OPT_ACTIVE); 5740 } else { 5741 (void) show_vnic(handle, sp->vs_vnic_id, &state); 5742 if (state.vs_status != DLADM_STATUS_OK) { 5743 die_dlerr(state.vs_status, 5744 "failed to show vnic '%s'", sp->vs_vnic); 5745 } 5746 } 5747 5748 if (interval == 0) 5749 break; 5750 5751 (void) fflush(stdout); 5752 (void) sleep(interval); 5753 } 5754 } 5755 5756 static void 5757 get_mac_stats(const char *dev, pktsum_t *stats) 5758 { 5759 kstat_ctl_t *kcp; 5760 kstat_t *ksp; 5761 char module[DLPI_LINKNAME_MAX]; 5762 uint_t instance; 5763 5764 5765 bzero(stats, sizeof (*stats)); 5766 5767 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 5768 return; 5769 5770 if ((kcp = kstat_open()) == NULL) { 5771 warn("kstat open operation failed"); 5772 return; 5773 } 5774 5775 ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL); 5776 if (ksp != NULL) 5777 dladm_get_stats(kcp, ksp, stats); 5778 5779 (void) kstat_close(kcp); 5780 5781 } 5782 5783 static void 5784 get_link_stats(const char *link, pktsum_t *stats) 5785 { 5786 kstat_ctl_t *kcp; 5787 kstat_t *ksp; 5788 5789 bzero(stats, sizeof (*stats)); 5790 5791 if ((kcp = kstat_open()) == NULL) { 5792 warn("kstat_open operation failed"); 5793 return; 5794 } 5795 5796 ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL); 5797 5798 if (ksp != NULL) 5799 dladm_get_stats(kcp, ksp, stats); 5800 5801 (void) kstat_close(kcp); 5802 } 5803 5804 static int 5805 query_kstat(char *module, int instance, const char *name, const char *stat, 5806 uint8_t type, void *val) 5807 { 5808 kstat_ctl_t *kcp; 5809 kstat_t *ksp; 5810 5811 if ((kcp = kstat_open()) == NULL) { 5812 warn("kstat open operation failed"); 5813 return (-1); 5814 } 5815 5816 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 5817 /* 5818 * The kstat query could fail if the underlying MAC 5819 * driver was already detached. 5820 */ 5821 goto bail; 5822 } 5823 5824 if (kstat_read(kcp, ksp, NULL) == -1) { 5825 warn("kstat read failed"); 5826 goto bail; 5827 } 5828 5829 if (dladm_kstat_value(ksp, stat, type, val) < 0) 5830 goto bail; 5831 5832 (void) kstat_close(kcp); 5833 return (0); 5834 5835 bail: 5836 (void) kstat_close(kcp); 5837 return (-1); 5838 } 5839 5840 static int 5841 get_one_kstat(const char *name, const char *stat, uint8_t type, 5842 void *val, boolean_t islink) 5843 { 5844 char module[DLPI_LINKNAME_MAX]; 5845 uint_t instance; 5846 5847 if (islink) { 5848 return (query_kstat("link", 0, name, stat, type, val)); 5849 } else { 5850 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS) 5851 return (-1); 5852 5853 return (query_kstat(module, instance, "mac", stat, type, val)); 5854 } 5855 } 5856 5857 static uint64_t 5858 get_ifspeed(const char *name, boolean_t islink) 5859 { 5860 uint64_t ifspeed = 0; 5861 5862 (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64, 5863 &ifspeed, islink); 5864 5865 return (ifspeed); 5866 } 5867 5868 static const char * 5869 get_linkstate(const char *name, boolean_t islink, char *buf) 5870 { 5871 link_state_t linkstate; 5872 5873 if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32, 5874 &linkstate, islink) != 0) { 5875 (void) strlcpy(buf, "?", DLADM_STRSIZE); 5876 return (buf); 5877 } 5878 return (dladm_linkstate2str(linkstate, buf)); 5879 } 5880 5881 static const char * 5882 get_linkduplex(const char *name, boolean_t islink, char *buf) 5883 { 5884 link_duplex_t linkduplex; 5885 5886 if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32, 5887 &linkduplex, islink) != 0) { 5888 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 5889 return (buf); 5890 } 5891 5892 return (dladm_linkduplex2str(linkduplex, buf)); 5893 } 5894 5895 static int 5896 parse_wifi_fields(char *str, ofmt_handle_t *ofmt, uint_t cmdtype, 5897 boolean_t parsable) 5898 { 5899 ofmt_field_t *template, *of; 5900 ofmt_cb_t *fn; 5901 ofmt_status_t oferr; 5902 5903 if (cmdtype == WIFI_CMD_SCAN) { 5904 template = wifi_common_fields; 5905 if (str == NULL) 5906 str = def_scan_wifi_fields; 5907 if (strcasecmp(str, "all") == 0) 5908 str = all_scan_wifi_fields; 5909 fn = print_wlan_attr_cb; 5910 } else if (cmdtype == WIFI_CMD_SHOW) { 5911 bcopy(wifi_common_fields, &wifi_show_fields[2], 5912 sizeof (wifi_common_fields)); 5913 template = wifi_show_fields; 5914 if (str == NULL) 5915 str = def_show_wifi_fields; 5916 if (strcasecmp(str, "all") == 0) 5917 str = all_show_wifi_fields; 5918 fn = print_link_attr_cb; 5919 } else { 5920 return (-1); 5921 } 5922 5923 for (of = template; of->of_name != NULL; of++) { 5924 if (of->of_cb == NULL) 5925 of->of_cb = fn; 5926 } 5927 5928 oferr = ofmt_open(str, template, (parsable ? OFMT_PARSABLE : 0), 5929 0, ofmt); 5930 ofmt_check(oferr, parsable, *ofmt, die, warn); 5931 return (0); 5932 } 5933 5934 typedef struct print_wifi_state { 5935 char *ws_link; 5936 boolean_t ws_parsable; 5937 boolean_t ws_header; 5938 ofmt_handle_t ws_ofmt; 5939 } print_wifi_state_t; 5940 5941 typedef struct wlan_scan_args_s { 5942 print_wifi_state_t *ws_state; 5943 void *ws_attr; 5944 } wlan_scan_args_t; 5945 5946 static boolean_t 5947 print_wlan_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 5948 { 5949 wlan_scan_args_t *w = ofarg->ofmt_cbarg; 5950 print_wifi_state_t *statep = w->ws_state; 5951 dladm_wlan_attr_t *attrp = w->ws_attr; 5952 char tmpbuf[DLADM_STRSIZE]; 5953 5954 if (ofarg->ofmt_id == 0) { 5955 (void) strlcpy(buf, (char *)statep->ws_link, bufsize); 5956 return (B_TRUE); 5957 } 5958 5959 if ((ofarg->ofmt_id & attrp->wa_valid) == 0) 5960 return (B_TRUE); 5961 5962 switch (ofarg->ofmt_id) { 5963 case DLADM_WLAN_ATTR_ESSID: 5964 (void) dladm_wlan_essid2str(&attrp->wa_essid, tmpbuf); 5965 break; 5966 case DLADM_WLAN_ATTR_BSSID: 5967 (void) dladm_wlan_bssid2str(&attrp->wa_bssid, tmpbuf); 5968 break; 5969 case DLADM_WLAN_ATTR_SECMODE: 5970 (void) dladm_wlan_secmode2str(&attrp->wa_secmode, tmpbuf); 5971 break; 5972 case DLADM_WLAN_ATTR_STRENGTH: 5973 (void) dladm_wlan_strength2str(&attrp->wa_strength, tmpbuf); 5974 break; 5975 case DLADM_WLAN_ATTR_MODE: 5976 (void) dladm_wlan_mode2str(&attrp->wa_mode, tmpbuf); 5977 break; 5978 case DLADM_WLAN_ATTR_SPEED: 5979 (void) dladm_wlan_speed2str(&attrp->wa_speed, tmpbuf); 5980 (void) strlcat(tmpbuf, "Mb", sizeof (tmpbuf)); 5981 break; 5982 case DLADM_WLAN_ATTR_AUTH: 5983 (void) dladm_wlan_auth2str(&attrp->wa_auth, tmpbuf); 5984 break; 5985 case DLADM_WLAN_ATTR_BSSTYPE: 5986 (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, tmpbuf); 5987 break; 5988 } 5989 (void) strlcpy(buf, tmpbuf, bufsize); 5990 5991 return (B_TRUE); 5992 } 5993 5994 static boolean_t 5995 print_scan_results(void *arg, dladm_wlan_attr_t *attrp) 5996 { 5997 print_wifi_state_t *statep = arg; 5998 wlan_scan_args_t warg; 5999 6000 bzero(&warg, sizeof (warg)); 6001 warg.ws_state = statep; 6002 warg.ws_attr = attrp; 6003 ofmt_print(statep->ws_ofmt, &warg); 6004 return (B_TRUE); 6005 } 6006 6007 static int 6008 scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6009 { 6010 print_wifi_state_t *statep = arg; 6011 dladm_status_t status; 6012 char link[MAXLINKNAMELEN]; 6013 6014 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 6015 sizeof (link))) != DLADM_STATUS_OK) { 6016 return (DLADM_WALK_CONTINUE); 6017 } 6018 6019 statep->ws_link = link; 6020 status = dladm_wlan_scan(dh, linkid, statep, print_scan_results); 6021 if (status != DLADM_STATUS_OK) 6022 die_dlerr(status, "cannot scan link '%s'", statep->ws_link); 6023 6024 return (DLADM_WALK_CONTINUE); 6025 } 6026 6027 static boolean_t 6028 print_wifi_status_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 6029 { 6030 static char tmpbuf[DLADM_STRSIZE]; 6031 wlan_scan_args_t *w = ofarg->ofmt_cbarg; 6032 dladm_wlan_linkattr_t *attrp = w->ws_attr; 6033 6034 if ((ofarg->ofmt_id & attrp->la_valid) != 0) { 6035 (void) dladm_wlan_linkstatus2str(&attrp->la_status, tmpbuf); 6036 (void) strlcpy(buf, tmpbuf, bufsize); 6037 } 6038 return (B_TRUE); 6039 } 6040 6041 static boolean_t 6042 print_link_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 6043 { 6044 wlan_scan_args_t *w = ofarg->ofmt_cbarg, w1; 6045 print_wifi_state_t *statep = w->ws_state; 6046 dladm_wlan_linkattr_t *attrp = w->ws_attr; 6047 6048 bzero(&w1, sizeof (w1)); 6049 w1.ws_state = statep; 6050 w1.ws_attr = &attrp->la_wlan_attr; 6051 ofarg->ofmt_cbarg = &w1; 6052 return (print_wlan_attr_cb(ofarg, buf, bufsize)); 6053 } 6054 6055 static int 6056 show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6057 { 6058 print_wifi_state_t *statep = arg; 6059 dladm_wlan_linkattr_t attr; 6060 dladm_status_t status; 6061 char link[MAXLINKNAMELEN]; 6062 wlan_scan_args_t warg; 6063 6064 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 6065 sizeof (link))) != DLADM_STATUS_OK) { 6066 return (DLADM_WALK_CONTINUE); 6067 } 6068 6069 /* dladm_wlan_get_linkattr() memsets attr with 0 */ 6070 status = dladm_wlan_get_linkattr(dh, linkid, &attr); 6071 if (status != DLADM_STATUS_OK) 6072 die_dlerr(status, "cannot get link attributes for %s", link); 6073 6074 statep->ws_link = link; 6075 6076 bzero(&warg, sizeof (warg)); 6077 warg.ws_state = statep; 6078 warg.ws_attr = &attr; 6079 ofmt_print(statep->ws_ofmt, &warg); 6080 return (DLADM_WALK_CONTINUE); 6081 } 6082 6083 static void 6084 do_display_wifi(int argc, char **argv, int cmd, const char *use) 6085 { 6086 int option; 6087 char *fields_str = NULL; 6088 int (*callback)(dladm_handle_t, datalink_id_t, void *); 6089 print_wifi_state_t state; 6090 datalink_id_t linkid = DATALINK_ALL_LINKID; 6091 dladm_status_t status; 6092 6093 if (cmd == WIFI_CMD_SCAN) 6094 callback = scan_wifi; 6095 else if (cmd == WIFI_CMD_SHOW) 6096 callback = show_wifi; 6097 else 6098 return; 6099 6100 state.ws_parsable = B_FALSE; 6101 state.ws_header = B_TRUE; 6102 opterr = 0; 6103 while ((option = getopt_long(argc, argv, ":o:p", 6104 wifi_longopts, NULL)) != -1) { 6105 switch (option) { 6106 case 'o': 6107 fields_str = optarg; 6108 break; 6109 case 'p': 6110 state.ws_parsable = B_TRUE; 6111 break; 6112 default: 6113 die_opterr(optopt, option, use); 6114 } 6115 } 6116 6117 if (state.ws_parsable && fields_str == NULL) 6118 die("-p requires -o"); 6119 6120 if (state.ws_parsable && strcasecmp(fields_str, "all") == 0) 6121 die("\"-o all\" is invalid with -p"); 6122 6123 if (optind == (argc - 1)) { 6124 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6125 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 6126 die_dlerr(status, "link %s is not valid", argv[optind]); 6127 } 6128 } else if (optind != argc) { 6129 usage(); 6130 } 6131 6132 if (parse_wifi_fields(fields_str, &state.ws_ofmt, cmd, 6133 state.ws_parsable) < 0) 6134 die("invalid field(s) specified"); 6135 6136 if (linkid == DATALINK_ALL_LINKID) { 6137 (void) dladm_walk_datalink_id(callback, handle, &state, 6138 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 6139 DL_WIFI, DLADM_OPT_ACTIVE); 6140 } else { 6141 (void) (*callback)(handle, linkid, &state); 6142 } 6143 ofmt_close(state.ws_ofmt); 6144 } 6145 6146 static void 6147 do_scan_wifi(int argc, char **argv, const char *use) 6148 { 6149 do_display_wifi(argc, argv, WIFI_CMD_SCAN, use); 6150 } 6151 6152 static void 6153 do_show_wifi(int argc, char **argv, const char *use) 6154 { 6155 do_display_wifi(argc, argv, WIFI_CMD_SHOW, use); 6156 } 6157 6158 typedef struct wlan_count_attr { 6159 uint_t wc_count; 6160 datalink_id_t wc_linkid; 6161 } wlan_count_attr_t; 6162 6163 /* ARGSUSED */ 6164 static int 6165 do_count_wlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6166 { 6167 wlan_count_attr_t *cp = arg; 6168 6169 if (cp->wc_count == 0) 6170 cp->wc_linkid = linkid; 6171 cp->wc_count++; 6172 return (DLADM_WALK_CONTINUE); 6173 } 6174 6175 static int 6176 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) 6177 { 6178 uint_t i; 6179 dladm_wlan_key_t *wk; 6180 int nfields = 1; 6181 char *field, *token, *lasts = NULL, c; 6182 6183 token = str; 6184 while ((c = *token++) != NULL) { 6185 if (c == ',') 6186 nfields++; 6187 } 6188 token = strdup(str); 6189 if (token == NULL) 6190 return (-1); 6191 6192 wk = malloc(nfields * sizeof (dladm_wlan_key_t)); 6193 if (wk == NULL) 6194 goto fail; 6195 6196 token = str; 6197 for (i = 0; i < nfields; i++) { 6198 char *s; 6199 dladm_secobj_class_t class; 6200 dladm_status_t status; 6201 6202 field = strtok_r(token, ",", &lasts); 6203 token = NULL; 6204 6205 (void) strlcpy(wk[i].wk_name, field, 6206 DLADM_WLAN_MAX_KEYNAME_LEN); 6207 6208 wk[i].wk_idx = 1; 6209 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 6210 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 6211 goto fail; 6212 6213 wk[i].wk_idx = (uint_t)(s[1] - '0'); 6214 *s = '\0'; 6215 } 6216 wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN; 6217 6218 status = dladm_get_secobj(handle, wk[i].wk_name, &class, 6219 wk[i].wk_val, &wk[i].wk_len, 0); 6220 if (status != DLADM_STATUS_OK) { 6221 if (status == DLADM_STATUS_NOTFOUND) { 6222 status = dladm_get_secobj(handle, wk[i].wk_name, 6223 &class, wk[i].wk_val, &wk[i].wk_len, 6224 DLADM_OPT_PERSIST); 6225 } 6226 if (status != DLADM_STATUS_OK) 6227 goto fail; 6228 } 6229 wk[i].wk_class = class; 6230 } 6231 *keys = wk; 6232 *key_countp = i; 6233 free(token); 6234 return (0); 6235 fail: 6236 free(wk); 6237 free(token); 6238 return (-1); 6239 } 6240 6241 static void 6242 do_connect_wifi(int argc, char **argv, const char *use) 6243 { 6244 int option; 6245 dladm_wlan_attr_t attr, *attrp; 6246 dladm_status_t status = DLADM_STATUS_OK; 6247 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 6248 datalink_id_t linkid = DATALINK_ALL_LINKID; 6249 dladm_wlan_key_t *keys = NULL; 6250 uint_t key_count = 0; 6251 uint_t flags = 0; 6252 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 6253 char buf[DLADM_STRSIZE]; 6254 6255 opterr = 0; 6256 (void) memset(&attr, 0, sizeof (attr)); 6257 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 6258 wifi_longopts, NULL)) != -1) { 6259 switch (option) { 6260 case 'e': 6261 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 6262 if (status != DLADM_STATUS_OK) 6263 die("invalid ESSID '%s'", optarg); 6264 6265 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 6266 /* 6267 * Try to connect without doing a scan. 6268 */ 6269 flags |= DLADM_WLAN_CONNECT_NOSCAN; 6270 break; 6271 case 'i': 6272 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 6273 if (status != DLADM_STATUS_OK) 6274 die("invalid BSSID %s", optarg); 6275 6276 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 6277 break; 6278 case 'a': 6279 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 6280 if (status != DLADM_STATUS_OK) 6281 die("invalid authentication mode '%s'", optarg); 6282 6283 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 6284 break; 6285 case 'm': 6286 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 6287 if (status != DLADM_STATUS_OK) 6288 die("invalid mode '%s'", optarg); 6289 6290 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 6291 break; 6292 case 'b': 6293 if ((status = dladm_wlan_str2bsstype(optarg, 6294 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 6295 die("invalid bsstype '%s'", optarg); 6296 } 6297 6298 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 6299 break; 6300 case 's': 6301 if ((status = dladm_wlan_str2secmode(optarg, 6302 &attr.wa_secmode)) != DLADM_STATUS_OK) { 6303 die("invalid security mode '%s'", optarg); 6304 } 6305 6306 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 6307 break; 6308 case 'k': 6309 if (parse_wlan_keys(optarg, &keys, &key_count) < 0) 6310 die("invalid key(s) '%s'", optarg); 6311 6312 if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP) 6313 keysecmode = DLADM_WLAN_SECMODE_WEP; 6314 else 6315 keysecmode = DLADM_WLAN_SECMODE_WPA; 6316 break; 6317 case 'T': 6318 if (strcasecmp(optarg, "forever") == 0) { 6319 timeout = -1; 6320 break; 6321 } 6322 if (!str2int(optarg, &timeout) || timeout < 0) 6323 die("invalid timeout value '%s'", optarg); 6324 break; 6325 case 'c': 6326 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 6327 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 6328 break; 6329 default: 6330 die_opterr(optopt, option, use); 6331 break; 6332 } 6333 } 6334 6335 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 6336 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) { 6337 die("key required for security mode '%s'", 6338 dladm_wlan_secmode2str(&attr.wa_secmode, buf)); 6339 } 6340 } else { 6341 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 6342 attr.wa_secmode != keysecmode) 6343 die("incompatible -s and -k options"); 6344 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 6345 attr.wa_secmode = keysecmode; 6346 } 6347 6348 if (optind == (argc - 1)) { 6349 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6350 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 6351 die_dlerr(status, "link %s is not valid", argv[optind]); 6352 } 6353 } else if (optind != argc) { 6354 usage(); 6355 } 6356 6357 if (linkid == DATALINK_ALL_LINKID) { 6358 wlan_count_attr_t wcattr; 6359 6360 wcattr.wc_linkid = DATALINK_INVALID_LINKID; 6361 wcattr.wc_count = 0; 6362 (void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr, 6363 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 6364 DL_WIFI, DLADM_OPT_ACTIVE); 6365 if (wcattr.wc_count == 0) { 6366 die("no wifi links are available"); 6367 } else if (wcattr.wc_count > 1) { 6368 die("link name is required when more than one wifi " 6369 "link is available"); 6370 } 6371 linkid = wcattr.wc_linkid; 6372 } 6373 attrp = (attr.wa_valid == 0) ? NULL : &attr; 6374 again: 6375 if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys, 6376 key_count, flags)) != DLADM_STATUS_OK) { 6377 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 6378 /* 6379 * Try again with scanning and filtering. 6380 */ 6381 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 6382 goto again; 6383 } 6384 6385 if (status == DLADM_STATUS_NOTFOUND) { 6386 if (attr.wa_valid == 0) { 6387 die("no wifi networks are available"); 6388 } else { 6389 die("no wifi networks with the specified " 6390 "criteria are available"); 6391 } 6392 } 6393 die_dlerr(status, "cannot connect"); 6394 } 6395 free(keys); 6396 } 6397 6398 /* ARGSUSED */ 6399 static int 6400 do_all_disconnect_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6401 { 6402 dladm_status_t status; 6403 6404 status = dladm_wlan_disconnect(dh, linkid); 6405 if (status != DLADM_STATUS_OK) 6406 warn_dlerr(status, "cannot disconnect link"); 6407 6408 return (DLADM_WALK_CONTINUE); 6409 } 6410 6411 static void 6412 do_disconnect_wifi(int argc, char **argv, const char *use) 6413 { 6414 int option; 6415 datalink_id_t linkid = DATALINK_ALL_LINKID; 6416 boolean_t all_links = B_FALSE; 6417 dladm_status_t status; 6418 wlan_count_attr_t wcattr; 6419 6420 opterr = 0; 6421 while ((option = getopt_long(argc, argv, ":a", 6422 wifi_longopts, NULL)) != -1) { 6423 switch (option) { 6424 case 'a': 6425 all_links = B_TRUE; 6426 break; 6427 default: 6428 die_opterr(optopt, option, use); 6429 break; 6430 } 6431 } 6432 6433 if (optind == (argc - 1)) { 6434 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6435 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 6436 die_dlerr(status, "link %s is not valid", argv[optind]); 6437 } 6438 } else if (optind != argc) { 6439 usage(); 6440 } 6441 6442 if (linkid == DATALINK_ALL_LINKID) { 6443 if (!all_links) { 6444 wcattr.wc_linkid = linkid; 6445 wcattr.wc_count = 0; 6446 (void) dladm_walk_datalink_id(do_count_wlan, handle, 6447 &wcattr, 6448 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 6449 DL_WIFI, DLADM_OPT_ACTIVE); 6450 if (wcattr.wc_count == 0) { 6451 die("no wifi links are available"); 6452 } else if (wcattr.wc_count > 1) { 6453 die("link name is required when more than " 6454 "one wifi link is available"); 6455 } 6456 linkid = wcattr.wc_linkid; 6457 } else { 6458 (void) dladm_walk_datalink_id(do_all_disconnect_wifi, 6459 handle, NULL, 6460 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 6461 DL_WIFI, DLADM_OPT_ACTIVE); 6462 return; 6463 } 6464 } 6465 status = dladm_wlan_disconnect(handle, linkid); 6466 if (status != DLADM_STATUS_OK) 6467 die_dlerr(status, "cannot disconnect"); 6468 } 6469 6470 static void 6471 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, 6472 const char *propname, dladm_prop_type_t type, const char *format, 6473 char **pptr) 6474 { 6475 int i; 6476 char *ptr, *lim; 6477 char buf[DLADM_STRSIZE]; 6478 char *unknown = "--", *notsup = ""; 6479 char **propvals = statep->ls_propvals; 6480 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 6481 dladm_status_t status; 6482 6483 status = dladm_get_linkprop(handle, linkid, type, propname, propvals, 6484 &valcnt); 6485 if (status != DLADM_STATUS_OK) { 6486 if (status == DLADM_STATUS_TEMPONLY) { 6487 if (type == DLADM_PROP_VAL_MODIFIABLE && 6488 statep->ls_persist) { 6489 valcnt = 1; 6490 propvals = &unknown; 6491 } else { 6492 statep->ls_status = status; 6493 statep->ls_retstatus = status; 6494 return; 6495 } 6496 } else if (status == DLADM_STATUS_NOTSUP || 6497 statep->ls_persist) { 6498 valcnt = 1; 6499 if (type == DLADM_PROP_VAL_CURRENT || 6500 type == DLADM_PROP_VAL_PERM) 6501 propvals = &unknown; 6502 else 6503 propvals = ¬sup; 6504 } else if (status == DLADM_STATUS_NOTDEFINED) { 6505 propvals = ¬sup; /* STR_UNDEF_VAL */ 6506 } else { 6507 if (statep->ls_proplist && 6508 statep->ls_status == DLADM_STATUS_OK) { 6509 warn_dlerr(status, 6510 "cannot get link property '%s' for %s", 6511 propname, statep->ls_link); 6512 } 6513 statep->ls_status = status; 6514 statep->ls_retstatus = status; 6515 return; 6516 } 6517 } 6518 6519 statep->ls_status = DLADM_STATUS_OK; 6520 6521 buf[0] = '\0'; 6522 ptr = buf; 6523 lim = buf + DLADM_STRSIZE; 6524 for (i = 0; i < valcnt; i++) { 6525 if (propvals[i][0] == '\0' && !statep->ls_parsable) 6526 ptr += snprintf(ptr, lim - ptr, "--,"); 6527 else 6528 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 6529 if (ptr >= lim) 6530 break; 6531 } 6532 if (valcnt > 0) 6533 buf[strlen(buf) - 1] = '\0'; 6534 6535 lim = statep->ls_line + MAX_PROP_LINE; 6536 if (statep->ls_parsable) { 6537 *pptr += snprintf(*pptr, lim - *pptr, 6538 "%s", buf); 6539 } else { 6540 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 6541 } 6542 } 6543 6544 static boolean_t 6545 print_linkprop_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 6546 { 6547 linkprop_args_t *arg = ofarg->ofmt_cbarg; 6548 char *propname = arg->ls_propname; 6549 show_linkprop_state_t *statep = arg->ls_state; 6550 char *ptr = statep->ls_line; 6551 char *lim = ptr + MAX_PROP_LINE; 6552 datalink_id_t linkid = arg->ls_linkid; 6553 6554 switch (ofarg->ofmt_id) { 6555 case LINKPROP_LINK: 6556 (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); 6557 break; 6558 case LINKPROP_PROPERTY: 6559 (void) snprintf(ptr, lim - ptr, "%s", propname); 6560 break; 6561 case LINKPROP_VALUE: 6562 print_linkprop(linkid, statep, propname, 6563 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 6564 DLADM_PROP_VAL_CURRENT, "%s", &ptr); 6565 /* 6566 * If we failed to query the link property, for example, query 6567 * the persistent value of a non-persistable link property, 6568 * simply skip the output. 6569 */ 6570 if (statep->ls_status != DLADM_STATUS_OK) { 6571 /* 6572 * Ignore the temponly error when we skip printing 6573 * link properties to avoid returning failure on exit. 6574 */ 6575 if (statep->ls_retstatus == DLADM_STATUS_TEMPONLY) 6576 statep->ls_retstatus = DLADM_STATUS_OK; 6577 goto skip; 6578 } 6579 ptr = statep->ls_line; 6580 break; 6581 case LINKPROP_PERM: 6582 print_linkprop(linkid, statep, propname, 6583 DLADM_PROP_VAL_PERM, "%s", &ptr); 6584 if (statep->ls_status != DLADM_STATUS_OK) 6585 goto skip; 6586 ptr = statep->ls_line; 6587 break; 6588 case LINKPROP_DEFAULT: 6589 print_linkprop(linkid, statep, propname, 6590 DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 6591 if (statep->ls_status != DLADM_STATUS_OK) 6592 goto skip; 6593 ptr = statep->ls_line; 6594 break; 6595 case LINKPROP_POSSIBLE: 6596 print_linkprop(linkid, statep, propname, 6597 DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 6598 if (statep->ls_status != DLADM_STATUS_OK) 6599 goto skip; 6600 ptr = statep->ls_line; 6601 break; 6602 default: 6603 die("invalid input"); 6604 break; 6605 } 6606 (void) strlcpy(buf, ptr, bufsize); 6607 return (B_TRUE); 6608 skip: 6609 return ((statep->ls_status == DLADM_STATUS_OK) ? 6610 B_TRUE : B_FALSE); 6611 } 6612 6613 static boolean_t 6614 linkprop_is_supported(datalink_id_t linkid, const char *propname, 6615 show_linkprop_state_t *statep) 6616 { 6617 dladm_status_t status; 6618 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 6619 6620 /* if used with -p flag, always print output */ 6621 if (statep->ls_proplist != NULL) 6622 return (B_TRUE); 6623 6624 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_DEFAULT, 6625 propname, statep->ls_propvals, &valcnt); 6626 6627 if (status == DLADM_STATUS_OK) 6628 return (B_TRUE); 6629 6630 /* 6631 * A system wide default value is not available for the 6632 * property. Check if current value can be retrieved. 6633 */ 6634 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT, 6635 propname, statep->ls_propvals, &valcnt); 6636 6637 return (status == DLADM_STATUS_OK); 6638 } 6639 6640 /* ARGSUSED */ 6641 static int 6642 show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname, 6643 void *arg) 6644 { 6645 show_linkprop_state_t *statep = arg; 6646 linkprop_args_t ls_arg; 6647 6648 bzero(&ls_arg, sizeof (ls_arg)); 6649 ls_arg.ls_state = statep; 6650 ls_arg.ls_propname = (char *)propname; 6651 ls_arg.ls_linkid = linkid; 6652 6653 /* 6654 * This will need to be fixed when kernel interfaces are added 6655 * to enable walking of all known private properties. For now, 6656 * we are limited to walking persistent private properties only. 6657 */ 6658 if ((propname[0] == '_') && !statep->ls_persist && 6659 (statep->ls_proplist == NULL)) 6660 return (DLADM_WALK_CONTINUE); 6661 if (!statep->ls_parsable && 6662 !linkprop_is_supported(linkid, propname, statep)) 6663 return (DLADM_WALK_CONTINUE); 6664 6665 ofmt_print(statep->ls_ofmt, &ls_arg); 6666 6667 return (DLADM_WALK_CONTINUE); 6668 } 6669 6670 static void 6671 do_show_linkprop(int argc, char **argv, const char *use) 6672 { 6673 int option; 6674 char propstr[DLADM_STRSIZE]; 6675 dladm_arg_list_t *proplist = NULL; 6676 datalink_id_t linkid = DATALINK_ALL_LINKID; 6677 show_linkprop_state_t state; 6678 uint32_t flags = DLADM_OPT_ACTIVE; 6679 dladm_status_t status; 6680 char *fields_str = NULL; 6681 ofmt_handle_t ofmt; 6682 ofmt_status_t oferr; 6683 uint_t ofmtflags = 0; 6684 6685 bzero(propstr, DLADM_STRSIZE); 6686 opterr = 0; 6687 state.ls_propvals = NULL; 6688 state.ls_line = NULL; 6689 state.ls_parsable = B_FALSE; 6690 state.ls_persist = B_FALSE; 6691 state.ls_header = B_TRUE; 6692 state.ls_retstatus = DLADM_STATUS_OK; 6693 6694 while ((option = getopt_long(argc, argv, ":p:cPo:", 6695 prop_longopts, NULL)) != -1) { 6696 switch (option) { 6697 case 'p': 6698 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 6699 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 6700 DLADM_STRSIZE) 6701 die("property list too long '%s'", propstr); 6702 break; 6703 case 'c': 6704 state.ls_parsable = B_TRUE; 6705 break; 6706 case 'P': 6707 state.ls_persist = B_TRUE; 6708 flags = DLADM_OPT_PERSIST; 6709 break; 6710 case 'o': 6711 fields_str = optarg; 6712 break; 6713 default: 6714 die_opterr(optopt, option, use); 6715 break; 6716 } 6717 } 6718 6719 if (optind == (argc - 1)) { 6720 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6721 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 6722 die_dlerr(status, "link %s is not valid", argv[optind]); 6723 } 6724 } else if (optind != argc) { 6725 usage(); 6726 } 6727 6728 if (dladm_parse_link_props(propstr, &proplist, B_TRUE) 6729 != DLADM_STATUS_OK) 6730 die("invalid link properties specified"); 6731 state.ls_proplist = proplist; 6732 state.ls_status = DLADM_STATUS_OK; 6733 6734 if (state.ls_parsable) 6735 ofmtflags |= OFMT_PARSABLE; 6736 else 6737 ofmtflags |= OFMT_WRAP; 6738 6739 oferr = ofmt_open(fields_str, linkprop_fields, ofmtflags, 0, &ofmt); 6740 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 6741 state.ls_ofmt = ofmt; 6742 6743 if (linkid == DATALINK_ALL_LINKID) { 6744 (void) dladm_walk_datalink_id(show_linkprop_onelink, handle, 6745 &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 6746 } else { 6747 (void) show_linkprop_onelink(handle, linkid, &state); 6748 } 6749 ofmt_close(ofmt); 6750 dladm_free_props(proplist); 6751 6752 if (state.ls_retstatus != DLADM_STATUS_OK) { 6753 dladm_close(handle); 6754 exit(EXIT_FAILURE); 6755 } 6756 } 6757 6758 static int 6759 show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg) 6760 { 6761 int i; 6762 char *buf; 6763 uint32_t flags; 6764 dladm_arg_list_t *proplist = NULL; 6765 show_linkprop_state_t *statep = arg; 6766 dlpi_handle_t dh = NULL; 6767 6768 statep->ls_status = DLADM_STATUS_OK; 6769 6770 if (dladm_datalink_id2info(hdl, linkid, &flags, NULL, NULL, 6771 statep->ls_link, MAXLINKNAMELEN) != DLADM_STATUS_OK) { 6772 statep->ls_status = DLADM_STATUS_NOTFOUND; 6773 return (DLADM_WALK_CONTINUE); 6774 } 6775 6776 if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) || 6777 (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) { 6778 statep->ls_status = DLADM_STATUS_BADARG; 6779 return (DLADM_WALK_CONTINUE); 6780 } 6781 6782 proplist = statep->ls_proplist; 6783 6784 /* 6785 * When some WiFi links are opened for the first time, their hardware 6786 * automatically scans for APs and does other slow operations. Thus, 6787 * if there are no open links, the retrieval of link properties 6788 * (below) will proceed slowly unless we hold the link open. 6789 * 6790 * Note that failure of dlpi_open() does not necessarily mean invalid 6791 * link properties, because dlpi_open() may fail because of incorrect 6792 * autopush configuration. Therefore, we ingore the return value of 6793 * dlpi_open(). 6794 */ 6795 if (!statep->ls_persist) 6796 (void) dlpi_open(statep->ls_link, &dh, 0); 6797 6798 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 6799 DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 6800 if (buf == NULL) 6801 die("insufficient memory"); 6802 6803 statep->ls_propvals = (char **)(void *)buf; 6804 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 6805 statep->ls_propvals[i] = buf + 6806 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 6807 i * DLADM_PROP_VAL_MAX; 6808 } 6809 statep->ls_line = buf + 6810 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 6811 6812 if (proplist != NULL) { 6813 for (i = 0; i < proplist->al_count; i++) { 6814 (void) show_linkprop(hdl, linkid, 6815 proplist->al_info[i].ai_name, statep); 6816 } 6817 } else { 6818 (void) dladm_walk_linkprop(hdl, linkid, statep, 6819 show_linkprop); 6820 } 6821 if (dh != NULL) 6822 dlpi_close(dh); 6823 free(buf); 6824 return (DLADM_WALK_CONTINUE); 6825 } 6826 6827 static int 6828 reset_one_linkprop(dladm_handle_t dh, datalink_id_t linkid, 6829 const char *propname, void *arg) 6830 { 6831 set_linkprop_state_t *statep = arg; 6832 dladm_status_t status; 6833 6834 status = dladm_set_linkprop(dh, linkid, propname, NULL, 0, 6835 DLADM_OPT_ACTIVE | (statep->ls_temp ? 0 : DLADM_OPT_PERSIST)); 6836 if (status != DLADM_STATUS_OK && 6837 status != DLADM_STATUS_PROPRDONLY && 6838 status != DLADM_STATUS_NOTSUP) { 6839 warn_dlerr(status, "cannot reset link property '%s' on '%s'", 6840 propname, statep->ls_name); 6841 statep->ls_status = status; 6842 } 6843 6844 return (DLADM_WALK_CONTINUE); 6845 } 6846 6847 static void 6848 set_linkprop(int argc, char **argv, boolean_t reset, const char *use) 6849 { 6850 int i, option; 6851 char errmsg[DLADM_STRSIZE]; 6852 char *altroot = NULL; 6853 datalink_id_t linkid; 6854 boolean_t temp = B_FALSE; 6855 dladm_status_t status = DLADM_STATUS_OK; 6856 char propstr[DLADM_STRSIZE]; 6857 dladm_arg_list_t *proplist = NULL; 6858 6859 opterr = 0; 6860 bzero(propstr, DLADM_STRSIZE); 6861 6862 while ((option = getopt_long(argc, argv, ":p:R:t", 6863 prop_longopts, NULL)) != -1) { 6864 switch (option) { 6865 case 'p': 6866 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 6867 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 6868 DLADM_STRSIZE) 6869 die("property list too long '%s'", propstr); 6870 break; 6871 case 't': 6872 temp = B_TRUE; 6873 break; 6874 case 'R': 6875 altroot = optarg; 6876 break; 6877 default: 6878 die_opterr(optopt, option, use); 6879 6880 } 6881 } 6882 6883 /* get link name (required last argument) */ 6884 if (optind != (argc - 1)) 6885 usage(); 6886 6887 if (dladm_parse_link_props(propstr, &proplist, reset) != 6888 DLADM_STATUS_OK) 6889 die("invalid link properties specified"); 6890 6891 if (proplist == NULL && !reset) 6892 die("link property must be specified"); 6893 6894 if (altroot != NULL) { 6895 dladm_free_props(proplist); 6896 altroot_cmd(altroot, argc, argv); 6897 } 6898 6899 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 6900 NULL); 6901 if (status != DLADM_STATUS_OK) 6902 die_dlerr(status, "link %s is not valid", argv[optind]); 6903 6904 if (proplist == NULL) { 6905 set_linkprop_state_t state; 6906 6907 state.ls_name = argv[optind]; 6908 state.ls_reset = reset; 6909 state.ls_temp = temp; 6910 state.ls_status = DLADM_STATUS_OK; 6911 6912 (void) dladm_walk_linkprop(handle, linkid, &state, 6913 reset_one_linkprop); 6914 6915 status = state.ls_status; 6916 goto done; 6917 } 6918 6919 for (i = 0; i < proplist->al_count; i++) { 6920 dladm_arg_info_t *aip = &proplist->al_info[i]; 6921 char **val; 6922 uint_t count; 6923 6924 if (reset) { 6925 val = NULL; 6926 count = 0; 6927 } else { 6928 val = aip->ai_val; 6929 count = aip->ai_count; 6930 if (count == 0) { 6931 warn("no value specified for '%s'", 6932 aip->ai_name); 6933 status = DLADM_STATUS_BADARG; 6934 continue; 6935 } 6936 } 6937 status = dladm_set_linkprop(handle, linkid, aip->ai_name, val, 6938 count, DLADM_OPT_ACTIVE | (temp ? 0 : DLADM_OPT_PERSIST)); 6939 switch (status) { 6940 case DLADM_STATUS_OK: 6941 break; 6942 case DLADM_STATUS_NOTFOUND: 6943 warn("invalid link property '%s'", aip->ai_name); 6944 break; 6945 case DLADM_STATUS_BADVAL: { 6946 int j; 6947 char *ptr, *lim; 6948 char **propvals = NULL; 6949 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 6950 dladm_status_t s; 6951 6952 ptr = malloc((sizeof (char *) + 6953 DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 6954 MAX_PROP_LINE); 6955 6956 propvals = (char **)(void *)ptr; 6957 if (propvals == NULL) 6958 die("insufficient memory"); 6959 6960 for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 6961 propvals[j] = ptr + sizeof (char *) * 6962 DLADM_MAX_PROP_VALCNT + 6963 j * DLADM_PROP_VAL_MAX; 6964 } 6965 s = dladm_get_linkprop(handle, linkid, 6966 DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals, 6967 &valcnt); 6968 6969 if (s != DLADM_STATUS_OK) { 6970 warn_dlerr(status, "cannot set link property " 6971 "'%s' on '%s'", aip->ai_name, argv[optind]); 6972 free(propvals); 6973 break; 6974 } 6975 6976 ptr = errmsg; 6977 lim = ptr + DLADM_STRSIZE; 6978 *ptr = '\0'; 6979 for (j = 0; j < valcnt; j++) { 6980 ptr += snprintf(ptr, lim - ptr, "%s,", 6981 propvals[j]); 6982 if (ptr >= lim) 6983 break; 6984 } 6985 if (ptr > errmsg) { 6986 *(ptr - 1) = '\0'; 6987 warn("link property '%s' must be one of: %s", 6988 aip->ai_name, errmsg); 6989 } else 6990 warn("invalid link property '%s'", *val); 6991 free(propvals); 6992 break; 6993 } 6994 default: 6995 if (reset) { 6996 warn_dlerr(status, "cannot reset link property " 6997 "'%s' on '%s'", aip->ai_name, argv[optind]); 6998 } else { 6999 warn_dlerr(status, "cannot set link property " 7000 "'%s' on '%s'", aip->ai_name, argv[optind]); 7001 } 7002 break; 7003 } 7004 } 7005 done: 7006 dladm_free_props(proplist); 7007 if (status != DLADM_STATUS_OK) { 7008 dladm_close(handle); 7009 exit(EXIT_FAILURE); 7010 } 7011 } 7012 7013 static void 7014 do_set_linkprop(int argc, char **argv, const char *use) 7015 { 7016 set_linkprop(argc, argv, B_FALSE, use); 7017 } 7018 7019 static void 7020 do_reset_linkprop(int argc, char **argv, const char *use) 7021 { 7022 set_linkprop(argc, argv, B_TRUE, use); 7023 } 7024 7025 static int 7026 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 7027 dladm_secobj_class_t class) 7028 { 7029 int error = 0; 7030 7031 if (class == DLADM_SECOBJ_CLASS_WPA) { 7032 if (len < 8 || len > 63) 7033 return (EINVAL); 7034 (void) memcpy(obj_val, buf, len); 7035 *obj_lenp = len; 7036 return (error); 7037 } 7038 7039 if (class == DLADM_SECOBJ_CLASS_WEP) { 7040 switch (len) { 7041 case 5: /* ASCII key sizes */ 7042 case 13: 7043 (void) memcpy(obj_val, buf, len); 7044 *obj_lenp = len; 7045 break; 7046 case 10: /* Hex key sizes, not preceded by 0x */ 7047 case 26: 7048 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 7049 break; 7050 case 12: /* Hex key sizes, preceded by 0x */ 7051 case 28: 7052 if (strncmp(buf, "0x", 2) != 0) 7053 return (EINVAL); 7054 error = hexascii_to_octet(buf + 2, len - 2, 7055 obj_val, obj_lenp); 7056 break; 7057 default: 7058 return (EINVAL); 7059 } 7060 return (error); 7061 } 7062 7063 return (ENOENT); 7064 } 7065 7066 static void 7067 defersig(int sig) 7068 { 7069 signalled = sig; 7070 } 7071 7072 static int 7073 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 7074 { 7075 uint_t len = 0; 7076 int c; 7077 struct termios stored, current; 7078 void (*sigfunc)(int); 7079 7080 /* 7081 * Turn off echo -- but before we do so, defer SIGINT handling 7082 * so that a ^C doesn't leave the terminal corrupted. 7083 */ 7084 sigfunc = signal(SIGINT, defersig); 7085 (void) fflush(stdin); 7086 (void) tcgetattr(0, &stored); 7087 current = stored; 7088 current.c_lflag &= ~(ICANON|ECHO); 7089 current.c_cc[VTIME] = 0; 7090 current.c_cc[VMIN] = 1; 7091 (void) tcsetattr(0, TCSANOW, ¤t); 7092 again: 7093 if (try == 1) 7094 (void) printf(gettext("provide value for '%s': "), objname); 7095 else 7096 (void) printf(gettext("confirm value for '%s': "), objname); 7097 7098 (void) fflush(stdout); 7099 while (signalled == 0) { 7100 c = getchar(); 7101 if (c == '\n' || c == '\r') { 7102 if (len != 0) 7103 break; 7104 (void) putchar('\n'); 7105 goto again; 7106 } 7107 7108 buf[len++] = c; 7109 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 7110 break; 7111 (void) putchar('*'); 7112 } 7113 7114 (void) putchar('\n'); 7115 (void) fflush(stdin); 7116 7117 /* 7118 * Restore terminal setting and handle deferred signals. 7119 */ 7120 (void) tcsetattr(0, TCSANOW, &stored); 7121 7122 (void) signal(SIGINT, sigfunc); 7123 if (signalled != 0) 7124 (void) kill(getpid(), signalled); 7125 7126 return (len); 7127 } 7128 7129 static int 7130 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 7131 dladm_secobj_class_t class, FILE *filep) 7132 { 7133 int rval; 7134 uint_t len, len2; 7135 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 7136 7137 if (filep == NULL) { 7138 len = get_secobj_from_tty(1, obj_name, buf); 7139 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 7140 if (rval == 0) { 7141 len2 = get_secobj_from_tty(2, obj_name, buf2); 7142 if (len != len2 || memcmp(buf, buf2, len) != 0) 7143 rval = ENOTSUP; 7144 } 7145 return (rval); 7146 } else { 7147 for (;;) { 7148 if (fgets(buf, sizeof (buf), filep) == NULL) 7149 break; 7150 if (isspace(buf[0])) 7151 continue; 7152 7153 len = strlen(buf); 7154 if (buf[len - 1] == '\n') { 7155 buf[len - 1] = '\0'; 7156 len--; 7157 } 7158 break; 7159 } 7160 (void) fclose(filep); 7161 } 7162 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 7163 } 7164 7165 static boolean_t 7166 check_auth(const char *auth) 7167 { 7168 struct passwd *pw; 7169 7170 if ((pw = getpwuid(getuid())) == NULL) 7171 return (B_FALSE); 7172 7173 return (chkauthattr(auth, pw->pw_name) != 0); 7174 } 7175 7176 static void 7177 audit_secobj(char *auth, char *class, char *obj, 7178 boolean_t success, boolean_t create) 7179 { 7180 adt_session_data_t *ah; 7181 adt_event_data_t *event; 7182 au_event_t flag; 7183 char *errstr; 7184 7185 if (create) { 7186 flag = ADT_dladm_create_secobj; 7187 errstr = "ADT_dladm_create_secobj"; 7188 } else { 7189 flag = ADT_dladm_delete_secobj; 7190 errstr = "ADT_dladm_delete_secobj"; 7191 } 7192 7193 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 7194 die("adt_start_session: %s", strerror(errno)); 7195 7196 if ((event = adt_alloc_event(ah, flag)) == NULL) 7197 die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 7198 7199 /* fill in audit info */ 7200 if (create) { 7201 event->adt_dladm_create_secobj.auth_used = auth; 7202 event->adt_dladm_create_secobj.obj_class = class; 7203 event->adt_dladm_create_secobj.obj_name = obj; 7204 } else { 7205 event->adt_dladm_delete_secobj.auth_used = auth; 7206 event->adt_dladm_delete_secobj.obj_class = class; 7207 event->adt_dladm_delete_secobj.obj_name = obj; 7208 } 7209 7210 if (success) { 7211 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 7212 die("adt_put_event (%s, success): %s", errstr, 7213 strerror(errno)); 7214 } 7215 } else { 7216 if (adt_put_event(event, ADT_FAILURE, 7217 ADT_FAIL_VALUE_AUTH) != 0) { 7218 die("adt_put_event: (%s, failure): %s", errstr, 7219 strerror(errno)); 7220 } 7221 } 7222 7223 adt_free_event(event); 7224 (void) adt_end_session(ah); 7225 } 7226 7227 static void 7228 do_create_secobj(int argc, char **argv, const char *use) 7229 { 7230 int option, rval; 7231 FILE *filep = NULL; 7232 char *obj_name = NULL; 7233 char *class_name = NULL; 7234 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 7235 uint_t obj_len; 7236 boolean_t success, temp = B_FALSE; 7237 dladm_status_t status; 7238 dladm_secobj_class_t class = -1; 7239 uid_t euid; 7240 7241 opterr = 0; 7242 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 7243 while ((option = getopt_long(argc, argv, ":f:c:R:t", 7244 wifi_longopts, NULL)) != -1) { 7245 switch (option) { 7246 case 'f': 7247 euid = geteuid(); 7248 (void) seteuid(getuid()); 7249 filep = fopen(optarg, "r"); 7250 if (filep == NULL) { 7251 die("cannot open %s: %s", optarg, 7252 strerror(errno)); 7253 } 7254 (void) seteuid(euid); 7255 break; 7256 case 'c': 7257 class_name = optarg; 7258 status = dladm_str2secobjclass(optarg, &class); 7259 if (status != DLADM_STATUS_OK) { 7260 die("invalid secure object class '%s', " 7261 "valid values are: wep, wpa", optarg); 7262 } 7263 break; 7264 case 't': 7265 temp = B_TRUE; 7266 break; 7267 case 'R': 7268 status = dladm_set_rootdir(optarg); 7269 if (status != DLADM_STATUS_OK) { 7270 die_dlerr(status, "invalid directory " 7271 "specified"); 7272 } 7273 break; 7274 default: 7275 die_opterr(optopt, option, use); 7276 break; 7277 } 7278 } 7279 7280 if (optind == (argc - 1)) 7281 obj_name = argv[optind]; 7282 else if (optind != argc) 7283 usage(); 7284 7285 if (class == -1) 7286 die("secure object class required"); 7287 7288 if (obj_name == NULL) 7289 die("secure object name required"); 7290 7291 if (!dladm_valid_secobj_name(obj_name)) 7292 die("invalid secure object name '%s'", obj_name); 7293 7294 success = check_auth(LINK_SEC_AUTH); 7295 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 7296 if (!success) 7297 die("authorization '%s' is required", LINK_SEC_AUTH); 7298 7299 rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 7300 if (rval != 0) { 7301 switch (rval) { 7302 case ENOENT: 7303 die("invalid secure object class"); 7304 break; 7305 case EINVAL: 7306 die("invalid secure object value"); 7307 break; 7308 case ENOTSUP: 7309 die("verification failed"); 7310 break; 7311 default: 7312 die("invalid secure object: %s", strerror(rval)); 7313 break; 7314 } 7315 } 7316 7317 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 7318 DLADM_OPT_CREATE | DLADM_OPT_ACTIVE); 7319 if (status != DLADM_STATUS_OK) { 7320 die_dlerr(status, "could not create secure object '%s'", 7321 obj_name); 7322 } 7323 if (temp) 7324 return; 7325 7326 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 7327 DLADM_OPT_PERSIST); 7328 if (status != DLADM_STATUS_OK) { 7329 warn_dlerr(status, "could not persistently create secure " 7330 "object '%s'", obj_name); 7331 } 7332 } 7333 7334 static void 7335 do_delete_secobj(int argc, char **argv, const char *use) 7336 { 7337 int i, option; 7338 boolean_t temp = B_FALSE; 7339 boolean_t success; 7340 dladm_status_t status, pstatus; 7341 int nfields = 1; 7342 char *field, *token, *lasts = NULL, c; 7343 7344 opterr = 0; 7345 status = pstatus = DLADM_STATUS_OK; 7346 while ((option = getopt_long(argc, argv, ":R:t", 7347 wifi_longopts, NULL)) != -1) { 7348 switch (option) { 7349 case 't': 7350 temp = B_TRUE; 7351 break; 7352 case 'R': 7353 status = dladm_set_rootdir(optarg); 7354 if (status != DLADM_STATUS_OK) { 7355 die_dlerr(status, "invalid directory " 7356 "specified"); 7357 } 7358 break; 7359 default: 7360 die_opterr(optopt, option, use); 7361 break; 7362 } 7363 } 7364 7365 if (optind != (argc - 1)) 7366 die("secure object name required"); 7367 7368 token = argv[optind]; 7369 while ((c = *token++) != NULL) { 7370 if (c == ',') 7371 nfields++; 7372 } 7373 token = strdup(argv[optind]); 7374 if (token == NULL) 7375 die("no memory"); 7376 7377 success = check_auth(LINK_SEC_AUTH); 7378 audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE); 7379 if (!success) 7380 die("authorization '%s' is required", LINK_SEC_AUTH); 7381 7382 for (i = 0; i < nfields; i++) { 7383 7384 field = strtok_r(token, ",", &lasts); 7385 token = NULL; 7386 status = dladm_unset_secobj(handle, field, DLADM_OPT_ACTIVE); 7387 if (!temp) { 7388 pstatus = dladm_unset_secobj(handle, field, 7389 DLADM_OPT_PERSIST); 7390 } else { 7391 pstatus = DLADM_STATUS_OK; 7392 } 7393 7394 if (status != DLADM_STATUS_OK) { 7395 warn_dlerr(status, "could not delete secure object " 7396 "'%s'", field); 7397 } 7398 if (pstatus != DLADM_STATUS_OK) { 7399 warn_dlerr(pstatus, "could not persistently delete " 7400 "secure object '%s'", field); 7401 } 7402 } 7403 free(token); 7404 7405 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) { 7406 dladm_close(handle); 7407 exit(EXIT_FAILURE); 7408 } 7409 } 7410 7411 typedef struct show_secobj_state { 7412 boolean_t ss_persist; 7413 boolean_t ss_parsable; 7414 boolean_t ss_header; 7415 ofmt_handle_t ss_ofmt; 7416 } show_secobj_state_t; 7417 7418 7419 static boolean_t 7420 show_secobj(dladm_handle_t dh, void *arg, const char *obj_name) 7421 { 7422 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 7423 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 7424 char buf[DLADM_STRSIZE]; 7425 uint_t flags = 0; 7426 dladm_secobj_class_t class; 7427 show_secobj_state_t *statep = arg; 7428 dladm_status_t status; 7429 secobj_fields_buf_t sbuf; 7430 7431 bzero(&sbuf, sizeof (secobj_fields_buf_t)); 7432 if (statep->ss_persist) 7433 flags |= DLADM_OPT_PERSIST; 7434 7435 status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len, 7436 flags); 7437 if (status != DLADM_STATUS_OK) 7438 die_dlerr(status, "cannot get secure object '%s'", obj_name); 7439 7440 (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), 7441 obj_name); 7442 (void) dladm_secobjclass2str(class, buf); 7443 (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf); 7444 if (getuid() == 0) { 7445 char val[DLADM_SECOBJ_VAL_MAX * 2]; 7446 uint_t len = sizeof (val); 7447 7448 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) 7449 (void) snprintf(sbuf.ss_val, 7450 sizeof (sbuf.ss_val), "%s", val); 7451 } 7452 ofmt_print(statep->ss_ofmt, &sbuf); 7453 return (B_TRUE); 7454 } 7455 7456 static void 7457 do_show_secobj(int argc, char **argv, const char *use) 7458 { 7459 int option; 7460 show_secobj_state_t state; 7461 dladm_status_t status; 7462 boolean_t o_arg = B_FALSE; 7463 uint_t i; 7464 uint_t flags; 7465 char *fields_str = NULL; 7466 char *def_fields = "object,class"; 7467 char *all_fields = "object,class,value"; 7468 char *field, *token, *lasts = NULL, c; 7469 ofmt_handle_t ofmt; 7470 ofmt_status_t oferr; 7471 uint_t ofmtflags = 0; 7472 7473 opterr = 0; 7474 bzero(&state, sizeof (state)); 7475 state.ss_parsable = B_FALSE; 7476 fields_str = def_fields; 7477 state.ss_persist = B_FALSE; 7478 state.ss_parsable = B_FALSE; 7479 state.ss_header = B_TRUE; 7480 while ((option = getopt_long(argc, argv, ":pPo:", 7481 wifi_longopts, NULL)) != -1) { 7482 switch (option) { 7483 case 'p': 7484 state.ss_parsable = B_TRUE; 7485 break; 7486 case 'P': 7487 state.ss_persist = B_TRUE; 7488 break; 7489 case 'o': 7490 o_arg = B_TRUE; 7491 if (strcasecmp(optarg, "all") == 0) 7492 fields_str = all_fields; 7493 else 7494 fields_str = optarg; 7495 break; 7496 default: 7497 die_opterr(optopt, option, use); 7498 break; 7499 } 7500 } 7501 7502 if (state.ss_parsable && !o_arg) 7503 die("option -c requires -o"); 7504 7505 if (state.ss_parsable && fields_str == all_fields) 7506 die("\"-o all\" is invalid with -p"); 7507 7508 if (state.ss_parsable) 7509 ofmtflags |= OFMT_PARSABLE; 7510 oferr = ofmt_open(fields_str, secobj_fields, ofmtflags, 0, &ofmt); 7511 ofmt_check(oferr, state.ss_parsable, ofmt, die, warn); 7512 state.ss_ofmt = ofmt; 7513 7514 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 7515 7516 if (optind == (argc - 1)) { 7517 uint_t obj_fields = 1; 7518 7519 token = argv[optind]; 7520 if (token == NULL) 7521 die("secure object name required"); 7522 while ((c = *token++) != NULL) { 7523 if (c == ',') 7524 obj_fields++; 7525 } 7526 token = strdup(argv[optind]); 7527 if (token == NULL) 7528 die("no memory"); 7529 for (i = 0; i < obj_fields; i++) { 7530 field = strtok_r(token, ",", &lasts); 7531 token = NULL; 7532 if (!show_secobj(handle, &state, field)) 7533 break; 7534 } 7535 free(token); 7536 ofmt_close(ofmt); 7537 return; 7538 } else if (optind != argc) 7539 usage(); 7540 7541 status = dladm_walk_secobj(handle, &state, show_secobj, flags); 7542 7543 if (status != DLADM_STATUS_OK) 7544 die_dlerr(status, "show-secobj"); 7545 ofmt_close(ofmt); 7546 } 7547 7548 /*ARGSUSED*/ 7549 static int 7550 i_dladm_init_linkprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 7551 { 7552 (void) dladm_init_linkprop(dh, linkid, B_TRUE); 7553 return (DLADM_WALK_CONTINUE); 7554 } 7555 7556 /*ARGSUSED*/ 7557 void 7558 do_init_linkprop(int argc, char **argv, const char *use) 7559 { 7560 int option; 7561 dladm_status_t status; 7562 datalink_id_t linkid = DATALINK_ALL_LINKID; 7563 datalink_media_t media = DATALINK_ANY_MEDIATYPE; 7564 uint_t any_media = B_TRUE; 7565 7566 opterr = 0; 7567 while ((option = getopt(argc, argv, ":w")) != -1) { 7568 switch (option) { 7569 case 'w': 7570 media = DL_WIFI; 7571 any_media = B_FALSE; 7572 break; 7573 default: 7574 /* 7575 * Because init-linkprop is not a public command, 7576 * print the usage instead. 7577 */ 7578 usage(); 7579 break; 7580 } 7581 } 7582 7583 if (optind == (argc - 1)) { 7584 if ((status = dladm_name2info(handle, argv[optind], &linkid, 7585 NULL, NULL, NULL)) != DLADM_STATUS_OK) 7586 die_dlerr(status, "link %s is not valid", argv[optind]); 7587 } else if (optind != argc) { 7588 usage(); 7589 } 7590 7591 if (linkid == DATALINK_ALL_LINKID) { 7592 /* 7593 * linkprops of links of other classes have been initialized as 7594 * part of the dladm up-xxx operation. 7595 */ 7596 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle, 7597 NULL, DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST); 7598 } else { 7599 (void) dladm_init_linkprop(handle, linkid, any_media); 7600 } 7601 } 7602 7603 static void 7604 do_show_ether(int argc, char **argv, const char *use) 7605 { 7606 int option; 7607 datalink_id_t linkid; 7608 print_ether_state_t state; 7609 char *fields_str = NULL; 7610 ofmt_handle_t ofmt; 7611 ofmt_status_t oferr; 7612 uint_t ofmtflags = 0; 7613 7614 bzero(&state, sizeof (state)); 7615 state.es_link = NULL; 7616 state.es_parsable = B_FALSE; 7617 7618 while ((option = getopt_long(argc, argv, "o:px", 7619 showeth_lopts, NULL)) != -1) { 7620 switch (option) { 7621 case 'x': 7622 state.es_extended = B_TRUE; 7623 break; 7624 case 'p': 7625 state.es_parsable = B_TRUE; 7626 break; 7627 case 'o': 7628 fields_str = optarg; 7629 break; 7630 default: 7631 die_opterr(optopt, option, use); 7632 break; 7633 } 7634 } 7635 7636 if (optind == (argc - 1)) 7637 state.es_link = argv[optind]; 7638 7639 if (state.es_parsable) 7640 ofmtflags |= OFMT_PARSABLE; 7641 oferr = ofmt_open(fields_str, ether_fields, ofmtflags, 7642 DLADM_DEFAULT_COL, &ofmt); 7643 ofmt_check(oferr, state.es_parsable, ofmt, die, warn); 7644 state.es_ofmt = ofmt; 7645 7646 if (state.es_link == NULL) { 7647 (void) dladm_walk_datalink_id(show_etherprop, handle, &state, 7648 DATALINK_CLASS_PHYS, DL_ETHER, DLADM_OPT_ACTIVE); 7649 } else { 7650 if (!link_is_ether(state.es_link, &linkid)) 7651 die("invalid link specified"); 7652 (void) show_etherprop(handle, linkid, &state); 7653 } 7654 ofmt_close(ofmt); 7655 } 7656 7657 static int 7658 show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 7659 { 7660 print_ether_state_t *statep = arg; 7661 ether_fields_buf_t ebuf; 7662 dladm_ether_info_t eattr; 7663 dladm_status_t status; 7664 7665 bzero(&ebuf, sizeof (ether_fields_buf_t)); 7666 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, 7667 ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) { 7668 return (DLADM_WALK_CONTINUE); 7669 } 7670 7671 status = dladm_ether_info(dh, linkid, &eattr); 7672 if (status != DLADM_STATUS_OK) 7673 goto cleanup; 7674 7675 (void) strlcpy(ebuf.eth_ptype, "current", sizeof (ebuf.eth_ptype)); 7676 7677 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 7678 sizeof (ebuf.eth_autoneg), &eattr, CURRENT); 7679 (void) dladm_ether_pause2str(ebuf.eth_pause, 7680 sizeof (ebuf.eth_pause), &eattr, CURRENT); 7681 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 7682 sizeof (ebuf.eth_spdx), &eattr, CURRENT); 7683 (void) strlcpy(ebuf.eth_state, 7684 dladm_linkstate2str(eattr.lei_state, ebuf.eth_state), 7685 sizeof (ebuf.eth_state)); 7686 (void) strlcpy(ebuf.eth_rem_fault, 7687 (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"), 7688 sizeof (ebuf.eth_rem_fault)); 7689 7690 ofmt_print(statep->es_ofmt, &ebuf); 7691 7692 if (statep->es_extended) 7693 show_ether_xprop(arg, &eattr); 7694 7695 cleanup: 7696 dladm_ether_info_done(&eattr); 7697 return (DLADM_WALK_CONTINUE); 7698 } 7699 7700 /* ARGSUSED */ 7701 static void 7702 do_init_secobj(int argc, char **argv, const char *use) 7703 { 7704 dladm_status_t status; 7705 7706 status = dladm_init_secobj(handle); 7707 if (status != DLADM_STATUS_OK) 7708 die_dlerr(status, "secure object initialization failed"); 7709 } 7710 7711 enum bridge_func { 7712 brCreate, brAdd, brModify 7713 }; 7714 7715 static void 7716 create_modify_add_bridge(int argc, char **argv, const char *use, 7717 enum bridge_func func) 7718 { 7719 int option; 7720 uint_t n, i, nlink; 7721 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 7722 char *altroot = NULL; 7723 char *links[MAXPORT]; 7724 datalink_id_t linkids[MAXPORT]; 7725 dladm_status_t status; 7726 const char *bridge; 7727 UID_STP_CFG_T cfg, cfg_old; 7728 dladm_bridge_prot_t brprot = DLADM_BRIDGE_PROT_UNKNOWN; 7729 dladm_bridge_prot_t brprot_old; 7730 7731 /* Set up the default configuration values */ 7732 cfg.field_mask = 0; 7733 cfg.bridge_priority = DEF_BR_PRIO; 7734 cfg.max_age = DEF_BR_MAXAGE; 7735 cfg.hello_time = DEF_BR_HELLOT; 7736 cfg.forward_delay = DEF_BR_FWDELAY; 7737 cfg.force_version = DEF_FORCE_VERS; 7738 7739 nlink = opterr = 0; 7740 while ((option = getopt_long(argc, argv, ":P:R:d:f:h:l:m:p:", 7741 bridge_lopts, NULL)) != -1) { 7742 switch (option) { 7743 case 'P': 7744 if (func == brAdd) 7745 die_opterr(optopt, option, use); 7746 status = dladm_bridge_str2prot(optarg, &brprot); 7747 if (status != DLADM_STATUS_OK) 7748 die_dlerr(status, "protection %s", optarg); 7749 break; 7750 case 'R': 7751 altroot = optarg; 7752 break; 7753 case 'd': 7754 if (func == brAdd) 7755 die_opterr(optopt, option, use); 7756 if (cfg.field_mask & BR_CFG_DELAY) 7757 die("forwarding delay set more than once"); 7758 if (!str2int(optarg, &cfg.forward_delay) || 7759 cfg.forward_delay < MIN_BR_FWDELAY || 7760 cfg.forward_delay > MAX_BR_FWDELAY) 7761 die("incorrect forwarding delay"); 7762 cfg.field_mask |= BR_CFG_DELAY; 7763 break; 7764 case 'f': 7765 if (func == brAdd) 7766 die_opterr(optopt, option, use); 7767 if (cfg.field_mask & BR_CFG_FORCE_VER) 7768 die("force protocol set more than once"); 7769 if (!str2int(optarg, &cfg.force_version) || 7770 cfg.force_version < 0) 7771 die("incorrect force protocol"); 7772 cfg.field_mask |= BR_CFG_FORCE_VER; 7773 break; 7774 case 'h': 7775 if (func == brAdd) 7776 die_opterr(optopt, option, use); 7777 if (cfg.field_mask & BR_CFG_HELLO) 7778 die("hello time set more than once"); 7779 if (!str2int(optarg, &cfg.hello_time) || 7780 cfg.hello_time < MIN_BR_HELLOT || 7781 cfg.hello_time > MAX_BR_HELLOT) 7782 die("incorrect hello time"); 7783 cfg.field_mask |= BR_CFG_HELLO; 7784 break; 7785 case 'l': 7786 if (func == brModify) 7787 die_opterr(optopt, option, use); 7788 if (nlink >= MAXPORT) 7789 die("too many links specified"); 7790 links[nlink++] = optarg; 7791 break; 7792 case 'm': 7793 if (func == brAdd) 7794 die_opterr(optopt, option, use); 7795 if (cfg.field_mask & BR_CFG_AGE) 7796 die("max age set more than once"); 7797 if (!str2int(optarg, &cfg.max_age) || 7798 cfg.max_age < MIN_BR_MAXAGE || 7799 cfg.max_age > MAX_BR_MAXAGE) 7800 die("incorrect max age"); 7801 cfg.field_mask |= BR_CFG_AGE; 7802 break; 7803 case 'p': 7804 if (func == brAdd) 7805 die_opterr(optopt, option, use); 7806 if (cfg.field_mask & BR_CFG_PRIO) 7807 die("priority set more than once"); 7808 if (!str2int(optarg, &cfg.bridge_priority) || 7809 cfg.bridge_priority < MIN_BR_PRIO || 7810 cfg.bridge_priority > MAX_BR_PRIO) 7811 die("incorrect priority"); 7812 cfg.bridge_priority &= 0xF000; 7813 cfg.field_mask |= BR_CFG_PRIO; 7814 break; 7815 default: 7816 die_opterr(optopt, option, use); 7817 break; 7818 } 7819 } 7820 7821 /* get the bridge name (required last argument) */ 7822 if (optind != (argc-1)) 7823 usage(); 7824 7825 bridge = argv[optind]; 7826 if (!dladm_valid_bridgename(bridge)) 7827 die("invalid bridge name '%s'", bridge); 7828 7829 /* 7830 * Get the current properties, if any, and merge in with changes. This 7831 * is necessary (even with the field_mask feature) so that the 7832 * value-checking macros will produce the right results with proposed 7833 * changes to existing configuration. We only need it for those 7834 * parameters, though. 7835 */ 7836 (void) dladm_bridge_get_properties(bridge, &cfg_old, &brprot_old); 7837 if (brprot == DLADM_BRIDGE_PROT_UNKNOWN) 7838 brprot = brprot_old; 7839 if (!(cfg.field_mask & BR_CFG_AGE)) 7840 cfg.max_age = cfg_old.max_age; 7841 if (!(cfg.field_mask & BR_CFG_HELLO)) 7842 cfg.hello_time = cfg_old.hello_time; 7843 if (!(cfg.field_mask & BR_CFG_DELAY)) 7844 cfg.forward_delay = cfg_old.forward_delay; 7845 7846 if (!CHECK_BRIDGE_CONFIG(cfg)) { 7847 warn("illegal forward delay / max age / hello time " 7848 "combination"); 7849 if (NO_MAXAGE(cfg)) { 7850 die("no max age possible: need forward delay >= %d or " 7851 "hello time <= %d", MIN_FWDELAY_NOM(cfg), 7852 MAX_HELLOTIME_NOM(cfg)); 7853 } else if (SMALL_MAXAGE(cfg)) { 7854 if (CAPPED_MAXAGE(cfg)) 7855 die("max age too small: need age >= %d and " 7856 "<= %d or hello time <= %d", 7857 MIN_MAXAGE(cfg), MAX_MAXAGE(cfg), 7858 MAX_HELLOTIME(cfg)); 7859 else 7860 die("max age too small: need age >= %d or " 7861 "hello time <= %d", 7862 MIN_MAXAGE(cfg), MAX_HELLOTIME(cfg)); 7863 } else if (FLOORED_MAXAGE(cfg)) { 7864 die("max age too large: need age >= %d and <= %d or " 7865 "forward delay >= %d", 7866 MIN_MAXAGE(cfg), MAX_MAXAGE(cfg), 7867 MIN_FWDELAY(cfg)); 7868 } else { 7869 die("max age too large: need age <= %d or forward " 7870 "delay >= %d", 7871 MAX_MAXAGE(cfg), MIN_FWDELAY(cfg)); 7872 } 7873 } 7874 7875 if (altroot != NULL) 7876 altroot_cmd(altroot, argc, argv); 7877 7878 for (n = 0; n < nlink; n++) { 7879 datalink_class_t class; 7880 uint32_t media; 7881 char pointless[DLADM_STRSIZE]; 7882 7883 if (dladm_name2info(handle, links[n], &linkids[n], NULL, &class, 7884 &media) != DLADM_STATUS_OK) 7885 die("invalid link name '%s'", links[n]); 7886 if (class & ~(DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | 7887 DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET)) 7888 die("%s %s cannot be bridged", 7889 dladm_class2str(class, pointless), links[n]); 7890 if (media != DL_ETHER && media != DL_100VG && 7891 media != DL_ETH_CSMA && media != DL_100BT) 7892 die("%s interface %s cannot be bridged", 7893 dladm_media2str(media, pointless), links[n]); 7894 } 7895 7896 if (func == brCreate) 7897 flags |= DLADM_OPT_CREATE; 7898 7899 if (func != brAdd) { 7900 status = dladm_bridge_configure(handle, bridge, &cfg, brprot, 7901 flags); 7902 if (status != DLADM_STATUS_OK) 7903 die_dlerr(status, "create operation failed"); 7904 } 7905 7906 status = DLADM_STATUS_OK; 7907 for (n = 0; n < nlink; n++) { 7908 status = dladm_bridge_setlink(handle, linkids[n], bridge); 7909 if (status != DLADM_STATUS_OK) 7910 break; 7911 } 7912 7913 if (n >= nlink) { 7914 /* 7915 * We were successful. If we're creating a new bridge, then 7916 * there's just one more step: enabling. If we're modifying or 7917 * just adding links, then we're done. 7918 */ 7919 if (func != brCreate || 7920 (status = dladm_bridge_enable(bridge)) == DLADM_STATUS_OK) 7921 return; 7922 } 7923 7924 /* clean up the partial configuration */ 7925 for (i = 0; i < n; i++) 7926 (void) dladm_bridge_setlink(handle, linkids[i], ""); 7927 7928 /* if failure for brCreate, then delete the bridge */ 7929 if (func == brCreate) 7930 (void) dladm_bridge_delete(handle, bridge, flags); 7931 7932 if (n < nlink) 7933 die_dlerr(status, "unable to add link %s to bridge %s", 7934 links[n], bridge); 7935 else 7936 die_dlerr(status, "unable to enable bridge %s", bridge); 7937 } 7938 7939 static void 7940 do_create_bridge(int argc, char **argv, const char *use) 7941 { 7942 create_modify_add_bridge(argc, argv, use, brCreate); 7943 } 7944 7945 static void 7946 do_modify_bridge(int argc, char **argv, const char *use) 7947 { 7948 create_modify_add_bridge(argc, argv, use, brModify); 7949 } 7950 7951 static void 7952 do_add_bridge(int argc, char **argv, const char *use) 7953 { 7954 create_modify_add_bridge(argc, argv, use, brAdd); 7955 } 7956 7957 static void 7958 do_delete_bridge(int argc, char **argv, const char *use) 7959 { 7960 char option; 7961 char *altroot = NULL; 7962 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 7963 dladm_status_t status; 7964 7965 opterr = 0; 7966 while ((option = getopt_long(argc, argv, ":R:", bridge_lopts, NULL)) != 7967 -1) { 7968 switch (option) { 7969 case 'R': 7970 altroot = optarg; 7971 break; 7972 default: 7973 die_opterr(optopt, option, use); 7974 break; 7975 } 7976 } 7977 7978 /* get the bridge name (required last argument) */ 7979 if (optind != (argc-1)) 7980 usage(); 7981 7982 if (altroot != NULL) 7983 altroot_cmd(altroot, argc, argv); 7984 7985 status = dladm_bridge_delete(handle, argv[optind], flags); 7986 if (status != DLADM_STATUS_OK) 7987 die_dlerr(status, "delete operation failed"); 7988 } 7989 7990 static void 7991 do_remove_bridge(int argc, char **argv, const char *use) 7992 { 7993 char option; 7994 uint_t n, nlink; 7995 char *links[MAXPORT]; 7996 datalink_id_t linkids[MAXPORT]; 7997 char *altroot = NULL; 7998 dladm_status_t status; 7999 boolean_t removed_one; 8000 8001 nlink = opterr = 0; 8002 while ((option = getopt_long(argc, argv, ":R:l:", bridge_lopts, 8003 NULL)) != -1) { 8004 switch (option) { 8005 case 'R': 8006 altroot = optarg; 8007 break; 8008 case 'l': 8009 if (nlink >= MAXPORT) 8010 die("too many links specified"); 8011 links[nlink++] = optarg; 8012 break; 8013 default: 8014 die_opterr(optopt, option, use); 8015 break; 8016 } 8017 } 8018 8019 if (nlink == 0) 8020 usage(); 8021 8022 /* get the bridge name (required last argument) */ 8023 if (optind != (argc-1)) 8024 usage(); 8025 8026 if (altroot != NULL) 8027 altroot_cmd(altroot, argc, argv); 8028 8029 for (n = 0; n < nlink; n++) { 8030 char bridge[MAXLINKNAMELEN]; 8031 8032 if (dladm_name2info(handle, links[n], &linkids[n], NULL, NULL, 8033 NULL) != DLADM_STATUS_OK) 8034 die("invalid link name '%s'", links[n]); 8035 status = dladm_bridge_getlink(handle, linkids[n], bridge, 8036 sizeof (bridge)); 8037 if (status != DLADM_STATUS_OK && 8038 status != DLADM_STATUS_NOTFOUND) { 8039 die_dlerr(status, "cannot get bridge status on %s", 8040 links[n]); 8041 } 8042 if (status == DLADM_STATUS_NOTFOUND || 8043 strcmp(bridge, argv[optind]) != 0) 8044 die("link %s is not on bridge %s", links[n], 8045 argv[optind]); 8046 } 8047 8048 removed_one = B_FALSE; 8049 for (n = 0; n < nlink; n++) { 8050 status = dladm_bridge_setlink(handle, linkids[n], ""); 8051 if (status == DLADM_STATUS_OK) { 8052 removed_one = B_TRUE; 8053 } else { 8054 warn_dlerr(status, 8055 "cannot remove link %s from bridge %s", 8056 links[n], argv[optind]); 8057 } 8058 } 8059 if (!removed_one) 8060 die("unable to remove any links from bridge %s", argv[optind]); 8061 } 8062 8063 static void 8064 fmt_int(char *buf, size_t buflen, int value, int runvalue, 8065 boolean_t printstar) 8066 { 8067 (void) snprintf(buf, buflen, "%d", value); 8068 if (value != runvalue && printstar) 8069 (void) strlcat(buf, "*", buflen); 8070 } 8071 8072 static void 8073 fmt_bridge_id(char *buf, size_t buflen, UID_BRIDGE_ID_T *bid) 8074 { 8075 (void) snprintf(buf, buflen, "%u/%x:%x:%x:%x:%x:%x", bid->prio, 8076 bid->addr[0], bid->addr[1], bid->addr[2], bid->addr[3], 8077 bid->addr[4], bid->addr[5]); 8078 } 8079 8080 static dladm_status_t 8081 print_bridge(show_state_t *state, datalink_id_t linkid, 8082 bridge_fields_buf_t *bbuf) 8083 { 8084 char link[MAXLINKNAMELEN]; 8085 datalink_class_t class; 8086 uint32_t flags; 8087 dladm_status_t status; 8088 UID_STP_CFG_T smfcfg, runcfg; 8089 UID_STP_STATE_T stpstate; 8090 dladm_bridge_prot_t smfprot, runprot; 8091 8092 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 8093 NULL, link, sizeof (link))) != DLADM_STATUS_OK) 8094 return (status); 8095 8096 if (!(state->ls_flags & flags)) 8097 return (DLADM_STATUS_NOTFOUND); 8098 8099 /* Convert observability node name back to bridge name */ 8100 if (!dladm_observe_to_bridge(link)) 8101 return (DLADM_STATUS_NOTFOUND); 8102 (void) strlcpy(bbuf->bridge_name, link, sizeof (bbuf->bridge_name)); 8103 8104 /* 8105 * If the running value differs from the one in SMF, and parsable 8106 * output is not requested, then we show the running value with an 8107 * asterisk. 8108 */ 8109 (void) dladm_bridge_get_properties(bbuf->bridge_name, &smfcfg, 8110 &smfprot); 8111 (void) dladm_bridge_run_properties(bbuf->bridge_name, &runcfg, 8112 &runprot); 8113 (void) snprintf(bbuf->bridge_protect, sizeof (bbuf->bridge_protect), 8114 "%s%s", state->ls_parsable || smfprot == runprot ? "" : "*", 8115 dladm_bridge_prot2str(runprot)); 8116 fmt_int(bbuf->bridge_priority, sizeof (bbuf->bridge_priority), 8117 smfcfg.bridge_priority, runcfg.bridge_priority, 8118 !state->ls_parsable && (runcfg.field_mask & BR_CFG_AGE)); 8119 fmt_int(bbuf->bridge_bmaxage, sizeof (bbuf->bridge_bmaxage), 8120 smfcfg.max_age, runcfg.max_age, 8121 !state->ls_parsable && (runcfg.field_mask & BR_CFG_AGE)); 8122 fmt_int(bbuf->bridge_bhellotime, 8123 sizeof (bbuf->bridge_bhellotime), smfcfg.hello_time, 8124 runcfg.hello_time, 8125 !state->ls_parsable && (runcfg.field_mask & BR_CFG_HELLO)); 8126 fmt_int(bbuf->bridge_bfwddelay, sizeof (bbuf->bridge_bfwddelay), 8127 smfcfg.forward_delay, runcfg.forward_delay, 8128 !state->ls_parsable && (runcfg.field_mask & BR_CFG_DELAY)); 8129 fmt_int(bbuf->bridge_forceproto, sizeof (bbuf->bridge_forceproto), 8130 smfcfg.force_version, runcfg.force_version, 8131 !state->ls_parsable && (runcfg.field_mask & BR_CFG_FORCE_VER)); 8132 fmt_int(bbuf->bridge_holdtime, sizeof (bbuf->bridge_holdtime), 8133 smfcfg.hold_time, runcfg.hold_time, 8134 !state->ls_parsable && (runcfg.field_mask & BR_CFG_HOLD_TIME)); 8135 8136 if (dladm_bridge_state(bbuf->bridge_name, &stpstate) == 8137 DLADM_STATUS_OK) { 8138 fmt_bridge_id(bbuf->bridge_address, 8139 sizeof (bbuf->bridge_address), &stpstate.bridge_id); 8140 (void) snprintf(bbuf->bridge_tctime, 8141 sizeof (bbuf->bridge_tctime), "%lu", 8142 stpstate.timeSince_Topo_Change); 8143 (void) snprintf(bbuf->bridge_tccount, 8144 sizeof (bbuf->bridge_tccount), "%lu", 8145 stpstate.Topo_Change_Count); 8146 (void) snprintf(bbuf->bridge_tchange, 8147 sizeof (bbuf->bridge_tchange), "%u", stpstate.Topo_Change); 8148 fmt_bridge_id(bbuf->bridge_desroot, 8149 sizeof (bbuf->bridge_desroot), &stpstate.designated_root); 8150 (void) snprintf(bbuf->bridge_rootcost, 8151 sizeof (bbuf->bridge_rootcost), "%lu", 8152 stpstate.root_path_cost); 8153 (void) snprintf(bbuf->bridge_rootport, 8154 sizeof (bbuf->bridge_rootport), "%u", stpstate.root_port); 8155 (void) snprintf(bbuf->bridge_maxage, 8156 sizeof (bbuf->bridge_maxage), "%d", stpstate.max_age); 8157 (void) snprintf(bbuf->bridge_hellotime, 8158 sizeof (bbuf->bridge_hellotime), "%d", stpstate.hello_time); 8159 (void) snprintf(bbuf->bridge_fwddelay, 8160 sizeof (bbuf->bridge_fwddelay), "%d", 8161 stpstate.forward_delay); 8162 } 8163 return (DLADM_STATUS_OK); 8164 } 8165 8166 static dladm_status_t 8167 print_bridge_stats(show_state_t *state, datalink_id_t linkid, 8168 bridge_statfields_buf_t *bbuf) 8169 { 8170 char link[MAXLINKNAMELEN]; 8171 datalink_class_t class; 8172 uint32_t flags; 8173 dladm_status_t status; 8174 kstat_ctl_t *kcp; 8175 kstat_t *ksp; 8176 brsum_t *brsum = (brsum_t *)&state->ls_prevstats; 8177 brsum_t newval; 8178 8179 #ifndef lint 8180 /* This is a compile-time assertion; optimizer normally fixes this */ 8181 extern void brsum_t_is_too_large(void); 8182 8183 if (sizeof (*brsum) > sizeof (state->ls_prevstats)) 8184 brsum_t_is_too_large(); 8185 #endif 8186 8187 if (state->ls_firstonly) { 8188 if (state->ls_donefirst) 8189 return (DLADM_WALK_CONTINUE); 8190 state->ls_donefirst = B_TRUE; 8191 } else { 8192 bzero(brsum, sizeof (*brsum)); 8193 } 8194 bzero(&newval, sizeof (newval)); 8195 8196 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 8197 NULL, link, sizeof (link))) != DLADM_STATUS_OK) 8198 return (status); 8199 8200 if (!(state->ls_flags & flags)) 8201 return (DLADM_STATUS_NOTFOUND); 8202 8203 if ((kcp = kstat_open()) == NULL) { 8204 warn("kstat open operation failed"); 8205 return (DLADM_STATUS_OK); 8206 } 8207 if ((ksp = kstat_lookup(kcp, "bridge", 0, link)) != NULL && 8208 kstat_read(kcp, ksp, NULL) != -1) { 8209 if (dladm_kstat_value(ksp, "drops", KSTAT_DATA_UINT64, 8210 &newval.drops) == DLADM_STATUS_OK) { 8211 (void) snprintf(bbuf->bridges_drops, 8212 sizeof (bbuf->bridges_drops), "%llu", 8213 newval.drops - brsum->drops); 8214 } 8215 if (dladm_kstat_value(ksp, "forward_direct", KSTAT_DATA_UINT64, 8216 &newval.forward_dir) == DLADM_STATUS_OK) { 8217 (void) snprintf(bbuf->bridges_forwards, 8218 sizeof (bbuf->bridges_forwards), "%llu", 8219 newval.forward_dir - brsum->forward_dir); 8220 } 8221 if (dladm_kstat_value(ksp, "forward_mbcast", KSTAT_DATA_UINT64, 8222 &newval.forward_mb) == DLADM_STATUS_OK) { 8223 (void) snprintf(bbuf->bridges_mbcast, 8224 sizeof (bbuf->bridges_mbcast), "%llu", 8225 newval.forward_mb - brsum->forward_mb); 8226 } 8227 if (dladm_kstat_value(ksp, "forward_unknown", KSTAT_DATA_UINT64, 8228 &newval.forward_unk) == DLADM_STATUS_OK) { 8229 (void) snprintf(bbuf->bridges_unknown, 8230 sizeof (bbuf->bridges_unknown), "%llu", 8231 newval.forward_unk - brsum->forward_unk); 8232 } 8233 if (dladm_kstat_value(ksp, "recv", KSTAT_DATA_UINT64, 8234 &newval.recv) == DLADM_STATUS_OK) { 8235 (void) snprintf(bbuf->bridges_recv, 8236 sizeof (bbuf->bridges_recv), "%llu", 8237 newval.recv - brsum->recv); 8238 } 8239 if (dladm_kstat_value(ksp, "sent", KSTAT_DATA_UINT64, 8240 &newval.sent) == DLADM_STATUS_OK) { 8241 (void) snprintf(bbuf->bridges_sent, 8242 sizeof (bbuf->bridges_sent), "%llu", 8243 newval.sent - brsum->sent); 8244 } 8245 } 8246 (void) kstat_close(kcp); 8247 8248 /* Convert observability node name back to bridge name */ 8249 if (!dladm_observe_to_bridge(link)) 8250 return (DLADM_STATUS_NOTFOUND); 8251 (void) strlcpy(bbuf->bridges_name, link, sizeof (bbuf->bridges_name)); 8252 8253 *brsum = newval; 8254 8255 return (DLADM_STATUS_OK); 8256 } 8257 8258 /* 8259 * This structure carries around extra state information for the show-bridge 8260 * command and allows us to use common support functions. 8261 */ 8262 typedef struct { 8263 show_state_t state; 8264 boolean_t show_stats; 8265 const char *bridge; 8266 } show_brstate_t; 8267 8268 /* ARGSUSED */ 8269 static int 8270 show_bridge(dladm_handle_t handle, datalink_id_t linkid, void *arg) 8271 { 8272 show_brstate_t *brstate = arg; 8273 void *buf; 8274 8275 if (brstate->show_stats) { 8276 bridge_statfields_buf_t bbuf; 8277 8278 bzero(&bbuf, sizeof (bbuf)); 8279 brstate->state.ls_status = print_bridge_stats(&brstate->state, 8280 linkid, &bbuf); 8281 buf = &bbuf; 8282 } else { 8283 bridge_fields_buf_t bbuf; 8284 8285 bzero(&bbuf, sizeof (bbuf)); 8286 brstate->state.ls_status = print_bridge(&brstate->state, linkid, 8287 &bbuf); 8288 buf = &bbuf; 8289 } 8290 if (brstate->state.ls_status == DLADM_STATUS_OK) 8291 ofmt_print(brstate->state.ls_ofmt, buf); 8292 return (DLADM_WALK_CONTINUE); 8293 } 8294 8295 static void 8296 fmt_bool(char *buf, size_t buflen, int val) 8297 { 8298 (void) strlcpy(buf, val ? "yes" : "no", buflen); 8299 } 8300 8301 static dladm_status_t 8302 print_bridge_link(show_state_t *state, datalink_id_t linkid, 8303 bridge_link_fields_buf_t *bbuf) 8304 { 8305 datalink_class_t class; 8306 uint32_t flags; 8307 dladm_status_t status; 8308 UID_STP_PORT_STATE_T stpstate; 8309 8310 status = dladm_datalink_id2info(handle, linkid, &flags, &class, NULL, 8311 bbuf->bridgel_link, sizeof (bbuf->bridgel_link)); 8312 if (status != DLADM_STATUS_OK) 8313 return (status); 8314 8315 if (!(state->ls_flags & flags)) 8316 return (DLADM_STATUS_NOTFOUND); 8317 8318 if (dladm_bridge_link_state(handle, linkid, &stpstate) == 8319 DLADM_STATUS_OK) { 8320 (void) snprintf(bbuf->bridgel_index, 8321 sizeof (bbuf->bridgel_index), "%u", stpstate.port_no); 8322 if (dlsym(RTLD_PROBE, "STP_IN_state2str")) { 8323 (void) strlcpy(bbuf->bridgel_state, 8324 STP_IN_state2str(stpstate.state), 8325 sizeof (bbuf->bridgel_state)); 8326 } else { 8327 (void) snprintf(bbuf->bridgel_state, 8328 sizeof (bbuf->bridgel_state), "%u", 8329 stpstate.state); 8330 } 8331 (void) snprintf(bbuf->bridgel_uptime, 8332 sizeof (bbuf->bridgel_uptime), "%lu", stpstate.uptime); 8333 (void) snprintf(bbuf->bridgel_opercost, 8334 sizeof (bbuf->bridgel_opercost), "%lu", 8335 stpstate.oper_port_path_cost); 8336 fmt_bool(bbuf->bridgel_operp2p, sizeof (bbuf->bridgel_operp2p), 8337 stpstate.oper_point2point); 8338 fmt_bool(bbuf->bridgel_operedge, 8339 sizeof (bbuf->bridgel_operedge), stpstate.oper_edge); 8340 fmt_bridge_id(bbuf->bridgel_desroot, 8341 sizeof (bbuf->bridgel_desroot), &stpstate.designated_root); 8342 (void) snprintf(bbuf->bridgel_descost, 8343 sizeof (bbuf->bridgel_descost), "%lu", 8344 stpstate.designated_cost); 8345 fmt_bridge_id(bbuf->bridgel_desbridge, 8346 sizeof (bbuf->bridgel_desbridge), 8347 &stpstate.designated_bridge); 8348 (void) snprintf(bbuf->bridgel_desport, 8349 sizeof (bbuf->bridgel_desport), "%u", 8350 stpstate.designated_port); 8351 fmt_bool(bbuf->bridgel_tcack, sizeof (bbuf->bridgel_tcack), 8352 stpstate.top_change_ack); 8353 } 8354 return (DLADM_STATUS_OK); 8355 } 8356 8357 static dladm_status_t 8358 print_bridge_link_stats(show_state_t *state, datalink_id_t linkid, 8359 bridge_link_statfields_buf_t *bbuf) 8360 { 8361 datalink_class_t class; 8362 uint32_t flags; 8363 dladm_status_t status; 8364 UID_STP_PORT_STATE_T stpstate; 8365 kstat_ctl_t *kcp; 8366 kstat_t *ksp; 8367 char bridge[MAXLINKNAMELEN]; 8368 char kstatname[MAXLINKNAMELEN*2 + 1]; 8369 brlsum_t *brlsum = (brlsum_t *)&state->ls_prevstats; 8370 brlsum_t newval; 8371 8372 #ifndef lint 8373 /* This is a compile-time assertion; optimizer normally fixes this */ 8374 extern void brlsum_t_is_too_large(void); 8375 8376 if (sizeof (*brlsum) > sizeof (state->ls_prevstats)) 8377 brlsum_t_is_too_large(); 8378 #endif 8379 8380 if (state->ls_firstonly) { 8381 if (state->ls_donefirst) 8382 return (DLADM_WALK_CONTINUE); 8383 state->ls_donefirst = B_TRUE; 8384 } else { 8385 bzero(brlsum, sizeof (*brlsum)); 8386 } 8387 bzero(&newval, sizeof (newval)); 8388 8389 status = dladm_datalink_id2info(handle, linkid, &flags, &class, NULL, 8390 bbuf->bridgels_link, sizeof (bbuf->bridgels_link)); 8391 if (status != DLADM_STATUS_OK) 8392 return (status); 8393 8394 if (!(state->ls_flags & flags)) 8395 return (DLADM_STATUS_NOTFOUND); 8396 8397 if (dladm_bridge_link_state(handle, linkid, &stpstate) == 8398 DLADM_STATUS_OK) { 8399 newval.cfgbpdu = stpstate.rx_cfg_bpdu_cnt; 8400 newval.tcnbpdu = stpstate.rx_tcn_bpdu_cnt; 8401 newval.rstpbpdu = stpstate.rx_rstp_bpdu_cnt; 8402 newval.txbpdu = stpstate.txCount; 8403 8404 (void) snprintf(bbuf->bridgels_cfgbpdu, 8405 sizeof (bbuf->bridgels_cfgbpdu), "%lu", 8406 newval.cfgbpdu - brlsum->cfgbpdu); 8407 (void) snprintf(bbuf->bridgels_tcnbpdu, 8408 sizeof (bbuf->bridgels_tcnbpdu), "%lu", 8409 newval.tcnbpdu - brlsum->tcnbpdu); 8410 (void) snprintf(bbuf->bridgels_rstpbpdu, 8411 sizeof (bbuf->bridgels_rstpbpdu), "%lu", 8412 newval.rstpbpdu - brlsum->rstpbpdu); 8413 (void) snprintf(bbuf->bridgels_txbpdu, 8414 sizeof (bbuf->bridgels_txbpdu), "%lu", 8415 newval.txbpdu - brlsum->txbpdu); 8416 } 8417 8418 if ((status = dladm_bridge_getlink(handle, linkid, bridge, 8419 sizeof (bridge))) != DLADM_STATUS_OK) 8420 goto bls_out; 8421 (void) snprintf(kstatname, sizeof (kstatname), "%s0-%s", bridge, 8422 bbuf->bridgels_link); 8423 if ((kcp = kstat_open()) == NULL) { 8424 warn("kstat open operation failed"); 8425 goto bls_out; 8426 } 8427 if ((ksp = kstat_lookup(kcp, "bridge", 0, kstatname)) != NULL && 8428 kstat_read(kcp, ksp, NULL) != -1) { 8429 if (dladm_kstat_value(ksp, "drops", KSTAT_DATA_UINT64, 8430 &newval.drops) != -1) { 8431 (void) snprintf(bbuf->bridgels_drops, 8432 sizeof (bbuf->bridgels_drops), "%llu", 8433 newval.drops - brlsum->drops); 8434 } 8435 if (dladm_kstat_value(ksp, "recv", KSTAT_DATA_UINT64, 8436 &newval.recv) != -1) { 8437 (void) snprintf(bbuf->bridgels_recv, 8438 sizeof (bbuf->bridgels_recv), "%llu", 8439 newval.recv - brlsum->recv); 8440 } 8441 if (dladm_kstat_value(ksp, "xmit", KSTAT_DATA_UINT64, 8442 &newval.xmit) != -1) { 8443 (void) snprintf(bbuf->bridgels_xmit, 8444 sizeof (bbuf->bridgels_xmit), "%llu", 8445 newval.xmit - brlsum->xmit); 8446 } 8447 } 8448 (void) kstat_close(kcp); 8449 bls_out: 8450 *brlsum = newval; 8451 8452 return (status); 8453 } 8454 8455 static void 8456 show_bridge_link(datalink_id_t linkid, show_brstate_t *brstate) 8457 { 8458 void *buf; 8459 8460 if (brstate->show_stats) { 8461 bridge_link_statfields_buf_t bbuf; 8462 8463 bzero(&bbuf, sizeof (bbuf)); 8464 brstate->state.ls_status = print_bridge_link_stats( 8465 &brstate->state, linkid, &bbuf); 8466 buf = &bbuf; 8467 } else { 8468 bridge_link_fields_buf_t bbuf; 8469 8470 bzero(&bbuf, sizeof (bbuf)); 8471 brstate->state.ls_status = print_bridge_link(&brstate->state, 8472 linkid, &bbuf); 8473 buf = &bbuf; 8474 } 8475 if (brstate->state.ls_status == DLADM_STATUS_OK) 8476 ofmt_print(brstate->state.ls_ofmt, buf); 8477 } 8478 8479 /* ARGSUSED */ 8480 static int 8481 show_bridge_link_walk(dladm_handle_t handle, datalink_id_t linkid, void *arg) 8482 { 8483 show_brstate_t *brstate = arg; 8484 char bridge[MAXLINKNAMELEN]; 8485 8486 if (dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)) == 8487 DLADM_STATUS_OK && strcmp(bridge, brstate->bridge) == 0) { 8488 show_bridge_link(linkid, brstate); 8489 } 8490 return (DLADM_WALK_CONTINUE); 8491 } 8492 8493 static void 8494 show_bridge_fwd(dladm_handle_t handle, bridge_listfwd_t *blf, 8495 show_state_t *state) 8496 { 8497 bridge_fwd_fields_buf_t bbuf; 8498 8499 bzero(&bbuf, sizeof (bbuf)); 8500 (void) snprintf(bbuf.bridgef_dest, sizeof (bbuf.bridgef_dest), 8501 "%s", ether_ntoa((struct ether_addr *)blf->blf_dest)); 8502 if (blf->blf_is_local) { 8503 (void) strlcpy(bbuf.bridgef_flags, "L", 8504 sizeof (bbuf.bridgef_flags)); 8505 } else { 8506 (void) snprintf(bbuf.bridgef_age, sizeof (bbuf.bridgef_age), 8507 "%2d.%03d", blf->blf_ms_age / 1000, blf->blf_ms_age % 1000); 8508 if (blf->blf_trill_nick != 0) { 8509 (void) snprintf(bbuf.bridgef_output, 8510 sizeof (bbuf.bridgef_output), "%u", 8511 blf->blf_trill_nick); 8512 } 8513 } 8514 if (blf->blf_linkid != DATALINK_INVALID_LINKID && 8515 blf->blf_trill_nick == 0) { 8516 state->ls_status = dladm_datalink_id2info(handle, 8517 blf->blf_linkid, NULL, NULL, NULL, bbuf.bridgef_output, 8518 sizeof (bbuf.bridgef_output)); 8519 } 8520 if (state->ls_status == DLADM_STATUS_OK) 8521 ofmt_print(state->ls_ofmt, &bbuf); 8522 } 8523 8524 static void 8525 show_bridge_trillnick(trill_listnick_t *tln, show_state_t *state) 8526 { 8527 bridge_trill_fields_buf_t bbuf; 8528 8529 bzero(&bbuf, sizeof (bbuf)); 8530 (void) snprintf(bbuf.bridget_nick, sizeof (bbuf.bridget_nick), 8531 "%u", tln->tln_nick); 8532 if (tln->tln_ours) { 8533 (void) strlcpy(bbuf.bridget_flags, "L", 8534 sizeof (bbuf.bridget_flags)); 8535 } else { 8536 state->ls_status = dladm_datalink_id2info(handle, 8537 tln->tln_linkid, NULL, NULL, NULL, bbuf.bridget_link, 8538 sizeof (bbuf.bridget_link)); 8539 (void) snprintf(bbuf.bridget_nexthop, 8540 sizeof (bbuf.bridget_nexthop), "%s", 8541 ether_ntoa((struct ether_addr *)tln->tln_nexthop)); 8542 } 8543 if (state->ls_status == DLADM_STATUS_OK) 8544 ofmt_print(state->ls_ofmt, &bbuf); 8545 } 8546 8547 static void 8548 do_show_bridge(int argc, char **argv, const char *use) 8549 { 8550 int option; 8551 enum { 8552 bridgeMode, linkMode, fwdMode, trillMode 8553 } op_mode = bridgeMode; 8554 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 8555 boolean_t parsable = B_FALSE; 8556 datalink_id_t linkid = DATALINK_ALL_LINKID; 8557 int interval = 0; 8558 show_brstate_t brstate; 8559 dladm_status_t status; 8560 char *fields_str = NULL; 8561 /* default: bridge-related data */ 8562 char *all_fields = "bridge,protect,address,priority,bmaxage," 8563 "bhellotime,bfwddelay,forceproto,tctime,tccount,tchange," 8564 "desroot,rootcost,rootport,maxage,hellotime,fwddelay,holdtime"; 8565 char *default_fields = "bridge,protect,address,priority," 8566 "desroot"; 8567 char *all_statfields = "bridge,drops,forwards,mbcast," 8568 "unknown,recv,sent"; 8569 char *default_statfields = "bridge,drops,forwards,mbcast," 8570 "unknown"; 8571 /* -l: link-related data */ 8572 char *all_link_fields = "link,index,state,uptime,opercost," 8573 "operp2p,operedge,desroot,descost,desbridge,desport,tcack"; 8574 char *default_link_fields = "link,state,uptime,desroot"; 8575 char *all_link_statfields = "link,cfgbpdu,tcnbpdu,rstpbpdu," 8576 "txbpdu,drops,recv,xmit"; 8577 char *default_link_statfields = "link,drops,recv,xmit"; 8578 /* -f: bridge forwarding table related data */ 8579 char *default_fwd_fields = "dest,age,flags,output"; 8580 /* -t: TRILL nickname table related data */ 8581 char *default_trill_fields = "nick,flags,link,nexthop"; 8582 char *default_str; 8583 char *all_str; 8584 ofmt_field_t *field_arr; 8585 ofmt_handle_t ofmt; 8586 ofmt_status_t oferr; 8587 uint_t ofmtflags = 0; 8588 8589 bzero(&brstate, sizeof (brstate)); 8590 8591 opterr = 0; 8592 while ((option = getopt_long(argc, argv, ":fi:lo:pst", 8593 bridge_show_lopts, NULL)) != -1) { 8594 switch (option) { 8595 case 'f': 8596 if (op_mode != bridgeMode && op_mode != fwdMode) 8597 die("-f is incompatible with -l or -t"); 8598 op_mode = fwdMode; 8599 break; 8600 case 'i': 8601 if (interval != 0) 8602 die_optdup(option); 8603 if (!str2int(optarg, &interval) || interval == 0) 8604 die("invalid interval value '%s'", optarg); 8605 break; 8606 case 'l': 8607 if (op_mode != bridgeMode && op_mode != linkMode) 8608 die("-l is incompatible with -f or -t"); 8609 op_mode = linkMode; 8610 break; 8611 case 'o': 8612 fields_str = optarg; 8613 break; 8614 case 'p': 8615 if (parsable) 8616 die_optdup(option); 8617 parsable = B_TRUE; 8618 break; 8619 case 's': 8620 if (brstate.show_stats) 8621 die_optdup(option); 8622 brstate.show_stats = B_TRUE; 8623 break; 8624 case 't': 8625 if (op_mode != bridgeMode && op_mode != trillMode) 8626 die("-t is incompatible with -f or -l"); 8627 op_mode = trillMode; 8628 break; 8629 default: 8630 die_opterr(optopt, option, use); 8631 break; 8632 } 8633 } 8634 8635 if (interval != 0 && !brstate.show_stats) 8636 die("the -i option can be used only with -s"); 8637 8638 if ((op_mode == fwdMode || op_mode == trillMode) && brstate.show_stats) 8639 die("the -f/-t and -s options cannot be used together"); 8640 8641 /* get the bridge name (optional last argument) */ 8642 if (optind == (argc-1)) { 8643 char lname[MAXLINKNAMELEN]; 8644 uint32_t lnkflg; 8645 datalink_class_t class; 8646 8647 brstate.bridge = argv[optind]; 8648 (void) snprintf(lname, sizeof (lname), "%s0", brstate.bridge); 8649 if ((status = dladm_name2info(handle, lname, &linkid, &lnkflg, 8650 &class, NULL)) != DLADM_STATUS_OK) { 8651 die_dlerr(status, "bridge %s is not valid", 8652 brstate.bridge); 8653 } 8654 8655 if (class != DATALINK_CLASS_BRIDGE) 8656 die("%s is not a bridge", brstate.bridge); 8657 8658 if (!(lnkflg & flags)) { 8659 die_dlerr(DLADM_STATUS_BADARG, 8660 "bridge %s is temporarily removed", brstate.bridge); 8661 } 8662 } else if (optind != argc) { 8663 usage(); 8664 } else if (op_mode != bridgeMode) { 8665 die("bridge name required for -l, -f, or -t"); 8666 return; 8667 } 8668 8669 brstate.state.ls_parsable = parsable; 8670 brstate.state.ls_flags = flags; 8671 brstate.state.ls_firstonly = (interval != 0); 8672 8673 switch (op_mode) { 8674 case bridgeMode: 8675 if (brstate.show_stats) { 8676 default_str = default_statfields; 8677 all_str = all_statfields; 8678 field_arr = bridge_statfields; 8679 } else { 8680 default_str = default_fields; 8681 all_str = all_fields; 8682 field_arr = bridge_fields; 8683 } 8684 break; 8685 8686 case linkMode: 8687 if (brstate.show_stats) { 8688 default_str = default_link_statfields; 8689 all_str = all_link_statfields; 8690 field_arr = bridge_link_statfields; 8691 } else { 8692 default_str = default_link_fields; 8693 all_str = all_link_fields; 8694 field_arr = bridge_link_fields; 8695 } 8696 break; 8697 8698 case fwdMode: 8699 default_str = all_str = default_fwd_fields; 8700 field_arr = bridge_fwd_fields; 8701 break; 8702 8703 case trillMode: 8704 default_str = all_str = default_trill_fields; 8705 field_arr = bridge_trill_fields; 8706 break; 8707 } 8708 8709 if (fields_str == NULL) 8710 fields_str = default_str; 8711 else if (strcasecmp(fields_str, "all") == 0) 8712 fields_str = all_str; 8713 8714 if (parsable) 8715 ofmtflags |= OFMT_PARSABLE; 8716 oferr = ofmt_open(fields_str, field_arr, ofmtflags, 0, &ofmt); 8717 ofmt_check(oferr, brstate.state.ls_parsable, ofmt, die, warn); 8718 brstate.state.ls_ofmt = ofmt; 8719 8720 for (;;) { 8721 brstate.state.ls_donefirst = B_FALSE; 8722 switch (op_mode) { 8723 case bridgeMode: 8724 if (linkid == DATALINK_ALL_LINKID) { 8725 (void) dladm_walk_datalink_id(show_bridge, 8726 handle, &brstate, DATALINK_CLASS_BRIDGE, 8727 DATALINK_ANY_MEDIATYPE, flags); 8728 } else { 8729 (void) show_bridge(handle, linkid, &brstate); 8730 if (brstate.state.ls_status != 8731 DLADM_STATUS_OK) { 8732 die_dlerr(brstate.state.ls_status, 8733 "failed to show bridge %s", 8734 brstate.bridge); 8735 } 8736 } 8737 break; 8738 8739 case linkMode: { 8740 datalink_id_t *dlp; 8741 uint_t i, nlinks; 8742 8743 dlp = dladm_bridge_get_portlist(brstate.bridge, 8744 &nlinks); 8745 if (dlp != NULL) { 8746 for (i = 0; i < nlinks; i++) 8747 show_bridge_link(dlp[i], &brstate); 8748 dladm_bridge_free_portlist(dlp); 8749 } else if (errno == ENOENT) { 8750 /* bridge not running; iterate on libdladm */ 8751 (void) dladm_walk_datalink_id( 8752 show_bridge_link_walk, handle, 8753 &brstate, DATALINK_CLASS_PHYS | 8754 DATALINK_CLASS_AGGR | 8755 DATALINK_CLASS_ETHERSTUB, 8756 DATALINK_ANY_MEDIATYPE, flags); 8757 } else { 8758 die("unable to get port list for bridge %s: %s", 8759 brstate.bridge, strerror(errno)); 8760 } 8761 break; 8762 } 8763 8764 case fwdMode: { 8765 bridge_listfwd_t *blf; 8766 uint_t i, nfwd; 8767 8768 blf = dladm_bridge_get_fwdtable(handle, brstate.bridge, 8769 &nfwd); 8770 if (blf == NULL) { 8771 die("unable to get forwarding entries for " 8772 "bridge %s", brstate.bridge); 8773 } else { 8774 for (i = 0; i < nfwd; i++) 8775 show_bridge_fwd(handle, blf + i, 8776 &brstate.state); 8777 dladm_bridge_free_fwdtable(blf); 8778 } 8779 break; 8780 } 8781 8782 case trillMode: { 8783 trill_listnick_t *tln; 8784 uint_t i, nnick; 8785 8786 tln = dladm_bridge_get_trillnick(brstate.bridge, 8787 &nnick); 8788 if (tln == NULL) { 8789 if (errno == ENOENT) 8790 die("bridge %s is not running TRILL", 8791 brstate.bridge); 8792 else 8793 die("unable to get TRILL nickname " 8794 "entries for bridge %s", 8795 brstate.bridge); 8796 } else { 8797 for (i = 0; i < nnick; i++) 8798 show_bridge_trillnick(tln + i, 8799 &brstate.state); 8800 dladm_bridge_free_trillnick(tln); 8801 } 8802 break; 8803 } 8804 } 8805 if (interval == 0) 8806 break; 8807 (void) sleep(interval); 8808 } 8809 } 8810 8811 /* 8812 * "-R" option support. It is used for live upgrading. Append dladm commands 8813 * to a upgrade script which will be run when the alternative root boots up: 8814 * 8815 * - If the /etc/dladm/datalink.conf file exists on the alternative root, 8816 * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink 8817 * script. This script will be run as part of the network/physical service. 8818 * We cannot defer this to /var/svc/profile/upgrade because then the 8819 * configuration will not be able to take effect before network/physical 8820 * plumbs various interfaces. 8821 * 8822 * - If the /etc/dladm/datalink.conf file does not exist on the alternative 8823 * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script, 8824 * which will be run in the manifest-import service. 8825 * 8826 * Note that the SMF team is considering to move the manifest-import service 8827 * to be run at the very begining of boot. Once that is done, the need for 8828 * the /var/svc/profile/upgrade_datalink script will not exist any more. 8829 */ 8830 static void 8831 altroot_cmd(char *altroot, int argc, char *argv[]) 8832 { 8833 char path[MAXPATHLEN]; 8834 struct stat stbuf; 8835 FILE *fp; 8836 int i; 8837 8838 /* 8839 * Check for the existence of the /etc/dladm/datalink.conf 8840 * configuration file, and determine the name of script file. 8841 */ 8842 (void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf", 8843 altroot); 8844 if (stat(path, &stbuf) < 0) { 8845 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 8846 SMF_UPGRADE_FILE); 8847 } else { 8848 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 8849 SMF_UPGRADEDATALINK_FILE); 8850 } 8851 8852 if ((fp = fopen(path, "a+")) == NULL) 8853 die("operation not supported on %s", altroot); 8854 8855 (void) fprintf(fp, "/sbin/dladm "); 8856 for (i = 0; i < argc; i++) { 8857 /* 8858 * Directly write to the file if it is not the "-R <altroot>" 8859 * option. In which case, skip it. 8860 */ 8861 if (strcmp(argv[i], "-R") != 0) 8862 (void) fprintf(fp, "%s ", argv[i]); 8863 else 8864 i ++; 8865 } 8866 (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG); 8867 (void) fclose(fp); 8868 dladm_close(handle); 8869 exit(EXIT_SUCCESS); 8870 } 8871 8872 /* 8873 * Convert the string to an integer. Note that the string must not have any 8874 * trailing non-integer characters. 8875 */ 8876 static boolean_t 8877 str2int(const char *str, int *valp) 8878 { 8879 int val; 8880 char *endp = NULL; 8881 8882 errno = 0; 8883 val = strtol(str, &endp, 10); 8884 if (errno != 0 || *endp != '\0') 8885 return (B_FALSE); 8886 8887 *valp = val; 8888 return (B_TRUE); 8889 } 8890 8891 /* PRINTFLIKE1 */ 8892 static void 8893 warn(const char *format, ...) 8894 { 8895 va_list alist; 8896 8897 format = gettext(format); 8898 (void) fprintf(stderr, "%s: warning: ", progname); 8899 8900 va_start(alist, format); 8901 (void) vfprintf(stderr, format, alist); 8902 va_end(alist); 8903 8904 (void) putc('\n', stderr); 8905 } 8906 8907 /* PRINTFLIKE2 */ 8908 static void 8909 warn_dlerr(dladm_status_t err, const char *format, ...) 8910 { 8911 va_list alist; 8912 char errmsg[DLADM_STRSIZE]; 8913 8914 format = gettext(format); 8915 (void) fprintf(stderr, gettext("%s: warning: "), progname); 8916 8917 va_start(alist, format); 8918 (void) vfprintf(stderr, format, alist); 8919 va_end(alist); 8920 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 8921 } 8922 8923 /* 8924 * Also closes the dladm handle if it is not NULL. 8925 */ 8926 /* PRINTFLIKE2 */ 8927 static void 8928 die_dlerr(dladm_status_t err, const char *format, ...) 8929 { 8930 va_list alist; 8931 char errmsg[DLADM_STRSIZE]; 8932 8933 format = gettext(format); 8934 (void) fprintf(stderr, "%s: ", progname); 8935 8936 va_start(alist, format); 8937 (void) vfprintf(stderr, format, alist); 8938 va_end(alist); 8939 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 8940 8941 /* close dladm handle if it was opened */ 8942 if (handle != NULL) 8943 dladm_close(handle); 8944 8945 exit(EXIT_FAILURE); 8946 } 8947 8948 /* PRINTFLIKE1 */ 8949 static void 8950 die(const char *format, ...) 8951 { 8952 va_list alist; 8953 8954 format = gettext(format); 8955 (void) fprintf(stderr, "%s: ", progname); 8956 8957 va_start(alist, format); 8958 (void) vfprintf(stderr, format, alist); 8959 va_end(alist); 8960 8961 (void) putc('\n', stderr); 8962 8963 /* close dladm handle if it was opened */ 8964 if (handle != NULL) 8965 dladm_close(handle); 8966 8967 exit(EXIT_FAILURE); 8968 } 8969 8970 static void 8971 die_optdup(int opt) 8972 { 8973 die("the option -%c cannot be specified more than once", opt); 8974 } 8975 8976 static void 8977 die_opterr(int opt, int opterr, const char *usage) 8978 { 8979 switch (opterr) { 8980 case ':': 8981 die("option '-%c' requires a value\nusage: %s", opt, 8982 gettext(usage)); 8983 break; 8984 case '?': 8985 default: 8986 die("unrecognized option '-%c'\nusage: %s", opt, 8987 gettext(usage)); 8988 break; 8989 } 8990 } 8991 8992 static void 8993 show_ether_xprop(void *arg, dladm_ether_info_t *eattr) 8994 { 8995 print_ether_state_t *statep = arg; 8996 ether_fields_buf_t ebuf; 8997 int i; 8998 8999 for (i = CAPABLE; i <= PEERADV; i++) { 9000 bzero(&ebuf, sizeof (ebuf)); 9001 (void) strlcpy(ebuf.eth_ptype, ptype[i], 9002 sizeof (ebuf.eth_ptype)); 9003 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 9004 sizeof (ebuf.eth_autoneg), eattr, i); 9005 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 9006 sizeof (ebuf.eth_spdx), eattr, i); 9007 (void) dladm_ether_pause2str(ebuf.eth_pause, 9008 sizeof (ebuf.eth_pause), eattr, i); 9009 (void) strlcpy(ebuf.eth_rem_fault, 9010 (eattr->lei_attr[i].le_fault ? "fault" : "none"), 9011 sizeof (ebuf.eth_rem_fault)); 9012 ofmt_print(statep->es_ofmt, &ebuf); 9013 } 9014 9015 } 9016 9017 static boolean_t 9018 link_is_ether(const char *link, datalink_id_t *linkid) 9019 { 9020 uint32_t media; 9021 datalink_class_t class; 9022 9023 if (dladm_name2info(handle, link, linkid, NULL, &class, &media) == 9024 DLADM_STATUS_OK) { 9025 if (class == DATALINK_CLASS_PHYS && media == DL_ETHER) 9026 return (B_TRUE); 9027 } 9028 return (B_FALSE); 9029 } 9030 9031 /* 9032 * default output callback function that, when invoked, 9033 * prints string which is offset by ofmt_arg->ofmt_id within buf. 9034 */ 9035 static boolean_t 9036 print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 9037 { 9038 char *value; 9039 9040 value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id; 9041 (void) strlcpy(buf, value, bufsize); 9042 return (B_TRUE); 9043 } 9044 9045 /* 9046 * Called from the walker dladm_walk_datalink_id() for each IB partition to 9047 * display IB partition specific information. 9048 */ 9049 static dladm_status_t 9050 print_part(show_part_state_t *state, datalink_id_t linkid) 9051 { 9052 dladm_part_attr_t attr; 9053 dladm_status_t status; 9054 dladm_conf_t conf; 9055 char part_over[MAXLINKNAMELEN]; 9056 char part_name[MAXLINKNAMELEN]; 9057 part_fields_buf_t pbuf; 9058 boolean_t force_in_conf = B_FALSE; 9059 9060 /* 9061 * Get the information about the IB partition from the partition 9062 * datlink ID 'linkid'. 9063 */ 9064 if ((status = dladm_part_info(handle, linkid, &attr, state->ps_flags)) 9065 != DLADM_STATUS_OK) 9066 return (status); 9067 9068 /* 9069 * If an IB Phys link name was provided on the command line we have 9070 * the Phys link's datalink ID in the ps_over_id field of the state 9071 * structure. Proceed only if the IB partition represented by 'linkid' 9072 * was created over Phys link denoted by ps_over_id. The 9073 * 'dia_physlinkid' field of dladm_part_attr_t represents the IB Phys 9074 * link over which the partition was created. 9075 */ 9076 if (state->ps_over_id != DATALINK_ALL_LINKID) 9077 if (state->ps_over_id != attr.dia_physlinkid) 9078 return (DLADM_STATUS_OK); 9079 9080 /* 9081 * The linkid argument passed to this function is the datalink ID 9082 * of the IB Partition. Get the partitions name from this linkid. 9083 */ 9084 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, 9085 NULL, part_name, sizeof (part_name)) != DLADM_STATUS_OK) 9086 return (DLADM_STATUS_BADARG); 9087 9088 bzero(part_over, sizeof (part_over)); 9089 9090 /* 9091 * The 'dia_physlinkid' field contains the datalink ID of the IB Phys 9092 * link over which the partition was created. Use this linkid to get the 9093 * linkover field. 9094 */ 9095 if (dladm_datalink_id2info(handle, attr.dia_physlinkid, NULL, NULL, 9096 NULL, part_over, sizeof (part_over)) != DLADM_STATUS_OK) 9097 (void) sprintf(part_over, "?"); 9098 state->ps_found = B_TRUE; 9099 9100 /* 9101 * Read the FFORCE field from this datalink's persistent configuration 9102 * database line to determine if this datalink was created forcibly. 9103 * If this datalink is a temporary datalink, then it will not have an 9104 * entry in the persistent configuration, so check if force create flag 9105 * is set in the partition attributes. 9106 * 9107 * We need this two level check since persistent partitions brought up 9108 * by up-part during boot will have force create flag always set, since 9109 * we want up-part to always succeed even if the port is currently down 9110 * or P_Key is not yet available in the subnet. 9111 */ 9112 if ((status = dladm_getsnap_conf(handle, linkid, &conf)) == 9113 DLADM_STATUS_OK) { 9114 (void) dladm_get_conf_field(handle, conf, FFORCE, 9115 &force_in_conf, sizeof (boolean_t)); 9116 dladm_destroy_conf(handle, conf); 9117 } else if (status == DLADM_STATUS_NOTFOUND) { 9118 /* 9119 * for a temp link the force create flag will determine 9120 * whether it was created with force flag. 9121 */ 9122 force_in_conf = ((attr.dia_flags & DLADM_PART_FORCE_CREATE) 9123 != 0); 9124 } 9125 9126 (void) snprintf(pbuf.part_link, sizeof (pbuf.part_link), 9127 "%s", part_name); 9128 9129 (void) snprintf(pbuf.part_over, sizeof (pbuf.part_over), 9130 "%s", part_over); 9131 9132 (void) snprintf(pbuf.part_pkey, sizeof (pbuf.part_pkey), 9133 "%X", attr.dia_pkey); 9134 9135 (void) get_linkstate(pbuf.part_link, B_TRUE, pbuf.part_state); 9136 9137 (void) snprintf(pbuf.part_flags, sizeof (pbuf.part_flags), 9138 "%c----", force_in_conf ? 'f' : '-'); 9139 9140 ofmt_print(state->ps_ofmt, &pbuf); 9141 9142 return (DLADM_STATUS_OK); 9143 } 9144 9145 /* ARGSUSED */ 9146 static int 9147 show_part(dladm_handle_t dh, datalink_id_t linkid, void *arg) 9148 { 9149 ((show_part_state_t *)arg)->ps_status = print_part(arg, linkid); 9150 return (DLADM_WALK_CONTINUE); 9151 } 9152 9153 /* 9154 * Show the information about the IB partition objects. 9155 */ 9156 static void 9157 do_show_part(int argc, char *argv[], const char *use) 9158 { 9159 int option; 9160 boolean_t l_arg = B_FALSE; 9161 uint32_t flags = DLADM_OPT_ACTIVE; 9162 datalink_id_t linkid = DATALINK_ALL_LINKID; 9163 datalink_id_t over_linkid = DATALINK_ALL_LINKID; 9164 char over_link[MAXLINKNAMELEN]; 9165 show_part_state_t state; 9166 dladm_status_t status; 9167 boolean_t o_arg = B_FALSE; 9168 char *fields_str = NULL; 9169 ofmt_handle_t ofmt; 9170 ofmt_status_t oferr; 9171 uint_t ofmtflags = 0; 9172 9173 bzero(&state, sizeof (state)); 9174 opterr = 0; 9175 while ((option = getopt_long(argc, argv, ":pPl:o:", show_part_lopts, 9176 NULL)) != -1) { 9177 switch (option) { 9178 case 'p': 9179 state.ps_parsable = B_TRUE; 9180 break; 9181 case 'P': 9182 flags = DLADM_OPT_PERSIST; 9183 break; 9184 case 'l': 9185 /* 9186 * The data link ID of the IB Phys link. When this 9187 * argument is provided we list only the partition 9188 * objects created over this IB Phys link. 9189 */ 9190 if (strlcpy(over_link, optarg, MAXLINKNAMELEN) >= 9191 MAXLINKNAMELEN) 9192 die("link name too long"); 9193 9194 l_arg = B_TRUE; 9195 break; 9196 case 'o': 9197 o_arg = B_TRUE; 9198 fields_str = optarg; 9199 break; 9200 default: 9201 die_opterr(optopt, option, use); 9202 } 9203 } 9204 9205 /* 9206 * Get the partition ID (optional last argument). 9207 */ 9208 if (optind == (argc - 1)) { 9209 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 9210 NULL, NULL); 9211 if (status != DLADM_STATUS_OK) { 9212 die_dlerr(status, "invalid partition link name '%s'", 9213 argv[optind]); 9214 } 9215 (void) strlcpy(state.ps_part, argv[optind], MAXLINKNAMELEN); 9216 } else if (optind != argc) { 9217 usage(); 9218 } 9219 9220 if (state.ps_parsable && !o_arg) 9221 die("-p requires -o"); 9222 9223 /* 9224 * If an IB Phys link name was provided as an argument, then get its 9225 * datalink ID. 9226 */ 9227 if (l_arg) { 9228 status = dladm_name2info(handle, over_link, &over_linkid, NULL, 9229 NULL, NULL); 9230 if (status != DLADM_STATUS_OK) { 9231 die_dlerr(status, "invalid link name '%s'", over_link); 9232 } 9233 } 9234 9235 state.ps_over_id = over_linkid; /* IB Phys link ID */ 9236 state.ps_found = B_FALSE; 9237 state.ps_flags = flags; 9238 9239 if (state.ps_parsable) 9240 ofmtflags |= OFMT_PARSABLE; 9241 oferr = ofmt_open(fields_str, part_fields, ofmtflags, 0, &ofmt); 9242 ofmt_check(oferr, state.ps_parsable, ofmt, die, warn); 9243 state.ps_ofmt = ofmt; 9244 9245 /* 9246 * If a specific IB partition name was not provided as an argument, 9247 * walk all the datalinks and display the information for all 9248 * IB partitions. If IB Phys link was provided limit it to only 9249 * IB partitions created over that IB Phys link. 9250 */ 9251 if (linkid == DATALINK_ALL_LINKID) { 9252 (void) dladm_walk_datalink_id(show_part, handle, &state, 9253 DATALINK_CLASS_PART, DATALINK_ANY_MEDIATYPE, flags); 9254 } else { 9255 (void) show_part(handle, linkid, &state); 9256 if (state.ps_status != DLADM_STATUS_OK) { 9257 ofmt_close(ofmt); 9258 die_dlerr(state.ps_status, "failed to show IB partition" 9259 " '%s'", state.ps_part); 9260 } 9261 } 9262 ofmt_close(ofmt); 9263 } 9264 9265 9266 /* 9267 * Called from the walker dladm_walk_datalink_id() for each IB Phys link to 9268 * display IB specific information for these Phys links. 9269 */ 9270 static dladm_status_t 9271 print_ib(show_ib_state_t *state, datalink_id_t phys_linkid) 9272 { 9273 dladm_ib_attr_t attr; 9274 dladm_status_t status; 9275 char linkname[MAXLINKNAMELEN]; 9276 char pkeystr[MAXPKEYLEN]; 9277 int i; 9278 ib_fields_buf_t ibuf; 9279 9280 bzero(&attr, sizeof (attr)); 9281 9282 /* 9283 * Get the attributes of the IB Phys link from active/Persistent config 9284 * based on the flag passed. 9285 */ 9286 if ((status = dladm_ib_info(handle, phys_linkid, &attr, 9287 state->is_flags)) != DLADM_STATUS_OK) 9288 return (status); 9289 9290 if ((state->is_link_id != DATALINK_ALL_LINKID) && (state->is_link_id 9291 != attr.dia_physlinkid)) { 9292 dladm_free_ib_info(&attr); 9293 return (DLADM_STATUS_OK); 9294 } 9295 9296 /* 9297 * Get the data link name for the phys_linkid. If we are doing show-ib 9298 * for all IB Phys links, we have only the datalink IDs not the 9299 * datalink name. 9300 */ 9301 if (dladm_datalink_id2info(handle, phys_linkid, NULL, NULL, NULL, 9302 linkname, MAXLINKNAMELEN) != DLADM_STATUS_OK) 9303 return (status); 9304 9305 (void) snprintf(ibuf.ib_link, sizeof (ibuf.ib_link), 9306 "%s", linkname); 9307 9308 (void) snprintf(ibuf.ib_portnum, sizeof (ibuf.ib_portnum), 9309 "%d", attr.dia_portnum); 9310 9311 (void) snprintf(ibuf.ib_hcaguid, sizeof (ibuf.ib_hcaguid), 9312 "%llX", attr.dia_hca_guid); 9313 9314 (void) snprintf(ibuf.ib_portguid, sizeof (ibuf.ib_portguid), 9315 "%llX", attr.dia_port_guid); 9316 9317 (void) get_linkstate(linkname, B_TRUE, ibuf.ib_state); 9318 9319 /* 9320 * Create a comma separated list of pkeys from the pkey table returned 9321 * by the IP over IB driver instance. 9322 */ 9323 bzero(ibuf.ib_pkeys, attr.dia_port_pkey_tbl_sz * sizeof (ib_pkey_t)); 9324 for (i = 0; i < attr.dia_port_pkey_tbl_sz; i++) { 9325 if (attr.dia_port_pkeys[i] != IB_PKEY_INVALID_FULL && 9326 attr.dia_port_pkeys[i] != IB_PKEY_INVALID_LIMITED) { 9327 if (i == 0) 9328 (void) snprintf(pkeystr, MAXPKEYLEN, "%X", 9329 attr.dia_port_pkeys[i]); 9330 else 9331 (void) snprintf(pkeystr, MAXPKEYLEN, ",%X", 9332 attr.dia_port_pkeys[i]); 9333 (void) strlcat(ibuf.ib_pkeys, pkeystr, MAXPKEYSTRSZ); 9334 } 9335 } 9336 9337 dladm_free_ib_info(&attr); 9338 9339 ofmt_print(state->is_ofmt, &ibuf); 9340 9341 return (DLADM_STATUS_OK); 9342 } 9343 9344 /* ARGSUSED */ 9345 static int 9346 show_ib(dladm_handle_t dh, datalink_id_t linkid, void *arg) 9347 { 9348 ((show_ib_state_t *)arg)->is_status = print_ib(arg, linkid); 9349 return (DLADM_WALK_CONTINUE); 9350 } 9351 9352 /* 9353 * Show the properties of one/all IB Phys links. This is different from 9354 * show-phys command since this will display IB specific information about the 9355 * Phys link like, HCA GUID, PORT GUID, PKEYS active for this port etc. 9356 */ 9357 static void 9358 do_show_ib(int argc, char *argv[], const char *use) 9359 { 9360 int option; 9361 uint32_t flags = DLADM_OPT_ACTIVE; 9362 datalink_id_t linkid = DATALINK_ALL_LINKID; 9363 show_ib_state_t state; 9364 dladm_status_t status; 9365 boolean_t o_arg = B_FALSE; 9366 char *fields_str = NULL; 9367 ofmt_handle_t ofmt; 9368 ofmt_status_t oferr; 9369 uint_t ofmtflags = 0; 9370 9371 bzero(&state, sizeof (state)); 9372 opterr = 0; 9373 while ((option = getopt_long(argc, argv, ":po:", show_lopts, 9374 NULL)) != -1) { 9375 switch (option) { 9376 case 'p': 9377 state.is_parsable = B_TRUE; 9378 break; 9379 case 'o': 9380 o_arg = B_TRUE; 9381 fields_str = optarg; 9382 break; 9383 default: 9384 die_opterr(optopt, option, use); 9385 } 9386 } 9387 9388 /* get IB Phys link ID (optional last argument) */ 9389 if (optind == (argc - 1)) { 9390 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 9391 NULL, NULL); 9392 if (status != DLADM_STATUS_OK) { 9393 die_dlerr(status, "invalid IB port name '%s'", 9394 argv[optind]); 9395 } 9396 (void) strlcpy(state.is_link, argv[optind], MAXLINKNAMELEN); 9397 } else if (optind != argc) { 9398 usage(); 9399 } 9400 9401 if (state.is_parsable && !o_arg) 9402 die("-p requires -o"); 9403 9404 /* 9405 * linkid is the data link ID of the IB Phys link. By default it will 9406 * be DATALINK_ALL_LINKID. 9407 */ 9408 state.is_link_id = linkid; 9409 state.is_flags = flags; 9410 9411 if (state.is_parsable) 9412 ofmtflags |= OFMT_PARSABLE; 9413 oferr = ofmt_open(fields_str, ib_fields, ofmtflags, 0, &ofmt); 9414 ofmt_check(oferr, state.is_parsable, ofmt, die, warn); 9415 state.is_ofmt = ofmt; 9416 9417 /* 9418 * If we are going to display the information for all IB Phys links 9419 * then we'll walk through all the datalinks for datalinks of Phys 9420 * class and media type IB. 9421 */ 9422 if (linkid == DATALINK_ALL_LINKID) { 9423 (void) dladm_walk_datalink_id(show_ib, handle, &state, 9424 DATALINK_CLASS_PHYS, DL_IB, flags); 9425 } else { 9426 /* 9427 * We need to display the information only for the IB phys link 9428 * linkid. Call show_ib for this link. 9429 */ 9430 (void) show_ib(handle, linkid, &state); 9431 if (state.is_status != DLADM_STATUS_OK) { 9432 ofmt_close(ofmt); 9433 die_dlerr(state.is_status, "failed to show IB Phys link" 9434 " '%s'", state.is_link); 9435 } 9436 } 9437 ofmt_close(ofmt); 9438 } 9439 9440 /* 9441 * Create an IP over Infiniband partition object over an IB Phys link. The IB 9442 * Phys link is associated with an Infiniband HCA port. The IB partition object 9443 * is created over a port, pkey combination. This partition object represents 9444 * an instance of IP over IB interface. 9445 */ 9446 /* ARGSUSED */ 9447 static void 9448 do_create_part(int argc, char *argv[], const char *use) 9449 { 9450 int status, option; 9451 int flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 9452 char *pname; 9453 char *l_arg = NULL; 9454 char *altroot = NULL; 9455 datalink_id_t physlinkid = 0; 9456 datalink_id_t partlinkid = 0; 9457 unsigned long opt_pkey; 9458 ib_pkey_t pkey = 0; 9459 char *endp = NULL; 9460 char propstr[DLADM_STRSIZE]; 9461 dladm_arg_list_t *proplist = NULL; 9462 9463 propstr[0] = '\0'; 9464 while ((option = getopt_long(argc, argv, ":tfl:P:R:p:", 9465 part_lopts, NULL)) != -1) { 9466 switch (option) { 9467 case 't': 9468 /* 9469 * Create a temporary IB partition object. This 9470 * instance is not entered into the persistent database 9471 * so it will not be recreated automatically on a 9472 * reboot. 9473 */ 9474 flags &= ~DLADM_OPT_PERSIST; 9475 break; 9476 case 'l': 9477 /* 9478 * The IB phys link over which the partition object will 9479 * be created. 9480 */ 9481 l_arg = optarg; 9482 break; 9483 case 'R': 9484 altroot = optarg; 9485 break; 9486 case 'p': 9487 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 9488 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 9489 DLADM_STRSIZE) 9490 die("property list too long '%s'", propstr); 9491 break; 9492 case 'P': 9493 /* 9494 * The P_Key for the port, pkey tuple of the partition 9495 * object. This P_Key should exist in the IB subnet. 9496 * The partition creation for a non-existent P_Key will 9497 * fail unless the -f option is used. 9498 * 9499 * The P_Key is expected to be a hexadecimal number. 9500 */ 9501 opt_pkey = strtoul(optarg, &endp, 16); 9502 if (errno == ERANGE || opt_pkey > USHRT_MAX || 9503 *endp != '\0') 9504 die("Invalid pkey"); 9505 9506 pkey = (ib_pkey_t)opt_pkey; 9507 break; 9508 case 'f': 9509 flags |= DLADM_OPT_FORCE; 9510 break; 9511 default: 9512 die_opterr(optopt, option, use); 9513 break; 9514 } 9515 } 9516 9517 /* check required options */ 9518 if (!l_arg) 9519 usage(); 9520 9521 /* the partition name is a required operand */ 9522 if (optind != (argc - 1)) 9523 usage(); 9524 9525 pname = argv[argc - 1]; 9526 9527 /* 9528 * Verify that the partition object's name is in the valid link name 9529 * format. 9530 */ 9531 if (!dladm_valid_linkname(pname)) 9532 die("Invalid link name '%s'", pname); 9533 9534 /* pkey is a mandatory argument */ 9535 if (pkey == 0) 9536 usage(); 9537 9538 if (altroot != NULL) 9539 altroot_cmd(altroot, argc, argv); 9540 9541 /* 9542 * Get the data link id of the IB Phys link over which we will be 9543 * creating partition object. 9544 */ 9545 if (dladm_name2info(handle, l_arg, 9546 &physlinkid, NULL, NULL, NULL) != DLADM_STATUS_OK) 9547 die("invalid link name '%s'", l_arg); 9548 9549 /* 9550 * parse the property list provided with -p option. 9551 */ 9552 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 9553 != DLADM_STATUS_OK) 9554 die("invalid IB partition property"); 9555 9556 /* 9557 * Call the library routine to create the partition object. 9558 */ 9559 status = dladm_part_create(handle, physlinkid, pkey, flags, pname, 9560 &partlinkid, proplist); 9561 if (status != DLADM_STATUS_OK) 9562 die_dlerr(status, 9563 "partition %x creation over %s failed", pkey, l_arg); 9564 } 9565 9566 /* 9567 * Delete an IP over Infiniband partition object. The partition object should 9568 * be unplumbed before attempting the delete. 9569 */ 9570 static void 9571 do_delete_part(int argc, char *argv[], const char *use) 9572 { 9573 int option, flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 9574 int status; 9575 char *altroot = NULL; 9576 datalink_id_t partid; 9577 9578 opterr = 0; 9579 while ((option = getopt_long(argc, argv, "R:t", part_lopts, 9580 NULL)) != -1) { 9581 switch (option) { 9582 case 't': 9583 flags &= ~DLADM_OPT_PERSIST; 9584 break; 9585 case 'R': 9586 altroot = optarg; 9587 break; 9588 default: 9589 die_opterr(optopt, option, use); 9590 } 9591 } 9592 9593 /* get partition name (required last argument) */ 9594 if (optind != (argc - 1)) 9595 usage(); 9596 9597 if (altroot != NULL) 9598 altroot_cmd(altroot, argc, argv); 9599 9600 /* 9601 * Get the data link id of the partition object given the partition 9602 * name. 9603 */ 9604 status = dladm_name2info(handle, argv[optind], &partid, NULL, NULL, 9605 NULL); 9606 if (status != DLADM_STATUS_OK) 9607 die("invalid link name '%s'", argv[optind]); 9608 9609 /* 9610 * Call the library routine to delete the IB partition. This will 9611 * result in the IB partition object and all its resources getting 9612 * deleted. 9613 */ 9614 status = dladm_part_delete(handle, partid, flags); 9615 if (status != DLADM_STATUS_OK) 9616 die_dlerr(status, "%s: partition deletion failed", 9617 argv[optind]); 9618 } 9619 9620 /* 9621 * Bring up all or one IB partition already present in the persistent database 9622 * but not active yet. 9623 * 9624 * This sub-command is used during the system boot up to bring up all IB 9625 * partitions present in the persistent database. This is similar to a 9626 * create partition except that, the partitions are always created even if the 9627 * HCA port is down or P_Key is not present in the IB subnet. This is similar 9628 * to using the 'force' option while creating the partition except that the 'f' 9629 * flag will be set in the flags field only if the create-part for this command 9630 * was called with '-f' option. 9631 */ 9632 /* ARGSUSED */ 9633 static void 9634 do_up_part(int argc, char *argv[], const char *use) 9635 { 9636 datalink_id_t partid = DATALINK_ALL_LINKID; 9637 dladm_status_t status; 9638 9639 /* 9640 * If a partition name was passed as an argument, get its data link 9641 * id. By default we'll attempt to bring up all IB partition data 9642 * links. 9643 */ 9644 if (argc == 2) { 9645 status = dladm_name2info(handle, argv[argc - 1], &partid, NULL, 9646 NULL, NULL); 9647 if (status != DLADM_STATUS_OK) 9648 return; 9649 } else if (argc > 2) { 9650 usage(); 9651 } 9652 9653 (void) dladm_part_up(handle, partid, 0); 9654 } 9655