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