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