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