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