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