1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2016 Nexenta Systems, Inc. 25 */ 26 27 #include <stdio.h> 28 #include <ctype.h> 29 #include <dlfcn.h> 30 #include <locale.h> 31 #include <signal.h> 32 #include <stdarg.h> 33 #include <stdlib.h> 34 #include <fcntl.h> 35 #include <string.h> 36 #include <stropts.h> 37 #include <sys/stat.h> 38 #include <errno.h> 39 #include <kstat.h> 40 #include <strings.h> 41 #include <getopt.h> 42 #include <unistd.h> 43 #include <priv.h> 44 #include <limits.h> 45 #include <termios.h> 46 #include <pwd.h> 47 #include <auth_attr.h> 48 #include <auth_list.h> 49 #include <libintl.h> 50 #include <libdevinfo.h> 51 #include <libdlpi.h> 52 #include <libdladm.h> 53 #include <libdllink.h> 54 #include <libdlstat.h> 55 #include <libdlaggr.h> 56 #include <libdlwlan.h> 57 #include <libdlvlan.h> 58 #include <libdlvnic.h> 59 #include <libdlib.h> 60 #include <libdlether.h> 61 #include <libdliptun.h> 62 #include <libdlsim.h> 63 #include <libdlbridge.h> 64 #include <libinetutil.h> 65 #include <libvrrpadm.h> 66 #include <bsm/adt.h> 67 #include <bsm/adt_event.h> 68 #include <libdlvnic.h> 69 #include <sys/types.h> 70 #include <sys/socket.h> 71 #include <sys/ib/ib_types.h> 72 #include <sys/processor.h> 73 #include <netinet/in.h> 74 #include <arpa/inet.h> 75 #include <net/if_types.h> 76 #include <stddef.h> 77 #include <stp_in.h> 78 #include <ofmt.h> 79 80 #define MAXPORT 256 81 #define MAXVNIC 256 82 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) 83 #define MAXLINELEN 1024 84 #define SMF_UPGRADE_FILE "/var/svc/profile/upgrade" 85 #define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink" 86 #define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)" 87 #define DLADM_DEFAULT_COL 80 88 89 /* 90 * used by the wifi show-* commands to set up ofmt_field_t structures. 91 */ 92 #define WIFI_CMD_SCAN 0x00000001 93 #define WIFI_CMD_SHOW 0x00000002 94 #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 95 96 /* No larger than pktsum_t */ 97 typedef struct brsum_s { 98 uint64_t drops; 99 uint64_t forward_dir; 100 uint64_t forward_mb; 101 uint64_t forward_unk; 102 uint64_t recv; 103 uint64_t sent; 104 } brsum_t; 105 106 /* No larger than pktsum_t */ 107 typedef struct brlsum_s { 108 uint32_t cfgbpdu; 109 uint32_t tcnbpdu; 110 uint32_t rstpbpdu; 111 uint32_t txbpdu; 112 uint64_t drops; 113 uint64_t recv; 114 uint64_t xmit; 115 } brlsum_t; 116 117 typedef struct show_state { 118 boolean_t ls_firstonly; 119 boolean_t ls_donefirst; 120 pktsum_t ls_prevstats; 121 uint32_t ls_flags; 122 dladm_status_t ls_status; 123 ofmt_handle_t ls_ofmt; 124 boolean_t ls_parsable; 125 boolean_t ls_mac; 126 boolean_t ls_hwgrp; 127 } show_state_t; 128 129 typedef struct show_grp_state { 130 pktsum_t gs_prevstats[MAXPORT]; 131 uint32_t gs_flags; 132 dladm_status_t gs_status; 133 boolean_t gs_parsable; 134 boolean_t gs_lacp; 135 boolean_t gs_extended; 136 boolean_t gs_stats; 137 boolean_t gs_firstonly; 138 boolean_t gs_donefirst; 139 ofmt_handle_t gs_ofmt; 140 } show_grp_state_t; 141 142 typedef struct show_vnic_state { 143 datalink_id_t vs_vnic_id; 144 datalink_id_t vs_link_id; 145 char vs_vnic[MAXLINKNAMELEN]; 146 char vs_link[MAXLINKNAMELEN]; 147 boolean_t vs_parsable; 148 boolean_t vs_found; 149 boolean_t vs_firstonly; 150 boolean_t vs_donefirst; 151 boolean_t vs_stats; 152 boolean_t vs_printstats; 153 pktsum_t vs_totalstats; 154 pktsum_t vs_prevstats[MAXVNIC]; 155 boolean_t vs_etherstub; 156 dladm_status_t vs_status; 157 uint32_t vs_flags; 158 ofmt_handle_t vs_ofmt; 159 } show_vnic_state_t; 160 161 typedef struct show_part_state { 162 datalink_id_t ps_over_id; 163 char ps_part[MAXLINKNAMELEN]; 164 boolean_t ps_parsable; 165 boolean_t ps_found; 166 dladm_status_t ps_status; 167 uint32_t ps_flags; 168 ofmt_handle_t ps_ofmt; 169 } show_part_state_t; 170 171 typedef struct show_ib_state { 172 datalink_id_t is_link_id; 173 char is_link[MAXLINKNAMELEN]; 174 boolean_t is_parsable; 175 dladm_status_t is_status; 176 uint32_t is_flags; 177 ofmt_handle_t is_ofmt; 178 } show_ib_state_t; 179 180 typedef struct show_usage_state_s { 181 boolean_t us_plot; 182 boolean_t us_parsable; 183 boolean_t us_printheader; 184 boolean_t us_first; 185 boolean_t us_showall; 186 ofmt_handle_t us_ofmt; 187 } show_usage_state_t; 188 189 /* 190 * callback functions for printing output and error diagnostics. 191 */ 192 static ofmt_cb_t print_default_cb, print_link_stats_cb, print_linkprop_cb; 193 static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb; 194 static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb; 195 static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb; 196 static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb; 197 198 typedef void cmdfunc_t(int, char **, const char *); 199 200 static cmdfunc_t do_show_link, do_show_wifi, do_show_phys; 201 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 202 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr; 203 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 204 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 205 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 206 static cmdfunc_t do_init_linkprop, do_init_secobj; 207 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan; 208 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys; 209 static cmdfunc_t do_show_linkmap; 210 static cmdfunc_t do_show_ether; 211 static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic; 212 static cmdfunc_t do_up_vnic; 213 static cmdfunc_t do_create_part, do_delete_part, do_show_part, do_show_ib; 214 static cmdfunc_t do_up_part; 215 static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub; 216 static cmdfunc_t do_create_simnet, do_modify_simnet; 217 static cmdfunc_t do_delete_simnet, do_show_simnet, do_up_simnet; 218 static cmdfunc_t do_show_usage; 219 static cmdfunc_t do_create_bridge, do_modify_bridge, do_delete_bridge; 220 static cmdfunc_t do_add_bridge, do_remove_bridge, do_show_bridge; 221 static cmdfunc_t do_create_iptun, do_modify_iptun, do_delete_iptun; 222 static cmdfunc_t do_show_iptun, do_up_iptun, do_down_iptun; 223 224 static void do_up_vnic_common(int, char **, const char *, boolean_t); 225 226 static int show_part(dladm_handle_t, datalink_id_t, void *); 227 228 static void altroot_cmd(char *, int, char **); 229 static int show_linkprop_onelink(dladm_handle_t, datalink_id_t, void *); 230 231 static void link_stats(datalink_id_t, uint_t, char *, show_state_t *); 232 static void aggr_stats(datalink_id_t, show_grp_state_t *, uint_t); 233 static void vnic_stats(show_vnic_state_t *, uint32_t); 234 235 static int get_one_kstat(const char *, const char *, uint8_t, 236 void *, boolean_t); 237 static void get_mac_stats(const char *, pktsum_t *); 238 static void get_link_stats(const char *, pktsum_t *); 239 static uint64_t get_ifspeed(const char *, boolean_t); 240 static const char *get_linkstate(const char *, boolean_t, char *); 241 static const char *get_linkduplex(const char *, boolean_t, char *); 242 243 static iptun_type_t iptun_gettypebyname(char *); 244 static const char *iptun_gettypebyvalue(iptun_type_t); 245 static dladm_status_t print_iptun(dladm_handle_t, datalink_id_t, 246 show_state_t *); 247 static int print_iptun_walker(dladm_handle_t, datalink_id_t, void *); 248 249 static int show_etherprop(dladm_handle_t, datalink_id_t, void *); 250 static void show_ether_xprop(void *, dladm_ether_info_t *); 251 static boolean_t link_is_ether(const char *, datalink_id_t *); 252 253 static boolean_t str2int(const char *, int *); 254 static void die(const char *, ...); 255 static void die_optdup(int); 256 static void die_opterr(int, int, const char *); 257 static void die_dlerr(dladm_status_t, const char *, ...); 258 static void warn(const char *, ...); 259 static void warn_dlerr(dladm_status_t, const char *, ...); 260 261 typedef struct cmd { 262 char *c_name; 263 cmdfunc_t *c_fn; 264 const char *c_usage; 265 } cmd_t; 266 267 static cmd_t cmds[] = { 268 { "rename-link", do_rename_link, 269 " rename-link <oldlink> <newlink>" }, 270 { "show-link", do_show_link, 271 " show-link [-pP] [-o <field>,..] [-s [-i <interval>]] " 272 "[<link>]\n" }, 273 { "create-aggr", do_create_aggr, 274 " create-aggr [-t] [-P <policy>] [-L <mode>] [-T <time>] " 275 "[-u <address>]\n" 276 "\t\t -l <link> [-l <link>...] <link>" }, 277 { "delete-aggr", do_delete_aggr, 278 " delete-aggr [-t] <link>" }, 279 { "add-aggr", do_add_aggr, 280 " add-aggr [-t] -l <link> [-l <link>...] <link>" }, 281 { "remove-aggr", do_remove_aggr, 282 " remove-aggr [-t] -l <link> [-l <link>...] <link>" }, 283 { "modify-aggr", do_modify_aggr, 284 " modify-aggr [-t] [-P <policy>] [-L <mode>] [-T <time>] " 285 "[-u <address>]\n" 286 "\t\t <link>" }, 287 { "show-aggr", do_show_aggr, 288 " show-aggr [-pPLx] [-o <field>,..] [-s [-i <interval>]] " 289 "[<link>]\n" }, 290 { "up-aggr", do_up_aggr, NULL }, 291 { "scan-wifi", do_scan_wifi, 292 " scan-wifi [-p] [-o <field>,...] [<link>]" }, 293 { "connect-wifi", do_connect_wifi, 294 " connect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...] " 295 "[-s wep|wpa]\n" 296 "\t\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g] " 297 "[-T <time>]\n" 298 "\t\t [<link>]" }, 299 { "disconnect-wifi", do_disconnect_wifi, 300 " disconnect-wifi [-a] [<link>]" }, 301 { "show-wifi", do_show_wifi, 302 " show-wifi [-p] [-o <field>,...] [<link>]\n" }, 303 { "set-linkprop", do_set_linkprop, 304 " set-linkprop [-t] -p <prop>=<value>[,...] <name>" }, 305 { "reset-linkprop", do_reset_linkprop, 306 " reset-linkprop [-t] [-p <prop>,...] <name>" }, 307 { "show-linkprop", do_show_linkprop, 308 " show-linkprop [-cP] [-o <field>,...] [-p <prop>,...] " 309 "<name>\n" }, 310 { "show-ether", do_show_ether, 311 " show-ether [-px][-o <field>,...] <link>\n" }, 312 { "create-secobj", do_create_secobj, 313 " create-secobj [-t] [-f <file>] -c <class> <secobj>" }, 314 { "delete-secobj", do_delete_secobj, 315 " delete-secobj [-t] <secobj>[,...]" }, 316 { "show-secobj", do_show_secobj, 317 " show-secobj [-pP] [-o <field>,...] [<secobj>,...]\n" }, 318 { "init-linkprop", do_init_linkprop, NULL }, 319 { "init-secobj", do_init_secobj, NULL }, 320 { "create-vlan", do_create_vlan, 321 " create-vlan [-ft] -l <link> -v <vid> [link]" }, 322 { "delete-vlan", do_delete_vlan, 323 " delete-vlan [-t] <link>" }, 324 { "show-vlan", do_show_vlan, 325 " show-vlan [-pP] [-o <field>,..] [<link>]\n" }, 326 { "up-vlan", do_up_vlan, NULL }, 327 { "create-iptun", do_create_iptun, 328 " create-iptun [-t] -T <type> " 329 "[-a {local|remote}=<addr>,...] <link>]" }, 330 { "delete-iptun", do_delete_iptun, 331 " delete-iptun [-t] <link>" }, 332 { "modify-iptun", do_modify_iptun, 333 " modify-iptun [-t] -a {local|remote}=<addr>,... <link>" }, 334 { "show-iptun", do_show_iptun, 335 " show-iptun [-pP] [-o <field>,..] [<link>]\n" }, 336 { "up-iptun", do_up_iptun, NULL }, 337 { "down-iptun", do_down_iptun, NULL }, 338 { "delete-phys", do_delete_phys, 339 " delete-phys <link>" }, 340 { "show-phys", do_show_phys, 341 " show-phys [-m | -H | -P] [[-p] [-o <field>[,...]] " 342 "[<link>]\n" }, 343 { "init-phys", do_init_phys, NULL }, 344 { "show-linkmap", do_show_linkmap, NULL }, 345 { "create-vnic", do_create_vnic, 346 " create-vnic [-t] -l <link> [-m <value> | auto |\n" 347 "\t\t {factory [-n <slot-id>]} | {random [-r <prefix>]} |\n" 348 "\t\t {vrrp -V <vrid> -A {inet | inet6}} [-v <vid> [-f]]\n" 349 "\t\t [-p <prop>=<value>[,...]] <vnic-link>" }, 350 { "delete-vnic", do_delete_vnic, 351 " delete-vnic [-t] <vnic-link>" }, 352 { "show-vnic", do_show_vnic, 353 " show-vnic [-pP] [-l <link>] [-s [-i <interval>]] " 354 "[<link>]\n" }, 355 { "up-vnic", do_up_vnic, NULL }, 356 { "create-part", do_create_part, 357 " create-part [-t] [-f] -l <link> [-P <pkey>]\n" 358 "\t\t [-R <root-dir>] <part-link>" }, 359 { "delete-part", do_delete_part, 360 " delete-part [-t] [-R <root-dir>] <part-link>"}, 361 { "show-part", do_show_part, 362 " show-part [-pP] [-o <field>,...][-l <linkover>]\n" 363 "\t\t [<part-link>]" }, 364 { "show-ib", do_show_ib, 365 " show-ib [-p] [-o <field>,...] [<link>]\n" }, 366 { "up-part", do_up_part, NULL }, 367 { "create-etherstub", do_create_etherstub, 368 " create-etherstub [-t] <link>" }, 369 { "delete-etherstub", do_delete_etherstub, 370 " delete-etherstub [-t] <link>" }, 371 { "show-etherstub", do_show_etherstub, 372 " show-etherstub [-t] [<link>]\n" }, 373 { "create-simnet", do_create_simnet, NULL }, 374 { "modify-simnet", do_modify_simnet, NULL }, 375 { "delete-simnet", do_delete_simnet, NULL }, 376 { "show-simnet", do_show_simnet, NULL }, 377 { "up-simnet", do_up_simnet, NULL }, 378 { "create-bridge", do_create_bridge, 379 " create-bridge [-R <root-dir>] [-P <protect>] " 380 "[-p <priority>]\n" 381 "\t\t [-m <max-age>] [-h <hello-time>] [-d <forward-delay>]\n" 382 "\t\t [-f <force-protocol>] [-l <link>]... <bridge>" }, 383 { "modify-bridge", do_modify_bridge, 384 " modify-bridge [-R <root-dir>] [-P <protect>] " 385 "[-p <priority>]\n" 386 "\t\t [-m <max-age>] [-h <hello-time>] [-d <forward-delay>]\n" 387 "\t\t [-f <force-protocol>] <bridge>" }, 388 { "delete-bridge", do_delete_bridge, 389 " delete-bridge [-R <root-dir>] <bridge>" }, 390 { "add-bridge", do_add_bridge, 391 " add-bridge [-R <root-dir>] -l <link> [-l <link>]... " 392 "<bridge>" }, 393 { "remove-bridge", do_remove_bridge, 394 " remove-bridge [-R <root-dir>] -l <link> [-l <link>]... " 395 "<bridge>" }, 396 { "show-bridge", do_show_bridge, 397 " show-bridge [-p] [-o <field>,...] [-s [-i <interval>]] " 398 "[<bridge>]\n" 399 " show-bridge -l [-p] [-o <field>,...] [-s [-i <interval>]]" 400 " <bridge>\n" 401 " show-bridge -f [-p] [-o <field>,...] [-s [-i <interval>]]" 402 " <bridge>\n" 403 " show-bridge -t [-p] [-o <field>,...] [-s [-i <interval>]]" 404 " <bridge>\n" }, 405 { "show-usage", do_show_usage, 406 " show-usage [-a] [-d | -F <format>] " 407 "[-s <DD/MM/YYYY,HH:MM:SS>]\n" 408 "\t\t [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<link>]" } 409 }; 410 411 static const struct option lopts[] = { 412 {"vlan-id", required_argument, 0, 'v'}, 413 {"output", required_argument, 0, 'o'}, 414 {"dev", required_argument, 0, 'd'}, 415 {"policy", required_argument, 0, 'P'}, 416 {"lacp-mode", required_argument, 0, 'L'}, 417 {"lacp-timer", required_argument, 0, 'T'}, 418 {"unicast", required_argument, 0, 'u'}, 419 {"temporary", no_argument, 0, 't'}, 420 {"root-dir", required_argument, 0, 'R'}, 421 {"link", required_argument, 0, 'l'}, 422 {"forcible", no_argument, 0, 'f'}, 423 {"bw-limit", required_argument, 0, 'b'}, 424 {"mac-address", required_argument, 0, 'm'}, 425 {"slot", required_argument, 0, 'n'}, 426 { 0, 0, 0, 0 } 427 }; 428 429 static const struct option show_lopts[] = { 430 {"statistics", no_argument, 0, 's'}, 431 {"continuous", no_argument, 0, 'S'}, 432 {"interval", required_argument, 0, 'i'}, 433 {"parsable", no_argument, 0, 'p'}, 434 {"parseable", no_argument, 0, 'p'}, 435 {"extended", no_argument, 0, 'x'}, 436 {"output", required_argument, 0, 'o'}, 437 {"persistent", no_argument, 0, 'P'}, 438 {"lacp", no_argument, 0, 'L'}, 439 { 0, 0, 0, 0 } 440 }; 441 442 static const struct option iptun_lopts[] = { 443 {"output", required_argument, 0, 'o'}, 444 {"tunnel-type", required_argument, 0, 'T'}, 445 {"address", required_argument, 0, 'a'}, 446 {"root-dir", required_argument, 0, 'R'}, 447 {"parsable", no_argument, 0, 'p'}, 448 {"parseable", no_argument, 0, 'p'}, 449 {"persistent", no_argument, 0, 'P'}, 450 { 0, 0, 0, 0 } 451 }; 452 453 static char * const iptun_addropts[] = { 454 #define IPTUN_LOCAL 0 455 "local", 456 #define IPTUN_REMOTE 1 457 "remote", 458 NULL}; 459 460 static const struct { 461 const char *type_name; 462 iptun_type_t type_value; 463 } iptun_types[] = { 464 {"ipv4", IPTUN_TYPE_IPV4}, 465 {"ipv6", IPTUN_TYPE_IPV6}, 466 {"6to4", IPTUN_TYPE_6TO4}, 467 {NULL, 0} 468 }; 469 470 static const struct option prop_longopts[] = { 471 {"temporary", no_argument, 0, 't' }, 472 {"output", required_argument, 0, 'o' }, 473 {"root-dir", required_argument, 0, 'R' }, 474 {"prop", required_argument, 0, 'p' }, 475 {"parsable", no_argument, 0, 'c' }, 476 {"parseable", no_argument, 0, 'c' }, 477 {"persistent", no_argument, 0, 'P' }, 478 { 0, 0, 0, 0 } 479 }; 480 481 static const struct option wifi_longopts[] = { 482 {"parsable", no_argument, 0, 'p' }, 483 {"parseable", no_argument, 0, 'p' }, 484 {"output", required_argument, 0, 'o' }, 485 {"essid", required_argument, 0, 'e' }, 486 {"bsstype", required_argument, 0, 'b' }, 487 {"mode", required_argument, 0, 'm' }, 488 {"key", required_argument, 0, 'k' }, 489 {"sec", required_argument, 0, 's' }, 490 {"auth", required_argument, 0, 'a' }, 491 {"create-ibss", required_argument, 0, 'c' }, 492 {"timeout", required_argument, 0, 'T' }, 493 {"all-links", no_argument, 0, 'a' }, 494 {"temporary", no_argument, 0, 't' }, 495 {"root-dir", required_argument, 0, 'R' }, 496 {"persistent", no_argument, 0, 'P' }, 497 {"file", required_argument, 0, 'f' }, 498 { 0, 0, 0, 0 } 499 }; 500 501 static const struct option showeth_lopts[] = { 502 {"parsable", no_argument, 0, 'p' }, 503 {"parseable", no_argument, 0, 'p' }, 504 {"extended", no_argument, 0, 'x' }, 505 {"output", required_argument, 0, 'o' }, 506 { 0, 0, 0, 0 } 507 }; 508 509 static const struct option vnic_lopts[] = { 510 {"temporary", no_argument, 0, 't' }, 511 {"root-dir", required_argument, 0, 'R' }, 512 {"dev", required_argument, 0, 'd' }, 513 {"mac-address", required_argument, 0, 'm' }, 514 {"cpus", required_argument, 0, 'c' }, 515 {"bw-limit", required_argument, 0, 'b' }, 516 {"slot", required_argument, 0, 'n' }, 517 {"mac-prefix", required_argument, 0, 'r' }, 518 {"vrid", required_argument, 0, 'V' }, 519 {"address-family", required_argument, 0, 'A' }, 520 { 0, 0, 0, 0 } 521 }; 522 523 static const struct option part_lopts[] = { 524 {"temporary", no_argument, 0, 't' }, 525 {"pkey", required_argument, 0, 'P' }, 526 {"link", required_argument, 0, 'l' }, 527 {"force", no_argument, 0, 'f' }, 528 {"root-dir", required_argument, 0, 'R' }, 529 {"prop", required_argument, 0, 'p' }, 530 { 0, 0, 0, 0 } 531 }; 532 533 static const struct option show_part_lopts[] = { 534 {"parsable", no_argument, 0, 'p' }, 535 {"parseable", no_argument, 0, 'p' }, 536 {"link", required_argument, 0, 'l' }, 537 {"persistent", no_argument, 0, 'P' }, 538 {"output", required_argument, 0, 'o' }, 539 { 0, 0, 0, 0 } 540 }; 541 542 static const struct option etherstub_lopts[] = { 543 {"temporary", no_argument, 0, 't' }, 544 {"root-dir", required_argument, 0, 'R' }, 545 { 0, 0, 0, 0 } 546 }; 547 548 static const struct option usage_opts[] = { 549 {"file", required_argument, 0, 'f' }, 550 {"format", required_argument, 0, 'F' }, 551 {"start", required_argument, 0, 's' }, 552 {"stop", required_argument, 0, 'e' }, 553 { 0, 0, 0, 0 } 554 }; 555 556 static const struct option simnet_lopts[] = { 557 {"temporary", no_argument, 0, 't' }, 558 {"root-dir", required_argument, 0, 'R' }, 559 {"media", required_argument, 0, 'm' }, 560 {"peer", required_argument, 0, 'p' }, 561 { 0, 0, 0, 0 } 562 }; 563 564 static const struct option bridge_lopts[] = { 565 { "protect", required_argument, 0, 'P' }, 566 { "root-dir", required_argument, 0, 'R' }, 567 { "forward-delay", required_argument, 0, 'd' }, 568 { "force-protocol", required_argument, 0, 'f' }, 569 { "hello-time", required_argument, 0, 'h' }, 570 { "link", required_argument, 0, 'l' }, 571 { "max-age", required_argument, 0, 'm' }, 572 { "priority", required_argument, 0, 'p' }, 573 { NULL, NULL, 0, 0 } 574 }; 575 576 static const struct option bridge_show_lopts[] = { 577 { "forwarding", no_argument, 0, 'f' }, 578 { "interval", required_argument, 0, 'i' }, 579 { "link", no_argument, 0, 'l' }, 580 { "output", required_argument, 0, 'o' }, 581 { "parsable", no_argument, 0, 'p' }, 582 { "parseable", no_argument, 0, 'p' }, 583 { "statistics", no_argument, 0, 's' }, 584 { "trill", no_argument, 0, 't' }, 585 { 0, 0, 0, 0 } 586 }; 587 588 /* 589 * structures for 'dladm show-ether' 590 */ 591 static const char *ptype[] = {LEI_ATTR_NAMES}; 592 593 typedef struct ether_fields_buf_s 594 { 595 char eth_link[15]; 596 char eth_ptype[8]; 597 char eth_state[8]; 598 char eth_autoneg[5]; 599 char eth_spdx[31]; 600 char eth_pause[6]; 601 char eth_rem_fault[16]; 602 } ether_fields_buf_t; 603 604 static const ofmt_field_t ether_fields[] = { 605 /* name, field width, offset callback */ 606 { "LINK", 16, 607 offsetof(ether_fields_buf_t, eth_link), print_default_cb}, 608 { "PTYPE", 9, 609 offsetof(ether_fields_buf_t, eth_ptype), print_default_cb}, 610 { "STATE", 9, 611 offsetof(ether_fields_buf_t, eth_state), 612 print_default_cb}, 613 { "AUTO", 6, 614 offsetof(ether_fields_buf_t, eth_autoneg), print_default_cb}, 615 { "SPEED-DUPLEX", 32, 616 offsetof(ether_fields_buf_t, eth_spdx), print_default_cb}, 617 { "PAUSE", 7, 618 offsetof(ether_fields_buf_t, eth_pause), print_default_cb}, 619 { "REM_FAULT", 17, 620 offsetof(ether_fields_buf_t, eth_rem_fault), print_default_cb}, 621 {NULL, 0, 622 0, NULL}} 623 ; 624 625 typedef struct print_ether_state { 626 const char *es_link; 627 boolean_t es_parsable; 628 boolean_t es_header; 629 boolean_t es_extended; 630 ofmt_handle_t es_ofmt; 631 } print_ether_state_t; 632 633 /* 634 * structures for 'dladm show-link -s' (print statistics) 635 */ 636 typedef enum { 637 LINK_S_LINK, 638 LINK_S_IPKTS, 639 LINK_S_RBYTES, 640 LINK_S_IERRORS, 641 LINK_S_OPKTS, 642 LINK_S_OBYTES, 643 LINK_S_OERRORS 644 } link_s_field_index_t; 645 646 static const ofmt_field_t link_s_fields[] = { 647 /* name, field width, index, callback */ 648 { "LINK", 15, LINK_S_LINK, print_link_stats_cb}, 649 { "IPACKETS", 10, LINK_S_IPKTS, print_link_stats_cb}, 650 { "RBYTES", 8, LINK_S_RBYTES, print_link_stats_cb}, 651 { "IERRORS", 10, LINK_S_IERRORS, print_link_stats_cb}, 652 { "OPACKETS", 12, LINK_S_OPKTS, print_link_stats_cb}, 653 { "OBYTES", 12, LINK_S_OBYTES, print_link_stats_cb}, 654 { "OERRORS", 8, LINK_S_OERRORS, print_link_stats_cb}} 655 ; 656 657 typedef struct link_args_s { 658 char *link_s_link; 659 pktsum_t *link_s_psum; 660 } link_args_t; 661 662 /* 663 * buffer used by print functions for show-{link,phys,vlan} commands. 664 */ 665 typedef struct link_fields_buf_s { 666 char link_name[MAXLINKNAMELEN]; 667 char link_class[DLADM_STRSIZE]; 668 char link_mtu[11]; 669 char link_state[DLADM_STRSIZE]; 670 char link_bridge[MAXLINKNAMELEN * MAXPORT]; 671 char link_over[MAXLINKNAMELEN * MAXPORT]; 672 char link_phys_state[DLADM_STRSIZE]; 673 char link_phys_media[DLADM_STRSIZE]; 674 char link_phys_speed[DLADM_STRSIZE]; 675 char link_phys_duplex[DLPI_LINKNAME_MAX]; 676 char link_phys_device[DLPI_LINKNAME_MAX]; 677 char link_flags[6]; 678 char link_vlan_vid[6]; 679 } link_fields_buf_t; 680 681 /* 682 * structures for 'dladm show-link' 683 */ 684 static const ofmt_field_t link_fields[] = { 685 /* name, field width, index, callback */ 686 { "LINK", 12, 687 offsetof(link_fields_buf_t, link_name), print_default_cb}, 688 { "CLASS", 10, 689 offsetof(link_fields_buf_t, link_class), print_default_cb}, 690 { "MTU", 7, 691 offsetof(link_fields_buf_t, link_mtu), print_default_cb}, 692 { "STATE", 9, 693 offsetof(link_fields_buf_t, link_state), print_default_cb}, 694 { "BRIDGE", 11, 695 offsetof(link_fields_buf_t, link_bridge), print_default_cb}, 696 { "OVER", 30, 697 offsetof(link_fields_buf_t, link_over), print_default_cb}, 698 { NULL, 0, 0, NULL}} 699 ; 700 701 /* 702 * structures for 'dladm show-aggr' 703 */ 704 typedef struct laggr_fields_buf_s { 705 char laggr_name[DLPI_LINKNAME_MAX]; 706 char laggr_policy[9]; 707 char laggr_addrpolicy[ETHERADDRL * 3 + 3]; 708 char laggr_lacpactivity[14]; 709 char laggr_lacptimer[DLADM_STRSIZE]; 710 char laggr_flags[7]; 711 } laggr_fields_buf_t; 712 713 typedef struct laggr_args_s { 714 int laggr_lport; /* -1 indicates the aggr itself */ 715 const char *laggr_link; 716 dladm_aggr_grp_attr_t *laggr_ginfop; 717 dladm_status_t *laggr_status; 718 pktsum_t *laggr_pktsumtot; /* -s only */ 719 pktsum_t *laggr_diffstats; /* -s only */ 720 boolean_t laggr_parsable; 721 } laggr_args_t; 722 723 static const ofmt_field_t laggr_fields[] = { 724 /* name, field width, offset, callback */ 725 { "LINK", 16, 726 offsetof(laggr_fields_buf_t, laggr_name), print_default_cb}, 727 { "POLICY", 9, 728 offsetof(laggr_fields_buf_t, laggr_policy), print_default_cb}, 729 { "ADDRPOLICY", ETHERADDRL * 3 + 3, 730 offsetof(laggr_fields_buf_t, laggr_addrpolicy), print_default_cb}, 731 { "LACPACTIVITY", 14, 732 offsetof(laggr_fields_buf_t, laggr_lacpactivity), print_default_cb}, 733 { "LACPTIMER", 12, 734 offsetof(laggr_fields_buf_t, laggr_lacptimer), print_default_cb}, 735 { "FLAGS", 8, 736 offsetof(laggr_fields_buf_t, laggr_flags), print_default_cb}, 737 { NULL, 0, 0, NULL}} 738 ; 739 740 /* 741 * structures for 'dladm show-aggr -x'. 742 */ 743 typedef enum { 744 AGGR_X_LINK, 745 AGGR_X_PORT, 746 AGGR_X_SPEED, 747 AGGR_X_DUPLEX, 748 AGGR_X_STATE, 749 AGGR_X_ADDRESS, 750 AGGR_X_PORTSTATE 751 } aggr_x_field_index_t; 752 753 static const ofmt_field_t aggr_x_fields[] = { 754 /* name, field width, index callback */ 755 { "LINK", 12, AGGR_X_LINK, print_xaggr_cb}, 756 { "PORT", 15, AGGR_X_PORT, print_xaggr_cb}, 757 { "SPEED", 5, AGGR_X_SPEED, print_xaggr_cb}, 758 { "DUPLEX", 10, AGGR_X_DUPLEX, print_xaggr_cb}, 759 { "STATE", 10, AGGR_X_STATE, print_xaggr_cb}, 760 { "ADDRESS", 19, AGGR_X_ADDRESS, print_xaggr_cb}, 761 { "PORTSTATE", 16, AGGR_X_PORTSTATE, print_xaggr_cb}, 762 { NULL, 0, 0, NULL}} 763 ; 764 765 /* 766 * structures for 'dladm show-aggr -s'. 767 */ 768 typedef enum { 769 AGGR_S_LINK, 770 AGGR_S_PORT, 771 AGGR_S_IPKTS, 772 AGGR_S_RBYTES, 773 AGGR_S_OPKTS, 774 AGGR_S_OBYTES, 775 AGGR_S_IPKTDIST, 776 AGGR_S_OPKTDIST 777 } aggr_s_field_index_t; 778 779 static const ofmt_field_t aggr_s_fields[] = { 780 { "LINK", 12, AGGR_S_LINK, print_aggr_stats_cb}, 781 { "PORT", 10, AGGR_S_PORT, print_aggr_stats_cb}, 782 { "IPACKETS", 8, AGGR_S_IPKTS, print_aggr_stats_cb}, 783 { "RBYTES", 8, AGGR_S_RBYTES, print_aggr_stats_cb}, 784 { "OPACKETS", 8, AGGR_S_OPKTS, print_aggr_stats_cb}, 785 { "OBYTES", 8, AGGR_S_OBYTES, print_aggr_stats_cb}, 786 { "IPKTDIST", 9, AGGR_S_IPKTDIST, print_aggr_stats_cb}, 787 { "OPKTDIST", 15, AGGR_S_OPKTDIST, print_aggr_stats_cb}, 788 { NULL, 0, 0, NULL}} 789 ; 790 791 /* 792 * structures for 'dladm show-aggr -L'. 793 */ 794 typedef enum { 795 AGGR_L_LINK, 796 AGGR_L_PORT, 797 AGGR_L_AGGREGATABLE, 798 AGGR_L_SYNC, 799 AGGR_L_COLL, 800 AGGR_L_DIST, 801 AGGR_L_DEFAULTED, 802 AGGR_L_EXPIRED 803 } aggr_l_field_index_t; 804 805 static const ofmt_field_t aggr_l_fields[] = { 806 /* name, field width, index */ 807 { "LINK", 12, AGGR_L_LINK, print_lacp_cb}, 808 { "PORT", 13, AGGR_L_PORT, print_lacp_cb}, 809 { "AGGREGATABLE", 13, AGGR_L_AGGREGATABLE, print_lacp_cb}, 810 { "SYNC", 5, AGGR_L_SYNC, print_lacp_cb}, 811 { "COLL", 5, AGGR_L_COLL, print_lacp_cb}, 812 { "DIST", 5, AGGR_L_DIST, print_lacp_cb}, 813 { "DEFAULTED", 10, AGGR_L_DEFAULTED, print_lacp_cb}, 814 { "EXPIRED", 15, AGGR_L_EXPIRED, print_lacp_cb}, 815 { NULL, 0, 0, NULL}} 816 ; 817 818 /* 819 * structures for 'dladm show-phys' 820 */ 821 822 static const ofmt_field_t phys_fields[] = { 823 /* name, field width, offset */ 824 { "LINK", 13, 825 offsetof(link_fields_buf_t, link_name), print_default_cb}, 826 { "MEDIA", 21, 827 offsetof(link_fields_buf_t, link_phys_media), print_default_cb}, 828 { "STATE", 11, 829 offsetof(link_fields_buf_t, link_phys_state), print_default_cb}, 830 { "SPEED", 7, 831 offsetof(link_fields_buf_t, link_phys_speed), print_default_cb}, 832 { "DUPLEX", 10, 833 offsetof(link_fields_buf_t, link_phys_duplex), print_default_cb}, 834 { "DEVICE", 13, 835 offsetof(link_fields_buf_t, link_phys_device), print_default_cb}, 836 { "FLAGS", 7, 837 offsetof(link_fields_buf_t, link_flags), print_default_cb}, 838 { NULL, 0, NULL, 0}} 839 ; 840 841 /* 842 * structures for 'dladm show-phys -m' 843 */ 844 845 typedef enum { 846 PHYS_M_LINK, 847 PHYS_M_SLOT, 848 PHYS_M_ADDRESS, 849 PHYS_M_INUSE, 850 PHYS_M_CLIENT 851 } phys_m_field_index_t; 852 853 static const ofmt_field_t phys_m_fields[] = { 854 /* name, field width, offset */ 855 { "LINK", 13, PHYS_M_LINK, print_phys_one_mac_cb}, 856 { "SLOT", 9, PHYS_M_SLOT, print_phys_one_mac_cb}, 857 { "ADDRESS", 19, PHYS_M_ADDRESS, print_phys_one_mac_cb}, 858 { "INUSE", 5, PHYS_M_INUSE, print_phys_one_mac_cb}, 859 { "CLIENT", 13, PHYS_M_CLIENT, print_phys_one_mac_cb}, 860 { NULL, 0, 0, NULL}} 861 ; 862 863 /* 864 * structures for 'dladm show-phys -H' 865 */ 866 867 typedef enum { 868 PHYS_H_LINK, 869 PHYS_H_RINGTYPE, 870 PHYS_H_RINGS, 871 PHYS_H_CLIENTS 872 } phys_h_field_index_t; 873 874 #define RINGSTRLEN 21 875 876 static const ofmt_field_t phys_h_fields[] = { 877 { "LINK", 13, PHYS_H_LINK, print_phys_one_hwgrp_cb}, 878 { "RINGTYPE", 9, PHYS_H_RINGTYPE, print_phys_one_hwgrp_cb}, 879 { "RINGS", RINGSTRLEN, PHYS_H_RINGS, print_phys_one_hwgrp_cb}, 880 { "CLIENTS", 24, PHYS_H_CLIENTS, print_phys_one_hwgrp_cb}, 881 { NULL, 0, 0, NULL}} 882 ; 883 884 /* 885 * structures for 'dladm show-vlan' 886 */ 887 static const ofmt_field_t vlan_fields[] = { 888 { "LINK", 16, 889 offsetof(link_fields_buf_t, link_name), print_default_cb}, 890 { "VID", 9, 891 offsetof(link_fields_buf_t, link_vlan_vid), print_default_cb}, 892 { "OVER", 13, 893 offsetof(link_fields_buf_t, link_over), print_default_cb}, 894 { "FLAGS", 7, 895 offsetof(link_fields_buf_t, link_flags), print_default_cb}, 896 { NULL, 0, 0, NULL}} 897 ; 898 899 /* 900 * structures common to 'dladm scan-wifi' and 'dladm show-wifi' 901 * callback will be determined in parse_wifi_fields. 902 */ 903 static ofmt_field_t wifi_common_fields[] = { 904 { "LINK", 11, 0, NULL}, 905 { "ESSID", 20, DLADM_WLAN_ATTR_ESSID, NULL}, 906 { "BSSID", 18, DLADM_WLAN_ATTR_BSSID, NULL}, 907 { "IBSSID", 18, DLADM_WLAN_ATTR_BSSID, NULL}, 908 { "MODE", 7, DLADM_WLAN_ATTR_MODE, NULL}, 909 { "SPEED", 7, DLADM_WLAN_ATTR_SPEED, NULL}, 910 { "BSSTYPE", 9, DLADM_WLAN_ATTR_BSSTYPE, NULL}, 911 { "SEC", 7, DLADM_WLAN_ATTR_SECMODE, NULL}, 912 { "STRENGTH", 11, DLADM_WLAN_ATTR_STRENGTH, NULL}, 913 { NULL, 0, 0, NULL}}; 914 915 /* 916 * the 'show-wifi' command supports all the fields in wifi_common_fields 917 * plus the AUTH and STATUS fields. 918 */ 919 static ofmt_field_t wifi_show_fields[A_CNT(wifi_common_fields) + 2] = { 920 { "AUTH", 9, DLADM_WLAN_ATTR_AUTH, NULL}, 921 { "STATUS", 18, DLADM_WLAN_LINKATTR_STATUS, print_wifi_status_cb}, 922 /* copy wifi_common_fields here */ 923 }; 924 925 static char *all_scan_wifi_fields = 926 "link,essid,bssid,sec,strength,mode,speed,bsstype"; 927 static char *all_show_wifi_fields = 928 "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 929 static char *def_scan_wifi_fields = 930 "link,essid,bssid,sec,strength,mode,speed"; 931 static char *def_show_wifi_fields = 932 "link,status,essid,sec,strength,mode,speed"; 933 934 /* 935 * structures for 'dladm show-linkprop' 936 */ 937 typedef enum { 938 LINKPROP_LINK, 939 LINKPROP_PROPERTY, 940 LINKPROP_PERM, 941 LINKPROP_VALUE, 942 LINKPROP_DEFAULT, 943 LINKPROP_POSSIBLE 944 } linkprop_field_index_t; 945 946 static const ofmt_field_t linkprop_fields[] = { 947 /* name, field width, index */ 948 { "LINK", 13, LINKPROP_LINK, print_linkprop_cb}, 949 { "PROPERTY", 16, LINKPROP_PROPERTY, print_linkprop_cb}, 950 { "PERM", 5, LINKPROP_PERM, print_linkprop_cb}, 951 { "VALUE", 15, LINKPROP_VALUE, print_linkprop_cb}, 952 { "DEFAULT", 15, LINKPROP_DEFAULT, print_linkprop_cb}, 953 { "POSSIBLE", 20, LINKPROP_POSSIBLE, print_linkprop_cb}, 954 { NULL, 0, 0, NULL}} 955 ; 956 957 #define MAX_PROP_LINE 512 958 959 typedef struct show_linkprop_state { 960 char ls_link[MAXLINKNAMELEN]; 961 char *ls_line; 962 char **ls_propvals; 963 dladm_arg_list_t *ls_proplist; 964 boolean_t ls_parsable; 965 boolean_t ls_persist; 966 boolean_t ls_header; 967 dladm_status_t ls_status; 968 dladm_status_t ls_retstatus; 969 ofmt_handle_t ls_ofmt; 970 } show_linkprop_state_t; 971 972 typedef struct set_linkprop_state { 973 const char *ls_name; 974 boolean_t ls_reset; 975 boolean_t ls_temp; 976 dladm_status_t ls_status; 977 } set_linkprop_state_t; 978 979 typedef struct linkprop_args_s { 980 show_linkprop_state_t *ls_state; 981 char *ls_propname; 982 datalink_id_t ls_linkid; 983 } linkprop_args_t; 984 985 /* 986 * structures for 'dladm show-secobj' 987 */ 988 typedef struct secobj_fields_buf_s { 989 char ss_obj_name[DLADM_SECOBJ_VAL_MAX]; 990 char ss_class[20]; 991 char ss_val[30]; 992 } secobj_fields_buf_t; 993 994 static const ofmt_field_t secobj_fields[] = { 995 { "OBJECT", 21, 996 offsetof(secobj_fields_buf_t, ss_obj_name), print_default_cb}, 997 { "CLASS", 21, 998 offsetof(secobj_fields_buf_t, ss_class), print_default_cb}, 999 { "VALUE", 31, 1000 offsetof(secobj_fields_buf_t, ss_val), print_default_cb}, 1001 { NULL, 0, 0, NULL}} 1002 ; 1003 1004 /* 1005 * structures for 'dladm show-vnic' 1006 */ 1007 typedef struct vnic_fields_buf_s 1008 { 1009 char vnic_link[DLPI_LINKNAME_MAX]; 1010 char vnic_over[DLPI_LINKNAME_MAX]; 1011 char vnic_speed[6]; 1012 char vnic_macaddr[18]; 1013 char vnic_macaddrtype[19]; 1014 char vnic_vid[6]; 1015 } vnic_fields_buf_t; 1016 1017 static const ofmt_field_t vnic_fields[] = { 1018 { "LINK", 13, 1019 offsetof(vnic_fields_buf_t, vnic_link), print_default_cb}, 1020 { "OVER", 13, 1021 offsetof(vnic_fields_buf_t, vnic_over), print_default_cb}, 1022 { "SPEED", 7, 1023 offsetof(vnic_fields_buf_t, vnic_speed), print_default_cb}, 1024 { "MACADDRESS", 18, 1025 offsetof(vnic_fields_buf_t, vnic_macaddr), print_default_cb}, 1026 { "MACADDRTYPE", 20, 1027 offsetof(vnic_fields_buf_t, vnic_macaddrtype), print_default_cb}, 1028 { "VID", 7, 1029 offsetof(vnic_fields_buf_t, vnic_vid), print_default_cb}, 1030 { NULL, 0, 0, NULL}} 1031 ; 1032 1033 /* 1034 * structures for 'dladm show-ib' 1035 */ 1036 typedef struct ib_fields_buf_s 1037 { 1038 char ib_link[DLPI_LINKNAME_MAX]; 1039 char ib_hcaguid[17]; 1040 char ib_portguid[17]; 1041 char ib_portnum[4]; 1042 char ib_state[6]; 1043 char ib_pkeys[MAXPKEYSTRSZ]; 1044 } ib_fields_buf_t; 1045 1046 static const ofmt_field_t ib_fields[] = { 1047 { "LINK", 13, 1048 offsetof(ib_fields_buf_t, ib_link), print_default_cb}, 1049 { "HCAGUID", IBGUIDSTRLEN, 1050 offsetof(ib_fields_buf_t, ib_hcaguid), print_default_cb}, 1051 { "PORTGUID", IBGUIDSTRLEN, 1052 offsetof(ib_fields_buf_t, ib_portguid), print_default_cb}, 1053 { "PORT", IBPORTSTRLEN, 1054 offsetof(ib_fields_buf_t, ib_portnum), print_default_cb}, 1055 { "STATE", 7, 1056 offsetof(ib_fields_buf_t, ib_state), print_default_cb}, 1057 { "PKEYS", 18, 1058 offsetof(ib_fields_buf_t, ib_pkeys), print_default_cb}, 1059 { NULL, 0, 0, NULL}}; 1060 1061 /* 1062 * structures for 'dladm show-part' 1063 */ 1064 typedef struct part_fields_buf_s 1065 { 1066 char part_link[DLPI_LINKNAME_MAX]; 1067 char part_pkey[5]; 1068 char part_over[DLPI_LINKNAME_MAX]; 1069 char part_state[8]; 1070 char part_flags[5]; 1071 } part_fields_buf_t; 1072 1073 static const ofmt_field_t part_fields[] = { 1074 { "LINK", 13, 1075 offsetof(part_fields_buf_t, part_link), print_default_cb}, 1076 { "PKEY", MAXPKEYLEN, 1077 offsetof(part_fields_buf_t, part_pkey), print_default_cb}, 1078 { "OVER", 13, 1079 offsetof(part_fields_buf_t, part_over), print_default_cb}, 1080 { "STATE", 9, 1081 offsetof(part_fields_buf_t, part_state), print_default_cb}, 1082 { "FLAGS", 5, 1083 offsetof(part_fields_buf_t, part_flags), print_default_cb}, 1084 { NULL, 0, 0, NULL}}; 1085 1086 /* 1087 * structures for 'dladm show-simnet' 1088 */ 1089 typedef struct simnet_fields_buf_s 1090 { 1091 char simnet_name[DLPI_LINKNAME_MAX]; 1092 char simnet_media[DLADM_STRSIZE]; 1093 char simnet_macaddr[18]; 1094 char simnet_otherlink[DLPI_LINKNAME_MAX]; 1095 } simnet_fields_buf_t; 1096 1097 static const ofmt_field_t simnet_fields[] = { 1098 { "LINK", 12, 1099 offsetof(simnet_fields_buf_t, simnet_name), print_default_cb}, 1100 { "MEDIA", 20, 1101 offsetof(simnet_fields_buf_t, simnet_media), print_default_cb}, 1102 { "MACADDRESS", 18, 1103 offsetof(simnet_fields_buf_t, simnet_macaddr), print_default_cb}, 1104 { "OTHERLINK", 12, 1105 offsetof(simnet_fields_buf_t, simnet_otherlink), print_default_cb}, 1106 { NULL, 0, 0, NULL}} 1107 ; 1108 1109 /* 1110 * structures for 'dladm show-usage' 1111 */ 1112 1113 typedef struct usage_fields_buf_s { 1114 char usage_link[12]; 1115 char usage_duration[10]; 1116 char usage_ipackets[9]; 1117 char usage_rbytes[10]; 1118 char usage_opackets[9]; 1119 char usage_obytes[10]; 1120 char usage_bandwidth[14]; 1121 } usage_fields_buf_t; 1122 1123 static const ofmt_field_t usage_fields[] = { 1124 { "LINK", 13, 1125 offsetof(usage_fields_buf_t, usage_link), print_default_cb}, 1126 { "DURATION", 11, 1127 offsetof(usage_fields_buf_t, usage_duration), print_default_cb}, 1128 { "IPACKETS", 10, 1129 offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb}, 1130 { "RBYTES", 11, 1131 offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb}, 1132 { "OPACKETS", 10, 1133 offsetof(usage_fields_buf_t, usage_opackets), print_default_cb}, 1134 { "OBYTES", 11, 1135 offsetof(usage_fields_buf_t, usage_obytes), print_default_cb}, 1136 { "BANDWIDTH", 15, 1137 offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb}, 1138 { NULL, 0, 0, NULL}} 1139 ; 1140 1141 1142 /* 1143 * structures for 'dladm show-usage link' 1144 */ 1145 1146 typedef struct usage_l_fields_buf_s { 1147 char usage_l_link[12]; 1148 char usage_l_stime[13]; 1149 char usage_l_etime[13]; 1150 char usage_l_rbytes[8]; 1151 char usage_l_obytes[8]; 1152 char usage_l_bandwidth[14]; 1153 } usage_l_fields_buf_t; 1154 1155 static const ofmt_field_t usage_l_fields[] = { 1156 /* name, field width, offset */ 1157 { "LINK", 13, 1158 offsetof(usage_l_fields_buf_t, usage_l_link), print_default_cb}, 1159 { "START", 14, 1160 offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb}, 1161 { "END", 14, 1162 offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb}, 1163 { "RBYTES", 9, 1164 offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb}, 1165 { "OBYTES", 9, 1166 offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb}, 1167 { "BANDWIDTH", 15, 1168 offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb}, 1169 { NULL, 0, 0, NULL}} 1170 ; 1171 1172 /* IPTUN_*FLAG_INDEX values are indices into iptun_flags below. */ 1173 enum { IPTUN_SFLAG_INDEX, IPTUN_IFLAG_INDEX, IPTUN_NUM_FLAGS }; 1174 1175 /* 1176 * structures for 'dladm show-iptun' 1177 */ 1178 typedef struct iptun_fields_buf_s { 1179 char iptun_name[MAXLINKNAMELEN]; 1180 char iptun_type[5]; 1181 char iptun_laddr[NI_MAXHOST]; 1182 char iptun_raddr[NI_MAXHOST]; 1183 char iptun_flags[IPTUN_NUM_FLAGS + 1]; 1184 } iptun_fields_buf_t; 1185 1186 static const ofmt_field_t iptun_fields[] = { 1187 { "LINK", 16, 1188 offsetof(iptun_fields_buf_t, iptun_name), print_default_cb }, 1189 { "TYPE", 6, 1190 offsetof(iptun_fields_buf_t, iptun_type), print_default_cb }, 1191 { "FLAGS", 7, 1192 offsetof(iptun_fields_buf_t, iptun_flags), print_default_cb }, 1193 { "LOCAL", 20, 1194 offsetof(iptun_fields_buf_t, iptun_laddr), print_default_cb }, 1195 { "REMOTE", 20, 1196 offsetof(iptun_fields_buf_t, iptun_raddr), print_default_cb }, 1197 { NULL, 0, 0, NULL} 1198 }; 1199 1200 /* 1201 * structures for 'dladm show-bridge'. These are based on sections 14.8.1.1.3 1202 * and 14.8.1.2.2 of IEEE 802.1D-2004. 1203 */ 1204 typedef struct bridge_fields_buf_s { 1205 char bridge_name[MAXLINKNAMELEN]; /* 14.4.1.2.3(b) */ 1206 char bridge_protect[7]; /* stp or trill */ 1207 char bridge_address[24]; /* 17.18.3, 7.12.5, 14.4.1.2.3(a) */ 1208 char bridge_priority[7]; /* 17.18.3 9.2.5 - only upper 4 bits */ 1209 char bridge_bmaxage[7]; /* 17.18.4 configured */ 1210 char bridge_bhellotime[7]; /* 17.18.4 configured */ 1211 char bridge_bfwddelay[7]; /* 17.18.4 configured */ 1212 char bridge_forceproto[3]; /* 17.13.4 configured */ 1213 char bridge_tctime[12]; /* 14.8.1.1.3(b) */ 1214 char bridge_tccount[12]; /* 17.17.8 */ 1215 char bridge_tchange[12]; /* 17.17.8 */ 1216 char bridge_desroot[24]; /* 17.18.6 priority "/" MAC */ 1217 char bridge_rootcost[12]; /* 17.18.6 */ 1218 char bridge_rootport[12]; /* 17.18.6 */ 1219 char bridge_maxage[7]; /* 17.18.7 for root */ 1220 char bridge_hellotime[7]; /* 17.13.6 for root */ 1221 char bridge_fwddelay[7]; /* 17.13.5 for root */ 1222 char bridge_holdtime[12]; /* 17.13.12 for root */ 1223 } bridge_fields_buf_t; 1224 1225 static ofmt_field_t bridge_fields[] = { 1226 /* name, field width, offset, callback */ 1227 { "BRIDGE", 12, 1228 offsetof(bridge_fields_buf_t, bridge_name), print_default_cb }, 1229 { "PROTECT", 8, 1230 offsetof(bridge_fields_buf_t, bridge_protect), print_default_cb }, 1231 { "ADDRESS", 19, 1232 offsetof(bridge_fields_buf_t, bridge_address), print_default_cb }, 1233 { "PRIORITY", 9, 1234 offsetof(bridge_fields_buf_t, bridge_priority), print_default_cb }, 1235 { "BMAXAGE", 8, 1236 offsetof(bridge_fields_buf_t, bridge_bmaxage), print_default_cb }, 1237 { "BHELLOTIME", 11, 1238 offsetof(bridge_fields_buf_t, bridge_bhellotime), print_default_cb }, 1239 { "BFWDDELAY", 10, 1240 offsetof(bridge_fields_buf_t, bridge_bfwddelay), print_default_cb }, 1241 { "FORCEPROTO", 11, 1242 offsetof(bridge_fields_buf_t, bridge_forceproto), print_default_cb }, 1243 { "TCTIME", 10, 1244 offsetof(bridge_fields_buf_t, bridge_tctime), print_default_cb }, 1245 { "TCCOUNT", 10, 1246 offsetof(bridge_fields_buf_t, bridge_tccount), print_default_cb }, 1247 { "TCHANGE", 10, 1248 offsetof(bridge_fields_buf_t, bridge_tchange), print_default_cb }, 1249 { "DESROOT", 23, 1250 offsetof(bridge_fields_buf_t, bridge_desroot), print_default_cb }, 1251 { "ROOTCOST", 11, 1252 offsetof(bridge_fields_buf_t, bridge_rootcost), print_default_cb }, 1253 { "ROOTPORT", 11, 1254 offsetof(bridge_fields_buf_t, bridge_rootport), print_default_cb }, 1255 { "MAXAGE", 8, 1256 offsetof(bridge_fields_buf_t, bridge_maxage), print_default_cb }, 1257 { "HELLOTIME", 10, 1258 offsetof(bridge_fields_buf_t, bridge_hellotime), print_default_cb }, 1259 { "FWDDELAY", 9, 1260 offsetof(bridge_fields_buf_t, bridge_fwddelay), print_default_cb }, 1261 { "HOLDTIME", 9, 1262 offsetof(bridge_fields_buf_t, bridge_holdtime), print_default_cb }, 1263 { NULL, 0, 0, NULL}}; 1264 1265 /* 1266 * structures for 'dladm show-bridge -l'. These are based on 14.4.1.2.3 and 1267 * 14.8.2.1.3 of IEEE 802.1D-2004. 1268 */ 1269 typedef struct bridge_link_fields_buf_s { 1270 char bridgel_link[MAXLINKNAMELEN]; 1271 char bridgel_index[7]; /* 14.4.1.2.3(d1) */ 1272 char bridgel_state[11]; /* 14.8.2.1.3(b) */ 1273 char bridgel_uptime[7]; /* 14.8.2.1.3(a) */ 1274 char bridgel_opercost[7] /* 14.8.2.1.3(d) */; 1275 char bridgel_operp2p[4]; /* 14.8.2.1.3(p) */ 1276 char bridgel_operedge[4]; /* 14.8.2.1.3(k) */ 1277 char bridgel_desroot[23]; /* 14.8.2.1.3(e) */ 1278 char bridgel_descost[12]; /* 14.8.2.1.3(f) */ 1279 char bridgel_desbridge[23]; /* 14.8.2.1.3(g) */ 1280 char bridgel_desport[7]; /* 14.8.2.1.3(h) */ 1281 char bridgel_tcack[4]; /* 14.8.2.1.3(i) */ 1282 } bridge_link_fields_buf_t; 1283 1284 static ofmt_field_t bridge_link_fields[] = { 1285 /* name, field width, offset, callback */ 1286 { "LINK", 12, 1287 offsetof(bridge_link_fields_buf_t, bridgel_link), print_default_cb }, 1288 { "INDEX", 8, 1289 offsetof(bridge_link_fields_buf_t, bridgel_index), print_default_cb }, 1290 { "STATE", 12, 1291 offsetof(bridge_link_fields_buf_t, bridgel_state), print_default_cb }, 1292 { "UPTIME", 8, 1293 offsetof(bridge_link_fields_buf_t, bridgel_uptime), print_default_cb }, 1294 { "OPERCOST", 9, 1295 offsetof(bridge_link_fields_buf_t, bridgel_opercost), print_default_cb }, 1296 { "OPERP2P", 8, 1297 offsetof(bridge_link_fields_buf_t, bridgel_operp2p), print_default_cb }, 1298 { "OPEREDGE", 9, 1299 offsetof(bridge_link_fields_buf_t, bridgel_operedge), print_default_cb }, 1300 { "DESROOT", 22, 1301 offsetof(bridge_link_fields_buf_t, bridgel_desroot), print_default_cb }, 1302 { "DESCOST", 11, 1303 offsetof(bridge_link_fields_buf_t, bridgel_descost), print_default_cb }, 1304 { "DESBRIDGE", 22, 1305 offsetof(bridge_link_fields_buf_t, bridgel_desbridge), print_default_cb }, 1306 { "DESPORT", 8, 1307 offsetof(bridge_link_fields_buf_t, bridgel_desport), print_default_cb }, 1308 { "TCACK", 6, 1309 offsetof(bridge_link_fields_buf_t, bridgel_tcack), print_default_cb }, 1310 { NULL, 0, 0, NULL}}; 1311 1312 /* 1313 * structures for 'dladm show-bridge -s'. These are not based on IEEE 1314 * 802.1D-2004. 1315 */ 1316 #define ULONG_DIG (((sizeof (ulong_t) * NBBY) * 3 / 10) + 1) 1317 #define UINT64_DIG (((sizeof (uint64_t) * NBBY) * 3 / 10) + 1) 1318 typedef struct bridge_statfields_buf_s { 1319 char bridges_name[MAXLINKNAMELEN]; 1320 char bridges_drops[UINT64_DIG]; 1321 char bridges_forwards[UINT64_DIG]; 1322 char bridges_mbcast[UINT64_DIG]; 1323 char bridges_unknown[UINT64_DIG]; 1324 char bridges_recv[UINT64_DIG]; 1325 char bridges_sent[UINT64_DIG]; 1326 } bridge_statfields_buf_t; 1327 1328 static ofmt_field_t bridge_statfields[] = { 1329 /* name, field width, offset, callback */ 1330 { "BRIDGE", 12, 1331 offsetof(bridge_statfields_buf_t, bridges_name), print_default_cb }, 1332 { "DROPS", 12, 1333 offsetof(bridge_statfields_buf_t, bridges_drops), print_default_cb }, 1334 { "FORWARDS", 12, 1335 offsetof(bridge_statfields_buf_t, bridges_forwards), print_default_cb }, 1336 { "MBCAST", 12, 1337 offsetof(bridge_statfields_buf_t, bridges_mbcast), print_default_cb }, 1338 { "UNKNOWN", 12, 1339 offsetof(bridge_statfields_buf_t, bridges_unknown), print_default_cb }, 1340 { "RECV", 12, 1341 offsetof(bridge_statfields_buf_t, bridges_recv), print_default_cb }, 1342 { "SENT", 12, 1343 offsetof(bridge_statfields_buf_t, bridges_sent), print_default_cb }, 1344 { NULL, 0, 0, NULL}}; 1345 1346 /* 1347 * structures for 'dladm show-bridge -s -l'. These are based in part on 1348 * section 14.6.1.1.3 of IEEE 802.1D-2004. 1349 */ 1350 typedef struct bridge_link_statfields_buf_s { 1351 char bridgels_link[MAXLINKNAMELEN]; 1352 char bridgels_cfgbpdu[ULONG_DIG]; 1353 char bridgels_tcnbpdu[ULONG_DIG]; 1354 char bridgels_rstpbpdu[ULONG_DIG]; 1355 char bridgels_txbpdu[ULONG_DIG]; 1356 char bridgels_drops[UINT64_DIG]; /* 14.6.1.1.3(d) */ 1357 char bridgels_recv[UINT64_DIG]; /* 14.6.1.1.3(a) */ 1358 char bridgels_xmit[UINT64_DIG]; /* 14.6.1.1.3(c) */ 1359 } bridge_link_statfields_buf_t; 1360 1361 static ofmt_field_t bridge_link_statfields[] = { 1362 /* name, field width, offset, callback */ 1363 { "LINK", 12, 1364 offsetof(bridge_link_statfields_buf_t, bridgels_link), print_default_cb }, 1365 { "CFGBPDU", 9, 1366 offsetof(bridge_link_statfields_buf_t, bridgels_cfgbpdu), 1367 print_default_cb }, 1368 { "TCNBPDU", 9, 1369 offsetof(bridge_link_statfields_buf_t, bridgels_tcnbpdu), 1370 print_default_cb }, 1371 { "RSTPBPDU", 9, 1372 offsetof(bridge_link_statfields_buf_t, bridgels_rstpbpdu), 1373 print_default_cb }, 1374 { "TXBPDU", 9, 1375 offsetof(bridge_link_statfields_buf_t, bridgels_txbpdu), print_default_cb }, 1376 { "DROPS", 9, 1377 offsetof(bridge_link_statfields_buf_t, bridgels_drops), print_default_cb }, 1378 { "RECV", 9, 1379 offsetof(bridge_link_statfields_buf_t, bridgels_recv), print_default_cb }, 1380 { "XMIT", 9, 1381 offsetof(bridge_link_statfields_buf_t, bridgels_xmit), print_default_cb }, 1382 { NULL, 0, 0, NULL}}; 1383 1384 /* 1385 * structures for 'dladm show-bridge -f'. These are based in part on 1386 * section 14.7.6.3.3 of IEEE 802.1D-2004. 1387 */ 1388 typedef struct bridge_fwd_fields_buf_s { 1389 char bridgef_dest[18]; /* 14.7.6.3.3(a) */ 1390 char bridgef_age[8]; 1391 char bridgef_flags[6]; 1392 char bridgef_output[MAXLINKNAMELEN]; /* 14.7.6.3.3(c) */ 1393 } bridge_fwd_fields_buf_t; 1394 1395 static ofmt_field_t bridge_fwd_fields[] = { 1396 /* name, field width, offset, callback */ 1397 { "DEST", 17, 1398 offsetof(bridge_fwd_fields_buf_t, bridgef_dest), print_default_cb }, 1399 { "AGE", 7, 1400 offsetof(bridge_fwd_fields_buf_t, bridgef_age), print_default_cb }, 1401 { "FLAGS", 6, 1402 offsetof(bridge_fwd_fields_buf_t, bridgef_flags), print_default_cb }, 1403 { "OUTPUT", 12, 1404 offsetof(bridge_fwd_fields_buf_t, bridgef_output), print_default_cb }, 1405 { NULL, 0, 0, NULL}}; 1406 1407 /* 1408 * structures for 'dladm show-bridge -t'. 1409 */ 1410 typedef struct bridge_trill_fields_buf_s { 1411 char bridget_nick[6]; 1412 char bridget_flags[6]; 1413 char bridget_link[MAXLINKNAMELEN]; 1414 char bridget_nexthop[18]; 1415 } bridge_trill_fields_buf_t; 1416 1417 static ofmt_field_t bridge_trill_fields[] = { 1418 /* name, field width, offset, callback */ 1419 { "NICK", 5, 1420 offsetof(bridge_trill_fields_buf_t, bridget_nick), print_default_cb }, 1421 { "FLAGS", 6, 1422 offsetof(bridge_trill_fields_buf_t, bridget_flags), print_default_cb }, 1423 { "LINK", 12, 1424 offsetof(bridge_trill_fields_buf_t, bridget_link), print_default_cb }, 1425 { "NEXTHOP", 17, 1426 offsetof(bridge_trill_fields_buf_t, bridget_nexthop), print_default_cb }, 1427 { NULL, 0, 0, NULL}}; 1428 1429 static char *progname; 1430 static sig_atomic_t signalled; 1431 1432 /* 1433 * Handle to libdladm. Opened in main() before the sub-command 1434 * specific function is called. 1435 */ 1436 static dladm_handle_t handle = NULL; 1437 1438 #define DLADM_ETHERSTUB_NAME "etherstub" 1439 #define DLADM_IS_ETHERSTUB(id) (id == DATALINK_INVALID_LINKID) 1440 1441 static void 1442 usage(void) 1443 { 1444 int i; 1445 cmd_t *cmdp; 1446 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ..." 1447 "\n")); 1448 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 1449 cmdp = &cmds[i]; 1450 if (cmdp->c_usage != NULL) 1451 (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage)); 1452 } 1453 1454 /* close dladm handle if it was opened */ 1455 if (handle != NULL) 1456 dladm_close(handle); 1457 1458 exit(EXIT_FAILURE); 1459 } 1460 1461 int 1462 main(int argc, char *argv[]) 1463 { 1464 int i; 1465 cmd_t *cmdp; 1466 dladm_status_t status; 1467 1468 (void) setlocale(LC_ALL, ""); 1469 #if !defined(TEXT_DOMAIN) 1470 #define TEXT_DOMAIN "SYS_TEST" 1471 #endif 1472 (void) textdomain(TEXT_DOMAIN); 1473 1474 progname = argv[0]; 1475 1476 if (argc < 2) 1477 usage(); 1478 1479 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 1480 cmdp = &cmds[i]; 1481 if (strcmp(argv[1], cmdp->c_name) == 0) { 1482 /* Open the libdladm handle */ 1483 if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) { 1484 die_dlerr(status, 1485 "could not open /dev/dld"); 1486 } 1487 1488 cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage); 1489 1490 dladm_close(handle); 1491 return (EXIT_SUCCESS); 1492 } 1493 } 1494 1495 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 1496 progname, argv[1]); 1497 usage(); 1498 return (EXIT_FAILURE); 1499 } 1500 1501 /*ARGSUSED*/ 1502 static int 1503 show_usage_date(dladm_usage_t *usage, void *arg) 1504 { 1505 show_usage_state_t *state = (show_usage_state_t *)arg; 1506 time_t stime; 1507 char timebuf[20]; 1508 dladm_status_t status; 1509 uint32_t flags; 1510 1511 /* 1512 * Only show usage information for existing links unless '-a' 1513 * is specified. 1514 */ 1515 if (!state->us_showall) { 1516 if ((status = dladm_name2info(handle, usage->du_name, 1517 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1518 return (status); 1519 } 1520 if ((flags & DLADM_OPT_ACTIVE) == 0) 1521 return (DLADM_STATUS_LINKINVAL); 1522 } 1523 1524 stime = usage->du_stime; 1525 (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y", 1526 localtime(&stime)); 1527 (void) printf("%s\n", timebuf); 1528 1529 return (DLADM_STATUS_OK); 1530 } 1531 1532 static int 1533 show_usage_time(dladm_usage_t *usage, void *arg) 1534 { 1535 show_usage_state_t *state = (show_usage_state_t *)arg; 1536 char buf[DLADM_STRSIZE]; 1537 usage_l_fields_buf_t ubuf; 1538 time_t time; 1539 double bw; 1540 dladm_status_t status; 1541 uint32_t flags; 1542 1543 /* 1544 * Only show usage information for existing links unless '-a' 1545 * is specified. 1546 */ 1547 if (!state->us_showall) { 1548 if ((status = dladm_name2info(handle, usage->du_name, 1549 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1550 return (status); 1551 } 1552 if ((flags & DLADM_OPT_ACTIVE) == 0) 1553 return (DLADM_STATUS_LINKINVAL); 1554 } 1555 1556 if (state->us_plot) { 1557 if (!state->us_printheader) { 1558 if (state->us_first) { 1559 (void) printf("# Time"); 1560 state->us_first = B_FALSE; 1561 } 1562 (void) printf(" %s", usage->du_name); 1563 if (usage->du_last) { 1564 (void) printf("\n"); 1565 state->us_first = B_TRUE; 1566 state->us_printheader = B_TRUE; 1567 } 1568 } else { 1569 if (state->us_first) { 1570 time = usage->du_etime; 1571 (void) strftime(buf, sizeof (buf), "%T", 1572 localtime(&time)); 1573 state->us_first = B_FALSE; 1574 (void) printf("%s", buf); 1575 } 1576 bw = (double)usage->du_bandwidth/1000; 1577 (void) printf(" %.2f", bw); 1578 if (usage->du_last) { 1579 (void) printf("\n"); 1580 state->us_first = B_TRUE; 1581 } 1582 } 1583 return (DLADM_STATUS_OK); 1584 } 1585 1586 bzero(&ubuf, sizeof (ubuf)); 1587 1588 (void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s", 1589 usage->du_name); 1590 time = usage->du_stime; 1591 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1592 (void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s", 1593 buf); 1594 time = usage->du_etime; 1595 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1596 (void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s", 1597 buf); 1598 (void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes), 1599 "%llu", usage->du_rbytes); 1600 (void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes), 1601 "%llu", usage->du_obytes); 1602 (void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth), 1603 "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1604 1605 ofmt_print(state->us_ofmt, &ubuf); 1606 return (DLADM_STATUS_OK); 1607 } 1608 1609 static int 1610 show_usage_res(dladm_usage_t *usage, void *arg) 1611 { 1612 show_usage_state_t *state = (show_usage_state_t *)arg; 1613 char buf[DLADM_STRSIZE]; 1614 usage_fields_buf_t ubuf; 1615 dladm_status_t status; 1616 uint32_t flags; 1617 1618 /* 1619 * Only show usage information for existing links unless '-a' 1620 * is specified. 1621 */ 1622 if (!state->us_showall) { 1623 if ((status = dladm_name2info(handle, usage->du_name, 1624 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1625 return (status); 1626 } 1627 if ((flags & DLADM_OPT_ACTIVE) == 0) 1628 return (DLADM_STATUS_LINKINVAL); 1629 } 1630 1631 bzero(&ubuf, sizeof (ubuf)); 1632 1633 (void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s", 1634 usage->du_name); 1635 (void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration), 1636 "%llu", usage->du_duration); 1637 (void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets), 1638 "%llu", usage->du_ipackets); 1639 (void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes), 1640 "%llu", usage->du_rbytes); 1641 (void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets), 1642 "%llu", usage->du_opackets); 1643 (void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes), 1644 "%llu", usage->du_obytes); 1645 (void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth), 1646 "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1647 1648 ofmt_print(state->us_ofmt, &ubuf); 1649 1650 return (DLADM_STATUS_OK); 1651 } 1652 1653 static boolean_t 1654 valid_formatspec(char *formatspec_str) 1655 { 1656 if (strcmp(formatspec_str, "gnuplot") == 0) 1657 return (B_TRUE); 1658 return (B_FALSE); 1659 1660 } 1661 1662 /*ARGSUSED*/ 1663 static void 1664 do_show_usage(int argc, char *argv[], const char *use) 1665 { 1666 char *file = NULL; 1667 int opt; 1668 dladm_status_t status; 1669 boolean_t d_arg = B_FALSE; 1670 char *stime = NULL; 1671 char *etime = NULL; 1672 char *resource = NULL; 1673 show_usage_state_t state; 1674 boolean_t o_arg = B_FALSE; 1675 boolean_t F_arg = B_FALSE; 1676 char *fields_str = NULL; 1677 char *formatspec_str = NULL; 1678 char *all_l_fields = 1679 "link,start,end,rbytes,obytes,bandwidth"; 1680 ofmt_handle_t ofmt; 1681 ofmt_status_t oferr; 1682 uint_t ofmtflags = 0; 1683 1684 bzero(&state, sizeof (show_usage_state_t)); 1685 state.us_parsable = B_FALSE; 1686 state.us_printheader = B_FALSE; 1687 state.us_plot = B_FALSE; 1688 state.us_first = B_TRUE; 1689 1690 while ((opt = getopt_long(argc, argv, "das:e:o:f:F:", 1691 usage_opts, NULL)) != -1) { 1692 switch (opt) { 1693 case 'd': 1694 d_arg = B_TRUE; 1695 break; 1696 case 'a': 1697 state.us_showall = B_TRUE; 1698 break; 1699 case 'f': 1700 file = optarg; 1701 break; 1702 case 's': 1703 stime = optarg; 1704 break; 1705 case 'e': 1706 etime = optarg; 1707 break; 1708 case 'o': 1709 o_arg = B_TRUE; 1710 fields_str = optarg; 1711 break; 1712 case 'F': 1713 state.us_plot = F_arg = B_TRUE; 1714 formatspec_str = optarg; 1715 break; 1716 default: 1717 die_opterr(optopt, opt, use); 1718 break; 1719 } 1720 } 1721 1722 if (file == NULL) 1723 die("show-usage requires a file"); 1724 1725 if (optind == (argc-1)) { 1726 uint32_t flags; 1727 1728 resource = argv[optind]; 1729 if (!state.us_showall && 1730 (((status = dladm_name2info(handle, resource, NULL, &flags, 1731 NULL, NULL)) != DLADM_STATUS_OK) || 1732 ((flags & DLADM_OPT_ACTIVE) == 0))) { 1733 die("invalid link: '%s'", resource); 1734 } 1735 } 1736 1737 if (F_arg && d_arg) 1738 die("incompatible -d and -F options"); 1739 1740 if (F_arg && valid_formatspec(formatspec_str) == B_FALSE) 1741 die("Format specifier %s not supported", formatspec_str); 1742 1743 if (state.us_parsable) 1744 ofmtflags |= OFMT_PARSABLE; 1745 1746 if (resource == NULL && stime == NULL && etime == NULL) { 1747 oferr = ofmt_open(fields_str, usage_fields, ofmtflags, 0, 1748 &ofmt); 1749 } else { 1750 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 1751 fields_str = all_l_fields; 1752 oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags, 0, 1753 &ofmt); 1754 1755 } 1756 ofmt_check(oferr, state.us_parsable, ofmt, die, warn); 1757 state.us_ofmt = ofmt; 1758 1759 if (d_arg) { 1760 /* Print log dates */ 1761 status = dladm_usage_dates(show_usage_date, 1762 DLADM_LOGTYPE_LINK, file, resource, &state); 1763 } else if (resource == NULL && stime == NULL && etime == NULL && 1764 !F_arg) { 1765 /* Print summary */ 1766 status = dladm_usage_summary(show_usage_res, 1767 DLADM_LOGTYPE_LINK, file, &state); 1768 } else if (resource != NULL) { 1769 /* Print log entries for named resource */ 1770 status = dladm_walk_usage_res(show_usage_time, 1771 DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state); 1772 } else { 1773 /* Print time and information for each link */ 1774 status = dladm_walk_usage_time(show_usage_time, 1775 DLADM_LOGTYPE_LINK, file, stime, etime, &state); 1776 } 1777 1778 if (status != DLADM_STATUS_OK) 1779 die_dlerr(status, "show-usage"); 1780 ofmt_close(ofmt); 1781 } 1782 1783 static void 1784 do_create_aggr(int argc, char *argv[], const char *use) 1785 { 1786 int option; 1787 int key = 0; 1788 uint32_t policy = AGGR_POLICY_L4; 1789 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 1790 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 1791 dladm_aggr_port_attr_db_t port[MAXPORT]; 1792 uint_t n, ndev, nlink; 1793 uint8_t mac_addr[ETHERADDRL]; 1794 boolean_t mac_addr_fixed = B_FALSE; 1795 boolean_t P_arg = B_FALSE; 1796 boolean_t l_arg = B_FALSE; 1797 boolean_t u_arg = B_FALSE; 1798 boolean_t T_arg = B_FALSE; 1799 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1800 char *altroot = NULL; 1801 char name[MAXLINKNAMELEN]; 1802 char *devs[MAXPORT]; 1803 char *links[MAXPORT]; 1804 dladm_status_t status; 1805 dladm_status_t pstatus; 1806 char propstr[DLADM_STRSIZE]; 1807 dladm_arg_list_t *proplist = NULL; 1808 int i; 1809 datalink_id_t linkid; 1810 1811 ndev = nlink = opterr = 0; 1812 bzero(propstr, DLADM_STRSIZE); 1813 1814 while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:", 1815 lopts, NULL)) != -1) { 1816 switch (option) { 1817 case 'd': 1818 if (ndev + nlink >= MAXPORT) 1819 die("too many ports specified"); 1820 1821 devs[ndev++] = optarg; 1822 break; 1823 case 'P': 1824 if (P_arg) 1825 die_optdup(option); 1826 1827 P_arg = B_TRUE; 1828 if (!dladm_aggr_str2policy(optarg, &policy)) 1829 die("invalid policy '%s'", optarg); 1830 break; 1831 case 'u': 1832 if (u_arg) 1833 die_optdup(option); 1834 1835 u_arg = B_TRUE; 1836 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 1837 mac_addr)) 1838 die("invalid MAC address '%s'", optarg); 1839 break; 1840 case 'l': 1841 if (isdigit(optarg[strlen(optarg) - 1])) { 1842 1843 /* 1844 * Ended with digit, possibly a link name. 1845 */ 1846 if (ndev + nlink >= MAXPORT) 1847 die("too many ports specified"); 1848 1849 links[nlink++] = optarg; 1850 break; 1851 } 1852 /* FALLTHROUGH */ 1853 case 'L': 1854 if (l_arg) 1855 die_optdup(option); 1856 1857 l_arg = B_TRUE; 1858 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 1859 die("invalid LACP mode '%s'", optarg); 1860 break; 1861 case 'T': 1862 if (T_arg) 1863 die_optdup(option); 1864 1865 T_arg = B_TRUE; 1866 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 1867 die("invalid LACP timer value '%s'", optarg); 1868 break; 1869 case 't': 1870 flags &= ~DLADM_OPT_PERSIST; 1871 break; 1872 case 'f': 1873 flags |= DLADM_OPT_FORCE; 1874 break; 1875 case 'R': 1876 altroot = optarg; 1877 break; 1878 case 'p': 1879 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 1880 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 1881 DLADM_STRSIZE) 1882 die("property list too long '%s'", propstr); 1883 break; 1884 1885 default: 1886 die_opterr(optopt, option, use); 1887 break; 1888 } 1889 } 1890 1891 if (ndev + nlink == 0) 1892 usage(); 1893 1894 /* get key value or the aggregation name (required last argument) */ 1895 if (optind != (argc-1)) 1896 usage(); 1897 1898 if (!str2int(argv[optind], &key)) { 1899 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= 1900 MAXLINKNAMELEN) { 1901 die("link name too long '%s'", argv[optind]); 1902 } 1903 1904 if (!dladm_valid_linkname(name)) 1905 die("invalid link name '%s'", argv[optind]); 1906 } else { 1907 (void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key); 1908 } 1909 1910 if (altroot != NULL) 1911 altroot_cmd(altroot, argc, argv); 1912 1913 for (n = 0; n < ndev; n++) { 1914 if ((status = dladm_dev2linkid(handle, devs[n], 1915 &port[n].lp_linkid)) != DLADM_STATUS_OK) { 1916 die_dlerr(status, "invalid dev name '%s'", devs[n]); 1917 } 1918 } 1919 1920 for (n = 0; n < nlink; n++) { 1921 if ((status = dladm_name2info(handle, links[n], 1922 &port[ndev + n].lp_linkid, NULL, NULL, NULL)) != 1923 DLADM_STATUS_OK) { 1924 die_dlerr(status, "invalid link name '%s'", links[n]); 1925 } 1926 } 1927 1928 status = dladm_aggr_create(handle, name, key, ndev + nlink, port, 1929 policy, mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, 1930 lacp_timer, flags); 1931 if (status != DLADM_STATUS_OK) 1932 goto done; 1933 1934 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 1935 != DLADM_STATUS_OK) 1936 die("invalid aggregation property"); 1937 1938 if (proplist == NULL) 1939 return; 1940 1941 status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL); 1942 if (status != DLADM_STATUS_OK) 1943 goto done; 1944 1945 for (i = 0; i < proplist->al_count; i++) { 1946 dladm_arg_info_t *aip = &proplist->al_info[i]; 1947 1948 pstatus = dladm_set_linkprop(handle, linkid, aip->ai_name, 1949 aip->ai_val, aip->ai_count, flags); 1950 1951 if (pstatus != DLADM_STATUS_OK) { 1952 die_dlerr(pstatus, 1953 "aggr creation succeeded but " 1954 "could not set property '%s'", aip->ai_name); 1955 } 1956 } 1957 done: 1958 dladm_free_props(proplist); 1959 if (status != DLADM_STATUS_OK) { 1960 if (status == DLADM_STATUS_NONOTIF) { 1961 die("not all links have link up/down detection; must " 1962 "use -f (see dladm(1M))"); 1963 } else { 1964 die_dlerr(status, "create operation failed"); 1965 } 1966 } 1967 } 1968 1969 /* 1970 * arg is either the key or the aggr name. Validate it and convert it to 1971 * the linkid if altroot is NULL. 1972 */ 1973 static dladm_status_t 1974 i_dladm_aggr_get_linkid(const char *altroot, const char *arg, 1975 datalink_id_t *linkidp, uint32_t flags) 1976 { 1977 int key = 0; 1978 char *aggr = NULL; 1979 dladm_status_t status; 1980 1981 if (!str2int(arg, &key)) 1982 aggr = (char *)arg; 1983 1984 if (aggr == NULL && key == 0) 1985 return (DLADM_STATUS_LINKINVAL); 1986 1987 if (altroot != NULL) 1988 return (DLADM_STATUS_OK); 1989 1990 if (aggr != NULL) { 1991 status = dladm_name2info(handle, aggr, linkidp, NULL, NULL, 1992 NULL); 1993 } else { 1994 status = dladm_key2linkid(handle, key, linkidp, flags); 1995 } 1996 1997 return (status); 1998 } 1999 2000 static void 2001 do_delete_aggr(int argc, char *argv[], const char *use) 2002 { 2003 int option; 2004 char *altroot = NULL; 2005 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 2006 dladm_status_t status; 2007 datalink_id_t linkid; 2008 2009 opterr = 0; 2010 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 2011 switch (option) { 2012 case 't': 2013 flags &= ~DLADM_OPT_PERSIST; 2014 break; 2015 case 'R': 2016 altroot = optarg; 2017 break; 2018 default: 2019 die_opterr(optopt, option, use); 2020 break; 2021 } 2022 } 2023 2024 /* get key value or the aggregation name (required last argument) */ 2025 if (optind != (argc-1)) 2026 usage(); 2027 2028 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 2029 if (status != DLADM_STATUS_OK) 2030 goto done; 2031 2032 if (altroot != NULL) 2033 altroot_cmd(altroot, argc, argv); 2034 2035 status = dladm_aggr_delete(handle, linkid, flags); 2036 done: 2037 if (status != DLADM_STATUS_OK) 2038 die_dlerr(status, "delete operation failed"); 2039 } 2040 2041 static void 2042 do_add_aggr(int argc, char *argv[], const char *use) 2043 { 2044 int option; 2045 uint_t n, ndev, nlink; 2046 char *altroot = NULL; 2047 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 2048 datalink_id_t linkid; 2049 dladm_status_t status; 2050 dladm_aggr_port_attr_db_t port[MAXPORT]; 2051 char *devs[MAXPORT]; 2052 char *links[MAXPORT]; 2053 2054 ndev = nlink = opterr = 0; 2055 while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts, 2056 NULL)) != -1) { 2057 switch (option) { 2058 case 'd': 2059 if (ndev + nlink >= MAXPORT) 2060 die("too many ports specified"); 2061 2062 devs[ndev++] = optarg; 2063 break; 2064 case 'l': 2065 if (ndev + nlink >= MAXPORT) 2066 die("too many ports specified"); 2067 2068 links[nlink++] = optarg; 2069 break; 2070 case 't': 2071 flags &= ~DLADM_OPT_PERSIST; 2072 break; 2073 case 'f': 2074 flags |= DLADM_OPT_FORCE; 2075 break; 2076 case 'R': 2077 altroot = optarg; 2078 break; 2079 default: 2080 die_opterr(optopt, option, use); 2081 break; 2082 } 2083 } 2084 2085 if (ndev + nlink == 0) 2086 usage(); 2087 2088 /* get key value or the aggregation name (required last argument) */ 2089 if (optind != (argc-1)) 2090 usage(); 2091 2092 if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, 2093 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) != 2094 DLADM_STATUS_OK) { 2095 goto done; 2096 } 2097 2098 if (altroot != NULL) 2099 altroot_cmd(altroot, argc, argv); 2100 2101 for (n = 0; n < ndev; n++) { 2102 if ((status = dladm_dev2linkid(handle, devs[n], 2103 &(port[n].lp_linkid))) != DLADM_STATUS_OK) { 2104 die_dlerr(status, "invalid <dev> '%s'", devs[n]); 2105 } 2106 } 2107 2108 for (n = 0; n < nlink; n++) { 2109 if ((status = dladm_name2info(handle, links[n], 2110 &port[n + ndev].lp_linkid, NULL, NULL, NULL)) != 2111 DLADM_STATUS_OK) { 2112 die_dlerr(status, "invalid <link> '%s'", links[n]); 2113 } 2114 } 2115 2116 status = dladm_aggr_add(handle, linkid, ndev + nlink, port, flags); 2117 done: 2118 if (status != DLADM_STATUS_OK) { 2119 /* 2120 * checking DLADM_STATUS_NOTSUP is a temporary workaround 2121 * and should be removed once 6399681 is fixed. 2122 */ 2123 if (status == DLADM_STATUS_NOTSUP) { 2124 die("add operation failed: link capabilities don't " 2125 "match"); 2126 } else if (status == DLADM_STATUS_NONOTIF) { 2127 die("not all links have link up/down detection; must " 2128 "use -f (see dladm(1M))"); 2129 } else { 2130 die_dlerr(status, "add operation failed"); 2131 } 2132 } 2133 } 2134 2135 static void 2136 do_remove_aggr(int argc, char *argv[], const char *use) 2137 { 2138 int option; 2139 dladm_aggr_port_attr_db_t port[MAXPORT]; 2140 uint_t n, ndev, nlink; 2141 char *devs[MAXPORT]; 2142 char *links[MAXPORT]; 2143 char *altroot = NULL; 2144 uint32_t flags; 2145 datalink_id_t linkid; 2146 dladm_status_t status; 2147 2148 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 2149 ndev = nlink = opterr = 0; 2150 while ((option = getopt_long(argc, argv, ":d:l:R:t", 2151 lopts, NULL)) != -1) { 2152 switch (option) { 2153 case 'd': 2154 if (ndev + nlink >= MAXPORT) 2155 die("too many ports specified"); 2156 2157 devs[ndev++] = optarg; 2158 break; 2159 case 'l': 2160 if (ndev + nlink >= MAXPORT) 2161 die("too many ports specified"); 2162 2163 links[nlink++] = optarg; 2164 break; 2165 case 't': 2166 flags &= ~DLADM_OPT_PERSIST; 2167 break; 2168 case 'R': 2169 altroot = optarg; 2170 break; 2171 default: 2172 die_opterr(optopt, option, use); 2173 break; 2174 } 2175 } 2176 2177 if (ndev + nlink == 0) 2178 usage(); 2179 2180 /* get key value or the aggregation name (required last argument) */ 2181 if (optind != (argc-1)) 2182 usage(); 2183 2184 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 2185 if (status != DLADM_STATUS_OK) 2186 goto done; 2187 2188 if (altroot != NULL) 2189 altroot_cmd(altroot, argc, argv); 2190 2191 for (n = 0; n < ndev; n++) { 2192 if ((status = dladm_dev2linkid(handle, devs[n], 2193 &(port[n].lp_linkid))) != DLADM_STATUS_OK) { 2194 die_dlerr(status, "invalid <dev> '%s'", devs[n]); 2195 } 2196 } 2197 2198 for (n = 0; n < nlink; n++) { 2199 if ((status = dladm_name2info(handle, links[n], 2200 &port[n + ndev].lp_linkid, NULL, NULL, NULL)) != 2201 DLADM_STATUS_OK) { 2202 die_dlerr(status, "invalid <link> '%s'", links[n]); 2203 } 2204 } 2205 2206 status = dladm_aggr_remove(handle, linkid, ndev + nlink, port, flags); 2207 done: 2208 if (status != DLADM_STATUS_OK) 2209 die_dlerr(status, "remove operation failed"); 2210 } 2211 2212 static void 2213 do_modify_aggr(int argc, char *argv[], const char *use) 2214 { 2215 int option; 2216 uint32_t policy = AGGR_POLICY_L4; 2217 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 2218 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 2219 uint8_t mac_addr[ETHERADDRL]; 2220 boolean_t mac_addr_fixed = B_FALSE; 2221 uint8_t modify_mask = 0; 2222 char *altroot = NULL; 2223 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 2224 datalink_id_t linkid; 2225 dladm_status_t status; 2226 2227 opterr = 0; 2228 while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts, 2229 NULL)) != -1) { 2230 switch (option) { 2231 case 'P': 2232 if (modify_mask & DLADM_AGGR_MODIFY_POLICY) 2233 die_optdup(option); 2234 2235 modify_mask |= DLADM_AGGR_MODIFY_POLICY; 2236 2237 if (!dladm_aggr_str2policy(optarg, &policy)) 2238 die("invalid policy '%s'", optarg); 2239 break; 2240 case 'u': 2241 if (modify_mask & DLADM_AGGR_MODIFY_MAC) 2242 die_optdup(option); 2243 2244 modify_mask |= DLADM_AGGR_MODIFY_MAC; 2245 2246 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 2247 mac_addr)) 2248 die("invalid MAC address '%s'", optarg); 2249 break; 2250 case 'l': 2251 case 'L': 2252 if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE) 2253 die_optdup(option); 2254 2255 modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE; 2256 2257 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 2258 die("invalid LACP mode '%s'", optarg); 2259 break; 2260 case 'T': 2261 if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER) 2262 die_optdup(option); 2263 2264 modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER; 2265 2266 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 2267 die("invalid LACP timer value '%s'", optarg); 2268 break; 2269 case 't': 2270 flags &= ~DLADM_OPT_PERSIST; 2271 break; 2272 case 'R': 2273 altroot = optarg; 2274 break; 2275 default: 2276 die_opterr(optopt, option, use); 2277 break; 2278 } 2279 } 2280 2281 if (modify_mask == 0) 2282 die("at least one of the -PulT options must be specified"); 2283 2284 /* get key value or the aggregation name (required last argument) */ 2285 if (optind != (argc-1)) 2286 usage(); 2287 2288 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 2289 if (status != DLADM_STATUS_OK) 2290 goto done; 2291 2292 if (altroot != NULL) 2293 altroot_cmd(altroot, argc, argv); 2294 2295 status = dladm_aggr_modify(handle, linkid, modify_mask, policy, 2296 mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, lacp_timer, 2297 flags); 2298 2299 done: 2300 if (status != DLADM_STATUS_OK) 2301 die_dlerr(status, "modify operation failed"); 2302 } 2303 2304 /*ARGSUSED*/ 2305 static void 2306 do_up_aggr(int argc, char *argv[], const char *use) 2307 { 2308 datalink_id_t linkid = DATALINK_ALL_LINKID; 2309 dladm_status_t status; 2310 2311 /* 2312 * get the key or the name of the aggregation (optional last argument) 2313 */ 2314 if (argc == 2) { 2315 if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid, 2316 DLADM_OPT_PERSIST)) != DLADM_STATUS_OK) 2317 goto done; 2318 } else if (argc > 2) { 2319 usage(); 2320 } 2321 2322 status = dladm_aggr_up(handle, linkid); 2323 done: 2324 if (status != DLADM_STATUS_OK) { 2325 if (argc == 2) { 2326 die_dlerr(status, 2327 "could not bring up aggregation '%s'", argv[1]); 2328 } else { 2329 die_dlerr(status, "could not bring aggregations up"); 2330 } 2331 } 2332 } 2333 2334 static void 2335 do_create_vlan(int argc, char *argv[], const char *use) 2336 { 2337 char *link = NULL; 2338 char drv[DLPI_LINKNAME_MAX]; 2339 uint_t ppa; 2340 datalink_id_t linkid; 2341 datalink_id_t dev_linkid; 2342 int vid = 0; 2343 int option; 2344 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2345 char *altroot = NULL; 2346 char vlan[MAXLINKNAMELEN]; 2347 char propstr[DLADM_STRSIZE]; 2348 dladm_arg_list_t *proplist = NULL; 2349 dladm_status_t status; 2350 2351 opterr = 0; 2352 bzero(propstr, DLADM_STRSIZE); 2353 2354 while ((option = getopt_long(argc, argv, ":tfR:l:v:p:", 2355 lopts, NULL)) != -1) { 2356 switch (option) { 2357 case 'v': 2358 if (vid != 0) 2359 die_optdup(option); 2360 2361 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 2362 die("invalid VLAN identifier '%s'", optarg); 2363 2364 break; 2365 case 'l': 2366 if (link != NULL) 2367 die_optdup(option); 2368 2369 link = optarg; 2370 break; 2371 case 't': 2372 flags &= ~DLADM_OPT_PERSIST; 2373 break; 2374 case 'R': 2375 altroot = optarg; 2376 break; 2377 case 'p': 2378 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 2379 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 2380 DLADM_STRSIZE) 2381 die("property list too long '%s'", propstr); 2382 break; 2383 case 'f': 2384 flags |= DLADM_OPT_FORCE; 2385 break; 2386 default: 2387 die_opterr(optopt, option, use); 2388 break; 2389 } 2390 } 2391 2392 /* get vlan name if there is any */ 2393 if ((vid == 0) || (link == NULL) || (argc - optind > 1)) 2394 usage(); 2395 2396 if (optind == (argc - 1)) { 2397 if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >= 2398 MAXLINKNAMELEN) { 2399 die("vlan name too long '%s'", argv[optind]); 2400 } 2401 } else { 2402 if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) || 2403 (ppa >= 1000) || 2404 (dlpi_makelink(vlan, drv, vid * 1000 + ppa) != 2405 DLPI_SUCCESS)) { 2406 die("invalid link name '%s'", link); 2407 } 2408 } 2409 2410 if (altroot != NULL) 2411 altroot_cmd(altroot, argc, argv); 2412 2413 if (dladm_name2info(handle, link, &dev_linkid, NULL, NULL, NULL) != 2414 DLADM_STATUS_OK) { 2415 die("invalid link name '%s'", link); 2416 } 2417 2418 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 2419 != DLADM_STATUS_OK) 2420 die("invalid vlan property"); 2421 2422 status = dladm_vlan_create(handle, vlan, dev_linkid, vid, proplist, 2423 flags, &linkid); 2424 switch (status) { 2425 case DLADM_STATUS_OK: 2426 break; 2427 2428 case DLADM_STATUS_NOTSUP: 2429 die("VLAN over '%s' may require lowered MTU; must use -f (see " 2430 "dladm(1M))", link); 2431 break; 2432 2433 case DLADM_STATUS_LINKBUSY: 2434 die("VLAN over '%s' may not use default_tag ID " 2435 "(see dladm(1M))", link); 2436 break; 2437 2438 default: 2439 die_dlerr(status, "create operation failed"); 2440 } 2441 } 2442 2443 static void 2444 do_delete_vlan(int argc, char *argv[], const char *use) 2445 { 2446 int option; 2447 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2448 char *altroot = NULL; 2449 datalink_id_t linkid; 2450 dladm_status_t status; 2451 2452 opterr = 0; 2453 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 2454 switch (option) { 2455 case 't': 2456 flags &= ~DLADM_OPT_PERSIST; 2457 break; 2458 case 'R': 2459 altroot = optarg; 2460 break; 2461 default: 2462 die_opterr(optopt, option, use); 2463 break; 2464 } 2465 } 2466 2467 /* get VLAN link name (required last argument) */ 2468 if (optind != (argc - 1)) 2469 usage(); 2470 2471 if (altroot != NULL) 2472 altroot_cmd(altroot, argc, argv); 2473 2474 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 2475 NULL); 2476 if (status != DLADM_STATUS_OK) 2477 goto done; 2478 2479 status = dladm_vlan_delete(handle, linkid, flags); 2480 done: 2481 if (status != DLADM_STATUS_OK) 2482 die_dlerr(status, "delete operation failed"); 2483 } 2484 2485 /*ARGSUSED*/ 2486 static void 2487 do_up_vlan(int argc, char *argv[], const char *use) 2488 { 2489 do_up_vnic_common(argc, argv, use, B_TRUE); 2490 } 2491 2492 static void 2493 do_rename_link(int argc, char *argv[], const char *use) 2494 { 2495 int option; 2496 char *link1, *link2; 2497 char *altroot = NULL; 2498 dladm_status_t status; 2499 2500 opterr = 0; 2501 while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) { 2502 switch (option) { 2503 case 'R': 2504 altroot = optarg; 2505 break; 2506 default: 2507 die_opterr(optopt, option, use); 2508 break; 2509 } 2510 } 2511 2512 /* get link1 and link2 name (required the last 2 arguments) */ 2513 if (optind != (argc - 2)) 2514 usage(); 2515 2516 if (altroot != NULL) 2517 altroot_cmd(altroot, argc, argv); 2518 2519 link1 = argv[optind++]; 2520 link2 = argv[optind]; 2521 if ((status = dladm_rename_link(handle, link1, link2)) != 2522 DLADM_STATUS_OK) 2523 die_dlerr(status, "rename operation failed"); 2524 } 2525 2526 /*ARGSUSED*/ 2527 static void 2528 do_delete_phys(int argc, char *argv[], const char *use) 2529 { 2530 datalink_id_t linkid = DATALINK_ALL_LINKID; 2531 dladm_status_t status; 2532 2533 /* get link name (required the last argument) */ 2534 if (argc > 2) 2535 usage(); 2536 2537 if (argc == 2) { 2538 if ((status = dladm_name2info(handle, argv[1], &linkid, NULL, 2539 NULL, NULL)) != DLADM_STATUS_OK) 2540 die_dlerr(status, "cannot delete '%s'", argv[1]); 2541 } 2542 2543 if ((status = dladm_phys_delete(handle, linkid)) != DLADM_STATUS_OK) { 2544 if (argc == 2) 2545 die_dlerr(status, "cannot delete '%s'", argv[1]); 2546 else 2547 die_dlerr(status, "delete operation failed"); 2548 } 2549 } 2550 2551 /*ARGSUSED*/ 2552 static int 2553 i_dladm_walk_linkmap(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2554 { 2555 char name[MAXLINKNAMELEN]; 2556 char mediabuf[DLADM_STRSIZE]; 2557 char classbuf[DLADM_STRSIZE]; 2558 datalink_class_t class; 2559 uint32_t media; 2560 uint32_t flags; 2561 2562 if (dladm_datalink_id2info(dh, linkid, &flags, &class, &media, name, 2563 MAXLINKNAMELEN) == DLADM_STATUS_OK) { 2564 (void) dladm_class2str(class, classbuf); 2565 (void) dladm_media2str(media, mediabuf); 2566 (void) printf("%-12s%8d %-12s%-20s %6d\n", name, 2567 linkid, classbuf, mediabuf, flags); 2568 } 2569 return (DLADM_WALK_CONTINUE); 2570 } 2571 2572 /*ARGSUSED*/ 2573 static void 2574 do_show_linkmap(int argc, char *argv[], const char *use) 2575 { 2576 if (argc != 1) 2577 die("invalid arguments"); 2578 2579 (void) printf("%-12s%8s %-12s%-20s %6s\n", "NAME", "LINKID", 2580 "CLASS", "MEDIA", "FLAGS"); 2581 2582 (void) dladm_walk_datalink_id(i_dladm_walk_linkmap, handle, NULL, 2583 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 2584 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2585 } 2586 2587 /* 2588 * Delete inactive physical links. 2589 */ 2590 /*ARGSUSED*/ 2591 static int 2592 purge_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2593 { 2594 datalink_class_t class; 2595 uint32_t flags; 2596 2597 if (dladm_datalink_id2info(dh, linkid, &flags, &class, NULL, NULL, 0) 2598 != DLADM_STATUS_OK) { 2599 return (DLADM_WALK_CONTINUE); 2600 } 2601 2602 if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE)) 2603 (void) dladm_phys_delete(dh, linkid); 2604 2605 return (DLADM_WALK_CONTINUE); 2606 } 2607 2608 /*ARGSUSED*/ 2609 static void 2610 do_init_phys(int argc, char *argv[], const char *use) 2611 { 2612 di_node_t devtree; 2613 2614 if (argc > 1) 2615 usage(); 2616 2617 /* 2618 * Force all the devices to attach, therefore all the network physical 2619 * devices can be known to the dlmgmtd daemon. 2620 */ 2621 if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL) 2622 di_fini(devtree); 2623 2624 (void) dladm_walk_datalink_id(purge_phys, handle, NULL, 2625 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 2626 } 2627 2628 /* 2629 * Print the active topology information. 2630 */ 2631 void 2632 print_link_topology(show_state_t *state, datalink_id_t linkid, 2633 datalink_class_t class, link_fields_buf_t *lbuf) 2634 { 2635 uint32_t flags = state->ls_flags; 2636 dladm_status_t status; 2637 char tmpbuf[MAXLINKNAMELEN]; 2638 2639 lbuf->link_over[0] = '\0'; 2640 lbuf->link_bridge[0] = '\0'; 2641 2642 switch (class) { 2643 case DATALINK_CLASS_AGGR: 2644 case DATALINK_CLASS_PHYS: 2645 case DATALINK_CLASS_ETHERSTUB: 2646 status = dladm_bridge_getlink(handle, linkid, lbuf->link_bridge, 2647 sizeof (lbuf->link_bridge)); 2648 if (status != DLADM_STATUS_OK && 2649 status != DLADM_STATUS_NOTFOUND) 2650 (void) strcpy(lbuf->link_bridge, "?"); 2651 break; 2652 } 2653 2654 switch (class) { 2655 case DATALINK_CLASS_VLAN: { 2656 dladm_vlan_attr_t vinfo; 2657 2658 if (dladm_vlan_info(handle, linkid, &vinfo, flags) != 2659 DLADM_STATUS_OK) { 2660 (void) strcpy(lbuf->link_over, "?"); 2661 break; 2662 } 2663 if (dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, NULL, 2664 NULL, lbuf->link_over, sizeof (lbuf->link_over)) != 2665 DLADM_STATUS_OK) 2666 (void) strcpy(lbuf->link_over, "?"); 2667 break; 2668 } 2669 case DATALINK_CLASS_AGGR: { 2670 dladm_aggr_grp_attr_t ginfo; 2671 int i; 2672 2673 if (dladm_aggr_info(handle, linkid, &ginfo, flags) != 2674 DLADM_STATUS_OK || ginfo.lg_nports == 0) { 2675 (void) strcpy(lbuf->link_over, "?"); 2676 break; 2677 } 2678 for (i = 0; i < ginfo.lg_nports; i++) { 2679 if (dladm_datalink_id2info(handle, 2680 ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, 2681 tmpbuf, sizeof (tmpbuf)) != DLADM_STATUS_OK) { 2682 (void) strcpy(lbuf->link_over, "?"); 2683 break; 2684 } 2685 (void) strlcat(lbuf->link_over, tmpbuf, 2686 sizeof (lbuf->link_over)); 2687 if (i != (ginfo.lg_nports - 1)) { 2688 (void) strlcat(lbuf->link_over, ",", 2689 sizeof (lbuf->link_over)); 2690 } 2691 } 2692 free(ginfo.lg_ports); 2693 break; 2694 } 2695 case DATALINK_CLASS_VNIC: { 2696 dladm_vnic_attr_t vinfo; 2697 2698 if (dladm_vnic_info(handle, linkid, &vinfo, flags) != 2699 DLADM_STATUS_OK) { 2700 (void) strcpy(lbuf->link_over, "?"); 2701 break; 2702 } 2703 if (dladm_datalink_id2info(handle, vinfo.va_link_id, NULL, NULL, 2704 NULL, lbuf->link_over, sizeof (lbuf->link_over)) != 2705 DLADM_STATUS_OK) 2706 (void) strcpy(lbuf->link_over, "?"); 2707 break; 2708 } 2709 2710 case DATALINK_CLASS_PART: { 2711 dladm_part_attr_t pinfo; 2712 2713 if (dladm_part_info(handle, linkid, &pinfo, flags) != 2714 DLADM_STATUS_OK) { 2715 (void) strcpy(lbuf->link_over, "?"); 2716 break; 2717 } 2718 if (dladm_datalink_id2info(handle, pinfo.dia_physlinkid, NULL, 2719 NULL, NULL, lbuf->link_over, sizeof (lbuf->link_over)) != 2720 DLADM_STATUS_OK) 2721 (void) strcpy(lbuf->link_over, "?"); 2722 break; 2723 } 2724 2725 case DATALINK_CLASS_BRIDGE: { 2726 datalink_id_t *dlp; 2727 uint_t i, nports; 2728 2729 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, 2730 NULL, tmpbuf, sizeof (tmpbuf)) != DLADM_STATUS_OK) { 2731 (void) strcpy(lbuf->link_over, "?"); 2732 break; 2733 } 2734 if (tmpbuf[0] != '\0') 2735 tmpbuf[strlen(tmpbuf) - 1] = '\0'; 2736 dlp = dladm_bridge_get_portlist(tmpbuf, &nports); 2737 if (dlp == NULL) { 2738 (void) strcpy(lbuf->link_over, "?"); 2739 break; 2740 } 2741 for (i = 0; i < nports; i++) { 2742 if (dladm_datalink_id2info(handle, dlp[i], NULL, 2743 NULL, NULL, tmpbuf, sizeof (tmpbuf)) != 2744 DLADM_STATUS_OK) { 2745 (void) strcpy(lbuf->link_over, "?"); 2746 break; 2747 } 2748 (void) strlcat(lbuf->link_over, tmpbuf, 2749 sizeof (lbuf->link_over)); 2750 if (i != nports - 1) { 2751 (void) strlcat(lbuf->link_over, ",", 2752 sizeof (lbuf->link_over)); 2753 } 2754 } 2755 dladm_bridge_free_portlist(dlp); 2756 break; 2757 } 2758 2759 case DATALINK_CLASS_SIMNET: { 2760 dladm_simnet_attr_t slinfo; 2761 2762 if (dladm_simnet_info(handle, linkid, &slinfo, flags) != 2763 DLADM_STATUS_OK) { 2764 (void) strcpy(lbuf->link_over, "?"); 2765 break; 2766 } 2767 if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID) { 2768 if (dladm_datalink_id2info(handle, 2769 slinfo.sna_peer_link_id, NULL, NULL, NULL, 2770 lbuf->link_over, sizeof (lbuf->link_over)) != 2771 DLADM_STATUS_OK) 2772 (void) strcpy(lbuf->link_over, "?"); 2773 } 2774 break; 2775 } 2776 } 2777 } 2778 2779 static dladm_status_t 2780 print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf) 2781 { 2782 char link[MAXLINKNAMELEN]; 2783 datalink_class_t class; 2784 uint_t mtu; 2785 uint32_t flags; 2786 dladm_status_t status; 2787 2788 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 2789 NULL, link, sizeof (link))) != DLADM_STATUS_OK) { 2790 goto done; 2791 } 2792 2793 if (!(state->ls_flags & flags)) { 2794 status = DLADM_STATUS_NOTFOUND; 2795 goto done; 2796 } 2797 2798 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2799 dladm_attr_t dlattr; 2800 2801 if (class == DATALINK_CLASS_PHYS) { 2802 dladm_phys_attr_t dpa; 2803 dlpi_handle_t dh; 2804 dlpi_info_t dlinfo; 2805 2806 if ((status = dladm_phys_info(handle, linkid, &dpa, 2807 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2808 goto done; 2809 } 2810 2811 if (!dpa.dp_novanity) 2812 goto link_mtu; 2813 2814 /* 2815 * This is a physical link that does not have 2816 * vanity naming support. 2817 */ 2818 if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) != 2819 DLPI_SUCCESS) { 2820 status = DLADM_STATUS_NOTFOUND; 2821 goto done; 2822 } 2823 2824 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 2825 dlpi_close(dh); 2826 status = DLADM_STATUS_BADARG; 2827 goto done; 2828 } 2829 2830 dlpi_close(dh); 2831 mtu = dlinfo.di_max_sdu; 2832 } else { 2833 link_mtu: 2834 status = dladm_info(handle, linkid, &dlattr); 2835 if (status != DLADM_STATUS_OK) 2836 goto done; 2837 mtu = dlattr.da_max_sdu; 2838 } 2839 } 2840 2841 (void) snprintf(lbuf->link_name, sizeof (lbuf->link_name), 2842 "%s", link); 2843 (void) dladm_class2str(class, lbuf->link_class); 2844 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2845 (void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu), 2846 "%u", mtu); 2847 (void) get_linkstate(link, B_TRUE, lbuf->link_state); 2848 } 2849 2850 print_link_topology(state, linkid, class, lbuf); 2851 done: 2852 return (status); 2853 } 2854 2855 /* ARGSUSED */ 2856 static int 2857 show_link(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2858 { 2859 show_state_t *state = (show_state_t *)arg; 2860 dladm_status_t status; 2861 link_fields_buf_t lbuf; 2862 2863 /* 2864 * first get all the link attributes into lbuf; 2865 */ 2866 bzero(&lbuf, sizeof (link_fields_buf_t)); 2867 if ((status = print_link(state, linkid, &lbuf)) == DLADM_STATUS_OK) 2868 ofmt_print(state->ls_ofmt, &lbuf); 2869 state->ls_status = status; 2870 return (DLADM_WALK_CONTINUE); 2871 } 2872 2873 static boolean_t 2874 print_link_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2875 { 2876 link_args_t *largs = ofarg->ofmt_cbarg; 2877 pktsum_t *diff_stats = largs->link_s_psum; 2878 2879 switch (ofarg->ofmt_id) { 2880 case LINK_S_LINK: 2881 (void) snprintf(buf, bufsize, "%s", largs->link_s_link); 2882 break; 2883 case LINK_S_IPKTS: 2884 (void) snprintf(buf, bufsize, "%llu", diff_stats->ipackets); 2885 break; 2886 case LINK_S_RBYTES: 2887 (void) snprintf(buf, bufsize, "%llu", diff_stats->rbytes); 2888 break; 2889 case LINK_S_IERRORS: 2890 (void) snprintf(buf, bufsize, "%u", diff_stats->ierrors); 2891 break; 2892 case LINK_S_OPKTS: 2893 (void) snprintf(buf, bufsize, "%llu", diff_stats->opackets); 2894 break; 2895 case LINK_S_OBYTES: 2896 (void) snprintf(buf, bufsize, "%llu", diff_stats->obytes); 2897 break; 2898 case LINK_S_OERRORS: 2899 (void) snprintf(buf, bufsize, "%u", diff_stats->oerrors); 2900 break; 2901 default: 2902 die("invalid input"); 2903 break; 2904 } 2905 return (B_TRUE); 2906 } 2907 2908 static int 2909 show_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2910 { 2911 char link[DLPI_LINKNAME_MAX]; 2912 datalink_class_t class; 2913 show_state_t *state = arg; 2914 pktsum_t stats, diff_stats; 2915 dladm_phys_attr_t dpa; 2916 link_args_t largs; 2917 2918 if (state->ls_firstonly) { 2919 if (state->ls_donefirst) 2920 return (DLADM_WALK_CONTINUE); 2921 state->ls_donefirst = B_TRUE; 2922 } else { 2923 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 2924 } 2925 2926 if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, link, 2927 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2928 return (DLADM_WALK_CONTINUE); 2929 } 2930 2931 if (class == DATALINK_CLASS_PHYS) { 2932 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) != 2933 DLADM_STATUS_OK) { 2934 return (DLADM_WALK_CONTINUE); 2935 } 2936 if (dpa.dp_novanity) 2937 get_mac_stats(dpa.dp_dev, &stats); 2938 else 2939 get_link_stats(link, &stats); 2940 } else { 2941 get_link_stats(link, &stats); 2942 } 2943 dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats); 2944 2945 largs.link_s_link = link; 2946 largs.link_s_psum = &diff_stats; 2947 ofmt_print(state->ls_ofmt, &largs); 2948 2949 state->ls_prevstats = stats; 2950 return (DLADM_WALK_CONTINUE); 2951 } 2952 2953 2954 static dladm_status_t 2955 print_aggr_info(show_grp_state_t *state, const char *link, 2956 dladm_aggr_grp_attr_t *ginfop) 2957 { 2958 char addr_str[ETHERADDRL * 3]; 2959 laggr_fields_buf_t lbuf; 2960 2961 (void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name), 2962 "%s", link); 2963 2964 (void) dladm_aggr_policy2str(ginfop->lg_policy, 2965 lbuf.laggr_policy); 2966 2967 if (ginfop->lg_mac_fixed) { 2968 (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); 2969 (void) snprintf(lbuf.laggr_addrpolicy, 2970 sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str); 2971 } else { 2972 (void) snprintf(lbuf.laggr_addrpolicy, 2973 sizeof (lbuf.laggr_addrpolicy), "auto"); 2974 } 2975 2976 (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, 2977 lbuf.laggr_lacpactivity); 2978 (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, 2979 lbuf.laggr_lacptimer); 2980 (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----", 2981 ginfop->lg_force ? 'f' : '-'); 2982 2983 ofmt_print(state->gs_ofmt, &lbuf); 2984 2985 return (DLADM_STATUS_OK); 2986 } 2987 2988 static boolean_t 2989 print_xaggr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2990 { 2991 const laggr_args_t *l = ofarg->ofmt_cbarg; 2992 boolean_t is_port = (l->laggr_lport >= 0); 2993 char tmpbuf[DLADM_STRSIZE]; 2994 const char *objname; 2995 dladm_aggr_port_attr_t *portp; 2996 dladm_phys_attr_t dpa; 2997 2998 if (is_port) { 2999 portp = &(l->laggr_ginfop->lg_ports[l->laggr_lport]); 3000 if (dladm_phys_info(handle, portp->lp_linkid, &dpa, 3001 DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) 3002 objname = "?"; 3003 else 3004 objname = dpa.dp_dev; 3005 } else { 3006 objname = l->laggr_link; 3007 } 3008 3009 switch (ofarg->ofmt_id) { 3010 case AGGR_X_LINK: 3011 (void) snprintf(buf, bufsize, "%s", 3012 (is_port && !l->laggr_parsable ? " " : l->laggr_link)); 3013 break; 3014 case AGGR_X_PORT: 3015 if (is_port) { 3016 if (dladm_datalink_id2info(handle, portp->lp_linkid, 3017 NULL, NULL, NULL, buf, bufsize) != DLADM_STATUS_OK) 3018 (void) sprintf(buf, "?"); 3019 } 3020 break; 3021 3022 case AGGR_X_SPEED: 3023 (void) snprintf(buf, bufsize, "%uMb", 3024 (uint_t)((get_ifspeed(objname, !is_port)) / 1000000ull)); 3025 break; 3026 3027 case AGGR_X_DUPLEX: 3028 (void) get_linkduplex(objname, !is_port, tmpbuf); 3029 (void) strlcpy(buf, tmpbuf, bufsize); 3030 break; 3031 3032 case AGGR_X_STATE: 3033 (void) get_linkstate(objname, !is_port, tmpbuf); 3034 (void) strlcpy(buf, tmpbuf, bufsize); 3035 break; 3036 case AGGR_X_ADDRESS: 3037 (void) dladm_aggr_macaddr2str( 3038 (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac), 3039 tmpbuf); 3040 (void) strlcpy(buf, tmpbuf, bufsize); 3041 break; 3042 case AGGR_X_PORTSTATE: 3043 if (is_port) { 3044 (void) dladm_aggr_portstate2str(portp->lp_state, 3045 tmpbuf); 3046 (void) strlcpy(buf, tmpbuf, bufsize); 3047 } 3048 break; 3049 } 3050 err: 3051 *(l->laggr_status) = DLADM_STATUS_OK; 3052 return (B_TRUE); 3053 } 3054 3055 static dladm_status_t 3056 print_aggr_extended(show_grp_state_t *state, const char *link, 3057 dladm_aggr_grp_attr_t *ginfop) 3058 { 3059 int i; 3060 dladm_status_t status; 3061 laggr_args_t largs; 3062 3063 largs.laggr_lport = -1; 3064 largs.laggr_link = link; 3065 largs.laggr_ginfop = ginfop; 3066 largs.laggr_status = &status; 3067 largs.laggr_parsable = state->gs_parsable; 3068 3069 ofmt_print(state->gs_ofmt, &largs); 3070 3071 if (status != DLADM_STATUS_OK) 3072 goto done; 3073 3074 for (i = 0; i < ginfop->lg_nports; i++) { 3075 largs.laggr_lport = i; 3076 ofmt_print(state->gs_ofmt, &largs); 3077 if (status != DLADM_STATUS_OK) 3078 goto done; 3079 } 3080 3081 status = DLADM_STATUS_OK; 3082 done: 3083 return (status); 3084 } 3085 3086 static boolean_t 3087 print_lacp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3088 { 3089 const laggr_args_t *l = ofarg->ofmt_cbarg; 3090 int portnum; 3091 boolean_t is_port = (l->laggr_lport >= 0); 3092 dladm_aggr_port_attr_t *portp; 3093 aggr_lacp_state_t *lstate; 3094 3095 if (!is_port) 3096 return (B_FALSE); /* cannot happen! */ 3097 3098 portnum = l->laggr_lport; 3099 portp = &(l->laggr_ginfop->lg_ports[portnum]); 3100 lstate = &(portp->lp_lacp_state); 3101 3102 switch (ofarg->ofmt_id) { 3103 case AGGR_L_LINK: 3104 (void) snprintf(buf, bufsize, "%s", 3105 (portnum > 0 ? "" : l->laggr_link)); 3106 break; 3107 3108 case AGGR_L_PORT: 3109 if (dladm_datalink_id2info(handle, portp->lp_linkid, NULL, NULL, 3110 NULL, buf, bufsize) != DLADM_STATUS_OK) 3111 (void) sprintf(buf, "?"); 3112 break; 3113 3114 case AGGR_L_AGGREGATABLE: 3115 (void) snprintf(buf, bufsize, "%s", 3116 (lstate->bit.aggregation ? "yes" : "no")); 3117 break; 3118 3119 case AGGR_L_SYNC: 3120 (void) snprintf(buf, bufsize, "%s", 3121 (lstate->bit.sync ? "yes" : "no")); 3122 break; 3123 3124 case AGGR_L_COLL: 3125 (void) snprintf(buf, bufsize, "%s", 3126 (lstate->bit.collecting ? "yes" : "no")); 3127 break; 3128 3129 case AGGR_L_DIST: 3130 (void) snprintf(buf, bufsize, "%s", 3131 (lstate->bit.distributing ? "yes" : "no")); 3132 break; 3133 3134 case AGGR_L_DEFAULTED: 3135 (void) snprintf(buf, bufsize, "%s", 3136 (lstate->bit.defaulted ? "yes" : "no")); 3137 break; 3138 3139 case AGGR_L_EXPIRED: 3140 (void) snprintf(buf, bufsize, "%s", 3141 (lstate->bit.expired ? "yes" : "no")); 3142 break; 3143 } 3144 3145 *(l->laggr_status) = DLADM_STATUS_OK; 3146 return (B_TRUE); 3147 } 3148 3149 static dladm_status_t 3150 print_aggr_lacp(show_grp_state_t *state, const char *link, 3151 dladm_aggr_grp_attr_t *ginfop) 3152 { 3153 int i; 3154 dladm_status_t status; 3155 laggr_args_t largs; 3156 3157 largs.laggr_link = link; 3158 largs.laggr_ginfop = ginfop; 3159 largs.laggr_status = &status; 3160 3161 for (i = 0; i < ginfop->lg_nports; i++) { 3162 largs.laggr_lport = i; 3163 ofmt_print(state->gs_ofmt, &largs); 3164 if (status != DLADM_STATUS_OK) 3165 goto done; 3166 } 3167 3168 status = DLADM_STATUS_OK; 3169 done: 3170 return (status); 3171 } 3172 3173 static boolean_t 3174 print_aggr_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3175 { 3176 const laggr_args_t *l = ofarg->ofmt_cbarg; 3177 int portnum; 3178 boolean_t is_port = (l->laggr_lport >= 0); 3179 dladm_aggr_port_attr_t *portp; 3180 dladm_status_t *stat, status; 3181 pktsum_t *diff_stats; 3182 3183 stat = l->laggr_status; 3184 *stat = DLADM_STATUS_OK; 3185 3186 if (is_port) { 3187 portnum = l->laggr_lport; 3188 portp = &(l->laggr_ginfop->lg_ports[portnum]); 3189 3190 if ((status = dladm_datalink_id2info(handle, 3191 portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) != 3192 DLADM_STATUS_OK) { 3193 goto err; 3194 } 3195 diff_stats = l->laggr_diffstats; 3196 } 3197 3198 switch (ofarg->ofmt_id) { 3199 case AGGR_S_LINK: 3200 (void) snprintf(buf, bufsize, "%s", 3201 (is_port ? "" : l->laggr_link)); 3202 break; 3203 case AGGR_S_PORT: 3204 /* 3205 * if (is_port), buf has port name. Otherwise we print 3206 * STR_UNDEF_VAL 3207 */ 3208 break; 3209 3210 case AGGR_S_IPKTS: 3211 if (is_port) { 3212 (void) snprintf(buf, bufsize, "%llu", 3213 diff_stats->ipackets); 3214 } else { 3215 (void) snprintf(buf, bufsize, "%llu", 3216 l->laggr_pktsumtot->ipackets); 3217 } 3218 break; 3219 3220 case AGGR_S_RBYTES: 3221 if (is_port) { 3222 (void) snprintf(buf, bufsize, "%llu", 3223 diff_stats->rbytes); 3224 } else { 3225 (void) snprintf(buf, bufsize, "%llu", 3226 l->laggr_pktsumtot->rbytes); 3227 } 3228 break; 3229 3230 case AGGR_S_OPKTS: 3231 if (is_port) { 3232 (void) snprintf(buf, bufsize, "%llu", 3233 diff_stats->opackets); 3234 } else { 3235 (void) snprintf(buf, bufsize, "%llu", 3236 l->laggr_pktsumtot->opackets); 3237 } 3238 break; 3239 case AGGR_S_OBYTES: 3240 if (is_port) { 3241 (void) snprintf(buf, bufsize, "%llu", 3242 diff_stats->obytes); 3243 } else { 3244 (void) snprintf(buf, bufsize, "%llu", 3245 l->laggr_pktsumtot->obytes); 3246 } 3247 break; 3248 3249 case AGGR_S_IPKTDIST: 3250 if (is_port) { 3251 (void) snprintf(buf, bufsize, "%-6.1f", 3252 (double)diff_stats->ipackets/ 3253 (double)l->laggr_pktsumtot->ipackets * 100); 3254 } 3255 break; 3256 case AGGR_S_OPKTDIST: 3257 if (is_port) { 3258 (void) snprintf(buf, bufsize, "%-6.1f", 3259 (double)diff_stats->opackets/ 3260 (double)l->laggr_pktsumtot->opackets * 100); 3261 } 3262 break; 3263 } 3264 return (B_TRUE); 3265 3266 err: 3267 *stat = status; 3268 return (B_TRUE); 3269 } 3270 3271 static dladm_status_t 3272 print_aggr_stats(show_grp_state_t *state, const char *link, 3273 dladm_aggr_grp_attr_t *ginfop) 3274 { 3275 dladm_phys_attr_t dpa; 3276 dladm_aggr_port_attr_t *portp; 3277 pktsum_t pktsumtot, *port_stat; 3278 dladm_status_t status; 3279 int i; 3280 laggr_args_t largs; 3281 3282 /* sum the ports statistics */ 3283 bzero(&pktsumtot, sizeof (pktsumtot)); 3284 3285 /* Allocate memory to keep stats of each port */ 3286 port_stat = malloc(ginfop->lg_nports * sizeof (pktsum_t)); 3287 if (port_stat == NULL) { 3288 /* Bail out; no memory */ 3289 return (DLADM_STATUS_NOMEM); 3290 } 3291 3292 3293 for (i = 0; i < ginfop->lg_nports; i++) { 3294 3295 portp = &(ginfop->lg_ports[i]); 3296 if ((status = dladm_phys_info(handle, portp->lp_linkid, &dpa, 3297 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 3298 goto done; 3299 } 3300 3301 get_mac_stats(dpa.dp_dev, &port_stat[i]); 3302 3303 /* 3304 * Let's re-use gs_prevstats[] to store the difference of the 3305 * counters since last use. We will store the new stats from 3306 * port_stat[] once we have the stats displayed. 3307 */ 3308 3309 dladm_stats_diff(&state->gs_prevstats[i], &port_stat[i], 3310 &state->gs_prevstats[i]); 3311 dladm_stats_total(&pktsumtot, &pktsumtot, 3312 &state->gs_prevstats[i]); 3313 } 3314 3315 largs.laggr_lport = -1; 3316 largs.laggr_link = link; 3317 largs.laggr_ginfop = ginfop; 3318 largs.laggr_status = &status; 3319 largs.laggr_pktsumtot = &pktsumtot; 3320 3321 ofmt_print(state->gs_ofmt, &largs); 3322 3323 if (status != DLADM_STATUS_OK) 3324 goto done; 3325 3326 for (i = 0; i < ginfop->lg_nports; i++) { 3327 largs.laggr_lport = i; 3328 largs.laggr_diffstats = &state->gs_prevstats[i]; 3329 ofmt_print(state->gs_ofmt, &largs); 3330 if (status != DLADM_STATUS_OK) 3331 goto done; 3332 } 3333 3334 status = DLADM_STATUS_OK; 3335 for (i = 0; i < ginfop->lg_nports; i++) 3336 state->gs_prevstats[i] = port_stat[i]; 3337 3338 done: 3339 free(port_stat); 3340 return (status); 3341 } 3342 3343 static dladm_status_t 3344 print_aggr(show_grp_state_t *state, datalink_id_t linkid) 3345 { 3346 char link[MAXLINKNAMELEN]; 3347 dladm_aggr_grp_attr_t ginfo; 3348 uint32_t flags; 3349 dladm_status_t status; 3350 3351 bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t)); 3352 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 3353 NULL, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 3354 return (status); 3355 } 3356 3357 if (!(state->gs_flags & flags)) 3358 return (DLADM_STATUS_NOTFOUND); 3359 3360 status = dladm_aggr_info(handle, linkid, &ginfo, state->gs_flags); 3361 if (status != DLADM_STATUS_OK) 3362 return (status); 3363 3364 if (state->gs_lacp) 3365 status = print_aggr_lacp(state, link, &ginfo); 3366 else if (state->gs_extended) 3367 status = print_aggr_extended(state, link, &ginfo); 3368 else if (state->gs_stats) 3369 status = print_aggr_stats(state, link, &ginfo); 3370 else 3371 status = print_aggr_info(state, link, &ginfo); 3372 3373 done: 3374 free(ginfo.lg_ports); 3375 return (status); 3376 } 3377 3378 /* ARGSUSED */ 3379 static int 3380 show_aggr(dladm_handle_t dh, datalink_id_t linkid, void *arg) 3381 { 3382 show_grp_state_t *state = arg; 3383 3384 state->gs_status = print_aggr(state, linkid); 3385 return (DLADM_WALK_CONTINUE); 3386 } 3387 3388 static void 3389 do_show_link(int argc, char *argv[], const char *use) 3390 { 3391 int option; 3392 boolean_t s_arg = B_FALSE; 3393 boolean_t i_arg = B_FALSE; 3394 uint32_t flags = DLADM_OPT_ACTIVE; 3395 boolean_t p_arg = B_FALSE; 3396 datalink_id_t linkid = DATALINK_ALL_LINKID; 3397 char linkname[MAXLINKNAMELEN]; 3398 uint32_t interval = 0; 3399 show_state_t state; 3400 dladm_status_t status; 3401 boolean_t o_arg = B_FALSE; 3402 char *fields_str = NULL; 3403 char *all_active_fields = "link,class,mtu,state,bridge,over"; 3404 char *all_inactive_fields = "link,class,bridge,over"; 3405 char *allstat_fields = 3406 "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; 3407 ofmt_handle_t ofmt; 3408 ofmt_status_t oferr; 3409 uint_t ofmtflags = 0; 3410 3411 bzero(&state, sizeof (state)); 3412 3413 opterr = 0; 3414 while ((option = getopt_long(argc, argv, ":pPsi:o:", 3415 show_lopts, NULL)) != -1) { 3416 switch (option) { 3417 case 'p': 3418 if (p_arg) 3419 die_optdup(option); 3420 3421 p_arg = B_TRUE; 3422 break; 3423 case 's': 3424 if (s_arg) 3425 die_optdup(option); 3426 3427 s_arg = B_TRUE; 3428 break; 3429 case 'P': 3430 if (flags != DLADM_OPT_ACTIVE) 3431 die_optdup(option); 3432 3433 flags = DLADM_OPT_PERSIST; 3434 break; 3435 case 'o': 3436 o_arg = B_TRUE; 3437 fields_str = optarg; 3438 break; 3439 case 'i': 3440 if (i_arg) 3441 die_optdup(option); 3442 3443 i_arg = B_TRUE; 3444 if (!dladm_str2interval(optarg, &interval)) 3445 die("invalid interval value '%s'", optarg); 3446 break; 3447 default: 3448 die_opterr(optopt, option, use); 3449 break; 3450 } 3451 } 3452 3453 if (i_arg && !s_arg) 3454 die("the option -i can be used only with -s"); 3455 3456 if (s_arg && flags != DLADM_OPT_ACTIVE) 3457 die("the option -P cannot be used with -s"); 3458 3459 /* get link name (optional last argument) */ 3460 if (optind == (argc-1)) { 3461 uint32_t f; 3462 3463 if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN) >= 3464 MAXLINKNAMELEN) 3465 die("link name too long"); 3466 if ((status = dladm_name2info(handle, linkname, &linkid, &f, 3467 NULL, NULL)) != DLADM_STATUS_OK) { 3468 die_dlerr(status, "link %s is not valid", linkname); 3469 } 3470 3471 if (!(f & flags)) { 3472 die_dlerr(DLADM_STATUS_BADARG, "link %s is %s", 3473 argv[optind], flags == DLADM_OPT_PERSIST ? 3474 "a temporary link" : "temporarily removed"); 3475 } 3476 } else if (optind != argc) { 3477 usage(); 3478 } 3479 3480 if (p_arg && !o_arg) 3481 die("-p requires -o"); 3482 3483 if (p_arg && strcasecmp(fields_str, "all") == 0) 3484 die("\"-o all\" is invalid with -p"); 3485 3486 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3487 if (s_arg) 3488 fields_str = allstat_fields; 3489 else if (flags & DLADM_OPT_ACTIVE) 3490 fields_str = all_active_fields; 3491 else 3492 fields_str = all_inactive_fields; 3493 } 3494 3495 state.ls_parsable = p_arg; 3496 state.ls_flags = flags; 3497 state.ls_donefirst = B_FALSE; 3498 3499 if (s_arg) { 3500 link_stats(linkid, interval, fields_str, &state); 3501 return; 3502 } 3503 if (state.ls_parsable) 3504 ofmtflags |= OFMT_PARSABLE; 3505 else 3506 ofmtflags |= OFMT_WRAP; 3507 3508 oferr = ofmt_open(fields_str, link_fields, ofmtflags, 0, &ofmt); 3509 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 3510 state.ls_ofmt = ofmt; 3511 3512 if (linkid == DATALINK_ALL_LINKID) { 3513 (void) dladm_walk_datalink_id(show_link, handle, &state, 3514 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 3515 } else { 3516 (void) show_link(handle, linkid, &state); 3517 if (state.ls_status != DLADM_STATUS_OK) { 3518 die_dlerr(state.ls_status, "failed to show link %s", 3519 argv[optind]); 3520 } 3521 } 3522 ofmt_close(ofmt); 3523 } 3524 3525 static void 3526 do_show_aggr(int argc, char *argv[], const char *use) 3527 { 3528 boolean_t L_arg = B_FALSE; 3529 boolean_t s_arg = B_FALSE; 3530 boolean_t i_arg = B_FALSE; 3531 boolean_t p_arg = B_FALSE; 3532 boolean_t x_arg = B_FALSE; 3533 show_grp_state_t state; 3534 uint32_t flags = DLADM_OPT_ACTIVE; 3535 datalink_id_t linkid = DATALINK_ALL_LINKID; 3536 int option; 3537 uint32_t interval = 0; 3538 int key; 3539 dladm_status_t status; 3540 boolean_t o_arg = B_FALSE; 3541 char *fields_str = NULL; 3542 char *all_fields = 3543 "link,policy,addrpolicy,lacpactivity,lacptimer,flags"; 3544 char *all_lacp_fields = 3545 "link,port,aggregatable,sync,coll,dist,defaulted,expired"; 3546 char *all_stats_fields = 3547 "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist"; 3548 char *all_extended_fields = 3549 "link,port,speed,duplex,state,address,portstate"; 3550 const ofmt_field_t *pf; 3551 ofmt_handle_t ofmt; 3552 ofmt_status_t oferr; 3553 uint_t ofmtflags = 0; 3554 3555 opterr = 0; 3556 while ((option = getopt_long(argc, argv, ":LpPxsi:o:", 3557 show_lopts, NULL)) != -1) { 3558 switch (option) { 3559 case 'L': 3560 if (L_arg) 3561 die_optdup(option); 3562 3563 L_arg = B_TRUE; 3564 break; 3565 case 'p': 3566 if (p_arg) 3567 die_optdup(option); 3568 3569 p_arg = B_TRUE; 3570 break; 3571 case 'x': 3572 if (x_arg) 3573 die_optdup(option); 3574 3575 x_arg = B_TRUE; 3576 break; 3577 case 'P': 3578 if (flags != DLADM_OPT_ACTIVE) 3579 die_optdup(option); 3580 3581 flags = DLADM_OPT_PERSIST; 3582 break; 3583 case 's': 3584 if (s_arg) 3585 die_optdup(option); 3586 3587 s_arg = B_TRUE; 3588 break; 3589 case 'o': 3590 o_arg = B_TRUE; 3591 fields_str = optarg; 3592 break; 3593 case 'i': 3594 if (i_arg) 3595 die_optdup(option); 3596 3597 i_arg = B_TRUE; 3598 if (!dladm_str2interval(optarg, &interval)) 3599 die("invalid interval value '%s'", optarg); 3600 break; 3601 default: 3602 die_opterr(optopt, option, use); 3603 break; 3604 } 3605 } 3606 3607 if (p_arg && !o_arg) 3608 die("-p requires -o"); 3609 3610 if (p_arg && strcasecmp(fields_str, "all") == 0) 3611 die("\"-o all\" is invalid with -p"); 3612 3613 if (i_arg && !s_arg) 3614 die("the option -i can be used only with -s"); 3615 3616 if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) { 3617 die("the option -%c cannot be used with -s", 3618 L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P'))); 3619 } 3620 3621 if (L_arg && flags != DLADM_OPT_ACTIVE) 3622 die("the option -P cannot be used with -L"); 3623 3624 if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE)) 3625 die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P'); 3626 3627 /* get aggregation key or aggrname (optional last argument) */ 3628 if (optind == (argc-1)) { 3629 if (!str2int(argv[optind], &key)) { 3630 status = dladm_name2info(handle, argv[optind], 3631 &linkid, NULL, NULL, NULL); 3632 } else { 3633 status = dladm_key2linkid(handle, (uint16_t)key, 3634 &linkid, DLADM_OPT_ACTIVE); 3635 } 3636 3637 if (status != DLADM_STATUS_OK) 3638 die("non-existent aggregation '%s'", argv[optind]); 3639 3640 } else if (optind != argc) { 3641 usage(); 3642 } 3643 3644 bzero(&state, sizeof (state)); 3645 state.gs_lacp = L_arg; 3646 state.gs_stats = s_arg; 3647 state.gs_flags = flags; 3648 state.gs_parsable = p_arg; 3649 state.gs_extended = x_arg; 3650 3651 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3652 if (state.gs_lacp) 3653 fields_str = all_lacp_fields; 3654 else if (state.gs_stats) 3655 fields_str = all_stats_fields; 3656 else if (state.gs_extended) 3657 fields_str = all_extended_fields; 3658 else 3659 fields_str = all_fields; 3660 } 3661 3662 if (state.gs_lacp) { 3663 pf = aggr_l_fields; 3664 } else if (state.gs_stats) { 3665 pf = aggr_s_fields; 3666 } else if (state.gs_extended) { 3667 pf = aggr_x_fields; 3668 } else { 3669 pf = laggr_fields; 3670 } 3671 3672 if (state.gs_parsable) 3673 ofmtflags |= OFMT_PARSABLE; 3674 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 3675 ofmt_check(oferr, state.gs_parsable, ofmt, die, warn); 3676 state.gs_ofmt = ofmt; 3677 3678 if (s_arg) { 3679 aggr_stats(linkid, &state, interval); 3680 ofmt_close(ofmt); 3681 return; 3682 } 3683 3684 if (linkid == DATALINK_ALL_LINKID) { 3685 (void) dladm_walk_datalink_id(show_aggr, handle, &state, 3686 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); 3687 } else { 3688 (void) show_aggr(handle, linkid, &state); 3689 if (state.gs_status != DLADM_STATUS_OK) { 3690 die_dlerr(state.gs_status, "failed to show aggr %s", 3691 argv[optind]); 3692 } 3693 } 3694 ofmt_close(ofmt); 3695 } 3696 3697 static dladm_status_t 3698 print_phys_default(show_state_t *state, datalink_id_t linkid, 3699 const char *link, uint32_t flags, uint32_t media) 3700 { 3701 dladm_phys_attr_t dpa; 3702 dladm_status_t status; 3703 link_fields_buf_t pattr; 3704 3705 status = dladm_phys_info(handle, linkid, &dpa, state->ls_flags); 3706 if (status != DLADM_STATUS_OK) 3707 goto done; 3708 3709 bzero(&pattr, sizeof (pattr)); 3710 (void) snprintf(pattr.link_phys_device, 3711 sizeof (pattr.link_phys_device), "%s", dpa.dp_dev); 3712 (void) dladm_media2str(media, pattr.link_phys_media); 3713 if (state->ls_flags == DLADM_OPT_ACTIVE) { 3714 boolean_t islink; 3715 3716 if (!dpa.dp_novanity) { 3717 (void) strlcpy(pattr.link_name, link, 3718 sizeof (pattr.link_name)); 3719 islink = B_TRUE; 3720 } else { 3721 /* 3722 * This is a physical link that does not have 3723 * vanity naming support. 3724 */ 3725 (void) strlcpy(pattr.link_name, dpa.dp_dev, 3726 sizeof (pattr.link_name)); 3727 islink = B_FALSE; 3728 } 3729 3730 (void) get_linkstate(pattr.link_name, islink, 3731 pattr.link_phys_state); 3732 (void) snprintf(pattr.link_phys_speed, 3733 sizeof (pattr.link_phys_speed), "%u", 3734 (uint_t)((get_ifspeed(pattr.link_name, 3735 islink)) / 1000000ull)); 3736 (void) get_linkduplex(pattr.link_name, islink, 3737 pattr.link_phys_duplex); 3738 } else { 3739 (void) snprintf(pattr.link_name, sizeof (pattr.link_name), 3740 "%s", link); 3741 (void) snprintf(pattr.link_flags, sizeof (pattr.link_flags), 3742 "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r'); 3743 } 3744 3745 ofmt_print(state->ls_ofmt, &pattr); 3746 3747 done: 3748 return (status); 3749 } 3750 3751 typedef struct { 3752 show_state_t *ms_state; 3753 char *ms_link; 3754 dladm_macaddr_attr_t *ms_mac_attr; 3755 } print_phys_mac_state_t; 3756 3757 /* 3758 * callback for ofmt_print() 3759 */ 3760 static boolean_t 3761 print_phys_one_mac_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3762 { 3763 print_phys_mac_state_t *mac_state = ofarg->ofmt_cbarg; 3764 dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr; 3765 boolean_t is_primary = (attr->ma_slot == 0); 3766 boolean_t is_parsable = mac_state->ms_state->ls_parsable; 3767 3768 switch (ofarg->ofmt_id) { 3769 case PHYS_M_LINK: 3770 (void) snprintf(buf, bufsize, "%s", 3771 (is_primary || is_parsable) ? mac_state->ms_link : " "); 3772 break; 3773 case PHYS_M_SLOT: 3774 if (is_primary) 3775 (void) snprintf(buf, bufsize, gettext("primary")); 3776 else 3777 (void) snprintf(buf, bufsize, "%d", attr->ma_slot); 3778 break; 3779 case PHYS_M_ADDRESS: 3780 (void) dladm_aggr_macaddr2str(attr->ma_addr, buf); 3781 break; 3782 case PHYS_M_INUSE: 3783 (void) snprintf(buf, bufsize, "%s", 3784 attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") : 3785 gettext("no")); 3786 break; 3787 case PHYS_M_CLIENT: 3788 /* 3789 * CR 6678526: resolve link id to actual link name if 3790 * it is valid. 3791 */ 3792 (void) snprintf(buf, bufsize, "%s", attr->ma_client_name); 3793 break; 3794 } 3795 3796 return (B_TRUE); 3797 } 3798 3799 typedef struct { 3800 show_state_t *hs_state; 3801 char *hs_link; 3802 dladm_hwgrp_attr_t *hs_grp_attr; 3803 } print_phys_hwgrp_state_t; 3804 3805 static boolean_t 3806 print_phys_one_hwgrp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3807 { 3808 int i; 3809 boolean_t first = B_TRUE; 3810 int start = -1; 3811 int end = -1; 3812 char ringstr[RINGSTRLEN]; 3813 char ringsubstr[RINGSTRLEN]; 3814 3815 print_phys_hwgrp_state_t *hg_state = ofarg->ofmt_cbarg; 3816 dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr; 3817 3818 switch (ofarg->ofmt_id) { 3819 case PHYS_H_LINK: 3820 (void) snprintf(buf, bufsize, "%s", attr->hg_link_name); 3821 break; 3822 case PHYS_H_RINGTYPE: 3823 (void) snprintf(buf, bufsize, "%s", 3824 attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX"); 3825 break; 3826 case PHYS_H_RINGS: 3827 ringstr[0] = '\0'; 3828 for (i = 0; i < attr->hg_n_rings; i++) { 3829 uint_t index = attr->hg_rings[i]; 3830 3831 if (start == -1) { 3832 start = index; 3833 end = index; 3834 } else if (index == end + 1) { 3835 end = index; 3836 } else { 3837 if (start == end) { 3838 if (first) { 3839 (void) snprintf( 3840 ringsubstr, 3841 RINGSTRLEN, "%d", 3842 start); 3843 first = B_FALSE; 3844 } else { 3845 (void) snprintf( 3846 ringsubstr, 3847 RINGSTRLEN, ",%d", 3848 start); 3849 } 3850 } else { 3851 if (first) { 3852 (void) snprintf( 3853 ringsubstr, 3854 RINGSTRLEN, 3855 "%d-%d", 3856 start, end); 3857 first = B_FALSE; 3858 } else { 3859 (void) snprintf( 3860 ringsubstr, 3861 RINGSTRLEN, 3862 ",%d-%d", 3863 start, end); 3864 } 3865 } 3866 (void) strlcat(ringstr, ringsubstr, 3867 RINGSTRLEN); 3868 start = index; 3869 end = index; 3870 } 3871 } 3872 /* The last one */ 3873 if (start != -1) { 3874 if (first) { 3875 if (start == end) { 3876 (void) snprintf(buf, bufsize, "%d", 3877 start); 3878 } else { 3879 (void) snprintf(buf, bufsize, "%d-%d", 3880 start, end); 3881 } 3882 } else { 3883 if (start == end) { 3884 (void) snprintf(ringsubstr, RINGSTRLEN, 3885 ",%d", start); 3886 } else { 3887 (void) snprintf(ringsubstr, RINGSTRLEN, 3888 ",%d-%d", start, end); 3889 } 3890 (void) strlcat(ringstr, ringsubstr, RINGSTRLEN); 3891 (void) snprintf(buf, bufsize, "%s", ringstr); 3892 } 3893 } 3894 break; 3895 case PHYS_H_CLIENTS: 3896 if (attr->hg_client_names[0] == '\0') { 3897 (void) snprintf(buf, bufsize, "--"); 3898 } else { 3899 (void) snprintf(buf, bufsize, "%s ", 3900 attr->hg_client_names); 3901 } 3902 break; 3903 } 3904 3905 return (B_TRUE); 3906 } 3907 3908 /* 3909 * callback for dladm_walk_macaddr, invoked for each MAC address slot 3910 */ 3911 static boolean_t 3912 print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr) 3913 { 3914 print_phys_mac_state_t *mac_state = arg; 3915 show_state_t *state = mac_state->ms_state; 3916 3917 mac_state->ms_mac_attr = attr; 3918 ofmt_print(state->ls_ofmt, mac_state); 3919 3920 return (B_TRUE); 3921 } 3922 3923 /* 3924 * invoked by show-phys -m for each physical data-link 3925 */ 3926 static dladm_status_t 3927 print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link) 3928 { 3929 print_phys_mac_state_t mac_state; 3930 3931 mac_state.ms_state = state; 3932 mac_state.ms_link = link; 3933 3934 return (dladm_walk_macaddr(handle, linkid, &mac_state, 3935 print_phys_mac_callback)); 3936 } 3937 3938 /* 3939 * callback for dladm_walk_hwgrp, invoked for each MAC hwgrp 3940 */ 3941 static boolean_t 3942 print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr) 3943 { 3944 print_phys_hwgrp_state_t *hwgrp_state = arg; 3945 show_state_t *state = hwgrp_state->hs_state; 3946 3947 hwgrp_state->hs_grp_attr = attr; 3948 ofmt_print(state->ls_ofmt, hwgrp_state); 3949 3950 return (B_TRUE); 3951 } 3952 3953 /* invoked by show-phys -H for each physical data-link */ 3954 static dladm_status_t 3955 print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link) 3956 { 3957 print_phys_hwgrp_state_t hwgrp_state; 3958 3959 hwgrp_state.hs_state = state; 3960 hwgrp_state.hs_link = link; 3961 return (dladm_walk_hwgrp(handle, linkid, &hwgrp_state, 3962 print_phys_hwgrp_callback)); 3963 } 3964 3965 /* 3966 * Parse the "local=<laddr>,remote=<raddr>" sub-options for the -a option of 3967 * *-iptun subcommands. 3968 */ 3969 static void 3970 iptun_process_addrarg(char *addrarg, iptun_params_t *params) 3971 { 3972 char *addrval; 3973 3974 while (*addrarg != '\0') { 3975 switch (getsubopt(&addrarg, iptun_addropts, &addrval)) { 3976 case IPTUN_LOCAL: 3977 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 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 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 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 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 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 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 ofmt_check(oferr, state.vs_parsable, ofmt, die, warn); 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 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 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 ofmt_check(oferr, state->ls_parsable, ofmt, die, warn); 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 ofmt_check(oferr, parsable, *ofmt, die, warn); 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 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 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 ofmt_check(oferr, state.ss_parsable, ofmt, die, warn); 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 ofmt_check(oferr, state.es_parsable, ofmt, die, warn); 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 ofmt_check(oferr, brstate.state.ls_parsable, ofmt, die, warn); 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 /* 9047 * Called from the walker dladm_walk_datalink_id() for each IB partition to 9048 * display IB partition specific information. 9049 */ 9050 static dladm_status_t 9051 print_part(show_part_state_t *state, datalink_id_t linkid) 9052 { 9053 dladm_part_attr_t attr; 9054 dladm_status_t status; 9055 dladm_conf_t conf; 9056 char part_over[MAXLINKNAMELEN]; 9057 char part_name[MAXLINKNAMELEN]; 9058 part_fields_buf_t pbuf; 9059 boolean_t force_in_conf = B_FALSE; 9060 9061 /* 9062 * Get the information about the IB partition from the partition 9063 * datlink ID 'linkid'. 9064 */ 9065 if ((status = dladm_part_info(handle, linkid, &attr, state->ps_flags)) 9066 != DLADM_STATUS_OK) 9067 return (status); 9068 9069 /* 9070 * If an IB Phys link name was provided on the command line we have 9071 * the Phys link's datalink ID in the ps_over_id field of the state 9072 * structure. Proceed only if the IB partition represented by 'linkid' 9073 * was created over Phys link denoted by ps_over_id. The 9074 * 'dia_physlinkid' field of dladm_part_attr_t represents the IB Phys 9075 * link over which the partition was created. 9076 */ 9077 if (state->ps_over_id != DATALINK_ALL_LINKID) 9078 if (state->ps_over_id != attr.dia_physlinkid) 9079 return (DLADM_STATUS_OK); 9080 9081 /* 9082 * The linkid argument passed to this function is the datalink ID 9083 * of the IB Partition. Get the partitions name from this linkid. 9084 */ 9085 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, 9086 NULL, part_name, sizeof (part_name)) != DLADM_STATUS_OK) 9087 return (DLADM_STATUS_BADARG); 9088 9089 bzero(part_over, sizeof (part_over)); 9090 9091 /* 9092 * The 'dia_physlinkid' field contains the datalink ID of the IB Phys 9093 * link over which the partition was created. Use this linkid to get the 9094 * linkover field. 9095 */ 9096 if (dladm_datalink_id2info(handle, attr.dia_physlinkid, NULL, NULL, 9097 NULL, part_over, sizeof (part_over)) != DLADM_STATUS_OK) 9098 (void) sprintf(part_over, "?"); 9099 state->ps_found = B_TRUE; 9100 9101 /* 9102 * Read the FFORCE field from this datalink's persistent configuration 9103 * database line to determine if this datalink was created forcibly. 9104 * If this datalink is a temporary datalink, then it will not have an 9105 * entry in the persistent configuration, so check if force create flag 9106 * is set in the partition attributes. 9107 * 9108 * We need this two level check since persistent partitions brought up 9109 * by up-part during boot will have force create flag always set, since 9110 * we want up-part to always succeed even if the port is currently down 9111 * or P_Key is not yet available in the subnet. 9112 */ 9113 if ((status = dladm_getsnap_conf(handle, linkid, &conf)) == 9114 DLADM_STATUS_OK) { 9115 (void) dladm_get_conf_field(handle, conf, FFORCE, 9116 &force_in_conf, sizeof (boolean_t)); 9117 dladm_destroy_conf(handle, conf); 9118 } else if (status == DLADM_STATUS_NOTFOUND) { 9119 /* 9120 * for a temp link the force create flag will determine 9121 * whether it was created with force flag. 9122 */ 9123 force_in_conf = ((attr.dia_flags & DLADM_PART_FORCE_CREATE) 9124 != 0); 9125 } 9126 9127 (void) snprintf(pbuf.part_link, sizeof (pbuf.part_link), 9128 "%s", part_name); 9129 9130 (void) snprintf(pbuf.part_over, sizeof (pbuf.part_over), 9131 "%s", part_over); 9132 9133 (void) snprintf(pbuf.part_pkey, sizeof (pbuf.part_pkey), 9134 "%X", attr.dia_pkey); 9135 9136 (void) get_linkstate(pbuf.part_link, B_TRUE, pbuf.part_state); 9137 9138 (void) snprintf(pbuf.part_flags, sizeof (pbuf.part_flags), 9139 "%c----", force_in_conf ? 'f' : '-'); 9140 9141 ofmt_print(state->ps_ofmt, &pbuf); 9142 9143 return (DLADM_STATUS_OK); 9144 } 9145 9146 /* ARGSUSED */ 9147 static int 9148 show_part(dladm_handle_t dh, datalink_id_t linkid, void *arg) 9149 { 9150 ((show_part_state_t *)arg)->ps_status = print_part(arg, linkid); 9151 return (DLADM_WALK_CONTINUE); 9152 } 9153 9154 /* 9155 * Show the information about the IB partition objects. 9156 */ 9157 static void 9158 do_show_part(int argc, char *argv[], const char *use) 9159 { 9160 int option; 9161 boolean_t l_arg = B_FALSE; 9162 uint32_t flags = DLADM_OPT_ACTIVE; 9163 datalink_id_t linkid = DATALINK_ALL_LINKID; 9164 datalink_id_t over_linkid = DATALINK_ALL_LINKID; 9165 char over_link[MAXLINKNAMELEN]; 9166 show_part_state_t state; 9167 dladm_status_t status; 9168 boolean_t o_arg = B_FALSE; 9169 char *fields_str = NULL; 9170 ofmt_handle_t ofmt; 9171 ofmt_status_t oferr; 9172 uint_t ofmtflags = 0; 9173 9174 bzero(&state, sizeof (state)); 9175 opterr = 0; 9176 while ((option = getopt_long(argc, argv, ":pPl:o:", show_part_lopts, 9177 NULL)) != -1) { 9178 switch (option) { 9179 case 'p': 9180 state.ps_parsable = B_TRUE; 9181 break; 9182 case 'P': 9183 flags = DLADM_OPT_PERSIST; 9184 break; 9185 case 'l': 9186 /* 9187 * The data link ID of the IB Phys link. When this 9188 * argument is provided we list only the partition 9189 * objects created over this IB Phys link. 9190 */ 9191 if (strlcpy(over_link, optarg, MAXLINKNAMELEN) >= 9192 MAXLINKNAMELEN) 9193 die("link name too long"); 9194 9195 l_arg = B_TRUE; 9196 break; 9197 case 'o': 9198 o_arg = B_TRUE; 9199 fields_str = optarg; 9200 break; 9201 default: 9202 die_opterr(optopt, option, use); 9203 } 9204 } 9205 9206 /* 9207 * Get the partition ID (optional last argument). 9208 */ 9209 if (optind == (argc - 1)) { 9210 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 9211 NULL, NULL); 9212 if (status != DLADM_STATUS_OK) { 9213 die_dlerr(status, "invalid partition link name '%s'", 9214 argv[optind]); 9215 } 9216 (void) strlcpy(state.ps_part, argv[optind], MAXLINKNAMELEN); 9217 } else if (optind != argc) { 9218 usage(); 9219 } 9220 9221 if (state.ps_parsable && !o_arg) 9222 die("-p requires -o"); 9223 9224 /* 9225 * If an IB Phys link name was provided as an argument, then get its 9226 * datalink ID. 9227 */ 9228 if (l_arg) { 9229 status = dladm_name2info(handle, over_link, &over_linkid, NULL, 9230 NULL, NULL); 9231 if (status != DLADM_STATUS_OK) { 9232 die_dlerr(status, "invalid link name '%s'", over_link); 9233 } 9234 } 9235 9236 state.ps_over_id = over_linkid; /* IB Phys link ID */ 9237 state.ps_found = B_FALSE; 9238 state.ps_flags = flags; 9239 9240 if (state.ps_parsable) 9241 ofmtflags |= OFMT_PARSABLE; 9242 oferr = ofmt_open(fields_str, part_fields, ofmtflags, 0, &ofmt); 9243 ofmt_check(oferr, state.ps_parsable, ofmt, die, warn); 9244 state.ps_ofmt = ofmt; 9245 9246 /* 9247 * If a specific IB partition name was not provided as an argument, 9248 * walk all the datalinks and display the information for all 9249 * IB partitions. If IB Phys link was provided limit it to only 9250 * IB partitions created over that IB Phys link. 9251 */ 9252 if (linkid == DATALINK_ALL_LINKID) { 9253 (void) dladm_walk_datalink_id(show_part, handle, &state, 9254 DATALINK_CLASS_PART, DATALINK_ANY_MEDIATYPE, flags); 9255 } else { 9256 (void) show_part(handle, linkid, &state); 9257 if (state.ps_status != DLADM_STATUS_OK) { 9258 ofmt_close(ofmt); 9259 die_dlerr(state.ps_status, "failed to show IB partition" 9260 " '%s'", state.ps_part); 9261 } 9262 } 9263 ofmt_close(ofmt); 9264 } 9265 9266 9267 /* 9268 * Called from the walker dladm_walk_datalink_id() for each IB Phys link to 9269 * display IB specific information for these Phys links. 9270 */ 9271 static dladm_status_t 9272 print_ib(show_ib_state_t *state, datalink_id_t phys_linkid) 9273 { 9274 dladm_ib_attr_t attr; 9275 dladm_status_t status; 9276 char linkname[MAXLINKNAMELEN]; 9277 char pkeystr[MAXPKEYLEN]; 9278 int i; 9279 ib_fields_buf_t ibuf; 9280 9281 bzero(&attr, sizeof (attr)); 9282 9283 /* 9284 * Get the attributes of the IB Phys link from active/Persistent config 9285 * based on the flag passed. 9286 */ 9287 if ((status = dladm_ib_info(handle, phys_linkid, &attr, 9288 state->is_flags)) != DLADM_STATUS_OK) 9289 return (status); 9290 9291 if ((state->is_link_id != DATALINK_ALL_LINKID) && (state->is_link_id 9292 != attr.dia_physlinkid)) { 9293 dladm_free_ib_info(&attr); 9294 return (DLADM_STATUS_OK); 9295 } 9296 9297 /* 9298 * Get the data link name for the phys_linkid. If we are doing show-ib 9299 * for all IB Phys links, we have only the datalink IDs not the 9300 * datalink name. 9301 */ 9302 if (dladm_datalink_id2info(handle, phys_linkid, NULL, NULL, NULL, 9303 linkname, MAXLINKNAMELEN) != DLADM_STATUS_OK) 9304 return (status); 9305 9306 (void) snprintf(ibuf.ib_link, sizeof (ibuf.ib_link), 9307 "%s", linkname); 9308 9309 (void) snprintf(ibuf.ib_portnum, sizeof (ibuf.ib_portnum), 9310 "%d", attr.dia_portnum); 9311 9312 (void) snprintf(ibuf.ib_hcaguid, sizeof (ibuf.ib_hcaguid), 9313 "%llX", attr.dia_hca_guid); 9314 9315 (void) snprintf(ibuf.ib_portguid, sizeof (ibuf.ib_portguid), 9316 "%llX", attr.dia_port_guid); 9317 9318 (void) get_linkstate(linkname, B_TRUE, ibuf.ib_state); 9319 9320 /* 9321 * Create a comma separated list of pkeys from the pkey table returned 9322 * by the IP over IB driver instance. 9323 */ 9324 bzero(ibuf.ib_pkeys, attr.dia_port_pkey_tbl_sz * sizeof (ib_pkey_t)); 9325 for (i = 0; i < attr.dia_port_pkey_tbl_sz; i++) { 9326 if (attr.dia_port_pkeys[i] != IB_PKEY_INVALID_FULL && 9327 attr.dia_port_pkeys[i] != IB_PKEY_INVALID_LIMITED) { 9328 if (i == 0) 9329 (void) snprintf(pkeystr, MAXPKEYLEN, "%X", 9330 attr.dia_port_pkeys[i]); 9331 else 9332 (void) snprintf(pkeystr, MAXPKEYLEN, ",%X", 9333 attr.dia_port_pkeys[i]); 9334 (void) strlcat(ibuf.ib_pkeys, pkeystr, MAXPKEYSTRSZ); 9335 } 9336 } 9337 9338 dladm_free_ib_info(&attr); 9339 9340 ofmt_print(state->is_ofmt, &ibuf); 9341 9342 return (DLADM_STATUS_OK); 9343 } 9344 9345 /* ARGSUSED */ 9346 static int 9347 show_ib(dladm_handle_t dh, datalink_id_t linkid, void *arg) 9348 { 9349 ((show_ib_state_t *)arg)->is_status = print_ib(arg, linkid); 9350 return (DLADM_WALK_CONTINUE); 9351 } 9352 9353 /* 9354 * Show the properties of one/all IB Phys links. This is different from 9355 * show-phys command since this will display IB specific information about the 9356 * Phys link like, HCA GUID, PORT GUID, PKEYS active for this port etc. 9357 */ 9358 static void 9359 do_show_ib(int argc, char *argv[], const char *use) 9360 { 9361 int option; 9362 uint32_t flags = DLADM_OPT_ACTIVE; 9363 datalink_id_t linkid = DATALINK_ALL_LINKID; 9364 show_ib_state_t state; 9365 dladm_status_t status; 9366 boolean_t o_arg = B_FALSE; 9367 char *fields_str = NULL; 9368 ofmt_handle_t ofmt; 9369 ofmt_status_t oferr; 9370 uint_t ofmtflags = 0; 9371 9372 bzero(&state, sizeof (state)); 9373 opterr = 0; 9374 while ((option = getopt_long(argc, argv, ":po:", show_lopts, 9375 NULL)) != -1) { 9376 switch (option) { 9377 case 'p': 9378 state.is_parsable = B_TRUE; 9379 break; 9380 case 'o': 9381 o_arg = B_TRUE; 9382 fields_str = optarg; 9383 break; 9384 default: 9385 die_opterr(optopt, option, use); 9386 } 9387 } 9388 9389 /* get IB Phys link ID (optional last argument) */ 9390 if (optind == (argc - 1)) { 9391 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 9392 NULL, NULL); 9393 if (status != DLADM_STATUS_OK) { 9394 die_dlerr(status, "invalid IB port name '%s'", 9395 argv[optind]); 9396 } 9397 (void) strlcpy(state.is_link, argv[optind], MAXLINKNAMELEN); 9398 } else if (optind != argc) { 9399 usage(); 9400 } 9401 9402 if (state.is_parsable && !o_arg) 9403 die("-p requires -o"); 9404 9405 /* 9406 * linkid is the data link ID of the IB Phys link. By default it will 9407 * be DATALINK_ALL_LINKID. 9408 */ 9409 state.is_link_id = linkid; 9410 state.is_flags = flags; 9411 9412 if (state.is_parsable) 9413 ofmtflags |= OFMT_PARSABLE; 9414 oferr = ofmt_open(fields_str, ib_fields, ofmtflags, 0, &ofmt); 9415 ofmt_check(oferr, state.is_parsable, ofmt, die, warn); 9416 state.is_ofmt = ofmt; 9417 9418 /* 9419 * If we are going to display the information for all IB Phys links 9420 * then we'll walk through all the datalinks for datalinks of Phys 9421 * class and media type IB. 9422 */ 9423 if (linkid == DATALINK_ALL_LINKID) { 9424 (void) dladm_walk_datalink_id(show_ib, handle, &state, 9425 DATALINK_CLASS_PHYS, DL_IB, flags); 9426 } else { 9427 /* 9428 * We need to display the information only for the IB phys link 9429 * linkid. Call show_ib for this link. 9430 */ 9431 (void) show_ib(handle, linkid, &state); 9432 if (state.is_status != DLADM_STATUS_OK) { 9433 ofmt_close(ofmt); 9434 die_dlerr(state.is_status, "failed to show IB Phys link" 9435 " '%s'", state.is_link); 9436 } 9437 } 9438 ofmt_close(ofmt); 9439 } 9440 9441 /* 9442 * Create an IP over Infiniband partition object over an IB Phys link. The IB 9443 * Phys link is associated with an Infiniband HCA port. The IB partition object 9444 * is created over a port, pkey combination. This partition object represents 9445 * an instance of IP over IB interface. 9446 */ 9447 /* ARGSUSED */ 9448 static void 9449 do_create_part(int argc, char *argv[], const char *use) 9450 { 9451 int status, option; 9452 int flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 9453 char *pname; 9454 char *l_arg = NULL; 9455 char *altroot = NULL; 9456 datalink_id_t physlinkid = 0; 9457 datalink_id_t partlinkid = 0; 9458 unsigned long opt_pkey; 9459 ib_pkey_t pkey = 0; 9460 char *endp = NULL; 9461 char propstr[DLADM_STRSIZE]; 9462 dladm_arg_list_t *proplist = NULL; 9463 9464 propstr[0] = '\0'; 9465 while ((option = getopt_long(argc, argv, ":tfl:P:R:p:", 9466 part_lopts, NULL)) != -1) { 9467 switch (option) { 9468 case 't': 9469 /* 9470 * Create a temporary IB partition object. This 9471 * instance is not entered into the persistent database 9472 * so it will not be recreated automatically on a 9473 * reboot. 9474 */ 9475 flags &= ~DLADM_OPT_PERSIST; 9476 break; 9477 case 'l': 9478 /* 9479 * The IB phys link over which the partition object will 9480 * be created. 9481 */ 9482 l_arg = optarg; 9483 break; 9484 case 'R': 9485 altroot = optarg; 9486 break; 9487 case 'p': 9488 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 9489 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 9490 DLADM_STRSIZE) 9491 die("property list too long '%s'", propstr); 9492 break; 9493 case 'P': 9494 /* 9495 * The P_Key for the port, pkey tuple of the partition 9496 * object. This P_Key should exist in the IB subnet. 9497 * The partition creation for a non-existent P_Key will 9498 * fail unless the -f option is used. 9499 * 9500 * The P_Key is expected to be a hexadecimal number. 9501 */ 9502 opt_pkey = strtoul(optarg, &endp, 16); 9503 if (errno == ERANGE || opt_pkey > USHRT_MAX || 9504 *endp != '\0') 9505 die("Invalid pkey"); 9506 9507 pkey = (ib_pkey_t)opt_pkey; 9508 break; 9509 case 'f': 9510 flags |= DLADM_OPT_FORCE; 9511 break; 9512 default: 9513 die_opterr(optopt, option, use); 9514 break; 9515 } 9516 } 9517 9518 /* check required options */ 9519 if (!l_arg) 9520 usage(); 9521 9522 /* the partition name is a required operand */ 9523 if (optind != (argc - 1)) 9524 usage(); 9525 9526 pname = argv[argc - 1]; 9527 9528 /* 9529 * Verify that the partition object's name is in the valid link name 9530 * format. 9531 */ 9532 if (!dladm_valid_linkname(pname)) 9533 die("Invalid link name '%s'", pname); 9534 9535 /* pkey is a mandatory argument */ 9536 if (pkey == 0) 9537 usage(); 9538 9539 if (altroot != NULL) 9540 altroot_cmd(altroot, argc, argv); 9541 9542 /* 9543 * Get the data link id of the IB Phys link over which we will be 9544 * creating partition object. 9545 */ 9546 if (dladm_name2info(handle, l_arg, 9547 &physlinkid, NULL, NULL, NULL) != DLADM_STATUS_OK) 9548 die("invalid link name '%s'", l_arg); 9549 9550 /* 9551 * parse the property list provided with -p option. 9552 */ 9553 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 9554 != DLADM_STATUS_OK) 9555 die("invalid IB partition property"); 9556 9557 /* 9558 * Call the library routine to create the partition object. 9559 */ 9560 status = dladm_part_create(handle, physlinkid, pkey, flags, pname, 9561 &partlinkid, proplist); 9562 if (status != DLADM_STATUS_OK) 9563 die_dlerr(status, 9564 "partition %x creation over %s failed", pkey, l_arg); 9565 } 9566 9567 /* 9568 * Delete an IP over Infiniband partition object. The partition object should 9569 * be unplumbed before attempting the delete. 9570 */ 9571 static void 9572 do_delete_part(int argc, char *argv[], const char *use) 9573 { 9574 int option, flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 9575 int status; 9576 char *altroot = NULL; 9577 datalink_id_t partid; 9578 9579 opterr = 0; 9580 while ((option = getopt_long(argc, argv, "R:t", part_lopts, 9581 NULL)) != -1) { 9582 switch (option) { 9583 case 't': 9584 flags &= ~DLADM_OPT_PERSIST; 9585 break; 9586 case 'R': 9587 altroot = optarg; 9588 break; 9589 default: 9590 die_opterr(optopt, option, use); 9591 } 9592 } 9593 9594 /* get partition name (required last argument) */ 9595 if (optind != (argc - 1)) 9596 usage(); 9597 9598 if (altroot != NULL) 9599 altroot_cmd(altroot, argc, argv); 9600 9601 /* 9602 * Get the data link id of the partition object given the partition 9603 * name. 9604 */ 9605 status = dladm_name2info(handle, argv[optind], &partid, NULL, NULL, 9606 NULL); 9607 if (status != DLADM_STATUS_OK) 9608 die("invalid link name '%s'", argv[optind]); 9609 9610 /* 9611 * Call the library routine to delete the IB partition. This will 9612 * result in the IB partition object and all its resources getting 9613 * deleted. 9614 */ 9615 status = dladm_part_delete(handle, partid, flags); 9616 if (status != DLADM_STATUS_OK) 9617 die_dlerr(status, "%s: partition deletion failed", 9618 argv[optind]); 9619 } 9620 9621 /* 9622 * Bring up all or one IB partition already present in the persistent database 9623 * but not active yet. 9624 * 9625 * This sub-command is used during the system boot up to bring up all IB 9626 * partitions present in the persistent database. This is similar to a 9627 * create partition except that, the partitions are always created even if the 9628 * HCA port is down or P_Key is not present in the IB subnet. This is similar 9629 * to using the 'force' option while creating the partition except that the 'f' 9630 * flag will be set in the flags field only if the create-part for this command 9631 * was called with '-f' option. 9632 */ 9633 /* ARGSUSED */ 9634 static void 9635 do_up_part(int argc, char *argv[], const char *use) 9636 { 9637 datalink_id_t partid = DATALINK_ALL_LINKID; 9638 dladm_status_t status; 9639 9640 /* 9641 * If a partition name was passed as an argument, get its data link 9642 * id. By default we'll attempt to bring up all IB partition data 9643 * links. 9644 */ 9645 if (argc == 2) { 9646 status = dladm_name2info(handle, argv[argc - 1], &partid, NULL, 9647 NULL, NULL); 9648 if (status != DLADM_STATUS_OK) 9649 return; 9650 } else if (argc > 2) { 9651 usage(); 9652 } 9653 9654 (void) dladm_part_up(handle, partid, 0); 9655 } 9656