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