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