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