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