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