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