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 */ 95typedef 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 */ 105typedef 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 115typedef 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 127typedef 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 140typedef 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 159typedef 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 169typedef 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 178typedef 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 */ 190static ofmt_cb_t print_default_cb, print_link_stats_cb, print_linkprop_cb; 191static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb; 192static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb; 193static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb; 194static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb; 195static void dladm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t); 196 197typedef void cmdfunc_t(int, char **, const char *); 198 199static cmdfunc_t do_show_link, do_show_wifi, do_show_phys; 200static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 201static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr; 202static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 203static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 204static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 205static cmdfunc_t do_init_linkprop, do_init_secobj; 206static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan; 207static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys; 208static cmdfunc_t do_show_linkmap; 209static cmdfunc_t do_show_ether; 210static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic; 211static cmdfunc_t do_up_vnic; 212static cmdfunc_t do_create_part, do_delete_part, do_show_part, do_show_ib; 213static cmdfunc_t do_up_part; 214static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub; 215static cmdfunc_t do_create_simnet, do_modify_simnet; 216static cmdfunc_t do_delete_simnet, do_show_simnet, do_up_simnet; 217static cmdfunc_t do_show_usage; 218static cmdfunc_t do_create_bridge, do_modify_bridge, do_delete_bridge; 219static cmdfunc_t do_add_bridge, do_remove_bridge, do_show_bridge; 220static cmdfunc_t do_create_iptun, do_modify_iptun, do_delete_iptun; 221static cmdfunc_t do_show_iptun, do_up_iptun, do_down_iptun; 222 223static void do_up_vnic_common(int, char **, const char *, boolean_t); 224 225static int show_part(dladm_handle_t, datalink_id_t, void *); 226 227static void altroot_cmd(char *, int, char **); 228static int show_linkprop_onelink(dladm_handle_t, datalink_id_t, void *); 229 230static void link_stats(datalink_id_t, uint_t, char *, show_state_t *); 231static void aggr_stats(datalink_id_t, show_grp_state_t *, uint_t); 232static void vnic_stats(show_vnic_state_t *, uint32_t); 233 234static int get_one_kstat(const char *, const char *, uint8_t, 235 void *, boolean_t); 236static void get_mac_stats(const char *, pktsum_t *); 237static void get_link_stats(const char *, pktsum_t *); 238static uint64_t get_ifspeed(const char *, boolean_t); 239static const char *get_linkstate(const char *, boolean_t, char *); 240static const char *get_linkduplex(const char *, boolean_t, char *); 241 242static iptun_type_t iptun_gettypebyname(char *); 243static const char *iptun_gettypebyvalue(iptun_type_t); 244static dladm_status_t print_iptun(dladm_handle_t, datalink_id_t, 245 show_state_t *); 246static int print_iptun_walker(dladm_handle_t, datalink_id_t, void *); 247 248static int show_etherprop(dladm_handle_t, datalink_id_t, void *); 249static void show_ether_xprop(void *, dladm_ether_info_t *); 250static boolean_t link_is_ether(const char *, datalink_id_t *); 251 252static boolean_t str2int(const char *, int *); 253static void die(const char *, ...); 254static void die_optdup(int); 255static void die_opterr(int, int, const char *); 256static void die_dlerr(dladm_status_t, const char *, ...); 257static void warn(const char *, ...); 258static void warn_dlerr(dladm_status_t, const char *, ...); 259 260typedef struct cmd { 261 char *c_name; 262 cmdfunc_t *c_fn; 263 const char *c_usage; 264} cmd_t; 265 266static 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 409static 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 427static 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 440static 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 451static char * const iptun_addropts[] = { 452#define IPTUN_LOCAL 0 453 "local", 454#define IPTUN_REMOTE 1 455 "remote", 456 NULL}; 457 458static 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 468static 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 479static 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 499static 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 507static 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 521static 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 531static 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 540static 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 546static 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 554static 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 562static 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 574static 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 */ 589static const char *ptype[] = {LEI_ATTR_NAMES}; 590 591typedef 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 602static 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 623typedef 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 */ 634typedef 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 644static 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 655typedef 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 */ 663typedef 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 */ 682static 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 */ 702typedef 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 711typedef 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 721static 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 */ 741typedef 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 751static 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 */ 766typedef 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 777static 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 */ 792typedef 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 803static 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 820static 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 843typedef 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 851static 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 865typedef 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 874static 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 */ 885static 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 */ 901static 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 */ 917static 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 923static char *all_scan_wifi_fields = 924 "link,essid,bssid,sec,strength,mode,speed,bsstype"; 925static char *all_show_wifi_fields = 926 "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 927static char *def_scan_wifi_fields = 928 "link,essid,bssid,sec,strength,mode,speed"; 929static char *def_show_wifi_fields = 930 "link,status,essid,sec,strength,mode,speed"; 931 932/* 933 * structures for 'dladm show-linkprop' 934 */ 935typedef 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 944static 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 957typedef 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 970typedef 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 977typedef 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 */ 986typedef 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 992static 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 */ 1005typedef 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 1015static 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 */ 1034typedef 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 1044static 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 */ 1062typedef 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 1071static 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 */ 1087typedef 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 1095static 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 1111typedef 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 1121static 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 1144typedef 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 1153static 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. */ 1171enum { IPTUN_SFLAG_INDEX, IPTUN_IFLAG_INDEX, IPTUN_NUM_FLAGS }; 1172 1173/* 1174 * structures for 'dladm show-iptun' 1175 */ 1176typedef 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 1184static 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 */ 1202typedef 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 1223static 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 */ 1267typedef 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 1282static 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) 1316typedef 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 1326static 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 */ 1348typedef 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 1359static 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 */ 1386typedef 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 1393static 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 */ 1408typedef 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 1415static 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 1427static char *progname; 1428static sig_atomic_t signalled; 1429 1430/* 1431 * Handle to libdladm. Opened in main() before the sub-command 1432 * specific function is called. 1433 */ 1434static dladm_handle_t handle = NULL; 1435 1436#define DLADM_ETHERSTUB_NAME "etherstub" 1437#define DLADM_IS_ETHERSTUB(id) (id == DATALINK_INVALID_LINKID) 1438 1439static void 1440usage(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 1459int 1460main(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*/ 1500static int 1501show_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 1530static int 1531show_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 1607static int 1608show_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 1651static boolean_t 1652valid_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*/ 1661static void 1662do_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 1781static void 1782do_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 } 1955done: 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 */ 1971static dladm_status_t 1972i_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 1998static void 1999do_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); 2034done: 2035 if (status != DLADM_STATUS_OK) 2036 die_dlerr(status, "delete operation failed"); 2037} 2038 2039static void 2040do_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); 2115done: 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 2133static void 2134do_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); 2205done: 2206 if (status != DLADM_STATUS_OK) 2207 die_dlerr(status, "remove operation failed"); 2208} 2209 2210static void 2211do_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 2297done: 2298 if (status != DLADM_STATUS_OK) 2299 die_dlerr(status, "modify operation failed"); 2300} 2301 2302/*ARGSUSED*/ 2303static void 2304do_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); 2321done: 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 2332static void 2333do_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 2441static void 2442do_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); 2478done: 2479 if (status != DLADM_STATUS_OK) 2480 die_dlerr(status, "delete operation failed"); 2481} 2482 2483/*ARGSUSED*/ 2484static void 2485do_up_vlan(int argc, char *argv[], const char *use) 2486{ 2487 do_up_vnic_common(argc, argv, use, B_TRUE); 2488} 2489 2490static void 2491do_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*/ 2525static void 2526do_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*/ 2550static int 2551i_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*/ 2571static void 2572do_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*/ 2589static int 2590purge_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*/ 2607static void 2608do_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 */ 2629void 2630print_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 2777static dladm_status_t 2778print_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 { 2831link_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); 2849done: 2850 return (status); 2851} 2852 2853/* ARGSUSED */ 2854static int 2855show_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 2871static boolean_t 2872print_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 2906static int 2907show_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 2952static dladm_status_t 2953print_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 2986static boolean_t 2987print_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 } 3048err: 3049 *(l->laggr_status) = DLADM_STATUS_OK; 3050 return (B_TRUE); 3051} 3052 3053static dladm_status_t 3054print_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; 3080done: 3081 return (status); 3082} 3083 3084static boolean_t 3085print_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 3147static dladm_status_t 3148print_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; 3167done: 3168 return (status); 3169} 3170 3171static boolean_t 3172print_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 3264err: 3265 *stat = status; 3266 return (B_TRUE); 3267} 3268 3269static dladm_status_t 3270print_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 3336done: 3337 free(port_stat); 3338 return (status); 3339} 3340 3341static dladm_status_t 3342print_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 3371done: 3372 free(ginfo.lg_ports); 3373 return (status); 3374} 3375 3376/* ARGSUSED */ 3377static int 3378show_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 3386static void 3387do_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 3538static void 3539do_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 3710static dladm_status_t 3711print_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 3759done: 3760 return (status); 3761} 3762 3763typedef 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 */ 3772static boolean_t 3773print_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 3811typedef 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 3817static boolean_t 3818print_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 */ 3923static boolean_t 3924print_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 */ 3938static dladm_status_t 3939print_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 */ 3953static boolean_t 3954print_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 */ 3966static dladm_status_t 3967print_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 */ 3981static void 3982iptun_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 */ 4013static void 4014iptun_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 4060static void 4061do_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 4076static void 4077do_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 4094static void 4095do_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 4112static void 4113do_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 */ 4179static void 4180do_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 */ 4202static void 4203do_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 4224static iptun_type_t 4225iptun_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 4238static const char * 4239iptun_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 4250static dladm_status_t 4251print_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 4302static int 4303print_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 4309static dladm_status_t 4310print_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 4340done: 4341 return (status); 4342} 4343 4344/* ARGSUSED */ 4345static int 4346show_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 */ 4357static dladm_status_t 4358print_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 4387done: 4388 return (status); 4389} 4390 4391/* ARGSUSED */ 4392static int 4393show_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 4406done: 4407 state->ls_status = status; 4408 return (DLADM_WALK_CONTINUE); 4409} 4410 4411static void 4412do_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 4539static void 4540do_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 4618static void 4619do_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 4805static void 4806do_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 4825static void 4826do_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 4876static void 4877do_delete_vnic(int argc, char *argv[], const char *use) 4878{ 4879 do_delete_vnic_common(argc, argv, use, B_FALSE); 4880} 4881 4882/* ARGSUSED */ 4883static void 4884do_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 4910done: 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 4921static void 4922do_up_vnic(int argc, char *argv[], const char *use) 4923{ 4924 do_up_vnic_common(argc, argv, use, B_FALSE); 4925} 4926 4927static void 4928dump_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 4941static void 4942dump_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 */ 4980static dladm_status_t 4981print_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 */ 5103static int 5104show_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 5112static void 5113do_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 5247static void 5248do_show_vnic(int argc, char *argv[], const char *use) 5249{ 5250 do_show_vnic_common(argc, argv, use, B_FALSE); 5251} 5252 5253static void 5254do_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 5302static void 5303do_delete_etherstub(int argc, char *argv[], const char *use) 5304{ 5305 do_delete_vnic_common(argc, argv, use, B_TRUE); 5306} 5307 5308/* ARGSUSED */ 5309static void 5310do_show_etherstub(int argc, char *argv[], const char *use) 5311{ 5312 do_show_vnic_common(argc, argv, use, B_TRUE); 5313} 5314 5315/* ARGSUSED */ 5316static void 5317do_up_simnet(int argc, char *argv[], const char *use) 5318{ 5319 (void) dladm_simnet_up(handle, DATALINK_ALL_LINKID, 0); 5320} 5321 5322static void 5323do_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 5378static void 5379do_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 5427static void 5428do_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 5484static dladm_status_t 5485print_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 */ 5526static int 5527show_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 5535static void 5536do_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 5621static void 5622link_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 5660static void 5661aggr_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 */ 5687static void 5688vnic_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 5769static void 5770get_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 5796static void 5797get_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 5817static int 5818query_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 5848bail: 5849 (void) kstat_close(kcp); 5850 return (-1); 5851} 5852 5853static int 5854get_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 5870static uint64_t 5871get_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