1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22/* 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2016 Nexenta Systems, Inc. 25 * Copyright 2020 Peter Tribble. 26 */ 27 28#include <stdio.h> 29#include <ctype.h> 30#include <dlfcn.h> 31#include <locale.h> 32#include <signal.h> 33#include <stdarg.h> 34#include <stdlib.h> 35#include <fcntl.h> 36#include <string.h> 37#include <stropts.h> 38#include <sys/stat.h> 39#include <errno.h> 40#include <kstat.h> 41#include <strings.h> 42#include <getopt.h> 43#include <unistd.h> 44#include <priv.h> 45#include <limits.h> 46#include <termios.h> 47#include <pwd.h> 48#include <auth_attr.h> 49#include <auth_list.h> 50#include <libintl.h> 51#include <libdevinfo.h> 52#include <libdlpi.h> 53#include <libdladm.h> 54#include <libdllink.h> 55#include <libdlstat.h> 56#include <libdlaggr.h> 57#include <libdlwlan.h> 58#include <libdlvlan.h> 59#include <libdlvnic.h> 60#include <libdlib.h> 61#include <libdlether.h> 62#include <libdliptun.h> 63#include <libdlsim.h> 64#include <libdlbridge.h> 65#include <libinetutil.h> 66#include <libvrrpadm.h> 67#include <bsm/adt.h> 68#include <bsm/adt_event.h> 69#include <libdlvnic.h> 70#include <sys/types.h> 71#include <sys/socket.h> 72#include <sys/ib/ib_types.h> 73#include <sys/processor.h> 74#include <netinet/in.h> 75#include <arpa/inet.h> 76#include <net/if_types.h> 77#include <stddef.h> 78#include <stp_in.h> 79#include <ofmt.h> 80 81#define MAXPORT 256 82#define MAXVNIC 256 83#define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) 84#define MAXLINELEN 1024 85#define SMF_UPGRADE_FILE "/var/svc/profile/upgrade" 86#define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink" 87#define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)" 88#define DLADM_DEFAULT_COL 80 89 90/* 91 * used by the wifi show-* commands to set up ofmt_field_t structures. 92 */ 93#define WIFI_CMD_SCAN 0x00000001 94#define WIFI_CMD_SHOW 0x00000002 95#define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 96 97/* No larger than pktsum_t */ 98typedef struct brsum_s { 99 uint64_t drops; 100 uint64_t forward_dir; 101 uint64_t forward_mb; 102 uint64_t forward_unk; 103 uint64_t recv; 104 uint64_t sent; 105} brsum_t; 106 107/* No larger than pktsum_t */ 108typedef struct brlsum_s { 109 uint32_t cfgbpdu; 110 uint32_t tcnbpdu; 111 uint32_t rstpbpdu; 112 uint32_t txbpdu; 113 uint64_t drops; 114 uint64_t recv; 115 uint64_t xmit; 116} brlsum_t; 117 118typedef struct show_state { 119 boolean_t ls_firstonly; 120 boolean_t ls_donefirst; 121 pktsum_t ls_prevstats; 122 uint32_t ls_flags; 123 dladm_status_t ls_status; 124 ofmt_handle_t ls_ofmt; 125 boolean_t ls_parsable; 126 boolean_t ls_mac; 127 boolean_t ls_hwgrp; 128} show_state_t; 129 130typedef struct show_grp_state { 131 pktsum_t gs_prevstats[MAXPORT]; 132 uint32_t gs_flags; 133 dladm_status_t gs_status; 134 boolean_t gs_parsable; 135 boolean_t gs_lacp; 136 boolean_t gs_extended; 137 boolean_t gs_stats; 138 boolean_t gs_firstonly; 139 boolean_t gs_donefirst; 140 ofmt_handle_t gs_ofmt; 141} show_grp_state_t; 142 143typedef struct show_vnic_state { 144 datalink_id_t vs_vnic_id; 145 datalink_id_t vs_link_id; 146 char vs_vnic[MAXLINKNAMELEN]; 147 char vs_link[MAXLINKNAMELEN]; 148 boolean_t vs_parsable; 149 boolean_t vs_found; 150 boolean_t vs_firstonly; 151 boolean_t vs_donefirst; 152 boolean_t vs_stats; 153 boolean_t vs_printstats; 154 pktsum_t vs_totalstats; 155 pktsum_t vs_prevstats[MAXVNIC]; 156 boolean_t vs_etherstub; 157 dladm_status_t vs_status; 158 uint32_t vs_flags; 159 ofmt_handle_t vs_ofmt; 160} show_vnic_state_t; 161 162typedef struct show_part_state { 163 datalink_id_t ps_over_id; 164 char ps_part[MAXLINKNAMELEN]; 165 boolean_t ps_parsable; 166 boolean_t ps_found; 167 dladm_status_t ps_status; 168 uint32_t ps_flags; 169 ofmt_handle_t ps_ofmt; 170} show_part_state_t; 171 172typedef struct show_ib_state { 173 datalink_id_t is_link_id; 174 char is_link[MAXLINKNAMELEN]; 175 boolean_t is_parsable; 176 dladm_status_t is_status; 177 uint32_t is_flags; 178 ofmt_handle_t is_ofmt; 179} show_ib_state_t; 180 181typedef struct show_usage_state_s { 182 boolean_t us_plot; 183 boolean_t us_parsable; 184 boolean_t us_printheader; 185 boolean_t us_first; 186 boolean_t us_showall; 187 ofmt_handle_t us_ofmt; 188} show_usage_state_t; 189 190/* 191 * callback functions for printing output and error diagnostics. 192 */ 193static ofmt_cb_t print_default_cb, print_link_stats_cb, print_linkprop_cb; 194static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb; 195static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb; 196static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb; 197static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb; 198 199typedef void cmdfunc_t(int, char **, const char *); 200 201static cmdfunc_t do_show_link, do_show_wifi, do_show_phys; 202static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 203static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr; 204static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 205static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 206static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 207static cmdfunc_t do_init_linkprop, do_init_secobj; 208static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan; 209static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys; 210static cmdfunc_t do_show_linkmap; 211static cmdfunc_t do_show_ether; 212static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic; 213static cmdfunc_t do_up_vnic; 214static cmdfunc_t do_create_part, do_delete_part, do_show_part, do_show_ib; 215static cmdfunc_t do_up_part; 216static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub; 217static cmdfunc_t do_create_simnet, do_modify_simnet; 218static cmdfunc_t do_delete_simnet, do_show_simnet, do_up_simnet; 219static cmdfunc_t do_show_usage; 220static cmdfunc_t do_create_bridge, do_modify_bridge, do_delete_bridge; 221static cmdfunc_t do_add_bridge, do_remove_bridge, do_show_bridge; 222static cmdfunc_t do_create_iptun, do_modify_iptun, do_delete_iptun; 223static cmdfunc_t do_show_iptun, do_up_iptun, do_down_iptun; 224 225static void do_up_vnic_common(int, char **, const char *, boolean_t); 226 227static int show_part(dladm_handle_t, datalink_id_t, void *); 228 229static void altroot_cmd(char *, int, char **); 230static int show_linkprop_onelink(dladm_handle_t, datalink_id_t, void *); 231 232static void link_stats(datalink_id_t, uint_t, char *, show_state_t *); 233static void aggr_stats(datalink_id_t, show_grp_state_t *, uint_t); 234static void vnic_stats(show_vnic_state_t *, uint32_t); 235 236static int get_one_kstat(const char *, const char *, uint8_t, 237 void *, boolean_t); 238static void get_mac_stats(const char *, pktsum_t *); 239static void get_link_stats(const char *, pktsum_t *); 240static uint64_t get_ifspeed(const char *, boolean_t); 241static const char *get_linkstate(const char *, boolean_t, char *); 242static const char *get_linkduplex(const char *, boolean_t, char *); 243 244static iptun_type_t iptun_gettypebyname(char *); 245static const char *iptun_gettypebyvalue(iptun_type_t); 246static dladm_status_t print_iptun(dladm_handle_t, datalink_id_t, 247 show_state_t *); 248static int print_iptun_walker(dladm_handle_t, datalink_id_t, void *); 249 250static int show_etherprop(dladm_handle_t, datalink_id_t, void *); 251static void show_ether_xprop(void *, dladm_ether_info_t *); 252static boolean_t link_is_ether(const char *, datalink_id_t *); 253 254static boolean_t str2int(const char *, int *); 255static void die(const char *, ...); 256static void die_optdup(int); 257static void die_opterr(int, int, const char *); 258static void die_dlerr(dladm_status_t, const char *, ...); 259static void warn(const char *, ...); 260static void warn_dlerr(dladm_status_t, const char *, ...); 261 262typedef struct cmd { 263 char *c_name; 264 cmdfunc_t *c_fn; 265 const char *c_usage; 266} cmd_t; 267 268static cmd_t cmds[] = { 269 { "rename-link", do_rename_link, 270 " rename-link <oldlink> <newlink>" }, 271 { "show-link", do_show_link, 272 " show-link [-pP] [-o <field>,..] [-s [-i <interval>]] " 273 "[<link>]\n" }, 274 { "create-aggr", do_create_aggr, 275 " create-aggr [-t] [-P <policy>] [-L <mode>] [-T <time>] " 276 "[-u <address>]\n" 277 "\t\t -l <link> [-l <link>...] <link>" }, 278 { "delete-aggr", do_delete_aggr, 279 " delete-aggr [-t] <link>" }, 280 { "add-aggr", do_add_aggr, 281 " add-aggr [-t] -l <link> [-l <link>...] <link>" }, 282 { "remove-aggr", do_remove_aggr, 283 " remove-aggr [-t] -l <link> [-l <link>...] <link>" }, 284 { "modify-aggr", do_modify_aggr, 285 " modify-aggr [-t] [-P <policy>] [-L <mode>] [-T <time>] " 286 "[-u <address>]\n" 287 "\t\t <link>" }, 288 { "show-aggr", do_show_aggr, 289 " show-aggr [-pPLx] [-o <field>,..] [-s [-i <interval>]] " 290 "[<link>]\n" }, 291 { "up-aggr", do_up_aggr, NULL }, 292 { "scan-wifi", do_scan_wifi, 293 " scan-wifi [-p] [-o <field>,...] [<link>]" }, 294 { "connect-wifi", do_connect_wifi, 295 " connect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...] " 296 "[-s wep|wpa]\n" 297 "\t\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g] " 298 "[-T <time>]\n" 299 "\t\t [<link>]" }, 300 { "disconnect-wifi", do_disconnect_wifi, 301 " disconnect-wifi [-a] [<link>]" }, 302 { "show-wifi", do_show_wifi, 303 " show-wifi [-p] [-o <field>,...] [<link>]\n" }, 304 { "set-linkprop", do_set_linkprop, 305 " set-linkprop [-t] -p <prop>=<value>[,...] <name>" }, 306 { "reset-linkprop", do_reset_linkprop, 307 " reset-linkprop [-t] [-p <prop>,...] <name>" }, 308 { "show-linkprop", do_show_linkprop, 309 " show-linkprop [-cP] [-o <field>,...] [-p <prop>,...] " 310 "<name>\n" }, 311 { "show-ether", do_show_ether, 312 " show-ether [-px][-o <field>,...] <link>\n" }, 313 { "create-secobj", do_create_secobj, 314 " create-secobj [-t] [-f <file>] -c <class> <secobj>" }, 315 { "delete-secobj", do_delete_secobj, 316 " delete-secobj [-t] <secobj>[,...]" }, 317 { "show-secobj", do_show_secobj, 318 " show-secobj [-pP] [-o <field>,...] [<secobj>,...]\n" }, 319 { "init-linkprop", do_init_linkprop, NULL }, 320 { "init-secobj", do_init_secobj, NULL }, 321 { "create-vlan", do_create_vlan, 322 " create-vlan [-ft] -l <link> -v <vid> [link]" }, 323 { "delete-vlan", do_delete_vlan, 324 " delete-vlan [-t] <link>" }, 325 { "show-vlan", do_show_vlan, 326 " show-vlan [-pP] [-o <field>,..] [<link>]\n" }, 327 { "up-vlan", do_up_vlan, NULL }, 328 { "create-iptun", do_create_iptun, 329 " create-iptun [-t] -T <type> " 330 "[-a {local|remote}=<addr>,...] <link>]" }, 331 { "delete-iptun", do_delete_iptun, 332 " delete-iptun [-t] <link>" }, 333 { "modify-iptun", do_modify_iptun, 334 " modify-iptun [-t] -a {local|remote}=<addr>,... <link>" }, 335 { "show-iptun", do_show_iptun, 336 " show-iptun [-pP] [-o <field>,..] [<link>]\n" }, 337 { "up-iptun", do_up_iptun, NULL }, 338 { "down-iptun", do_down_iptun, NULL }, 339 { "delete-phys", do_delete_phys, 340 " delete-phys <link>" }, 341 { "show-phys", do_show_phys, 342 " show-phys [-m | -H | -P] [[-p] [-o <field>[,...]] " 343 "[<link>]\n" }, 344 { "init-phys", do_init_phys, NULL }, 345 { "show-linkmap", do_show_linkmap, NULL }, 346 { "create-vnic", do_create_vnic, 347 " create-vnic [-t] -l <link> [-m <value> | auto |\n" 348 "\t\t {factory [-n <slot-id>]} | {random [-r <prefix>]} |\n" 349 "\t\t {vrrp -V <vrid> -A {inet | inet6}} [-v <vid> [-f]]\n" 350 "\t\t [-p <prop>=<value>[,...]] <vnic-link>" }, 351 { "delete-vnic", do_delete_vnic, 352 " delete-vnic [-t] <vnic-link>" }, 353 { "show-vnic", do_show_vnic, 354 " show-vnic [-pP] [-l <link>] [-s [-i <interval>]] " 355 "[<link>]\n" }, 356 { "up-vnic", do_up_vnic, NULL }, 357 { "create-part", do_create_part, 358 " create-part [-t] [-f] -l <link> [-P <pkey>]\n" 359 "\t\t [-R <root-dir>] <part-link>" }, 360 { "delete-part", do_delete_part, 361 " delete-part [-t] [-R <root-dir>] <part-link>"}, 362 { "show-part", do_show_part, 363 " show-part [-pP] [-o <field>,...][-l <linkover>]\n" 364 "\t\t [<part-link>]" }, 365 { "show-ib", do_show_ib, 366 " show-ib [-p] [-o <field>,...] [<link>]\n" }, 367 { "up-part", do_up_part, NULL }, 368 { "create-etherstub", do_create_etherstub, 369 " create-etherstub [-t] <link>" }, 370 { "delete-etherstub", do_delete_etherstub, 371 " delete-etherstub [-t] <link>" }, 372 { "show-etherstub", do_show_etherstub, 373 " show-etherstub [-t] [<link>]\n" }, 374 { "create-simnet", do_create_simnet, NULL }, 375 { "modify-simnet", do_modify_simnet, NULL }, 376 { "delete-simnet", do_delete_simnet, NULL }, 377 { "show-simnet", do_show_simnet, NULL }, 378 { "up-simnet", do_up_simnet, NULL }, 379 { "create-bridge", do_create_bridge, 380 " create-bridge [-R <root-dir>] [-P <protect>] " 381 "[-p <priority>]\n" 382 "\t\t [-m <max-age>] [-h <hello-time>] [-d <forward-delay>]\n" 383 "\t\t [-f <force-protocol>] [-l <link>]... <bridge>" }, 384 { "modify-bridge", do_modify_bridge, 385 " modify-bridge [-R <root-dir>] [-P <protect>] " 386 "[-p <priority>]\n" 387 "\t\t [-m <max-age>] [-h <hello-time>] [-d <forward-delay>]\n" 388 "\t\t [-f <force-protocol>] <bridge>" }, 389 { "delete-bridge", do_delete_bridge, 390 " delete-bridge [-R <root-dir>] <bridge>" }, 391 { "add-bridge", do_add_bridge, 392 " add-bridge [-R <root-dir>] -l <link> [-l <link>]... " 393 "<bridge>" }, 394 { "remove-bridge", do_remove_bridge, 395 " remove-bridge [-R <root-dir>] -l <link> [-l <link>]... " 396 "<bridge>" }, 397 { "show-bridge", do_show_bridge, 398 " show-bridge [-p] [-o <field>,...] [-s [-i <interval>]] " 399 "[<bridge>]\n" 400 " show-bridge -l [-p] [-o <field>,...] [-s [-i <interval>]]" 401 " <bridge>\n" 402 " show-bridge -f [-p] [-o <field>,...] [-s [-i <interval>]]" 403 " <bridge>\n" 404 " show-bridge -t [-p] [-o <field>,...] [-s [-i <interval>]]" 405 " <bridge>\n" }, 406 { "show-usage", do_show_usage, 407 " show-usage [-a] [-d | -F <format>] " 408 "[-s <DD/MM/YYYY,HH:MM:SS>]\n" 409 "\t\t [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<link>]" } 410}; 411 412static const struct option lopts[] = { 413 {"vlan-id", required_argument, 0, 'v'}, 414 {"output", required_argument, 0, 'o'}, 415 {"dev", required_argument, 0, 'd'}, 416 {"policy", required_argument, 0, 'P'}, 417 {"lacp-mode", required_argument, 0, 'L'}, 418 {"lacp-timer", required_argument, 0, 'T'}, 419 {"unicast", required_argument, 0, 'u'}, 420 {"temporary", no_argument, 0, 't'}, 421 {"root-dir", required_argument, 0, 'R'}, 422 {"link", required_argument, 0, 'l'}, 423 {"forcible", no_argument, 0, 'f'}, 424 {"bw-limit", required_argument, 0, 'b'}, 425 {"mac-address", required_argument, 0, 'm'}, 426 {"slot", required_argument, 0, 'n'}, 427 { NULL, 0, NULL, 0 } 428}; 429 430static const struct option show_lopts[] = { 431 {"statistics", no_argument, 0, 's'}, 432 {"continuous", no_argument, 0, 'S'}, 433 {"interval", required_argument, 0, 'i'}, 434 {"parsable", no_argument, 0, 'p'}, 435 {"parseable", no_argument, 0, 'p'}, 436 {"extended", no_argument, 0, 'x'}, 437 {"output", required_argument, 0, 'o'}, 438 {"persistent", no_argument, 0, 'P'}, 439 {"lacp", no_argument, 0, 'L'}, 440 { NULL, 0, NULL, 0 } 441}; 442 443static const struct option iptun_lopts[] = { 444 {"output", required_argument, 0, 'o'}, 445 {"tunnel-type", required_argument, 0, 'T'}, 446 {"address", required_argument, 0, 'a'}, 447 {"root-dir", required_argument, 0, 'R'}, 448 {"parsable", no_argument, 0, 'p'}, 449 {"parseable", no_argument, 0, 'p'}, 450 {"persistent", no_argument, 0, 'P'}, 451 { NULL, 0, NULL, 0 } 452}; 453 454static char * const iptun_addropts[] = { 455#define IPTUN_LOCAL 0 456 "local", 457#define IPTUN_REMOTE 1 458 "remote", 459 NULL}; 460 461static const struct { 462 const char *type_name; 463 iptun_type_t type_value; 464} iptun_types[] = { 465 {"ipv4", IPTUN_TYPE_IPV4}, 466 {"ipv6", IPTUN_TYPE_IPV6}, 467 {"6to4", IPTUN_TYPE_6TO4}, 468 {NULL, 0} 469}; 470 471static const struct option prop_longopts[] = { 472 {"temporary", no_argument, 0, 't' }, 473 {"output", required_argument, 0, 'o' }, 474 {"root-dir", required_argument, 0, 'R' }, 475 {"prop", required_argument, 0, 'p' }, 476 {"parsable", no_argument, 0, 'c' }, 477 {"parseable", no_argument, 0, 'c' }, 478 {"persistent", no_argument, 0, 'P' }, 479 { NULL, 0, NULL, 0 } 480}; 481 482static const struct option wifi_longopts[] = { 483 {"parsable", no_argument, 0, 'p' }, 484 {"parseable", no_argument, 0, 'p' }, 485 {"output", required_argument, 0, 'o' }, 486 {"essid", required_argument, 0, 'e' }, 487 {"bsstype", required_argument, 0, 'b' }, 488 {"mode", required_argument, 0, 'm' }, 489 {"key", required_argument, 0, 'k' }, 490 {"sec", required_argument, 0, 's' }, 491 {"auth", required_argument, 0, 'a' }, 492 {"create-ibss", required_argument, 0, 'c' }, 493 {"timeout", required_argument, 0, 'T' }, 494 {"all-links", no_argument, 0, 'a' }, 495 {"temporary", no_argument, 0, 't' }, 496 {"root-dir", required_argument, 0, 'R' }, 497 {"persistent", no_argument, 0, 'P' }, 498 {"file", required_argument, 0, 'f' }, 499 { NULL, 0, NULL, 0 } 500}; 501 502static const struct option showeth_lopts[] = { 503 {"parsable", no_argument, 0, 'p' }, 504 {"parseable", no_argument, 0, 'p' }, 505 {"extended", no_argument, 0, 'x' }, 506 {"output", required_argument, 0, 'o' }, 507 { NULL, 0, NULL, 0 } 508}; 509 510static const struct option vnic_lopts[] = { 511 {"temporary", no_argument, 0, 't' }, 512 {"root-dir", required_argument, 0, 'R' }, 513 {"dev", required_argument, 0, 'd' }, 514 {"mac-address", required_argument, 0, 'm' }, 515 {"cpus", required_argument, 0, 'c' }, 516 {"bw-limit", required_argument, 0, 'b' }, 517 {"slot", required_argument, 0, 'n' }, 518 {"mac-prefix", required_argument, 0, 'r' }, 519 {"vrid", required_argument, 0, 'V' }, 520 {"address-family", required_argument, 0, 'A' }, 521 { NULL, 0, NULL, 0 } 522}; 523 524static const struct option part_lopts[] = { 525 {"temporary", no_argument, 0, 't' }, 526 {"pkey", required_argument, 0, 'P' }, 527 {"link", required_argument, 0, 'l' }, 528 {"force", no_argument, 0, 'f' }, 529 {"root-dir", required_argument, 0, 'R' }, 530 {"prop", required_argument, 0, 'p' }, 531 { NULL, 0, NULL, 0 } 532}; 533 534static const struct option show_part_lopts[] = { 535 {"parsable", no_argument, 0, 'p' }, 536 {"parseable", no_argument, 0, 'p' }, 537 {"link", required_argument, 0, 'l' }, 538 {"persistent", no_argument, 0, 'P' }, 539 {"output", required_argument, 0, 'o' }, 540 { NULL, 0, NULL, 0 } 541}; 542 543static const struct option etherstub_lopts[] = { 544 {"temporary", no_argument, 0, 't' }, 545 {"root-dir", required_argument, 0, 'R' }, 546 { NULL, 0, NULL, 0 } 547}; 548 549static const struct option usage_opts[] = { 550 {"file", required_argument, 0, 'f' }, 551 {"format", required_argument, 0, 'F' }, 552 {"start", required_argument, 0, 's' }, 553 {"stop", required_argument, 0, 'e' }, 554 { NULL, 0, NULL, 0 } 555}; 556 557static const struct option simnet_lopts[] = { 558 {"temporary", no_argument, 0, 't' }, 559 {"root-dir", required_argument, 0, 'R' }, 560 {"media", required_argument, 0, 'm' }, 561 {"peer", required_argument, 0, 'p' }, 562 { NULL, 0, NULL, 0 } 563}; 564 565static const struct option bridge_lopts[] = { 566 { "protect", required_argument, 0, 'P' }, 567 { "root-dir", required_argument, 0, 'R' }, 568 { "forward-delay", required_argument, 0, 'd' }, 569 { "force-protocol", required_argument, 0, 'f' }, 570 { "hello-time", required_argument, 0, 'h' }, 571 { "link", required_argument, 0, 'l' }, 572 { "max-age", required_argument, 0, 'm' }, 573 { "priority", required_argument, 0, 'p' }, 574 { NULL, 0, NULL, 0 } 575}; 576 577static const struct option bridge_show_lopts[] = { 578 { "forwarding", no_argument, 0, 'f' }, 579 { "interval", required_argument, 0, 'i' }, 580 { "link", no_argument, 0, 'l' }, 581 { "output", required_argument, 0, 'o' }, 582 { "parsable", no_argument, 0, 'p' }, 583 { "parseable", no_argument, 0, 'p' }, 584 { "statistics", no_argument, 0, 's' }, 585 { "trill", no_argument, 0, 't' }, 586 { NULL, 0, NULL, 0 } 587}; 588 589/* 590 * structures for 'dladm show-ether' 591 */ 592static const char *ptype[] = {LEI_ATTR_NAMES}; 593 594typedef struct ether_fields_buf_s 595{ 596 char eth_link[15]; 597 char eth_ptype[8]; 598 char eth_state[8]; 599 char eth_autoneg[5]; 600 char eth_spdx[31]; 601 char eth_pause[6]; 602 char eth_rem_fault[16]; 603} ether_fields_buf_t; 604 605static const ofmt_field_t ether_fields[] = { 606/* name, field width, offset callback */ 607{ "LINK", 16, 608 offsetof(ether_fields_buf_t, eth_link), print_default_cb}, 609{ "PTYPE", 9, 610 offsetof(ether_fields_buf_t, eth_ptype), print_default_cb}, 611{ "STATE", 9, 612 offsetof(ether_fields_buf_t, eth_state), 613 print_default_cb}, 614{ "AUTO", 6, 615 offsetof(ether_fields_buf_t, eth_autoneg), print_default_cb}, 616{ "SPEED-DUPLEX", 32, 617 offsetof(ether_fields_buf_t, eth_spdx), print_default_cb}, 618{ "PAUSE", 7, 619 offsetof(ether_fields_buf_t, eth_pause), print_default_cb}, 620{ "REM_FAULT", 17, 621 offsetof(ether_fields_buf_t, eth_rem_fault), print_default_cb}, 622{NULL, 0, 623 0, NULL}} 624; 625 626typedef struct print_ether_state { 627 const char *es_link; 628 boolean_t es_parsable; 629 boolean_t es_header; 630 boolean_t es_extended; 631 ofmt_handle_t es_ofmt; 632} print_ether_state_t; 633 634/* 635 * structures for 'dladm show-link -s' (print statistics) 636 */ 637typedef enum { 638 LINK_S_LINK, 639 LINK_S_IPKTS, 640 LINK_S_RBYTES, 641 LINK_S_IERRORS, 642 LINK_S_OPKTS, 643 LINK_S_OBYTES, 644 LINK_S_OERRORS 645} link_s_field_index_t; 646 647static const ofmt_field_t link_s_fields[] = { 648/* name, field width, index, callback */ 649{ "LINK", 15, LINK_S_LINK, print_link_stats_cb}, 650{ "IPACKETS", 10, LINK_S_IPKTS, print_link_stats_cb}, 651{ "RBYTES", 8, LINK_S_RBYTES, print_link_stats_cb}, 652{ "IERRORS", 10, LINK_S_IERRORS, print_link_stats_cb}, 653{ "OPACKETS", 12, LINK_S_OPKTS, print_link_stats_cb}, 654{ "OBYTES", 12, LINK_S_OBYTES, print_link_stats_cb}, 655{ "OERRORS", 8, LINK_S_OERRORS, print_link_stats_cb}, 656{ NULL, 0, 0, NULL}}; 657 658typedef struct link_args_s { 659 char *link_s_link; 660 pktsum_t *link_s_psum; 661} link_args_t; 662 663/* 664 * buffer used by print functions for show-{link,phys,vlan} commands. 665 */ 666typedef struct link_fields_buf_s { 667 char link_name[MAXLINKNAMELEN]; 668 char link_class[DLADM_STRSIZE]; 669 char link_mtu[11]; 670 char link_state[DLADM_STRSIZE]; 671 char link_bridge[MAXLINKNAMELEN * MAXPORT]; 672 char link_over[MAXLINKNAMELEN * MAXPORT]; 673 char link_phys_state[DLADM_STRSIZE]; 674 char link_phys_media[DLADM_STRSIZE]; 675 char link_phys_speed[DLADM_STRSIZE]; 676 char link_phys_duplex[DLPI_LINKNAME_MAX]; 677 char link_phys_device[DLPI_LINKNAME_MAX]; 678 char link_flags[6]; 679 char link_vlan_vid[6]; 680} link_fields_buf_t; 681 682/* 683 * structures for 'dladm show-link' 684 */ 685static const ofmt_field_t link_fields[] = { 686/* name, field width, index, callback */ 687{ "LINK", 12, 688 offsetof(link_fields_buf_t, link_name), print_default_cb}, 689{ "CLASS", 10, 690 offsetof(link_fields_buf_t, link_class), print_default_cb}, 691{ "MTU", 7, 692 offsetof(link_fields_buf_t, link_mtu), print_default_cb}, 693{ "STATE", 9, 694 offsetof(link_fields_buf_t, link_state), print_default_cb}, 695{ "BRIDGE", 11, 696 offsetof(link_fields_buf_t, link_bridge), print_default_cb}, 697{ "OVER", 30, 698 offsetof(link_fields_buf_t, link_over), print_default_cb}, 699{ NULL, 0, 0, NULL}} 700; 701 702/* 703 * structures for 'dladm show-aggr' 704 */ 705typedef struct laggr_fields_buf_s { 706 char laggr_name[DLPI_LINKNAME_MAX]; 707 char laggr_policy[9]; 708 char laggr_addrpolicy[ETHERADDRL * 3 + 3]; 709 char laggr_lacpactivity[14]; 710 char laggr_lacptimer[DLADM_STRSIZE]; 711 char laggr_flags[7]; 712} laggr_fields_buf_t; 713 714typedef struct laggr_args_s { 715 int laggr_lport; /* -1 indicates the aggr itself */ 716 const char *laggr_link; 717 dladm_aggr_grp_attr_t *laggr_ginfop; 718 dladm_status_t *laggr_status; 719 pktsum_t *laggr_pktsumtot; /* -s only */ 720 pktsum_t *laggr_diffstats; /* -s only */ 721 boolean_t laggr_parsable; 722} laggr_args_t; 723 724static const ofmt_field_t laggr_fields[] = { 725/* name, field width, offset, callback */ 726{ "LINK", 16, 727 offsetof(laggr_fields_buf_t, laggr_name), print_default_cb}, 728{ "POLICY", 9, 729 offsetof(laggr_fields_buf_t, laggr_policy), print_default_cb}, 730{ "ADDRPOLICY", ETHERADDRL * 3 + 3, 731 offsetof(laggr_fields_buf_t, laggr_addrpolicy), print_default_cb}, 732{ "LACPACTIVITY", 14, 733 offsetof(laggr_fields_buf_t, laggr_lacpactivity), print_default_cb}, 734{ "LACPTIMER", 12, 735 offsetof(laggr_fields_buf_t, laggr_lacptimer), print_default_cb}, 736{ "FLAGS", 8, 737 offsetof(laggr_fields_buf_t, laggr_flags), print_default_cb}, 738{ NULL, 0, 0, NULL}} 739; 740 741/* 742 * structures for 'dladm show-aggr -x'. 743 */ 744typedef enum { 745 AGGR_X_LINK, 746 AGGR_X_PORT, 747 AGGR_X_SPEED, 748 AGGR_X_DUPLEX, 749 AGGR_X_STATE, 750 AGGR_X_ADDRESS, 751 AGGR_X_PORTSTATE 752} aggr_x_field_index_t; 753 754static const ofmt_field_t aggr_x_fields[] = { 755/* name, field width, index callback */ 756{ "LINK", 12, AGGR_X_LINK, print_xaggr_cb}, 757{ "PORT", 15, AGGR_X_PORT, print_xaggr_cb}, 758{ "SPEED", 5, AGGR_X_SPEED, print_xaggr_cb}, 759{ "DUPLEX", 10, AGGR_X_DUPLEX, print_xaggr_cb}, 760{ "STATE", 10, AGGR_X_STATE, print_xaggr_cb}, 761{ "ADDRESS", 19, AGGR_X_ADDRESS, print_xaggr_cb}, 762{ "PORTSTATE", 16, AGGR_X_PORTSTATE, print_xaggr_cb}, 763{ NULL, 0, 0, NULL}} 764; 765 766/* 767 * structures for 'dladm show-aggr -s'. 768 */ 769typedef enum { 770 AGGR_S_LINK, 771 AGGR_S_PORT, 772 AGGR_S_IPKTS, 773 AGGR_S_RBYTES, 774 AGGR_S_OPKTS, 775 AGGR_S_OBYTES, 776 AGGR_S_IPKTDIST, 777 AGGR_S_OPKTDIST 778} aggr_s_field_index_t; 779 780static const ofmt_field_t aggr_s_fields[] = { 781{ "LINK", 12, AGGR_S_LINK, print_aggr_stats_cb}, 782{ "PORT", 10, AGGR_S_PORT, print_aggr_stats_cb}, 783{ "IPACKETS", 8, AGGR_S_IPKTS, print_aggr_stats_cb}, 784{ "RBYTES", 8, AGGR_S_RBYTES, print_aggr_stats_cb}, 785{ "OPACKETS", 8, AGGR_S_OPKTS, print_aggr_stats_cb}, 786{ "OBYTES", 8, AGGR_S_OBYTES, print_aggr_stats_cb}, 787{ "IPKTDIST", 9, AGGR_S_IPKTDIST, print_aggr_stats_cb}, 788{ "OPKTDIST", 15, AGGR_S_OPKTDIST, print_aggr_stats_cb}, 789{ NULL, 0, 0, NULL}} 790; 791 792/* 793 * structures for 'dladm show-aggr -L'. 794 */ 795typedef enum { 796 AGGR_L_LINK, 797 AGGR_L_PORT, 798 AGGR_L_AGGREGATABLE, 799 AGGR_L_SYNC, 800 AGGR_L_COLL, 801 AGGR_L_DIST, 802 AGGR_L_DEFAULTED, 803 AGGR_L_EXPIRED 804} aggr_l_field_index_t; 805 806static const ofmt_field_t aggr_l_fields[] = { 807/* name, field width, index */ 808{ "LINK", 12, AGGR_L_LINK, print_lacp_cb}, 809{ "PORT", 13, AGGR_L_PORT, print_lacp_cb}, 810{ "AGGREGATABLE", 13, AGGR_L_AGGREGATABLE, print_lacp_cb}, 811{ "SYNC", 5, AGGR_L_SYNC, print_lacp_cb}, 812{ "COLL", 5, AGGR_L_COLL, print_lacp_cb}, 813{ "DIST", 5, AGGR_L_DIST, print_lacp_cb}, 814{ "DEFAULTED", 10, AGGR_L_DEFAULTED, print_lacp_cb}, 815{ "EXPIRED", 15, AGGR_L_EXPIRED, print_lacp_cb}, 816{ NULL, 0, 0, NULL}} 817; 818 819/* 820 * structures for 'dladm show-phys' 821 */ 822 823static const ofmt_field_t phys_fields[] = { 824/* name, field width, offset */ 825{ "LINK", 13, 826 offsetof(link_fields_buf_t, link_name), print_default_cb}, 827{ "MEDIA", 21, 828 offsetof(link_fields_buf_t, link_phys_media), print_default_cb}, 829{ "STATE", 11, 830 offsetof(link_fields_buf_t, link_phys_state), print_default_cb}, 831{ "SPEED", 7, 832 offsetof(link_fields_buf_t, link_phys_speed), print_default_cb}, 833{ "DUPLEX", 10, 834 offsetof(link_fields_buf_t, link_phys_duplex), print_default_cb}, 835{ "DEVICE", 13, 836 offsetof(link_fields_buf_t, link_phys_device), print_default_cb}, 837{ "FLAGS", 7, 838 offsetof(link_fields_buf_t, link_flags), print_default_cb}, 839{ NULL, 0, 0, NULL}} 840; 841 842/* 843 * structures for 'dladm show-phys -m' 844 */ 845 846typedef enum { 847 PHYS_M_LINK, 848 PHYS_M_SLOT, 849 PHYS_M_ADDRESS, 850 PHYS_M_INUSE, 851 PHYS_M_CLIENT 852} phys_m_field_index_t; 853 854static const ofmt_field_t phys_m_fields[] = { 855/* name, field width, offset */ 856{ "LINK", 13, PHYS_M_LINK, print_phys_one_mac_cb}, 857{ "SLOT", 9, PHYS_M_SLOT, print_phys_one_mac_cb}, 858{ "ADDRESS", 19, PHYS_M_ADDRESS, print_phys_one_mac_cb}, 859{ "INUSE", 5, PHYS_M_INUSE, print_phys_one_mac_cb}, 860{ "CLIENT", 13, PHYS_M_CLIENT, print_phys_one_mac_cb}, 861{ NULL, 0, 0, NULL}} 862; 863 864/* 865 * structures for 'dladm show-phys -H' 866 */ 867 868typedef enum { 869 PHYS_H_LINK, 870 PHYS_H_RINGTYPE, 871 PHYS_H_RINGS, 872 PHYS_H_CLIENTS 873} phys_h_field_index_t; 874 875#define RINGSTRLEN 21 876 877static const ofmt_field_t phys_h_fields[] = { 878{ "LINK", 13, PHYS_H_LINK, print_phys_one_hwgrp_cb}, 879{ "RINGTYPE", 9, PHYS_H_RINGTYPE, print_phys_one_hwgrp_cb}, 880{ "RINGS", RINGSTRLEN, PHYS_H_RINGS, print_phys_one_hwgrp_cb}, 881{ "CLIENTS", 24, PHYS_H_CLIENTS, print_phys_one_hwgrp_cb}, 882{ NULL, 0, 0, NULL}} 883; 884 885/* 886 * structures for 'dladm show-vlan' 887 */ 888static const ofmt_field_t vlan_fields[] = { 889{ "LINK", 16, 890 offsetof(link_fields_buf_t, link_name), print_default_cb}, 891{ "VID", 9, 892 offsetof(link_fields_buf_t, link_vlan_vid), print_default_cb}, 893{ "OVER", 13, 894 offsetof(link_fields_buf_t, link_over), print_default_cb}, 895{ "FLAGS", 7, 896 offsetof(link_fields_buf_t, link_flags), print_default_cb}, 897{ NULL, 0, 0, NULL}} 898; 899 900/* 901 * structures common to 'dladm scan-wifi' and 'dladm show-wifi' 902 * callback will be determined in parse_wifi_fields. 903 */ 904static ofmt_field_t wifi_common_fields[] = { 905{ "LINK", 11, 0, NULL}, 906{ "ESSID", 20, DLADM_WLAN_ATTR_ESSID, NULL}, 907{ "BSSID", 18, DLADM_WLAN_ATTR_BSSID, NULL}, 908{ "IBSSID", 18, DLADM_WLAN_ATTR_BSSID, NULL}, 909{ "MODE", 7, DLADM_WLAN_ATTR_MODE, NULL}, 910{ "SPEED", 7, DLADM_WLAN_ATTR_SPEED, NULL}, 911{ "BSSTYPE", 9, DLADM_WLAN_ATTR_BSSTYPE, NULL}, 912{ "SEC", 7, DLADM_WLAN_ATTR_SECMODE, NULL}, 913{ "STRENGTH", 11, DLADM_WLAN_ATTR_STRENGTH, NULL}, 914{ NULL, 0, 0, NULL}}; 915 916/* 917 * the 'show-wifi' command supports all the fields in wifi_common_fields 918 * plus the AUTH and STATUS fields. 919 */ 920static ofmt_field_t wifi_show_fields[A_CNT(wifi_common_fields) + 2] = { 921{ "AUTH", 9, DLADM_WLAN_ATTR_AUTH, NULL}, 922{ "STATUS", 18, DLADM_WLAN_LINKATTR_STATUS, print_wifi_status_cb}, 923/* copy wifi_common_fields here */ 924}; 925 926static char *all_scan_wifi_fields = 927 "link,essid,bssid,sec,strength,mode,speed,bsstype"; 928static char *all_show_wifi_fields = 929 "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 930static char *def_scan_wifi_fields = 931 "link,essid,bssid,sec,strength,mode,speed"; 932static char *def_show_wifi_fields = 933 "link,status,essid,sec,strength,mode,speed"; 934 935/* 936 * structures for 'dladm show-linkprop' 937 */ 938typedef enum { 939 LINKPROP_LINK, 940 LINKPROP_PROPERTY, 941 LINKPROP_PERM, 942 LINKPROP_VALUE, 943 LINKPROP_DEFAULT, 944 LINKPROP_POSSIBLE 945} linkprop_field_index_t; 946 947static const ofmt_field_t linkprop_fields[] = { 948/* name, field width, index */ 949{ "LINK", 13, LINKPROP_LINK, print_linkprop_cb}, 950{ "PROPERTY", 16, LINKPROP_PROPERTY, print_linkprop_cb}, 951{ "PERM", 5, LINKPROP_PERM, print_linkprop_cb}, 952{ "VALUE", 15, LINKPROP_VALUE, print_linkprop_cb}, 953{ "DEFAULT", 15, LINKPROP_DEFAULT, print_linkprop_cb}, 954{ "POSSIBLE", 20, LINKPROP_POSSIBLE, print_linkprop_cb}, 955{ NULL, 0, 0, NULL}} 956; 957 958#define MAX_PROP_LINE 512 959 960typedef struct show_linkprop_state { 961 char ls_link[MAXLINKNAMELEN]; 962 char *ls_line; 963 char **ls_propvals; 964 dladm_arg_list_t *ls_proplist; 965 boolean_t ls_parsable; 966 boolean_t ls_persist; 967 boolean_t ls_header; 968 dladm_status_t ls_status; 969 dladm_status_t ls_retstatus; 970 ofmt_handle_t ls_ofmt; 971} show_linkprop_state_t; 972 973typedef struct set_linkprop_state { 974 const char *ls_name; 975 boolean_t ls_reset; 976 boolean_t ls_temp; 977 dladm_status_t ls_status; 978} set_linkprop_state_t; 979 980typedef struct linkprop_args_s { 981 show_linkprop_state_t *ls_state; 982 char *ls_propname; 983 datalink_id_t ls_linkid; 984} linkprop_args_t; 985 986/* 987 * structures for 'dladm show-secobj' 988 */ 989typedef struct secobj_fields_buf_s { 990 char ss_obj_name[DLADM_SECOBJ_VAL_MAX]; 991 char ss_class[20]; 992 char ss_val[30]; 993} secobj_fields_buf_t; 994 995static const ofmt_field_t secobj_fields[] = { 996{ "OBJECT", 21, 997 offsetof(secobj_fields_buf_t, ss_obj_name), print_default_cb}, 998{ "CLASS", 21, 999 offsetof(secobj_fields_buf_t, ss_class), print_default_cb}, 1000{ "VALUE", 31, 1001 offsetof(secobj_fields_buf_t, ss_val), print_default_cb}, 1002{ NULL, 0, 0, NULL}} 1003; 1004 1005/* 1006 * structures for 'dladm show-vnic' 1007 */ 1008typedef struct vnic_fields_buf_s 1009{ 1010 char vnic_link[DLPI_LINKNAME_MAX]; 1011 char vnic_over[DLPI_LINKNAME_MAX]; 1012 char vnic_speed[6]; 1013 char vnic_macaddr[18]; 1014 char vnic_macaddrtype[19]; 1015 char vnic_vid[6]; 1016} vnic_fields_buf_t; 1017 1018static const ofmt_field_t vnic_fields[] = { 1019{ "LINK", 13, 1020 offsetof(vnic_fields_buf_t, vnic_link), print_default_cb}, 1021{ "OVER", 13, 1022 offsetof(vnic_fields_buf_t, vnic_over), print_default_cb}, 1023{ "SPEED", 7, 1024 offsetof(vnic_fields_buf_t, vnic_speed), print_default_cb}, 1025{ "MACADDRESS", 18, 1026 offsetof(vnic_fields_buf_t, vnic_macaddr), print_default_cb}, 1027{ "MACADDRTYPE", 20, 1028 offsetof(vnic_fields_buf_t, vnic_macaddrtype), print_default_cb}, 1029{ "VID", 7, 1030 offsetof(vnic_fields_buf_t, vnic_vid), print_default_cb}, 1031{ NULL, 0, 0, NULL}} 1032; 1033 1034/* 1035 * structures for 'dladm show-ib' 1036 */ 1037typedef struct ib_fields_buf_s 1038{ 1039 char ib_link[DLPI_LINKNAME_MAX]; 1040 char ib_hcaguid[17]; 1041 char ib_portguid[17]; 1042 char ib_portnum[4]; 1043 char ib_state[6]; 1044 char ib_pkeys[MAXPKEYSTRSZ]; 1045} ib_fields_buf_t; 1046 1047static const ofmt_field_t ib_fields[] = { 1048{ "LINK", 13, 1049 offsetof(ib_fields_buf_t, ib_link), print_default_cb}, 1050{ "HCAGUID", IBGUIDSTRLEN, 1051 offsetof(ib_fields_buf_t, ib_hcaguid), print_default_cb}, 1052{ "PORTGUID", IBGUIDSTRLEN, 1053 offsetof(ib_fields_buf_t, ib_portguid), print_default_cb}, 1054{ "PORT", IBPORTSTRLEN, 1055 offsetof(ib_fields_buf_t, ib_portnum), print_default_cb}, 1056{ "STATE", 7, 1057 offsetof(ib_fields_buf_t, ib_state), print_default_cb}, 1058{ "PKEYS", 18, 1059 offsetof(ib_fields_buf_t, ib_pkeys), print_default_cb}, 1060{ NULL, 0, 0, NULL}}; 1061 1062/* 1063 * structures for 'dladm show-part' 1064 */ 1065typedef struct part_fields_buf_s 1066{ 1067 char part_link[DLPI_LINKNAME_MAX]; 1068 char part_pkey[5]; 1069 char part_over[DLPI_LINKNAME_MAX]; 1070 char part_state[8]; 1071 char part_flags[5]; 1072} part_fields_buf_t; 1073 1074static const ofmt_field_t part_fields[] = { 1075{ "LINK", 13, 1076 offsetof(part_fields_buf_t, part_link), print_default_cb}, 1077{ "PKEY", MAXPKEYLEN, 1078 offsetof(part_fields_buf_t, part_pkey), print_default_cb}, 1079{ "OVER", 13, 1080 offsetof(part_fields_buf_t, part_over), print_default_cb}, 1081{ "STATE", 9, 1082 offsetof(part_fields_buf_t, part_state), print_default_cb}, 1083{ "FLAGS", 5, 1084 offsetof(part_fields_buf_t, part_flags), print_default_cb}, 1085{ NULL, 0, 0, NULL}}; 1086 1087/* 1088 * structures for 'dladm show-simnet' 1089 */ 1090typedef struct simnet_fields_buf_s 1091{ 1092 char simnet_name[DLPI_LINKNAME_MAX]; 1093 char simnet_media[DLADM_STRSIZE]; 1094 char simnet_macaddr[18]; 1095 char simnet_otherlink[DLPI_LINKNAME_MAX]; 1096} simnet_fields_buf_t; 1097 1098static const ofmt_field_t simnet_fields[] = { 1099{ "LINK", 12, 1100 offsetof(simnet_fields_buf_t, simnet_name), print_default_cb}, 1101{ "MEDIA", 20, 1102 offsetof(simnet_fields_buf_t, simnet_media), print_default_cb}, 1103{ "MACADDRESS", 18, 1104 offsetof(simnet_fields_buf_t, simnet_macaddr), print_default_cb}, 1105{ "OTHERLINK", 12, 1106 offsetof(simnet_fields_buf_t, simnet_otherlink), print_default_cb}, 1107{ NULL, 0, 0, NULL}} 1108; 1109 1110/* 1111 * structures for 'dladm show-usage' 1112 */ 1113 1114typedef struct usage_fields_buf_s { 1115 char usage_link[12]; 1116 char usage_duration[10]; 1117 char usage_ipackets[9]; 1118 char usage_rbytes[10]; 1119 char usage_opackets[9]; 1120 char usage_obytes[10]; 1121 char usage_bandwidth[15]; 1122} usage_fields_buf_t; 1123 1124static const ofmt_field_t usage_fields[] = { 1125{ "LINK", 13, 1126 offsetof(usage_fields_buf_t, usage_link), print_default_cb}, 1127{ "DURATION", 11, 1128 offsetof(usage_fields_buf_t, usage_duration), print_default_cb}, 1129{ "IPACKETS", 10, 1130 offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb}, 1131{ "RBYTES", 11, 1132 offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb}, 1133{ "OPACKETS", 10, 1134 offsetof(usage_fields_buf_t, usage_opackets), print_default_cb}, 1135{ "OBYTES", 11, 1136 offsetof(usage_fields_buf_t, usage_obytes), print_default_cb}, 1137{ "BANDWIDTH", 16, 1138 offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb}, 1139{ NULL, 0, 0, NULL}} 1140; 1141 1142 1143/* 1144 * structures for 'dladm show-usage link' 1145 */ 1146 1147typedef struct usage_l_fields_buf_s { 1148 char usage_l_link[12]; 1149 char usage_l_stime[13]; 1150 char usage_l_etime[13]; 1151 char usage_l_rbytes[8]; 1152 char usage_l_obytes[8]; 1153 char usage_l_bandwidth[15]; 1154} usage_l_fields_buf_t; 1155 1156static const ofmt_field_t usage_l_fields[] = { 1157/* name, field width, offset */ 1158{ "LINK", 13, 1159 offsetof(usage_l_fields_buf_t, usage_l_link), print_default_cb}, 1160{ "START", 14, 1161 offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb}, 1162{ "END", 14, 1163 offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb}, 1164{ "RBYTES", 9, 1165 offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb}, 1166{ "OBYTES", 9, 1167 offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb}, 1168{ "BANDWIDTH", 16, 1169 offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb}, 1170{ NULL, 0, 0, NULL}} 1171; 1172 1173/* IPTUN_*FLAG_INDEX values are indices into iptun_flags below. */ 1174enum { IPTUN_SFLAG_INDEX, IPTUN_IFLAG_INDEX, IPTUN_NUM_FLAGS }; 1175 1176/* 1177 * structures for 'dladm show-iptun' 1178 */ 1179typedef struct iptun_fields_buf_s { 1180 char iptun_name[MAXLINKNAMELEN]; 1181 char iptun_type[5]; 1182 char iptun_laddr[NI_MAXHOST]; 1183 char iptun_raddr[NI_MAXHOST]; 1184 char iptun_flags[IPTUN_NUM_FLAGS + 1]; 1185} iptun_fields_buf_t; 1186 1187static const ofmt_field_t iptun_fields[] = { 1188{ "LINK", 16, 1189 offsetof(iptun_fields_buf_t, iptun_name), print_default_cb }, 1190{ "TYPE", 6, 1191 offsetof(iptun_fields_buf_t, iptun_type), print_default_cb }, 1192{ "FLAGS", 7, 1193 offsetof(iptun_fields_buf_t, iptun_flags), print_default_cb }, 1194{ "LOCAL", 20, 1195 offsetof(iptun_fields_buf_t, iptun_laddr), print_default_cb }, 1196{ "REMOTE", 20, 1197 offsetof(iptun_fields_buf_t, iptun_raddr), print_default_cb }, 1198{ NULL, 0, 0, NULL} 1199}; 1200 1201/* 1202 * structures for 'dladm show-bridge'. These are based on sections 14.8.1.1.3 1203 * and 14.8.1.2.2 of IEEE 802.1D-2004. 1204 */ 1205typedef struct bridge_fields_buf_s { 1206 char bridge_name[MAXLINKNAMELEN]; /* 14.4.1.2.3(b) */ 1207 char bridge_protect[7]; /* stp or trill */ 1208 char bridge_address[24]; /* 17.18.3, 7.12.5, 14.4.1.2.3(a) */ 1209 char bridge_priority[7]; /* 17.18.3 9.2.5 - only upper 4 bits */ 1210 char bridge_bmaxage[7]; /* 17.18.4 configured */ 1211 char bridge_bhellotime[7]; /* 17.18.4 configured */ 1212 char bridge_bfwddelay[7]; /* 17.18.4 configured */ 1213 char bridge_forceproto[3]; /* 17.13.4 configured */ 1214 char bridge_tctime[12]; /* 14.8.1.1.3(b) */ 1215 char bridge_tccount[12]; /* 17.17.8 */ 1216 char bridge_tchange[12]; /* 17.17.8 */ 1217 char bridge_desroot[24]; /* 17.18.6 priority "/" MAC */ 1218 char bridge_rootcost[12]; /* 17.18.6 */ 1219 char bridge_rootport[12]; /* 17.18.6 */ 1220 char bridge_maxage[7]; /* 17.18.7 for root */ 1221 char bridge_hellotime[7]; /* 17.13.6 for root */ 1222 char bridge_fwddelay[7]; /* 17.13.5 for root */ 1223 char bridge_holdtime[12]; /* 17.13.12 for root */ 1224} bridge_fields_buf_t; 1225 1226static ofmt_field_t bridge_fields[] = { 1227/* name, field width, offset, callback */ 1228{ "BRIDGE", 12, 1229 offsetof(bridge_fields_buf_t, bridge_name), print_default_cb }, 1230{ "PROTECT", 8, 1231 offsetof(bridge_fields_buf_t, bridge_protect), print_default_cb }, 1232{ "ADDRESS", 19, 1233 offsetof(bridge_fields_buf_t, bridge_address), print_default_cb }, 1234{ "PRIORITY", 9, 1235 offsetof(bridge_fields_buf_t, bridge_priority), print_default_cb }, 1236{ "BMAXAGE", 8, 1237 offsetof(bridge_fields_buf_t, bridge_bmaxage), print_default_cb }, 1238{ "BHELLOTIME", 11, 1239 offsetof(bridge_fields_buf_t, bridge_bhellotime), print_default_cb }, 1240{ "BFWDDELAY", 10, 1241 offsetof(bridge_fields_buf_t, bridge_bfwddelay), print_default_cb }, 1242{ "FORCEPROTO", 11, 1243 offsetof(bridge_fields_buf_t, bridge_forceproto), print_default_cb }, 1244{ "TCTIME", 10, 1245 offsetof(bridge_fields_buf_t, bridge_tctime), print_default_cb }, 1246{ "TCCOUNT", 10, 1247 offsetof(bridge_fields_buf_t, bridge_tccount), print_default_cb }, 1248{ "TCHANGE", 10, 1249 offsetof(bridge_fields_buf_t, bridge_tchange), print_default_cb }, 1250{ "DESROOT", 23, 1251 offsetof(bridge_fields_buf_t, bridge_desroot), print_default_cb }, 1252{ "ROOTCOST", 11, 1253 offsetof(bridge_fields_buf_t, bridge_rootcost), print_default_cb }, 1254{ "ROOTPORT", 11, 1255 offsetof(bridge_fields_buf_t, bridge_rootport), print_default_cb }, 1256{ "MAXAGE", 8, 1257 offsetof(bridge_fields_buf_t, bridge_maxage), print_default_cb }, 1258{ "HELLOTIME", 10, 1259 offsetof(bridge_fields_buf_t, bridge_hellotime), print_default_cb }, 1260{ "FWDDELAY", 9, 1261 offsetof(bridge_fields_buf_t, bridge_fwddelay), print_default_cb }, 1262{ "HOLDTIME", 9, 1263 offsetof(bridge_fields_buf_t, bridge_holdtime), print_default_cb }, 1264{ NULL, 0, 0, NULL}}; 1265 1266/* 1267 * structures for 'dladm show-bridge -l'. These are based on 14.4.1.2.3 and 1268 * 14.8.2.1.3 of IEEE 802.1D-2004. 1269 */ 1270typedef struct bridge_link_fields_buf_s { 1271 char bridgel_link[MAXLINKNAMELEN]; 1272 char bridgel_index[7]; /* 14.4.1.2.3(d1) */ 1273 char bridgel_state[11]; /* 14.8.2.1.3(b) */ 1274 char bridgel_uptime[7]; /* 14.8.2.1.3(a) */ 1275 char bridgel_opercost[7] /* 14.8.2.1.3(d) */; 1276 char bridgel_operp2p[4]; /* 14.8.2.1.3(p) */ 1277 char bridgel_operedge[4]; /* 14.8.2.1.3(k) */ 1278 char bridgel_desroot[23]; /* 14.8.2.1.3(e) */ 1279 char bridgel_descost[12]; /* 14.8.2.1.3(f) */ 1280 char bridgel_desbridge[23]; /* 14.8.2.1.3(g) */ 1281 char bridgel_desport[7]; /* 14.8.2.1.3(h) */ 1282 char bridgel_tcack[4]; /* 14.8.2.1.3(i) */ 1283} bridge_link_fields_buf_t; 1284 1285static ofmt_field_t bridge_link_fields[] = { 1286/* name, field width, offset, callback */ 1287{ "LINK", 12, 1288 offsetof(bridge_link_fields_buf_t, bridgel_link), print_default_cb }, 1289{ "INDEX", 8, 1290 offsetof(bridge_link_fields_buf_t, bridgel_index), print_default_cb }, 1291{ "STATE", 12, 1292 offsetof(bridge_link_fields_buf_t, bridgel_state), print_default_cb }, 1293{ "UPTIME", 8, 1294 offsetof(bridge_link_fields_buf_t, bridgel_uptime), print_default_cb }, 1295{ "OPERCOST", 9, 1296 offsetof(bridge_link_fields_buf_t, bridgel_opercost), print_default_cb }, 1297{ "OPERP2P", 8, 1298 offsetof(bridge_link_fields_buf_t, bridgel_operp2p), print_default_cb }, 1299{ "OPEREDGE", 9, 1300 offsetof(bridge_link_fields_buf_t, bridgel_operedge), print_default_cb }, 1301{ "DESROOT", 22, 1302 offsetof(bridge_link_fields_buf_t, bridgel_desroot), print_default_cb }, 1303{ "DESCOST", 11, 1304 offsetof(bridge_link_fields_buf_t, bridgel_descost), print_default_cb }, 1305{ "DESBRIDGE", 22, 1306 offsetof(bridge_link_fields_buf_t, bridgel_desbridge), print_default_cb }, 1307{ "DESPORT", 8, 1308 offsetof(bridge_link_fields_buf_t, bridgel_desport), print_default_cb }, 1309{ "TCACK", 6, 1310 offsetof(bridge_link_fields_buf_t, bridgel_tcack), print_default_cb }, 1311{ NULL, 0, 0, NULL}}; 1312 1313/* 1314 * structures for 'dladm show-bridge -s'. These are not based on IEEE 1315 * 802.1D-2004. 1316 */ 1317#define ULONG_DIG (((sizeof (ulong_t) * NBBY) * 3 / 10) + 1) 1318#define UINT64_DIG (((sizeof (uint64_t) * NBBY) * 3 / 10) + 1) 1319typedef struct bridge_statfields_buf_s { 1320 char bridges_name[MAXLINKNAMELEN]; 1321 char bridges_drops[UINT64_DIG]; 1322 char bridges_forwards[UINT64_DIG]; 1323 char bridges_mbcast[UINT64_DIG]; 1324 char bridges_unknown[UINT64_DIG]; 1325 char bridges_recv[UINT64_DIG]; 1326 char bridges_sent[UINT64_DIG]; 1327} bridge_statfields_buf_t; 1328 1329static ofmt_field_t bridge_statfields[] = { 1330/* name, field width, offset, callback */ 1331{ "BRIDGE", 12, 1332 offsetof(bridge_statfields_buf_t, bridges_name), print_default_cb }, 1333{ "DROPS", 12, 1334 offsetof(bridge_statfields_buf_t, bridges_drops), print_default_cb }, 1335{ "FORWARDS", 12, 1336 offsetof(bridge_statfields_buf_t, bridges_forwards), print_default_cb }, 1337{ "MBCAST", 12, 1338 offsetof(bridge_statfields_buf_t, bridges_mbcast), print_default_cb }, 1339{ "UNKNOWN", 12, 1340 offsetof(bridge_statfields_buf_t, bridges_unknown), print_default_cb }, 1341{ "RECV", 12, 1342 offsetof(bridge_statfields_buf_t, bridges_recv), print_default_cb }, 1343{ "SENT", 12, 1344 offsetof(bridge_statfields_buf_t, bridges_sent), print_default_cb }, 1345{ NULL, 0, 0, NULL}}; 1346 1347/* 1348 * structures for 'dladm show-bridge -s -l'. These are based in part on 1349 * section 14.6.1.1.3 of IEEE 802.1D-2004. 1350 */ 1351typedef struct bridge_link_statfields_buf_s { 1352 char bridgels_link[MAXLINKNAMELEN]; 1353 char bridgels_cfgbpdu[ULONG_DIG]; 1354 char bridgels_tcnbpdu[ULONG_DIG]; 1355 char bridgels_rstpbpdu[ULONG_DIG]; 1356 char bridgels_txbpdu[ULONG_DIG]; 1357 char bridgels_drops[UINT64_DIG]; /* 14.6.1.1.3(d) */ 1358 char bridgels_recv[UINT64_DIG]; /* 14.6.1.1.3(a) */ 1359 char bridgels_xmit[UINT64_DIG]; /* 14.6.1.1.3(c) */ 1360} bridge_link_statfields_buf_t; 1361 1362static ofmt_field_t bridge_link_statfields[] = { 1363/* name, field width, offset, callback */ 1364{ "LINK", 12, 1365 offsetof(bridge_link_statfields_buf_t, bridgels_link), print_default_cb }, 1366{ "CFGBPDU", 9, 1367 offsetof(bridge_link_statfields_buf_t, bridgels_cfgbpdu), 1368 print_default_cb }, 1369{ "TCNBPDU", 9, 1370 offsetof(bridge_link_statfields_buf_t, bridgels_tcnbpdu), 1371 print_default_cb }, 1372{ "RSTPBPDU", 9, 1373 offsetof(bridge_link_statfields_buf_t, bridgels_rstpbpdu), 1374 print_default_cb }, 1375{ "TXBPDU", 9, 1376 offsetof(bridge_link_statfields_buf_t, bridgels_txbpdu), print_default_cb }, 1377{ "DROPS", 9, 1378 offsetof(bridge_link_statfields_buf_t, bridgels_drops), print_default_cb }, 1379{ "RECV", 9, 1380 offsetof(bridge_link_statfields_buf_t, bridgels_recv), print_default_cb }, 1381{ "XMIT", 9, 1382 offsetof(bridge_link_statfields_buf_t, bridgels_xmit), print_default_cb }, 1383{ NULL, 0, 0, NULL}}; 1384 1385/* 1386 * structures for 'dladm show-bridge -f'. These are based in part on 1387 * section 14.7.6.3.3 of IEEE 802.1D-2004. 1388 */ 1389typedef struct bridge_fwd_fields_buf_s { 1390 char bridgef_dest[18]; /* 14.7.6.3.3(a) */ 1391 char bridgef_age[8]; 1392 char bridgef_flags[6]; 1393 char bridgef_output[MAXLINKNAMELEN]; /* 14.7.6.3.3(c) */ 1394} bridge_fwd_fields_buf_t; 1395 1396static ofmt_field_t bridge_fwd_fields[] = { 1397/* name, field width, offset, callback */ 1398{ "DEST", 17, 1399 offsetof(bridge_fwd_fields_buf_t, bridgef_dest), print_default_cb }, 1400{ "AGE", 7, 1401 offsetof(bridge_fwd_fields_buf_t, bridgef_age), print_default_cb }, 1402{ "FLAGS", 6, 1403 offsetof(bridge_fwd_fields_buf_t, bridgef_flags), print_default_cb }, 1404{ "OUTPUT", 12, 1405 offsetof(bridge_fwd_fields_buf_t, bridgef_output), print_default_cb }, 1406{ NULL, 0, 0, NULL}}; 1407 1408/* 1409 * structures for 'dladm show-bridge -t'. 1410 */ 1411typedef struct bridge_trill_fields_buf_s { 1412 char bridget_nick[6]; 1413 char bridget_flags[6]; 1414 char bridget_link[MAXLINKNAMELEN]; 1415 char bridget_nexthop[18]; 1416} bridge_trill_fields_buf_t; 1417 1418static ofmt_field_t bridge_trill_fields[] = { 1419/* name, field width, offset, callback */ 1420{ "NICK", 5, 1421 offsetof(bridge_trill_fields_buf_t, bridget_nick), print_default_cb }, 1422{ "FLAGS", 6, 1423 offsetof(bridge_trill_fields_buf_t, bridget_flags), print_default_cb }, 1424{ "LINK", 12, 1425 offsetof(bridge_trill_fields_buf_t, bridget_link), print_default_cb }, 1426{ "NEXTHOP", 17, 1427 offsetof(bridge_trill_fields_buf_t, bridget_nexthop), print_default_cb }, 1428{ NULL, 0, 0, NULL}}; 1429 1430static char *progname; 1431static sig_atomic_t signalled; 1432 1433/* 1434 * Handle to libdladm. Opened in main() before the sub-command 1435 * specific function is called. 1436 */ 1437static dladm_handle_t handle = NULL; 1438 1439#define DLADM_ETHERSTUB_NAME "etherstub" 1440#define DLADM_IS_ETHERSTUB(id) (id == DATALINK_INVALID_LINKID) 1441 1442static void 1443usage(void) 1444{ 1445 int i; 1446 cmd_t *cmdp; 1447 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ..." 1448 "\n")); 1449 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 1450 cmdp = &cmds[i]; 1451 if (cmdp->c_usage != NULL) 1452 (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage)); 1453 } 1454 1455 /* close dladm handle if it was opened */ 1456 if (handle != NULL) 1457 dladm_close(handle); 1458 1459 exit(EXIT_FAILURE); 1460} 1461 1462int 1463main(int argc, char *argv[]) 1464{ 1465 int i; 1466 cmd_t *cmdp; 1467 dladm_status_t status; 1468 1469 (void) setlocale(LC_ALL, ""); 1470#if !defined(TEXT_DOMAIN) 1471#define TEXT_DOMAIN "SYS_TEST" 1472#endif 1473 (void) textdomain(TEXT_DOMAIN); 1474 1475 progname = argv[0]; 1476 1477 if (argc < 2) 1478 usage(); 1479 1480 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 1481 cmdp = &cmds[i]; 1482 if (strcmp(argv[1], cmdp->c_name) == 0) { 1483 /* Open the libdladm handle */ 1484 if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) { 1485 die_dlerr(status, 1486 "could not open /dev/dld"); 1487 } 1488 1489 cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage); 1490 1491 dladm_close(handle); 1492 return (EXIT_SUCCESS); 1493 } 1494 } 1495 1496 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 1497 progname, argv[1]); 1498 usage(); 1499 return (EXIT_FAILURE); 1500} 1501 1502/*ARGSUSED*/ 1503static int 1504show_usage_date(dladm_usage_t *usage, void *arg) 1505{ 1506 show_usage_state_t *state = (show_usage_state_t *)arg; 1507 time_t stime; 1508 char timebuf[20]; 1509 dladm_status_t status; 1510 uint32_t flags; 1511 1512 /* 1513 * Only show usage information for existing links unless '-a' 1514 * is specified. 1515 */ 1516 if (!state->us_showall) { 1517 if ((status = dladm_name2info(handle, usage->du_name, 1518 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1519 return (status); 1520 } 1521 if ((flags & DLADM_OPT_ACTIVE) == 0) 1522 return (DLADM_STATUS_LINKINVAL); 1523 } 1524 1525 stime = usage->du_stime; 1526 (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y", 1527 localtime(&stime)); 1528 (void) printf("%s\n", timebuf); 1529 1530 return (DLADM_STATUS_OK); 1531} 1532 1533static int 1534show_usage_time(dladm_usage_t *usage, void *arg) 1535{ 1536 show_usage_state_t *state = (show_usage_state_t *)arg; 1537 char buf[DLADM_STRSIZE]; 1538 usage_l_fields_buf_t ubuf; 1539 time_t time; 1540 double bw; 1541 dladm_status_t status; 1542 uint32_t flags; 1543 1544 /* 1545 * Only show usage information for existing links unless '-a' 1546 * is specified. 1547 */ 1548 if (!state->us_showall) { 1549 if ((status = dladm_name2info(handle, usage->du_name, 1550 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1551 return (status); 1552 } 1553 if ((flags & DLADM_OPT_ACTIVE) == 0) 1554 return (DLADM_STATUS_LINKINVAL); 1555 } 1556 1557 if (state->us_plot) { 1558 if (!state->us_printheader) { 1559 if (state->us_first) { 1560 (void) printf("# Time"); 1561 state->us_first = B_FALSE; 1562 } 1563 (void) printf(" %s", usage->du_name); 1564 if (usage->du_last) { 1565 (void) printf("\n"); 1566 state->us_first = B_TRUE; 1567 state->us_printheader = B_TRUE; 1568 } 1569 } else { 1570 if (state->us_first) { 1571 time = usage->du_etime; 1572 (void) strftime(buf, sizeof (buf), "%T", 1573 localtime(&time)); 1574 state->us_first = B_FALSE; 1575 (void) printf("%s", buf); 1576 } 1577 bw = (double)usage->du_bandwidth/1000; 1578 (void) printf(" %.2f", bw); 1579 if (usage->du_last) { 1580 (void) printf("\n"); 1581 state->us_first = B_TRUE; 1582 } 1583 } 1584 return (DLADM_STATUS_OK); 1585 } 1586 1587 bzero(&ubuf, sizeof (ubuf)); 1588 1589 (void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s", 1590 usage->du_name); 1591 time = usage->du_stime; 1592 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1593 (void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s", 1594 buf); 1595 time = usage->du_etime; 1596 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1597 (void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s", 1598 buf); 1599 (void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes), 1600 "%llu", usage->du_rbytes); 1601 (void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes), 1602 "%llu", usage->du_obytes); 1603 (void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth), 1604 "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1605 1606 ofmt_print(state->us_ofmt, &ubuf); 1607 return (DLADM_STATUS_OK); 1608} 1609 1610static int 1611show_usage_res(dladm_usage_t *usage, void *arg) 1612{ 1613 show_usage_state_t *state = (show_usage_state_t *)arg; 1614 char buf[DLADM_STRSIZE]; 1615 usage_fields_buf_t ubuf; 1616 dladm_status_t status; 1617 uint32_t flags; 1618 1619 /* 1620 * Only show usage information for existing links unless '-a' 1621 * is specified. 1622 */ 1623 if (!state->us_showall) { 1624 if ((status = dladm_name2info(handle, usage->du_name, 1625 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1626 return (status); 1627 } 1628 if ((flags & DLADM_OPT_ACTIVE) == 0) 1629 return (DLADM_STATUS_LINKINVAL); 1630 } 1631 1632 bzero(&ubuf, sizeof (ubuf)); 1633 1634 (void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s", 1635 usage->du_name); 1636 (void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration), 1637 "%llu", usage->du_duration); 1638 (void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets), 1639 "%llu", usage->du_ipackets); 1640 (void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes), 1641 "%llu", usage->du_rbytes); 1642 (void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets), 1643 "%llu", usage->du_opackets); 1644 (void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes), 1645 "%llu", usage->du_obytes); 1646 (void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth), 1647 "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1648 1649 ofmt_print(state->us_ofmt, &ubuf); 1650 1651 return (DLADM_STATUS_OK); 1652} 1653 1654static boolean_t 1655valid_formatspec(char *formatspec_str) 1656{ 1657 if (strcmp(formatspec_str, "gnuplot") == 0) 1658 return (B_TRUE); 1659 return (B_FALSE); 1660 1661} 1662 1663/*ARGSUSED*/ 1664static void 1665do_show_usage(int argc, char *argv[], const char *use) 1666{ 1667 char *file = NULL; 1668 int opt; 1669 dladm_status_t status; 1670 boolean_t d_arg = B_FALSE; 1671 char *stime = NULL; 1672 char *etime = NULL; 1673 char *resource = NULL; 1674 show_usage_state_t state; 1675 boolean_t o_arg = B_FALSE; 1676 boolean_t F_arg = B_FALSE; 1677 char *fields_str = NULL; 1678 char *formatspec_str = NULL; 1679 char *all_l_fields = 1680 "link,start,end,rbytes,obytes,bandwidth"; 1681 ofmt_handle_t ofmt; 1682 ofmt_status_t oferr; 1683 uint_t ofmtflags = 0; 1684 1685 bzero(&state, sizeof (show_usage_state_t)); 1686 state.us_parsable = B_FALSE; 1687 state.us_printheader = B_FALSE; 1688 state.us_plot = B_FALSE; 1689 state.us_first = B_TRUE; 1690 1691 while ((opt = getopt_long(argc, argv, "das:e:o:f:F:", 1692 usage_opts, NULL)) != -1) { 1693 switch (opt) { 1694 case 'd': 1695 d_arg = B_TRUE; 1696 break; 1697 case 'a': 1698 state.us_showall = B_TRUE; 1699 break; 1700 case 'f': 1701 file = optarg; 1702 break; 1703 case 's': 1704 stime = optarg; 1705 break; 1706 case 'e': 1707 etime = optarg; 1708 break; 1709 case 'o': 1710 o_arg = B_TRUE; 1711 fields_str = optarg; 1712 break; 1713 case 'F': 1714 state.us_plot = F_arg = B_TRUE; 1715 formatspec_str = optarg; 1716 break; 1717 default: 1718 die_opterr(optopt, opt, use); 1719 break; 1720 } 1721 } 1722 1723 if (file == NULL) 1724 die("show-usage requires a file"); 1725 1726 if (optind == (argc-1)) { 1727 uint32_t flags; 1728 1729 resource = argv[optind]; 1730 if (!state.us_showall && 1731 (((status = dladm_name2info(handle, resource, NULL, &flags, 1732 NULL, NULL)) != DLADM_STATUS_OK) || 1733 ((flags & DLADM_OPT_ACTIVE) == 0))) { 1734 die("invalid link: '%s'", resource); 1735 } 1736 } 1737 1738 if (F_arg && d_arg) 1739 die("incompatible -d and -F options"); 1740 1741 if (F_arg && valid_formatspec(formatspec_str) == B_FALSE) 1742 die("Format specifier %s not supported", formatspec_str); 1743 1744 if (state.us_parsable) 1745 ofmtflags |= OFMT_PARSABLE; 1746 1747 if (resource == NULL && stime == NULL && etime == NULL) { 1748 oferr = ofmt_open(fields_str, usage_fields, ofmtflags, 0, 1749 &ofmt); 1750 } else { 1751 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 1752 fields_str = all_l_fields; 1753 oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags, 0, 1754 &ofmt); 1755 1756 } 1757 ofmt_check(oferr, state.us_parsable, ofmt, die, warn); 1758 state.us_ofmt = ofmt; 1759 1760 if (d_arg) { 1761 /* Print log dates */ 1762 status = dladm_usage_dates(show_usage_date, 1763 DLADM_LOGTYPE_LINK, file, resource, &state); 1764 } else if (resource == NULL && stime == NULL && etime == NULL && 1765 !F_arg) { 1766 /* Print summary */ 1767 status = dladm_usage_summary(show_usage_res, 1768 DLADM_LOGTYPE_LINK, file, &state); 1769 } else if (resource != NULL) { 1770 /* Print log entries for named resource */ 1771 status = dladm_walk_usage_res(show_usage_time, 1772 DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state); 1773 } else { 1774 /* Print time and information for each link */ 1775 status = dladm_walk_usage_time(show_usage_time, 1776 DLADM_LOGTYPE_LINK, file, stime, etime, &state); 1777 } 1778 1779 if (status != DLADM_STATUS_OK) 1780 die_dlerr(status, "show-usage"); 1781 ofmt_close(ofmt); 1782} 1783 1784static void 1785do_create_aggr(int argc, char *argv[], const char *use) 1786{ 1787 int option; 1788 int key = 0; 1789 uint32_t policy = AGGR_POLICY_L4; 1790 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 1791 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 1792 dladm_aggr_port_attr_db_t port[MAXPORT]; 1793 uint_t n, ndev, nlink; 1794 uint8_t mac_addr[ETHERADDRL]; 1795 boolean_t mac_addr_fixed = B_FALSE; 1796 boolean_t P_arg = B_FALSE; 1797 boolean_t l_arg = B_FALSE; 1798 boolean_t u_arg = B_FALSE; 1799 boolean_t T_arg = B_FALSE; 1800 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1801 char *altroot = NULL; 1802 char name[MAXLINKNAMELEN]; 1803 char *devs[MAXPORT]; 1804 char *links[MAXPORT]; 1805 dladm_status_t status; 1806 dladm_status_t pstatus; 1807 char propstr[DLADM_STRSIZE]; 1808 dladm_arg_list_t *proplist = NULL; 1809 int i; 1810 datalink_id_t linkid; 1811 1812 ndev = nlink = opterr = 0; 1813 bzero(propstr, DLADM_STRSIZE); 1814 1815 while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:", 1816 lopts, NULL)) != -1) { 1817 switch (option) { 1818 case 'd': 1819 if (ndev + nlink >= MAXPORT) 1820 die("too many ports specified"); 1821 1822 devs[ndev++] = optarg; 1823 break; 1824 case 'P': 1825 if (P_arg) 1826 die_optdup(option); 1827 1828 P_arg = B_TRUE; 1829 if (!dladm_aggr_str2policy(optarg, &policy)) 1830 die("invalid policy '%s'", optarg); 1831 break; 1832 case 'u': 1833 if (u_arg) 1834 die_optdup(option); 1835 1836 u_arg = B_TRUE; 1837 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 1838 mac_addr)) 1839 die("invalid MAC address '%s'", optarg); 1840 break; 1841 case 'l': 1842 if (isdigit(optarg[strlen(optarg) - 1])) { 1843 1844 /* 1845 * Ended with digit, possibly a link name. 1846 */ 1847 if (ndev + nlink >= MAXPORT) 1848 die("too many ports specified"); 1849 1850 links[nlink++] = optarg; 1851 break; 1852 } 1853 /* FALLTHROUGH */ 1854 case 'L': 1855 if (l_arg) 1856 die_optdup(option); 1857 1858 l_arg = B_TRUE; 1859 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 1860 die("invalid LACP mode '%s'", optarg); 1861 break; 1862 case 'T': 1863 if (T_arg) 1864 die_optdup(option); 1865 1866 T_arg = B_TRUE; 1867 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 1868 die("invalid LACP timer value '%s'", optarg); 1869 break; 1870 case 't': 1871 flags &= ~DLADM_OPT_PERSIST; 1872 break; 1873 case 'f': 1874 flags |= DLADM_OPT_FORCE; 1875 break; 1876 case 'R': 1877 altroot = optarg; 1878 break; 1879 case 'p': 1880 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 1881 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 1882 DLADM_STRSIZE) 1883 die("property list too long '%s'", propstr); 1884 break; 1885 1886 default: 1887 die_opterr(optopt, option, use); 1888 break; 1889 } 1890 } 1891 1892 if (ndev + nlink == 0) 1893 usage(); 1894 1895 /* get key value or the aggregation name (required last argument) */ 1896 if (optind != (argc-1)) 1897 usage(); 1898 1899 if (!str2int(argv[optind], &key)) { 1900 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= 1901 MAXLINKNAMELEN) { 1902 die("link name too long '%s'", argv[optind]); 1903 } 1904 1905 if (!dladm_valid_linkname(name)) 1906 die("invalid link name '%s'", argv[optind]); 1907 } else { 1908 (void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key); 1909 } 1910 1911 if (altroot != NULL) 1912 altroot_cmd(altroot, argc, argv); 1913 1914 for (n = 0; n < ndev; n++) { 1915 if ((status = dladm_dev2linkid(handle, devs[n], 1916 &port[n].lp_linkid)) != DLADM_STATUS_OK) { 1917 die_dlerr(status, "invalid dev name '%s'", devs[n]); 1918 } 1919 } 1920 1921 for (n = 0; n < nlink; n++) { 1922 if ((status = dladm_name2info(handle, links[n], 1923 &port[ndev + n].lp_linkid, NULL, NULL, NULL)) != 1924 DLADM_STATUS_OK) { 1925 die_dlerr(status, "invalid link name '%s'", links[n]); 1926 } 1927 } 1928 1929 status = dladm_aggr_create(handle, name, key, ndev + nlink, port, 1930 policy, mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, 1931 lacp_timer, flags); 1932 if (status != DLADM_STATUS_OK) 1933 goto done; 1934 1935 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 1936 != DLADM_STATUS_OK) 1937 die("invalid aggregation property"); 1938 1939 if (proplist == NULL) 1940 return; 1941 1942 status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL); 1943 if (status != DLADM_STATUS_OK) 1944 goto done; 1945 1946 for (i = 0; i < proplist->al_count; i++) { 1947 dladm_arg_info_t *aip = &proplist->al_info[i]; 1948 1949 pstatus = dladm_set_linkprop(handle, linkid, aip->ai_name, 1950 aip->ai_val, aip->ai_count, flags); 1951 1952 if (pstatus != DLADM_STATUS_OK) { 1953 die_dlerr(pstatus, 1954 "aggr creation succeeded but " 1955 "could not set property '%s'", aip->ai_name); 1956 } 1957 } 1958done: 1959 dladm_free_props(proplist); 1960 if (status != DLADM_STATUS_OK) { 1961 if (status == DLADM_STATUS_NONOTIF) { 1962 die("not all links have link up/down detection; must " 1963 "use -f (see dladm(1M))"); 1964 } else { 1965 die_dlerr(status, "create operation failed"); 1966 } 1967 } 1968} 1969 1970/* 1971 * arg is either the key or the aggr name. Validate it and convert it to 1972 * the linkid if altroot is NULL. 1973 */ 1974static dladm_status_t 1975i_dladm_aggr_get_linkid(const char *altroot, const char *arg, 1976 datalink_id_t *linkidp, uint32_t flags) 1977{ 1978 int key = 0; 1979 char *aggr = NULL; 1980 dladm_status_t status; 1981 1982 if (!str2int(arg, &key)) 1983 aggr = (char *)arg; 1984 1985 if (aggr == NULL && key == 0) 1986 return (DLADM_STATUS_LINKINVAL); 1987 1988 if (altroot != NULL) 1989 return (DLADM_STATUS_OK); 1990 1991 if (aggr != NULL) { 1992 status = dladm_name2info(handle, aggr, linkidp, NULL, NULL, 1993 NULL); 1994 } else { 1995 status = dladm_key2linkid(handle, key, linkidp, flags); 1996 } 1997 1998 return (status); 1999} 2000 2001static void 2002do_delete_aggr(int argc, char *argv[], const char *use) 2003{ 2004 int option; 2005 char *altroot = NULL; 2006 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 2007 dladm_status_t status; 2008 datalink_id_t linkid; 2009 2010 opterr = 0; 2011 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 2012 switch (option) { 2013 case 't': 2014 flags &= ~DLADM_OPT_PERSIST; 2015 break; 2016 case 'R': 2017 altroot = optarg; 2018 break; 2019 default: 2020 die_opterr(optopt, option, use); 2021 break; 2022 } 2023 } 2024 2025 /* get key value or the aggregation name (required last argument) */ 2026 if (optind != (argc-1)) 2027 usage(); 2028 2029 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 2030 if (status != DLADM_STATUS_OK) 2031 goto done; 2032 2033 if (altroot != NULL) 2034 altroot_cmd(altroot, argc, argv); 2035 2036 status = dladm_aggr_delete(handle, linkid, flags); 2037done: 2038 if (status != DLADM_STATUS_OK) 2039 die_dlerr(status, "delete operation failed"); 2040} 2041 2042static void 2043do_add_aggr(int argc, char *argv[], const char *use) 2044{ 2045 int option; 2046 uint_t n, ndev, nlink; 2047 char *altroot = NULL; 2048 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 2049 datalink_id_t linkid; 2050 dladm_status_t status; 2051 dladm_aggr_port_attr_db_t port[MAXPORT]; 2052 char *devs[MAXPORT]; 2053 char *links[MAXPORT]; 2054 2055 ndev = nlink = opterr = 0; 2056 while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts, 2057 NULL)) != -1) { 2058 switch (option) { 2059 case 'd': 2060 if (ndev + nlink >= MAXPORT) 2061 die("too many ports specified"); 2062 2063 devs[ndev++] = optarg; 2064 break; 2065 case 'l': 2066 if (ndev + nlink >= MAXPORT) 2067 die("too many ports specified"); 2068 2069 links[nlink++] = optarg; 2070 break; 2071 case 't': 2072 flags &= ~DLADM_OPT_PERSIST; 2073 break; 2074 case 'f': 2075 flags |= DLADM_OPT_FORCE; 2076 break; 2077 case 'R': 2078 altroot = optarg; 2079 break; 2080 default: 2081 die_opterr(optopt, option, use); 2082 break; 2083 } 2084 } 2085 2086 if (ndev + nlink == 0) 2087 usage(); 2088 2089 /* get key value or the aggregation name (required last argument) */ 2090 if (optind != (argc-1)) 2091 usage(); 2092 2093 if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, 2094 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) != 2095 DLADM_STATUS_OK) { 2096 goto done; 2097 } 2098 2099 if (altroot != NULL) 2100 altroot_cmd(altroot, argc, argv); 2101 2102 for (n = 0; n < ndev; n++) { 2103 if ((status = dladm_dev2linkid(handle, devs[n], 2104 &(port[n].lp_linkid))) != DLADM_STATUS_OK) { 2105 die_dlerr(status, "invalid <dev> '%s'", devs[n]); 2106 } 2107 } 2108 2109 for (n = 0; n < nlink; n++) { 2110 if ((status = dladm_name2info(handle, links[n], 2111 &port[n + ndev].lp_linkid, NULL, NULL, NULL)) != 2112 DLADM_STATUS_OK) { 2113 die_dlerr(status, "invalid <link> '%s'", links[n]); 2114 } 2115 } 2116 2117 status = dladm_aggr_add(handle, linkid, ndev + nlink, port, flags); 2118done: 2119 if (status != DLADM_STATUS_OK) { 2120 /* 2121 * checking DLADM_STATUS_NOTSUP is a temporary workaround 2122 * and should be removed once 6399681 is fixed. 2123 */ 2124 if (status == DLADM_STATUS_NOTSUP) { 2125 die("add operation failed: link capabilities don't " 2126 "match"); 2127 } else if (status == DLADM_STATUS_NONOTIF) { 2128 die("not all links have link up/down detection; must " 2129 "use -f (see dladm(1M))"); 2130 } else { 2131 die_dlerr(status, "add operation failed"); 2132 } 2133 } 2134} 2135 2136static void 2137do_remove_aggr(int argc, char *argv[], const char *use) 2138{ 2139 int option; 2140 dladm_aggr_port_attr_db_t port[MAXPORT]; 2141 uint_t n, ndev, nlink; 2142 char *devs[MAXPORT]; 2143 char *links[MAXPORT]; 2144 char *altroot = NULL; 2145 uint32_t flags; 2146 datalink_id_t linkid; 2147 dladm_status_t status; 2148 2149 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 2150 ndev = nlink = opterr = 0; 2151 while ((option = getopt_long(argc, argv, ":d:l:R:t", 2152 lopts, NULL)) != -1) { 2153 switch (option) { 2154 case 'd': 2155 if (ndev + nlink >= MAXPORT) 2156 die("too many ports specified"); 2157 2158 devs[ndev++] = optarg; 2159 break; 2160 case 'l': 2161 if (ndev + nlink >= MAXPORT) 2162 die("too many ports specified"); 2163 2164 links[nlink++] = optarg; 2165 break; 2166 case 't': 2167 flags &= ~DLADM_OPT_PERSIST; 2168 break; 2169 case 'R': 2170 altroot = optarg; 2171 break; 2172 default: 2173 die_opterr(optopt, option, use); 2174 break; 2175 } 2176 } 2177 2178 if (ndev + nlink == 0) 2179 usage(); 2180 2181 /* get key value or the aggregation name (required last argument) */ 2182 if (optind != (argc-1)) 2183 usage(); 2184 2185 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 2186 if (status != DLADM_STATUS_OK) 2187 goto done; 2188 2189 if (altroot != NULL) 2190 altroot_cmd(altroot, argc, argv); 2191 2192 for (n = 0; n < ndev; n++) { 2193 if ((status = dladm_dev2linkid(handle, devs[n], 2194 &(port[n].lp_linkid))) != DLADM_STATUS_OK) { 2195 die_dlerr(status, "invalid <dev> '%s'", devs[n]); 2196 } 2197 } 2198 2199 for (n = 0; n < nlink; n++) { 2200 if ((status = dladm_name2info(handle, links[n], 2201 &port[n + ndev].lp_linkid, NULL, NULL, NULL)) != 2202 DLADM_STATUS_OK) { 2203 die_dlerr(status, "invalid <link> '%s'", links[n]); 2204 } 2205 } 2206 2207 status = dladm_aggr_remove(handle, linkid, ndev + nlink, port, flags); 2208done: 2209 if (status != DLADM_STATUS_OK) 2210 die_dlerr(status, "remove operation failed"); 2211} 2212 2213static void 2214do_modify_aggr(int argc, char *argv[], const char *use) 2215{ 2216 int option; 2217 uint32_t policy = AGGR_POLICY_L4; 2218 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 2219 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 2220 uint8_t mac_addr[ETHERADDRL]; 2221 boolean_t mac_addr_fixed = B_FALSE; 2222 uint8_t modify_mask = 0; 2223 char *altroot = NULL; 2224 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 2225 datalink_id_t linkid; 2226 dladm_status_t status; 2227 2228 opterr = 0; 2229 while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts, 2230 NULL)) != -1) { 2231 switch (option) { 2232 case 'P': 2233 if (modify_mask & DLADM_AGGR_MODIFY_POLICY) 2234 die_optdup(option); 2235 2236 modify_mask |= DLADM_AGGR_MODIFY_POLICY; 2237 2238 if (!dladm_aggr_str2policy(optarg, &policy)) 2239 die("invalid policy '%s'", optarg); 2240 break; 2241 case 'u': 2242 if (modify_mask & DLADM_AGGR_MODIFY_MAC) 2243 die_optdup(option); 2244 2245 modify_mask |= DLADM_AGGR_MODIFY_MAC; 2246 2247 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 2248 mac_addr)) 2249 die("invalid MAC address '%s'", optarg); 2250 break; 2251 case 'l': 2252 case 'L': 2253 if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE) 2254 die_optdup(option); 2255 2256 modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE; 2257 2258 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 2259 die("invalid LACP mode '%s'", optarg); 2260 break; 2261 case 'T': 2262 if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER) 2263 die_optdup(option); 2264 2265 modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER; 2266 2267 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 2268 die("invalid LACP timer value '%s'", optarg); 2269 break; 2270 case 't': 2271 flags &= ~DLADM_OPT_PERSIST; 2272 break; 2273 case 'R': 2274 altroot = optarg; 2275 break; 2276 default: 2277 die_opterr(optopt, option, use); 2278 break; 2279 } 2280 } 2281 2282 if (modify_mask == 0) 2283 die("at least one of the -PulT options must be specified"); 2284 2285 /* get key value or the aggregation name (required last argument) */ 2286 if (optind != (argc-1)) 2287 usage(); 2288 2289 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 2290 if (status != DLADM_STATUS_OK) 2291 goto done; 2292 2293 if (altroot != NULL) 2294 altroot_cmd(altroot, argc, argv); 2295 2296 status = dladm_aggr_modify(handle, linkid, modify_mask, policy, 2297 mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, lacp_timer, 2298 flags); 2299 2300done: 2301 if (status != DLADM_STATUS_OK) 2302 die_dlerr(status, "modify operation failed"); 2303} 2304 2305/*ARGSUSED*/ 2306static void 2307do_up_aggr(int argc, char *argv[], const char *use) 2308{ 2309 datalink_id_t linkid = DATALINK_ALL_LINKID; 2310 dladm_status_t status; 2311 2312 /* 2313 * get the key or the name of the aggregation (optional last argument) 2314 */ 2315 if (argc == 2) { 2316 if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid, 2317 DLADM_OPT_PERSIST)) != DLADM_STATUS_OK) 2318 goto done; 2319 } else if (argc > 2) { 2320 usage(); 2321 } 2322 2323 status = dladm_aggr_up(handle, linkid); 2324done: 2325 if (status != DLADM_STATUS_OK) { 2326 if (argc == 2) { 2327 die_dlerr(status, 2328 "could not bring up aggregation '%s'", argv[1]); 2329 } else { 2330 die_dlerr(status, "could not bring aggregations up"); 2331 } 2332 } 2333} 2334 2335static void 2336do_create_vlan(int argc, char *argv[], const char *use) 2337{ 2338 char *link = NULL; 2339 char drv[DLPI_LINKNAME_MAX]; 2340 uint_t ppa; 2341 datalink_id_t linkid; 2342 datalink_id_t dev_linkid; 2343 int vid = 0; 2344 int option; 2345 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2346 char *altroot = NULL; 2347 char vlan[MAXLINKNAMELEN]; 2348 char propstr[DLADM_STRSIZE]; 2349 dladm_arg_list_t *proplist = NULL; 2350 dladm_status_t status; 2351 2352 opterr = 0; 2353 bzero(propstr, DLADM_STRSIZE); 2354 2355 while ((option = getopt_long(argc, argv, ":tfR:l:v:p:", 2356 lopts, NULL)) != -1) { 2357 switch (option) { 2358 case 'v': 2359 if (vid != 0) 2360 die_optdup(option); 2361 2362 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 2363 die("invalid VLAN identifier '%s'", optarg); 2364 2365 break; 2366 case 'l': 2367 if (link != NULL) 2368 die_optdup(option); 2369 2370 link = optarg; 2371 break; 2372 case 't': 2373 flags &= ~DLADM_OPT_PERSIST; 2374 break; 2375 case 'R': 2376 altroot = optarg; 2377 break; 2378 case 'p': 2379 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 2380 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 2381 DLADM_STRSIZE) 2382 die("property list too long '%s'", propstr); 2383 break; 2384 case 'f': 2385 flags |= DLADM_OPT_FORCE; 2386 break; 2387 default: 2388 die_opterr(optopt, option, use); 2389 break; 2390 } 2391 } 2392 2393 /* get vlan name if there is any */ 2394 if ((vid == 0) || (link == NULL) || (argc - optind > 1)) 2395 usage(); 2396 2397 if (optind == (argc - 1)) { 2398 if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >= 2399 MAXLINKNAMELEN) { 2400 die("vlan name too long '%s'", argv[optind]); 2401 } 2402 } else { 2403 if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) || 2404 (ppa >= 1000) || 2405 (dlpi_makelink(vlan, drv, vid * 1000 + ppa) != 2406 DLPI_SUCCESS)) { 2407 die("invalid link name '%s'", link); 2408 } 2409 } 2410 2411 if (altroot != NULL) 2412 altroot_cmd(altroot, argc, argv); 2413 2414 if (dladm_name2info(handle, link, &dev_linkid, NULL, NULL, NULL) != 2415 DLADM_STATUS_OK) { 2416 die("invalid link name '%s'", link); 2417 } 2418 2419 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 2420 != DLADM_STATUS_OK) 2421 die("invalid vlan property"); 2422 2423 status = dladm_vlan_create(handle, vlan, dev_linkid, vid, proplist, 2424 flags, &linkid); 2425 switch (status) { 2426 case DLADM_STATUS_OK: 2427 break; 2428 2429 case DLADM_STATUS_NOTSUP: 2430 die("VLAN over '%s' may require lowered MTU; must use -f (see " 2431 "dladm(1M))", link); 2432 break; 2433 2434 case DLADM_STATUS_LINKBUSY: 2435 die("VLAN over '%s' may not use default_tag ID " 2436 "(see dladm(1M))", link); 2437 break; 2438 2439 default: 2440 die_dlerr(status, "create operation failed"); 2441 } 2442} 2443 2444static void 2445do_delete_vlan(int argc, char *argv[], const char *use) 2446{ 2447 int option; 2448 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2449 char *altroot = NULL; 2450 datalink_id_t linkid; 2451 dladm_status_t status; 2452 2453 opterr = 0; 2454 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 2455 switch (option) { 2456 case 't': 2457 flags &= ~DLADM_OPT_PERSIST; 2458 break; 2459 case 'R': 2460 altroot = optarg; 2461 break; 2462 default: 2463 die_opterr(optopt, option, use); 2464 break; 2465 } 2466 } 2467 2468 /* get VLAN link name (required last argument) */ 2469 if (optind != (argc - 1)) 2470 usage(); 2471 2472 if (altroot != NULL) 2473 altroot_cmd(altroot, argc, argv); 2474 2475 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 2476 NULL); 2477 if (status != DLADM_STATUS_OK) 2478 goto done; 2479 2480 status = dladm_vlan_delete(handle, linkid, flags); 2481done: 2482 if (status != DLADM_STATUS_OK) 2483 die_dlerr(status, "delete operation failed"); 2484} 2485 2486/*ARGSUSED*/ 2487static void 2488do_up_vlan(int argc, char *argv[], const char *use) 2489{ 2490 do_up_vnic_common(argc, argv, use, B_TRUE); 2491} 2492 2493static void 2494do_rename_link(int argc, char *argv[], const char *use) 2495{ 2496 int option; 2497 char *link1, *link2; 2498 char *altroot = NULL; 2499 dladm_status_t status; 2500 2501 opterr = 0; 2502 while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) { 2503 switch (option) { 2504 case 'R': 2505 altroot = optarg; 2506 break; 2507 default: 2508 die_opterr(optopt, option, use); 2509 break; 2510 } 2511 } 2512 2513 /* get link1 and link2 name (required the last 2 arguments) */ 2514 if (optind != (argc - 2)) 2515 usage(); 2516 2517 if (altroot != NULL) 2518 altroot_cmd(altroot, argc, argv); 2519 2520 link1 = argv[optind++]; 2521 link2 = argv[optind]; 2522 if ((status = dladm_rename_link(handle, link1, link2)) != 2523 DLADM_STATUS_OK) 2524 die_dlerr(status, "rename operation failed"); 2525} 2526 2527/*ARGSUSED*/ 2528static void 2529do_delete_phys(int argc, char *argv[], const char *use) 2530{ 2531 datalink_id_t linkid = DATALINK_ALL_LINKID; 2532 dladm_status_t status; 2533 2534 /* get link name (required the last argument) */ 2535 if (argc > 2) 2536 usage(); 2537 2538 if (argc == 2) { 2539 if ((status = dladm_name2info(handle, argv[1], &linkid, NULL, 2540 NULL, NULL)) != DLADM_STATUS_OK) 2541 die_dlerr(status, "cannot delete '%s'", argv[1]); 2542 } 2543 2544 if ((status = dladm_phys_delete(handle, linkid)) != DLADM_STATUS_OK) { 2545 if (argc == 2) 2546 die_dlerr(status, "cannot delete '%s'", argv[1]); 2547 else 2548 die_dlerr(status, "delete operation failed"); 2549 } 2550} 2551 2552/*ARGSUSED*/ 2553static int 2554i_dladm_walk_linkmap(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2555{ 2556 char name[MAXLINKNAMELEN]; 2557 char mediabuf[DLADM_STRSIZE]; 2558 char classbuf[DLADM_STRSIZE]; 2559 datalink_class_t class; 2560 uint32_t media; 2561 uint32_t flags; 2562 2563 if (dladm_datalink_id2info(dh, linkid, &flags, &class, &media, name, 2564 MAXLINKNAMELEN) == DLADM_STATUS_OK) { 2565 (void) dladm_class2str(class, classbuf); 2566 (void) dladm_media2str(media, mediabuf); 2567 (void) printf("%-12s%8d %-12s%-20s %6d\n", name, 2568 linkid, classbuf, mediabuf, flags); 2569 } 2570 return (DLADM_WALK_CONTINUE); 2571} 2572 2573/*ARGSUSED*/ 2574static void 2575do_show_linkmap(int argc, char *argv[], const char *use) 2576{ 2577 if (argc != 1) 2578 die("invalid arguments"); 2579 2580 (void) printf("%-12s%8s %-12s%-20s %6s\n", "NAME", "LINKID", 2581 "CLASS", "MEDIA", "FLAGS"); 2582 2583 (void) dladm_walk_datalink_id(i_dladm_walk_linkmap, handle, NULL, 2584 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 2585 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2586} 2587 2588/* 2589 * Delete inactive physical links. 2590 */ 2591/*ARGSUSED*/ 2592static int 2593purge_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2594{ 2595 datalink_class_t class; 2596 uint32_t flags; 2597 2598 if (dladm_datalink_id2info(dh, linkid, &flags, &class, NULL, NULL, 0) 2599 != DLADM_STATUS_OK) { 2600 return (DLADM_WALK_CONTINUE); 2601 } 2602 2603 if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE)) 2604 (void) dladm_phys_delete(dh, linkid); 2605 2606 return (DLADM_WALK_CONTINUE); 2607} 2608 2609/*ARGSUSED*/ 2610static void 2611do_init_phys(int argc, char *argv[], const char *use) 2612{ 2613 di_node_t devtree; 2614 2615 if (argc > 1) 2616 usage(); 2617 2618 /* 2619 * Force all the devices to attach, therefore all the network physical 2620 * devices can be known to the dlmgmtd daemon. 2621 */ 2622 if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL) 2623 di_fini(devtree); 2624 2625 (void) dladm_walk_datalink_id(purge_phys, handle, NULL, 2626 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 2627} 2628 2629/* 2630 * Print the active topology information. 2631 */ 2632void 2633print_link_topology(show_state_t *state, datalink_id_t linkid, 2634 datalink_class_t class, link_fields_buf_t *lbuf) 2635{ 2636 uint32_t flags = state->ls_flags; 2637 dladm_status_t status; 2638 char tmpbuf[MAXLINKNAMELEN]; 2639 2640 lbuf->link_over[0] = '\0'; 2641 lbuf->link_bridge[0] = '\0'; 2642 2643 switch (class) { 2644 case DATALINK_CLASS_AGGR: 2645 case DATALINK_CLASS_PHYS: 2646 case DATALINK_CLASS_ETHERSTUB: 2647 status = dladm_bridge_getlink(handle, linkid, lbuf->link_bridge, 2648 sizeof (lbuf->link_bridge)); 2649 if (status != DLADM_STATUS_OK && 2650 status != DLADM_STATUS_NOTFOUND) 2651 (void) strcpy(lbuf->link_bridge, "?"); 2652 break; 2653 } 2654 2655 switch (class) { 2656 case DATALINK_CLASS_VLAN: { 2657 dladm_vlan_attr_t vinfo; 2658 2659 if (dladm_vlan_info(handle, linkid, &vinfo, flags) != 2660 DLADM_STATUS_OK) { 2661 (void) strcpy(lbuf->link_over, "?"); 2662 break; 2663 } 2664 if (dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, NULL, 2665 NULL, lbuf->link_over, sizeof (lbuf->link_over)) != 2666 DLADM_STATUS_OK) 2667 (void) strcpy(lbuf->link_over, "?"); 2668 break; 2669 } 2670 case DATALINK_CLASS_AGGR: { 2671 dladm_aggr_grp_attr_t ginfo; 2672 int i; 2673 2674 if (dladm_aggr_info(handle, linkid, &ginfo, flags) != 2675 DLADM_STATUS_OK || ginfo.lg_nports == 0) { 2676 (void) strcpy(lbuf->link_over, "?"); 2677 break; 2678 } 2679 for (i = 0; i < ginfo.lg_nports; i++) { 2680 if (dladm_datalink_id2info(handle, 2681 ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, 2682 tmpbuf, sizeof (tmpbuf)) != DLADM_STATUS_OK) { 2683 (void) strcpy(lbuf->link_over, "?"); 2684 break; 2685 } 2686 (void) strlcat(lbuf->link_over, tmpbuf, 2687 sizeof (lbuf->link_over)); 2688 if (i != (ginfo.lg_nports - 1)) { 2689 (void) strlcat(lbuf->link_over, ",", 2690 sizeof (lbuf->link_over)); 2691 } 2692 } 2693 free(ginfo.lg_ports); 2694 break; 2695 } 2696 case DATALINK_CLASS_VNIC: { 2697 dladm_vnic_attr_t vinfo; 2698 2699 if (dladm_vnic_info(handle, linkid, &vinfo, flags) != 2700 DLADM_STATUS_OK) { 2701 (void) strcpy(lbuf->link_over, "?"); 2702 break; 2703 } 2704 if (dladm_datalink_id2info(handle, vinfo.va_link_id, NULL, NULL, 2705 NULL, lbuf->link_over, sizeof (lbuf->link_over)) != 2706 DLADM_STATUS_OK) 2707 (void) strcpy(lbuf->link_over, "?"); 2708 break; 2709 } 2710 2711 case DATALINK_CLASS_PART: { 2712 dladm_part_attr_t pinfo; 2713 2714 if (dladm_part_info(handle, linkid, &pinfo, flags) != 2715 DLADM_STATUS_OK) { 2716 (void) strcpy(lbuf->link_over, "?"); 2717 break; 2718 } 2719 if (dladm_datalink_id2info(handle, pinfo.dia_physlinkid, NULL, 2720 NULL, NULL, lbuf->link_over, sizeof (lbuf->link_over)) != 2721 DLADM_STATUS_OK) 2722 (void) strcpy(lbuf->link_over, "?"); 2723 break; 2724 } 2725 2726 case DATALINK_CLASS_BRIDGE: { 2727 datalink_id_t *dlp; 2728 uint_t i, nports; 2729 2730 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, 2731 NULL, tmpbuf, sizeof (tmpbuf)) != DLADM_STATUS_OK) { 2732 (void) strcpy(lbuf->link_over, "?"); 2733 break; 2734 } 2735 if (tmpbuf[0] != '\0') 2736 tmpbuf[strlen(tmpbuf) - 1] = '\0'; 2737 dlp = dladm_bridge_get_portlist(tmpbuf, &nports); 2738 if (dlp == NULL) { 2739 (void) strcpy(lbuf->link_over, "?"); 2740 break; 2741 } 2742 for (i = 0; i < nports; i++) { 2743 if (dladm_datalink_id2info(handle, dlp[i], NULL, 2744 NULL, NULL, tmpbuf, sizeof (tmpbuf)) != 2745 DLADM_STATUS_OK) { 2746 (void) strcpy(lbuf->link_over, "?"); 2747 break; 2748 } 2749 (void) strlcat(lbuf->link_over, tmpbuf, 2750 sizeof (lbuf->link_over)); 2751 if (i != nports - 1) { 2752 (void) strlcat(lbuf->link_over, ",", 2753 sizeof (lbuf->link_over)); 2754 } 2755 } 2756 dladm_bridge_free_portlist(dlp); 2757 break; 2758 } 2759 2760 case DATALINK_CLASS_SIMNET: { 2761 dladm_simnet_attr_t slinfo; 2762 2763 if (dladm_simnet_info(handle, linkid, &slinfo, flags) != 2764 DLADM_STATUS_OK) { 2765 (void) strcpy(lbuf->link_over, "?"); 2766 break; 2767 } 2768 if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID) { 2769 if (dladm_datalink_id2info(handle, 2770 slinfo.sna_peer_link_id, NULL, NULL, NULL, 2771 lbuf->link_over, sizeof (lbuf->link_over)) != 2772 DLADM_STATUS_OK) 2773 (void) strcpy(lbuf->link_over, "?"); 2774 } 2775 break; 2776 } 2777 } 2778} 2779 2780static dladm_status_t 2781print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf) 2782{ 2783 char link[MAXLINKNAMELEN]; 2784 datalink_class_t class; 2785 uint_t mtu; 2786 uint32_t flags; 2787 dladm_status_t status; 2788 2789 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 2790 NULL, link, sizeof (link))) != DLADM_STATUS_OK) { 2791 goto done; 2792 } 2793 2794 if (!(state->ls_flags & flags)) { 2795 status = DLADM_STATUS_NOTFOUND; 2796 goto done; 2797 } 2798 2799 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2800 dladm_attr_t dlattr; 2801 2802 if (class == DATALINK_CLASS_PHYS) { 2803 dladm_phys_attr_t dpa; 2804 dlpi_handle_t dh; 2805 dlpi_info_t dlinfo; 2806 2807 if ((status = dladm_phys_info(handle, linkid, &dpa, 2808 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2809 goto done; 2810 } 2811 2812 if (!dpa.dp_novanity) 2813 goto link_mtu; 2814 2815 /* 2816 * This is a physical link that does not have 2817 * vanity naming support. 2818 */ 2819 if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) != 2820 DLPI_SUCCESS) { 2821 status = DLADM_STATUS_NOTFOUND; 2822 goto done; 2823 } 2824 2825 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 2826 dlpi_close(dh); 2827 status = DLADM_STATUS_BADARG; 2828 goto done; 2829 } 2830 2831 dlpi_close(dh); 2832 mtu = dlinfo.di_max_sdu; 2833 } else { 2834link_mtu: 2835 status = dladm_info(handle, linkid, &dlattr); 2836 if (status != DLADM_STATUS_OK) 2837 goto done; 2838 mtu = dlattr.da_max_sdu; 2839 } 2840 } 2841 2842 (void) snprintf(lbuf->link_name, sizeof (lbuf->link_name), 2843 "%s", link); 2844 (void) dladm_class2str(class, lbuf->link_class); 2845 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2846 (void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu), 2847 "%u", mtu); 2848 (void) get_linkstate(link, B_TRUE, lbuf->link_state); 2849 } 2850 2851 print_link_topology(state, linkid, class, lbuf); 2852done: 2853 return (status); 2854} 2855 2856/* ARGSUSED */ 2857static int 2858show_link(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2859{ 2860 show_state_t *state = (show_state_t *)arg; 2861 dladm_status_t status; 2862 link_fields_buf_t lbuf; 2863 2864 /* 2865 * first get all the link attributes into lbuf; 2866 */ 2867 bzero(&lbuf, sizeof (link_fields_buf_t)); 2868 if ((status = print_link(state, linkid, &lbuf)) == DLADM_STATUS_OK) 2869 ofmt_print(state->ls_ofmt, &lbuf); 2870 state->ls_status = status; 2871 return (DLADM_WALK_CONTINUE); 2872} 2873 2874static boolean_t 2875print_link_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2876{ 2877 link_args_t *largs = ofarg->ofmt_cbarg; 2878 pktsum_t *diff_stats = largs->link_s_psum; 2879 2880 switch (ofarg->ofmt_id) { 2881 case LINK_S_LINK: 2882 (void) snprintf(buf, bufsize, "%s", largs->link_s_link); 2883 break; 2884 case LINK_S_IPKTS: 2885 (void) snprintf(buf, bufsize, "%llu", diff_stats->ipackets); 2886 break; 2887 case LINK_S_RBYTES: 2888 (void) snprintf(buf, bufsize, "%llu", diff_stats->rbytes); 2889 break; 2890 case LINK_S_IERRORS: 2891 (void) snprintf(buf, bufsize, "%u", diff_stats->ierrors); 2892 break; 2893 case LINK_S_OPKTS: 2894 (void) snprintf(buf, bufsize, "%llu", diff_stats->opackets); 2895 break; 2896 case LINK_S_OBYTES: 2897 (void) snprintf(buf, bufsize, "%llu", diff_stats->obytes); 2898 break; 2899 case LINK_S_OERRORS: 2900 (void) snprintf(buf, bufsize, "%u", diff_stats->oerrors); 2901 break; 2902 default: 2903 die("invalid input"); 2904 break; 2905 } 2906 return (B_TRUE); 2907} 2908 2909static int 2910show_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2911{ 2912 char link[DLPI_LINKNAME_MAX]; 2913 datalink_class_t class; 2914 show_state_t *state = arg; 2915 pktsum_t stats, diff_stats; 2916 dladm_phys_attr_t dpa; 2917 link_args_t largs; 2918 2919 if (state->ls_firstonly) { 2920 if (state->ls_donefirst) 2921 return (DLADM_WALK_CONTINUE); 2922 state->ls_donefirst = B_TRUE; 2923 } else { 2924 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 2925 } 2926 2927 if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, link, 2928 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2929 return (DLADM_WALK_CONTINUE); 2930 } 2931 2932 if (class == DATALINK_CLASS_PHYS) { 2933 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) != 2934 DLADM_STATUS_OK) { 2935 return (DLADM_WALK_CONTINUE); 2936 } 2937 if (dpa.dp_novanity) 2938 get_mac_stats(dpa.dp_dev, &stats); 2939 else 2940 get_link_stats(link, &stats); 2941 } else { 2942 get_link_stats(link, &stats); 2943 } 2944 dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats); 2945 2946 largs.link_s_link = link; 2947 largs.link_s_psum = &diff_stats; 2948 ofmt_print(state->ls_ofmt, &largs); 2949 2950 state->ls_prevstats = stats; 2951 return (DLADM_WALK_CONTINUE); 2952} 2953 2954 2955static dladm_status_t 2956print_aggr_info(show_grp_state_t *state, const char *link, 2957 dladm_aggr_grp_attr_t *ginfop) 2958{ 2959 char addr_str[ETHERADDRL * 3]; 2960 laggr_fields_buf_t lbuf; 2961 2962 (void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name), 2963 "%s", link); 2964 2965 (void) dladm_aggr_policy2str(ginfop->lg_policy, 2966 lbuf.laggr_policy); 2967 2968 if (ginfop->lg_mac_fixed) { 2969 (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); 2970 (void) snprintf(lbuf.laggr_addrpolicy, 2971 sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str); 2972 } else { 2973 (void) snprintf(lbuf.laggr_addrpolicy, 2974 sizeof (lbuf.laggr_addrpolicy), "auto"); 2975 } 2976 2977 (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, 2978 lbuf.laggr_lacpactivity); 2979 (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, 2980 lbuf.laggr_lacptimer); 2981 (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----", 2982 ginfop->lg_force ? 'f' : '-'); 2983 2984 ofmt_print(state->gs_ofmt, &lbuf); 2985 2986 return (DLADM_STATUS_OK); 2987} 2988 2989static boolean_t 2990print_xaggr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2991{ 2992 const laggr_args_t *l = ofarg->ofmt_cbarg; 2993 boolean_t is_port = (l->laggr_lport >= 0); 2994 char tmpbuf[DLADM_STRSIZE]; 2995 const char *objname; 2996 dladm_aggr_port_attr_t *portp; 2997 dladm_phys_attr_t dpa; 2998 2999 if (is_port) { 3000 portp = &(l->laggr_ginfop->lg_ports[l->laggr_lport]); 3001 if (dladm_phys_info(handle, portp->lp_linkid, &dpa, 3002 DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) 3003 objname = "?"; 3004 else 3005 objname = dpa.dp_dev; 3006 } else { 3007 objname = l->laggr_link; 3008 } 3009 3010 switch (ofarg->ofmt_id) { 3011 case AGGR_X_LINK: 3012 (void) snprintf(buf, bufsize, "%s", 3013 (is_port && !l->laggr_parsable ? " " : l->laggr_link)); 3014 break; 3015 case AGGR_X_PORT: 3016 if (is_port) { 3017 if (dladm_datalink_id2info(handle, portp->lp_linkid, 3018 NULL, NULL, NULL, buf, bufsize) != DLADM_STATUS_OK) 3019 (void) sprintf(buf, "?"); 3020 } 3021 break; 3022 3023 case AGGR_X_SPEED: 3024 (void) snprintf(buf, bufsize, "%uMb", 3025 (uint_t)((get_ifspeed(objname, !is_port)) / 1000000ull)); 3026 break; 3027 3028 case AGGR_X_DUPLEX: 3029 (void) get_linkduplex(objname, !is_port, tmpbuf); 3030 (void) strlcpy(buf, tmpbuf, bufsize); 3031 break; 3032 3033 case AGGR_X_STATE: 3034 (void) get_linkstate(objname, !is_port, tmpbuf); 3035 (void) strlcpy(buf, tmpbuf, bufsize); 3036 break; 3037 case AGGR_X_ADDRESS: 3038 (void) dladm_aggr_macaddr2str( 3039 (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac), 3040 tmpbuf); 3041 (void) strlcpy(buf, tmpbuf, bufsize); 3042 break; 3043 case AGGR_X_PORTSTATE: 3044 if (is_port) { 3045 (void) dladm_aggr_portstate2str(portp->lp_state, 3046 tmpbuf); 3047 (void) strlcpy(buf, tmpbuf, bufsize); 3048 } 3049 break; 3050 } 3051err: 3052 *(l->laggr_status) = DLADM_STATUS_OK; 3053 return (B_TRUE); 3054} 3055 3056static dladm_status_t 3057print_aggr_extended(show_grp_state_t *state, const char *link, 3058 dladm_aggr_grp_attr_t *ginfop) 3059{ 3060 int i; 3061 dladm_status_t status; 3062 laggr_args_t largs; 3063 3064 largs.laggr_lport = -1; 3065 largs.laggr_link = link; 3066 largs.laggr_ginfop = ginfop; 3067 largs.laggr_status = &status; 3068 largs.laggr_parsable = state->gs_parsable; 3069 3070 ofmt_print(state->gs_ofmt, &largs); 3071 3072 if (status != DLADM_STATUS_OK) 3073 goto done; 3074 3075 for (i = 0; i < ginfop->lg_nports; i++) { 3076 largs.laggr_lport = i; 3077 ofmt_print(state->gs_ofmt, &largs); 3078 if (status != DLADM_STATUS_OK) 3079 goto done; 3080 } 3081 3082 status = DLADM_STATUS_OK; 3083done: 3084 return (status); 3085} 3086 3087static boolean_t 3088print_lacp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3089{ 3090 const laggr_args_t *l = ofarg->ofmt_cbarg; 3091 int portnum; 3092 boolean_t is_port = (l->laggr_lport >= 0); 3093 dladm_aggr_port_attr_t *portp; 3094 aggr_lacp_state_t *lstate; 3095 3096 if (!is_port) 3097 return (B_FALSE); /* cannot happen! */ 3098 3099 portnum = l->laggr_lport; 3100 portp = &(l->laggr_ginfop->lg_ports[portnum]); 3101 lstate = &(portp->lp_lacp_state); 3102 3103 switch (ofarg->ofmt_id) { 3104 case AGGR_L_LINK: 3105 (void) snprintf(buf, bufsize, "%s", 3106 (portnum > 0 ? "" : l->laggr_link)); 3107 break; 3108 3109 case AGGR_L_PORT: 3110 if (dladm_datalink_id2info(handle, portp->lp_linkid, NULL, NULL, 3111 NULL, buf, bufsize) != DLADM_STATUS_OK) 3112 (void) sprintf(buf, "?"); 3113 break; 3114 3115 case AGGR_L_AGGREGATABLE: 3116 (void) snprintf(buf, bufsize, "%s", 3117 (lstate->bit.aggregation ? "yes" : "no")); 3118 break; 3119 3120 case AGGR_L_SYNC: 3121 (void) snprintf(buf, bufsize, "%s", 3122 (lstate->bit.sync ? "yes" : "no")); 3123 break; 3124 3125 case AGGR_L_COLL: 3126 (void) snprintf(buf, bufsize, "%s", 3127 (lstate->bit.collecting ? "yes" : "no")); 3128 break; 3129 3130 case AGGR_L_DIST: 3131 (void) snprintf(buf, bufsize, "%s", 3132 (lstate->bit.distributing ? "yes" : "no")); 3133 break; 3134 3135 case AGGR_L_DEFAULTED: 3136 (void) snprintf(buf, bufsize, "%s", 3137 (lstate->bit.defaulted ? "yes" : "no")); 3138 break; 3139 3140 case AGGR_L_EXPIRED: 3141 (void) snprintf(buf, bufsize, "%s", 3142 (lstate->bit.expired ? "yes" : "no")); 3143 break; 3144 } 3145 3146 *(l->laggr_status) = DLADM_STATUS_OK; 3147 return (B_TRUE); 3148} 3149 3150static dladm_status_t 3151print_aggr_lacp(show_grp_state_t *state, const char *link, 3152 dladm_aggr_grp_attr_t *ginfop) 3153{ 3154 int i; 3155 dladm_status_t status; 3156 laggr_args_t largs; 3157 3158 largs.laggr_link = link; 3159 largs.laggr_ginfop = ginfop; 3160 largs.laggr_status = &status; 3161 3162 for (i = 0; i < ginfop->lg_nports; i++) { 3163 largs.laggr_lport = i; 3164 ofmt_print(state->gs_ofmt, &largs); 3165 if (status != DLADM_STATUS_OK) 3166 goto done; 3167 } 3168 3169 status = DLADM_STATUS_OK; 3170done: 3171 return (status); 3172} 3173 3174static boolean_t 3175print_aggr_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3176{ 3177 const laggr_args_t *l = ofarg->ofmt_cbarg; 3178 int portnum; 3179 boolean_t is_port = (l->laggr_lport >= 0); 3180 dladm_aggr_port_attr_t *portp; 3181 dladm_status_t *stat, status; 3182 pktsum_t *diff_stats; 3183 3184 stat = l->laggr_status; 3185 *stat = DLADM_STATUS_OK; 3186 3187 if (is_port) { 3188 portnum = l->laggr_lport; 3189 portp = &(l->laggr_ginfop->lg_ports[portnum]); 3190 3191 if ((status = dladm_datalink_id2info(handle, 3192 portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) != 3193 DLADM_STATUS_OK) { 3194 goto err; 3195 } 3196 diff_stats = l->laggr_diffstats; 3197 } 3198 3199 switch (ofarg->ofmt_id) { 3200 case AGGR_S_LINK: 3201 (void) snprintf(buf, bufsize, "%s", 3202 (is_port ? "" : l->laggr_link)); 3203 break; 3204 case AGGR_S_PORT: 3205 /* 3206 * if (is_port), buf has port name. Otherwise we print 3207 * STR_UNDEF_VAL 3208 */ 3209 break; 3210 3211 case AGGR_S_IPKTS: 3212 if (is_port) { 3213 (void) snprintf(buf, bufsize, "%llu", 3214 diff_stats->ipackets); 3215 } else { 3216 (void) snprintf(buf, bufsize, "%llu", 3217 l->laggr_pktsumtot->ipackets); 3218 } 3219 break; 3220 3221 case AGGR_S_RBYTES: 3222 if (is_port) { 3223 (void) snprintf(buf, bufsize, "%llu", 3224 diff_stats->rbytes); 3225 } else { 3226 (void) snprintf(buf, bufsize, "%llu", 3227 l->laggr_pktsumtot->rbytes); 3228 } 3229 break; 3230 3231 case AGGR_S_OPKTS: 3232 if (is_port) { 3233 (void) snprintf(buf, bufsize, "%llu", 3234 diff_stats->opackets); 3235 } else { 3236 (void) snprintf(buf, bufsize, "%llu", 3237 l->laggr_pktsumtot->opackets); 3238 } 3239 break; 3240 case AGGR_S_OBYTES: 3241 if (is_port) { 3242 (void) snprintf(buf, bufsize, "%llu", 3243 diff_stats->obytes); 3244 } else { 3245 (void) snprintf(buf, bufsize, "%llu", 3246 l->laggr_pktsumtot->obytes); 3247 } 3248 break; 3249 3250 case AGGR_S_IPKTDIST: 3251 if (is_port) { 3252 (void) snprintf(buf, bufsize, "%-6.1f", 3253 (double)diff_stats->ipackets/ 3254 (double)l->laggr_pktsumtot->ipackets * 100); 3255 } 3256 break; 3257 case AGGR_S_OPKTDIST: 3258 if (is_port) { 3259 (void) snprintf(buf, bufsize, "%-6.1f", 3260 (double)diff_stats->opackets/ 3261 (double)l->laggr_pktsumtot->opackets * 100); 3262 } 3263 break; 3264 } 3265 return (B_TRUE); 3266 3267err: 3268 *stat = status; 3269 return (B_TRUE); 3270} 3271 3272static dladm_status_t 3273print_aggr_stats(show_grp_state_t *state, const char *link, 3274 dladm_aggr_grp_attr_t *ginfop) 3275{ 3276 dladm_phys_attr_t dpa; 3277 dladm_aggr_port_attr_t *portp; 3278 pktsum_t pktsumtot, *port_stat; 3279 dladm_status_t status; 3280 int i; 3281 laggr_args_t largs; 3282 3283 /* sum the ports statistics */ 3284 bzero(&pktsumtot, sizeof (pktsumtot)); 3285 3286 /* Allocate memory to keep stats of each port */ 3287 port_stat = malloc(ginfop->lg_nports * sizeof (pktsum_t)); 3288 if (port_stat == NULL) { 3289 /* Bail out; no memory */ 3290 return (DLADM_STATUS_NOMEM); 3291 } 3292 3293 3294 for (i = 0; i < ginfop->lg_nports; i++) { 3295 3296 portp = &(ginfop->lg_ports[i]); 3297 if ((status = dladm_phys_info(handle, portp->lp_linkid, &dpa, 3298 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 3299 goto done; 3300 } 3301 3302 get_mac_stats(dpa.dp_dev, &port_stat[i]); 3303 3304 /* 3305 * Let's re-use gs_prevstats[] to store the difference of the 3306 * counters since last use. We will store the new stats from 3307 * port_stat[] once we have the stats displayed. 3308 */ 3309 3310 dladm_stats_diff(&state->gs_prevstats[i], &port_stat[i], 3311 &state->gs_prevstats[i]); 3312 dladm_stats_total(&pktsumtot, &pktsumtot, 3313 &state->gs_prevstats[i]); 3314 } 3315 3316 largs.laggr_lport = -1; 3317 largs.laggr_link = link; 3318 largs.laggr_ginfop = ginfop; 3319 largs.laggr_status = &status; 3320 largs.laggr_pktsumtot = &pktsumtot; 3321 3322 ofmt_print(state->gs_ofmt, &largs); 3323 3324 if (status != DLADM_STATUS_OK) 3325 goto done; 3326 3327 for (i = 0; i < ginfop->lg_nports; i++) { 3328 largs.laggr_lport = i; 3329 largs.laggr_diffstats = &state->gs_prevstats[i]; 3330 ofmt_print(state->gs_ofmt, &largs); 3331 if (status != DLADM_STATUS_OK) 3332 goto done; 3333 } 3334 3335 status = DLADM_STATUS_OK; 3336 for (i = 0; i < ginfop->lg_nports; i++) 3337 state->gs_prevstats[i] = port_stat[i]; 3338 3339done: 3340 free(port_stat); 3341 return (status); 3342} 3343 3344static dladm_status_t 3345print_aggr(show_grp_state_t *state, datalink_id_t linkid) 3346{ 3347 char link[MAXLINKNAMELEN]; 3348 dladm_aggr_grp_attr_t ginfo; 3349 uint32_t flags; 3350 dladm_status_t status; 3351 3352 bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t)); 3353 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 3354 NULL, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 3355 return (status); 3356 } 3357 3358 if (!(state->gs_flags & flags)) 3359 return (DLADM_STATUS_NOTFOUND); 3360 3361 status = dladm_aggr_info(handle, linkid, &ginfo, state->gs_flags); 3362 if (status != DLADM_STATUS_OK) 3363 return (status); 3364 3365 if (state->gs_lacp) 3366 status = print_aggr_lacp(state, link, &ginfo); 3367 else if (state->gs_extended) 3368 status = print_aggr_extended(state, link, &ginfo); 3369 else if (state->gs_stats) 3370 status = print_aggr_stats(state, link, &ginfo); 3371 else 3372 status = print_aggr_info(state, link, &ginfo); 3373 3374done: 3375 free(ginfo.lg_ports); 3376 return (status); 3377} 3378 3379/* ARGSUSED */ 3380static int 3381show_aggr(dladm_handle_t dh, datalink_id_t linkid, void *arg) 3382{ 3383 show_grp_state_t *state = arg; 3384 3385 state->gs_status = print_aggr(state, linkid); 3386 return (DLADM_WALK_CONTINUE); 3387} 3388 3389static void 3390do_show_link(int argc, char *argv[], const char *use) 3391{ 3392 int option; 3393 boolean_t s_arg = B_FALSE; 3394 boolean_t i_arg = B_FALSE; 3395 uint32_t flags = DLADM_OPT_ACTIVE; 3396 boolean_t p_arg = B_FALSE; 3397 datalink_id_t linkid = DATALINK_ALL_LINKID; 3398 char linkname[MAXLINKNAMELEN]; 3399 uint32_t interval = 0; 3400 show_state_t state; 3401 dladm_status_t status; 3402 boolean_t o_arg = B_FALSE; 3403 char *fields_str = NULL; 3404 char *all_active_fields = "link,class,mtu,state,bridge,over"; 3405 char *all_inactive_fields = "link,class,bridge,over"; 3406 char *allstat_fields = 3407 "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; 3408 ofmt_handle_t ofmt; 3409 ofmt_status_t oferr; 3410 uint_t ofmtflags = 0; 3411 3412 bzero(&state, sizeof (state)); 3413 3414 opterr = 0; 3415 while ((option = getopt_long(argc, argv, ":pPsi:o:", 3416 show_lopts, NULL)) != -1) { 3417 switch (option) { 3418 case 'p': 3419 if (p_arg) 3420 die_optdup(option); 3421 3422 p_arg = B_TRUE; 3423 break; 3424 case 's': 3425 if (s_arg) 3426 die_optdup(option); 3427 3428 s_arg = B_TRUE; 3429 break; 3430 case 'P': 3431 if (flags != DLADM_OPT_ACTIVE) 3432 die_optdup(option); 3433 3434 flags = DLADM_OPT_PERSIST; 3435 break; 3436 case 'o': 3437 o_arg = B_TRUE; 3438 fields_str = optarg; 3439 break; 3440 case 'i': 3441 if (i_arg) 3442 die_optdup(option); 3443 3444 i_arg = B_TRUE; 3445 if (!dladm_str2interval(optarg, &interval)) 3446 die("invalid interval value '%s'", optarg); 3447 break; 3448 default: 3449 die_opterr(optopt, option, use); 3450 break; 3451 } 3452 } 3453 3454 if (i_arg && !s_arg) 3455 die("the option -i can be used only with -s"); 3456 3457 if (s_arg && flags != DLADM_OPT_ACTIVE) 3458 die("the option -P cannot be used with -s"); 3459 3460 /* get link name (optional last argument) */ 3461 if (optind == (argc-1)) { 3462 uint32_t f; 3463 3464 if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN) >= 3465 MAXLINKNAMELEN) 3466 die("link name too long"); 3467 if ((status = dladm_name2info(handle, linkname, &linkid, &f, 3468 NULL, NULL)) != DLADM_STATUS_OK) { 3469 die_dlerr(status, "link %s is not valid", linkname); 3470 } 3471 3472 if (!(f & flags)) { 3473 die_dlerr(DLADM_STATUS_BADARG, "link %s is %s", 3474 argv[optind], flags == DLADM_OPT_PERSIST ? 3475 "a temporary link" : "temporarily removed"); 3476 } 3477 } else if (optind != argc) { 3478 usage(); 3479 } 3480 3481 if (p_arg && !o_arg) 3482 die("-p requires -o"); 3483 3484 if (p_arg && strcasecmp(fields_str, "all") == 0) 3485 die("\"-o all\" is invalid with -p"); 3486 3487 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3488 if (s_arg) 3489 fields_str = allstat_fields; 3490 else if (flags & DLADM_OPT_ACTIVE) 3491 fields_str = all_active_fields; 3492 else 3493 fields_str = all_inactive_fields; 3494 } 3495 3496 state.ls_parsable = p_arg; 3497 state.ls_flags = flags; 3498 state.ls_donefirst = B_FALSE; 3499 3500 if (s_arg) { 3501 link_stats(linkid, interval, fields_str, &state); 3502 return; 3503 } 3504 if (state.ls_parsable) 3505 ofmtflags |= OFMT_PARSABLE; 3506 else 3507 ofmtflags |= OFMT_WRAP; 3508 3509 oferr = ofmt_open(fields_str, link_fields, ofmtflags, 0, &ofmt); 3510 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 3511 state.ls_ofmt = ofmt; 3512 3513 if (linkid == DATALINK_ALL_LINKID) { 3514 (void) dladm_walk_datalink_id(show_link, handle, &state, 3515 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 3516 } else { 3517 (void) show_link(handle, linkid, &state); 3518 if (state.ls_status != DLADM_STATUS_OK) { 3519 die_dlerr(state.ls_status, "failed to show link %s", 3520 argv[optind]); 3521 } 3522 } 3523 ofmt_close(ofmt); 3524} 3525 3526static void 3527do_show_aggr(int argc, char *argv[], const char *use) 3528{ 3529 boolean_t L_arg = B_FALSE; 3530 boolean_t s_arg = B_FALSE; 3531 boolean_t i_arg = B_FALSE; 3532 boolean_t p_arg = B_FALSE; 3533 boolean_t x_arg = B_FALSE; 3534 show_grp_state_t state; 3535 uint32_t flags = DLADM_OPT_ACTIVE; 3536 datalink_id_t linkid = DATALINK_ALL_LINKID; 3537 int option; 3538 uint32_t interval = 0; 3539 int key; 3540 dladm_status_t status; 3541 boolean_t o_arg = B_FALSE; 3542 char *fields_str = NULL; 3543 char *all_fields = 3544 "link,policy,addrpolicy,lacpactivity,lacptimer,flags"; 3545 char *all_lacp_fields = 3546 "link,port,aggregatable,sync,coll,dist,defaulted,expired"; 3547 char *all_stats_fields = 3548 "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist"; 3549 char *all_extended_fields = 3550 "link,port,speed,duplex,state,address,portstate"; 3551 const ofmt_field_t *pf; 3552 ofmt_handle_t ofmt; 3553 ofmt_status_t oferr; 3554 uint_t ofmtflags = 0; 3555 3556 opterr = 0; 3557 while ((option = getopt_long(argc, argv, ":LpPxsi:o:", 3558 show_lopts, NULL)) != -1) { 3559 switch (option) { 3560 case 'L': 3561 if (L_arg) 3562 die_optdup(option); 3563 3564 L_arg = B_TRUE; 3565 break; 3566 case 'p': 3567 if (p_arg) 3568 die_optdup(option); 3569 3570 p_arg = B_TRUE; 3571 break; 3572 case 'x': 3573 if (x_arg) 3574 die_optdup(option); 3575 3576 x_arg = B_TRUE; 3577 break; 3578 case 'P': 3579 if (flags != DLADM_OPT_ACTIVE) 3580 die_optdup(option); 3581 3582 flags = DLADM_OPT_PERSIST; 3583 break; 3584 case 's': 3585 if (s_arg) 3586 die_optdup(option); 3587 3588 s_arg = B_TRUE; 3589 break; 3590 case 'o': 3591 o_arg = B_TRUE; 3592 fields_str = optarg; 3593 break; 3594 case 'i': 3595 if (i_arg) 3596 die_optdup(option); 3597 3598 i_arg = B_TRUE; 3599 if (!dladm_str2interval(optarg, &interval)) 3600 die("invalid interval value '%s'", optarg); 3601 break; 3602 default: 3603 die_opterr(optopt, option, use); 3604 break; 3605 } 3606 } 3607 3608 if (p_arg && !o_arg) 3609 die("-p requires -o"); 3610 3611 if (p_arg && strcasecmp(fields_str, "all") == 0) 3612 die("\"-o all\" is invalid with -p"); 3613 3614 if (i_arg && !s_arg) 3615 die("the option -i can be used only with -s"); 3616 3617 if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) { 3618 die("the option -%c cannot be used with -s", 3619 L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P'))); 3620 } 3621 3622 if (L_arg && flags != DLADM_OPT_ACTIVE) 3623 die("the option -P cannot be used with -L"); 3624 3625 if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE)) 3626 die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P'); 3627 3628 /* get aggregation key or aggrname (optional last argument) */ 3629 if (optind == (argc-1)) { 3630 if (!str2int(argv[optind], &key)) { 3631 status = dladm_name2info(handle, argv[optind], 3632 &linkid, NULL, NULL, NULL); 3633 } else { 3634 status = dladm_key2linkid(handle, (uint16_t)key, 3635 &linkid, DLADM_OPT_ACTIVE); 3636 } 3637 3638 if (status != DLADM_STATUS_OK) 3639 die("non-existent aggregation '%s'", argv[optind]); 3640 3641 } else if (optind != argc) { 3642 usage(); 3643 } 3644 3645 bzero(&state, sizeof (state)); 3646 state.gs_lacp = L_arg; 3647 state.gs_stats = s_arg; 3648 state.gs_flags = flags; 3649 state.gs_parsable = p_arg; 3650 state.gs_extended = x_arg; 3651 3652 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3653 if (state.gs_lacp) 3654 fields_str = all_lacp_fields; 3655 else if (state.gs_stats) 3656 fields_str = all_stats_fields; 3657 else if (state.gs_extended) 3658 fields_str = all_extended_fields; 3659 else 3660 fields_str = all_fields; 3661 } 3662 3663 if (state.gs_lacp) { 3664 pf = aggr_l_fields; 3665 } else if (state.gs_stats) { 3666 pf = aggr_s_fields; 3667 } else if (state.gs_extended) { 3668 pf = aggr_x_fields; 3669 } else { 3670 pf = laggr_fields; 3671 } 3672 3673 if (state.gs_parsable) 3674 ofmtflags |= OFMT_PARSABLE; 3675 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 3676 ofmt_check(oferr, state.gs_parsable, ofmt, die, warn); 3677 state.gs_ofmt = ofmt; 3678 3679 if (s_arg) { 3680 aggr_stats(linkid, &state, interval); 3681 ofmt_close(ofmt); 3682 return; 3683 } 3684 3685 if (linkid == DATALINK_ALL_LINKID) { 3686 (void) dladm_walk_datalink_id(show_aggr, handle, &state, 3687 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); 3688 } else { 3689 (void) show_aggr(handle, linkid, &state); 3690 if (state.gs_status != DLADM_STATUS_OK) { 3691 die_dlerr(state.gs_status, "failed to show aggr %s", 3692 argv[optind]); 3693 } 3694 } 3695 ofmt_close(ofmt); 3696} 3697 3698static dladm_status_t 3699print_phys_default(show_state_t *state, datalink_id_t linkid, 3700 const char *link, uint32_t flags, uint32_t media) 3701{ 3702 dladm_phys_attr_t dpa; 3703 dladm_status_t status; 3704 link_fields_buf_t pattr; 3705 3706 status = dladm_phys_info(handle, linkid, &dpa, state->ls_flags); 3707 if (status != DLADM_STATUS_OK) 3708 goto done; 3709 3710 bzero(&pattr, sizeof (pattr)); 3711 (void) snprintf(pattr.link_phys_device, 3712 sizeof (pattr.link_phys_device), "%s", dpa.dp_dev); 3713 (void) dladm_media2str(media, pattr.link_phys_media); 3714 if (state->ls_flags == DLADM_OPT_ACTIVE) { 3715 boolean_t islink; 3716 3717 if (!dpa.dp_novanity) { 3718 (void) strlcpy(pattr.link_name, link, 3719 sizeof (pattr.link_name)); 3720 islink = B_TRUE; 3721 } else { 3722 /* 3723 * This is a physical link that does not have 3724 * vanity naming support. 3725 */ 3726 (void) strlcpy(pattr.link_name, dpa.dp_dev, 3727 sizeof (pattr.link_name)); 3728 islink = B_FALSE; 3729 } 3730 3731 (void) get_linkstate(pattr.link_name, islink, 3732 pattr.link_phys_state); 3733 (void) snprintf(pattr.link_phys_speed, 3734 sizeof (pattr.link_phys_speed), "%u", 3735 (uint_t)((get_ifspeed(pattr.link_name, 3736 islink)) / 1000000ull)); 3737 (void) get_linkduplex(pattr.link_name, islink, 3738 pattr.link_phys_duplex); 3739 } else { 3740 (void) snprintf(pattr.link_name, sizeof (pattr.link_name), 3741 "%s", link); 3742 (void) snprintf(pattr.link_flags, sizeof (pattr.link_flags), 3743 "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r'); 3744 } 3745 3746 ofmt_print(state->ls_ofmt, &pattr); 3747 3748done: 3749 return (status); 3750} 3751 3752typedef struct { 3753 show_state_t *ms_state; 3754 char *ms_link; 3755 dladm_macaddr_attr_t *ms_mac_attr; 3756} print_phys_mac_state_t; 3757 3758/* 3759 * callback for ofmt_print() 3760 */ 3761static boolean_t 3762print_phys_one_mac_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3763{ 3764 print_phys_mac_state_t *mac_state = ofarg->ofmt_cbarg; 3765 dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr; 3766 boolean_t is_primary = (attr->ma_slot == 0); 3767 boolean_t is_parsable = mac_state->ms_state->ls_parsable; 3768 3769 switch (ofarg->ofmt_id) { 3770 case PHYS_M_LINK: 3771 (void) snprintf(buf, bufsize, "%s", 3772 (is_primary || is_parsable) ? mac_state->ms_link : " "); 3773 break; 3774 case PHYS_M_SLOT: 3775 if (is_primary) 3776 (void) snprintf(buf, bufsize, gettext("primary")); 3777 else 3778 (void) snprintf(buf, bufsize, "%d", attr->ma_slot); 3779 break; 3780 case PHYS_M_ADDRESS: 3781 (void) dladm_aggr_macaddr2str(attr->ma_addr, buf); 3782 break; 3783 case PHYS_M_INUSE: 3784 (void) snprintf(buf, bufsize, "%s", 3785 attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") : 3786 gettext("no")); 3787 break; 3788 case PHYS_M_CLIENT: 3789 /* 3790 * CR 6678526: resolve link id to actual link name if 3791 * it is valid. 3792 */ 3793 (void) snprintf(buf, bufsize, "%s", attr->ma_client_name); 3794 break; 3795 } 3796 3797 return (B_TRUE); 3798} 3799 3800typedef struct { 3801 show_state_t *hs_state; 3802 char *hs_link; 3803 dladm_hwgrp_attr_t *hs_grp_attr; 3804} print_phys_hwgrp_state_t; 3805 3806static boolean_t 3807print_phys_one_hwgrp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3808{ 3809 int i; 3810 boolean_t first = B_TRUE; 3811 int start = -1; 3812 int end = -1; 3813 char ringstr[RINGSTRLEN]; 3814 char ringsubstr[RINGSTRLEN]; 3815 3816 print_phys_hwgrp_state_t *hg_state = ofarg->ofmt_cbarg; 3817 dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr; 3818 3819 switch (ofarg->ofmt_id) { 3820 case PHYS_H_LINK: 3821 (void) snprintf(buf, bufsize, "%s", attr->hg_link_name); 3822 break; 3823 case PHYS_H_RINGTYPE: 3824 (void) snprintf(buf, bufsize, "%s", 3825 attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX"); 3826 break; 3827 case PHYS_H_RINGS: 3828 ringstr[0] = '\0'; 3829 for (i = 0; i < attr->hg_n_rings; i++) { 3830 uint_t index = attr->hg_rings[i]; 3831 3832 if (start == -1) { 3833 start = index; 3834 end = index; 3835 } else if (index == end + 1) { 3836 end = index; 3837 } else { 3838 if (start == end) { 3839 if (first) { 3840 (void) snprintf( 3841 ringsubstr, 3842 RINGSTRLEN, "%d", 3843 start); 3844 first = B_FALSE; 3845 } else { 3846 (void) snprintf( 3847 ringsubstr, 3848 RINGSTRLEN, ",%d", 3849 start); 3850 } 3851 } else { 3852 if (first) { 3853 (void) snprintf( 3854 ringsubstr, 3855 RINGSTRLEN, 3856 "%d-%d", 3857 start, end); 3858 first = B_FALSE; 3859 } else { 3860 (void) snprintf( 3861 ringsubstr, 3862 RINGSTRLEN, 3863 ",%d-%d", 3864 start, end); 3865 } 3866 } 3867 (void) strlcat(ringstr, ringsubstr, 3868 RINGSTRLEN); 3869 start = index; 3870 end = index; 3871 } 3872 } 3873 /* The last one */ 3874 if (start != -1) { 3875 if (first) { 3876 if (start == end) { 3877 (void) snprintf(buf, bufsize, "%d", 3878 start); 3879 } else { 3880 (void) snprintf(buf, bufsize, "%d-%d", 3881 start, end); 3882 } 3883 } else { 3884 if (start == end) { 3885 (void) snprintf(ringsubstr, RINGSTRLEN, 3886 ",%d", start); 3887 } else { 3888 (void) snprintf(ringsubstr, RINGSTRLEN, 3889 ",%d-%d", start, end); 3890 } 3891 (void) strlcat(ringstr, ringsubstr, RINGSTRLEN); 3892 (void) snprintf(buf, bufsize, "%s", ringstr); 3893 } 3894 } 3895 break; 3896 case PHYS_H_CLIENTS: 3897 if (attr->hg_client_names[0] == '\0') { 3898 (void) snprintf(buf, bufsize, "--"); 3899 } else { 3900 (void) snprintf(buf, bufsize, "%s ", 3901 attr->hg_client_names); 3902 } 3903 break; 3904 } 3905 3906 return (B_TRUE); 3907} 3908 3909/* 3910 * callback for dladm_walk_macaddr, invoked for each MAC address slot 3911 */ 3912static boolean_t 3913print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr) 3914{ 3915 print_phys_mac_state_t *mac_state = arg; 3916 show_state_t *state = mac_state->ms_state; 3917 3918 mac_state->ms_mac_attr = attr; 3919 ofmt_print(state->ls_ofmt, mac_state); 3920 3921 return (B_TRUE); 3922} 3923 3924/* 3925 * invoked by show-phys -m for each physical data-link 3926 */ 3927static dladm_status_t 3928print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link) 3929{ 3930 print_phys_mac_state_t mac_state; 3931 3932 mac_state.ms_state = state; 3933 mac_state.ms_link = link; 3934 3935 return (dladm_walk_macaddr(handle, linkid, &mac_state, 3936 print_phys_mac_callback)); 3937} 3938 3939/* 3940 * callback for dladm_walk_hwgrp, invoked for each MAC hwgrp 3941 */ 3942static boolean_t 3943print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr) 3944{ 3945 print_phys_hwgrp_state_t *hwgrp_state = arg; 3946 show_state_t *state = hwgrp_state->hs_state; 3947 3948 hwgrp_state->hs_grp_attr = attr; 3949 ofmt_print(state->ls_ofmt, hwgrp_state); 3950 3951 return (B_TRUE); 3952} 3953 3954/* invoked by show-phys -H for each physical data-link */ 3955static dladm_status_t 3956print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link) 3957{ 3958 print_phys_hwgrp_state_t hwgrp_state; 3959 3960 hwgrp_state.hs_state = state; 3961 hwgrp_state.hs_link = link; 3962 return (dladm_walk_hwgrp(handle, linkid, &hwgrp_state, 3963 print_phys_hwgrp_callback)); 3964} 3965 3966/* 3967 * Parse the "local=<laddr>,remote=<raddr>" sub-options for the -a option of 3968 * *-iptun subcommands. 3969 */ 3970static void 3971iptun_process_addrarg(char *addrarg, iptun_params_t *params) 3972{ 3973 char *addrval; 3974 3975 while (*addrarg != '\0') { 3976 switch (getsubopt(&addrarg, iptun_addropts, &addrval)) { 3977 case IPTUN_LOCAL: 3978 if (addrval == NULL) 3979 die("tunnel source address value is missing"); 3980 params->iptun_param_flags |= IPTUN_PARAM_LADDR; 3981 if (strlcpy(params->iptun_param_laddr, addrval, 3982 sizeof (params->iptun_param_laddr)) >= 3983 sizeof (params->iptun_param_laddr)) 3984 die("tunnel source address is too long"); 3985 break; 3986 case IPTUN_REMOTE: 3987 if (addrval == NULL) 3988 die("tunnel destination address value " 3989 "is missing"); 3990 params->iptun_param_flags |= IPTUN_PARAM_RADDR; 3991 if (strlcpy(params->iptun_param_raddr, addrval, 3992 sizeof (params->iptun_param_raddr)) >= 3993 sizeof (params->iptun_param_raddr)) 3994 die("tunnel destination address is too long"); 3995 break; 3996 default: 3997 die("invalid address type: %s", addrval); 3998 break; 3999 } 4000 } 4001} 4002 4003/* 4004 * Convenience routine to process iptun-create/modify/delete subcommand 4005 * arguments. 4006 */ 4007static void 4008iptun_process_args(int argc, char *argv[], const char *opts, 4009 iptun_params_t *params, uint32_t *flags, char *name, const char *use) 4010{ 4011 int option; 4012 char *altroot = NULL; 4013 4014 if (params != NULL) 4015 bzero(params, sizeof (*params)); 4016 *flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4017 4018 opterr = 0; 4019 while ((option = getopt_long(argc, argv, opts, iptun_lopts, NULL)) != 4020 -1) { 4021 switch (option) { 4022 case 'a': 4023 iptun_process_addrarg(optarg, params); 4024 break; 4025 case 'R': 4026 altroot = optarg; 4027 break; 4028 case 't': 4029 *flags &= ~DLADM_OPT_PERSIST; 4030 break; 4031 case 'T': 4032 params->iptun_param_type = iptun_gettypebyname(optarg); 4033 if (params->iptun_param_type == IPTUN_TYPE_UNKNOWN) 4034 die("unknown tunnel type: %s", optarg); 4035 params->iptun_param_flags |= IPTUN_PARAM_TYPE; 4036 break; 4037 default: 4038 die_opterr(optopt, option, use); 4039 break; 4040 } 4041 } 4042 4043 /* Get the required tunnel name argument. */ 4044 if (argc - optind != 1) 4045 usage(); 4046 4047 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 4048 die("tunnel name is too long"); 4049 4050 if (altroot != NULL) 4051 altroot_cmd(altroot, argc, argv); 4052} 4053 4054static void 4055do_create_iptun(int argc, char *argv[], const char *use) 4056{ 4057 iptun_params_t params; 4058 dladm_status_t status; 4059 uint32_t flags; 4060 char name[MAXLINKNAMELEN]; 4061 4062 iptun_process_args(argc, argv, ":a:R:tT:", ¶ms, &flags, name, 4063 use); 4064 4065 status = dladm_iptun_create(handle, name, ¶ms, flags); 4066 if (status != DLADM_STATUS_OK) 4067 die_dlerr(status, "could not create tunnel"); 4068} 4069 4070static void 4071do_delete_iptun(int argc, char *argv[], const char *use) 4072{ 4073 uint32_t flags; 4074 datalink_id_t linkid; 4075 dladm_status_t status; 4076 char name[MAXLINKNAMELEN]; 4077 4078 iptun_process_args(argc, argv, ":R:t", NULL, &flags, name, use); 4079 4080 status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL); 4081 if (status != DLADM_STATUS_OK) 4082 die_dlerr(status, "could not delete tunnel"); 4083 status = dladm_iptun_delete(handle, linkid, flags); 4084 if (status != DLADM_STATUS_OK) 4085 die_dlerr(status, "could not delete tunnel"); 4086} 4087 4088static void 4089do_modify_iptun(int argc, char *argv[], const char *use) 4090{ 4091 iptun_params_t params; 4092 uint32_t flags; 4093 dladm_status_t status; 4094 char name[MAXLINKNAMELEN]; 4095 4096 iptun_process_args(argc, argv, ":a:R:t", ¶ms, &flags, name, use); 4097 4098 if ((status = dladm_name2info(handle, name, ¶ms.iptun_param_linkid, 4099 NULL, NULL, NULL)) != DLADM_STATUS_OK) 4100 die_dlerr(status, "could not modify tunnel"); 4101 status = dladm_iptun_modify(handle, ¶ms, flags); 4102 if (status != DLADM_STATUS_OK) 4103 die_dlerr(status, "could not modify tunnel"); 4104} 4105 4106static void 4107do_show_iptun(int argc, char *argv[], const char *use) 4108{ 4109 char option; 4110 datalink_id_t linkid; 4111 uint32_t flags = DLADM_OPT_ACTIVE; 4112 char *name = NULL; 4113 dladm_status_t status; 4114 const char *fields_str = NULL; 4115 show_state_t state; 4116 ofmt_handle_t ofmt; 4117 ofmt_status_t oferr; 4118 uint_t ofmtflags = 0; 4119 4120 bzero(&state, sizeof (state)); 4121 opterr = 0; 4122 while ((option = getopt_long(argc, argv, ":pPo:", 4123 iptun_lopts, NULL)) != -1) { 4124 switch (option) { 4125 case 'o': 4126 fields_str = optarg; 4127 break; 4128 case 'p': 4129 state.ls_parsable = B_TRUE; 4130 ofmtflags = OFMT_PARSABLE; 4131 break; 4132 case 'P': 4133 flags = DLADM_OPT_PERSIST; 4134 break; 4135 default: 4136 die_opterr(optopt, option, use); 4137 break; 4138 } 4139 } 4140 4141 /* 4142 * Get the optional tunnel name argument. If there is one, it must 4143 * be the last thing remaining on the command-line. 4144 */ 4145 if (argc - optind > 1) 4146 die(gettext(use)); 4147 if (argc - optind == 1) 4148 name = argv[optind]; 4149 4150 oferr = ofmt_open(fields_str, iptun_fields, ofmtflags, 4151 DLADM_DEFAULT_COL, &ofmt); 4152 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 4153 4154 state.ls_ofmt = ofmt; 4155 state.ls_flags = flags; 4156 4157 if (name == NULL) { 4158 (void) dladm_walk_datalink_id(print_iptun_walker, handle, 4159 &state, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE, 4160 flags); 4161 status = state.ls_status; 4162 } else { 4163 if ((status = dladm_name2info(handle, name, &linkid, NULL, NULL, 4164 NULL)) == DLADM_STATUS_OK) 4165 status = print_iptun(handle, linkid, &state); 4166 } 4167 4168 if (status != DLADM_STATUS_OK) 4169 die_dlerr(status, "unable to obtain tunnel status"); 4170} 4171 4172/* ARGSUSED */ 4173static void 4174do_up_iptun(int argc, char *argv[], const char *use) 4175{ 4176 datalink_id_t linkid = DATALINK_ALL_LINKID; 4177 dladm_status_t status = DLADM_STATUS_OK; 4178 4179 /* 4180 * Get the optional tunnel name argument. If there is one, it must 4181 * be the last thing remaining on the command-line. 4182 */ 4183 if (argc - optind > 1) 4184 usage(); 4185 if (argc - optind == 1) { 4186 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 4187 NULL, NULL); 4188 } 4189 if (status == DLADM_STATUS_OK) 4190 status = dladm_iptun_up(handle, linkid); 4191 if (status != DLADM_STATUS_OK) 4192 die_dlerr(status, "unable to configure IP tunnel links"); 4193} 4194 4195/* ARGSUSED */ 4196static void 4197do_down_iptun(int argc, char *argv[], const char *use) 4198{ 4199 datalink_id_t linkid = DATALINK_ALL_LINKID; 4200 dladm_status_t status = DLADM_STATUS_OK; 4201 4202 /* 4203 * Get the optional tunnel name argument. If there is one, it must 4204 * be the last thing remaining on the command-line. 4205 */ 4206 if (argc - optind > 1) 4207 usage(); 4208 if (argc - optind == 1) { 4209 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 4210 NULL, NULL); 4211 } 4212 if (status == DLADM_STATUS_OK) 4213 status = dladm_iptun_down(handle, linkid); 4214 if (status != DLADM_STATUS_OK) 4215 die_dlerr(status, "unable to bring down IP tunnel links"); 4216} 4217 4218static iptun_type_t 4219iptun_gettypebyname(char *typestr) 4220{ 4221 int i; 4222 4223 for (i = 0; iptun_types[i].type_name != NULL; i++) { 4224 if (strncmp(iptun_types[i].type_name, typestr, 4225 strlen(iptun_types[i].type_name)) == 0) { 4226 return (iptun_types[i].type_value); 4227 } 4228 } 4229 return (IPTUN_TYPE_UNKNOWN); 4230} 4231 4232static const char * 4233iptun_gettypebyvalue(iptun_type_t type) 4234{ 4235 int i; 4236 4237 for (i = 0; iptun_types[i].type_name != NULL; i++) { 4238 if (iptun_types[i].type_value == type) 4239 return (iptun_types[i].type_name); 4240 } 4241 return (NULL); 4242} 4243 4244static dladm_status_t 4245print_iptun(dladm_handle_t dh, datalink_id_t linkid, show_state_t *state) 4246{ 4247 dladm_status_t status; 4248 iptun_params_t params; 4249 iptun_fields_buf_t lbuf; 4250 const char *laddr; 4251 const char *raddr; 4252 4253 params.iptun_param_linkid = linkid; 4254 status = dladm_iptun_getparams(dh, ¶ms, state->ls_flags); 4255 if (status != DLADM_STATUS_OK) 4256 return (status); 4257 4258 /* LINK */ 4259 status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, 4260 lbuf.iptun_name, sizeof (lbuf.iptun_name)); 4261 if (status != DLADM_STATUS_OK) 4262 return (status); 4263 4264 /* TYPE */ 4265 (void) strlcpy(lbuf.iptun_type, 4266 iptun_gettypebyvalue(params.iptun_param_type), 4267 sizeof (lbuf.iptun_type)); 4268 4269 /* FLAGS */ 4270 (void) memset(lbuf.iptun_flags, '-', IPTUN_NUM_FLAGS); 4271 lbuf.iptun_flags[IPTUN_NUM_FLAGS] = '\0'; 4272 if (params.iptun_param_flags & IPTUN_PARAM_IPSECPOL) 4273 lbuf.iptun_flags[IPTUN_SFLAG_INDEX] = 's'; 4274 if (params.iptun_param_flags & IPTUN_PARAM_IMPLICIT) 4275 lbuf.iptun_flags[IPTUN_IFLAG_INDEX] = 'i'; 4276 4277 /* LOCAL */ 4278 if (params.iptun_param_flags & IPTUN_PARAM_LADDR) 4279 laddr = params.iptun_param_laddr; 4280 else 4281 laddr = (state->ls_parsable) ? "" : "--"; 4282 (void) strlcpy(lbuf.iptun_laddr, laddr, sizeof (lbuf.iptun_laddr)); 4283 4284 /* REMOTE */ 4285 if (params.iptun_param_flags & IPTUN_PARAM_RADDR) 4286 raddr = params.iptun_param_raddr; 4287 else 4288 raddr = (state->ls_parsable) ? "" : "--"; 4289 (void) strlcpy(lbuf.iptun_raddr, raddr, sizeof (lbuf.iptun_raddr)); 4290 4291 ofmt_print(state->ls_ofmt, &lbuf); 4292 4293 return (DLADM_STATUS_OK); 4294} 4295 4296static int 4297print_iptun_walker(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4298{ 4299 ((show_state_t *)arg)->ls_status = print_iptun(dh, linkid, arg); 4300 return (DLADM_WALK_CONTINUE); 4301} 4302 4303static dladm_status_t 4304print_phys(show_state_t *state, datalink_id_t linkid) 4305{ 4306 char link[MAXLINKNAMELEN]; 4307 uint32_t flags; 4308 dladm_status_t status; 4309 datalink_class_t class; 4310 uint32_t media; 4311 4312 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 4313 &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 4314 goto done; 4315 } 4316 4317 if (class != DATALINK_CLASS_PHYS) { 4318 status = DLADM_STATUS_BADARG; 4319 goto done; 4320 } 4321 4322 if (!(state->ls_flags & flags)) { 4323 status = DLADM_STATUS_NOTFOUND; 4324 goto done; 4325 } 4326 4327 if (state->ls_mac) 4328 status = print_phys_mac(state, linkid, link); 4329 else if (state->ls_hwgrp) 4330 status = print_phys_hwgrp(state, linkid, link); 4331 else 4332 status = print_phys_default(state, linkid, link, flags, media); 4333 4334done: 4335 return (status); 4336} 4337 4338/* ARGSUSED */ 4339static int 4340show_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4341{ 4342 show_state_t *state = arg; 4343 4344 state->ls_status = print_phys(state, linkid); 4345 return (DLADM_WALK_CONTINUE); 4346} 4347 4348/* 4349 * Print the active topology information. 4350 */ 4351static dladm_status_t 4352print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l) 4353{ 4354 dladm_vlan_attr_t vinfo; 4355 uint32_t flags; 4356 dladm_status_t status; 4357 4358 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL, 4359 l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) { 4360 goto done; 4361 } 4362 4363 if (!(state->ls_flags & flags)) { 4364 status = DLADM_STATUS_NOTFOUND; 4365 goto done; 4366 } 4367 4368 if ((status = dladm_vlan_info(handle, linkid, &vinfo, 4369 state->ls_flags)) != DLADM_STATUS_OK || 4370 (status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, 4371 NULL, NULL, l->link_over, sizeof (l->link_over))) != 4372 DLADM_STATUS_OK) { 4373 goto done; 4374 } 4375 4376 (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d", 4377 vinfo.dv_vid); 4378 (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----", 4379 vinfo.dv_force ? 'f' : '-'); 4380 4381done: 4382 return (status); 4383} 4384 4385/* ARGSUSED */ 4386static int 4387show_vlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4388{ 4389 show_state_t *state = arg; 4390 dladm_status_t status; 4391 link_fields_buf_t lbuf; 4392 4393 bzero(&lbuf, sizeof (link_fields_buf_t)); 4394 status = print_vlan(state, linkid, &lbuf); 4395 if (status != DLADM_STATUS_OK) 4396 goto done; 4397 4398 ofmt_print(state->ls_ofmt, &lbuf); 4399 4400done: 4401 state->ls_status = status; 4402 return (DLADM_WALK_CONTINUE); 4403} 4404 4405static void 4406do_show_phys(int argc, char *argv[], const char *use) 4407{ 4408 int option; 4409 uint32_t flags = DLADM_OPT_ACTIVE; 4410 boolean_t p_arg = B_FALSE; 4411 boolean_t o_arg = B_FALSE; 4412 boolean_t m_arg = B_FALSE; 4413 boolean_t H_arg = B_FALSE; 4414 datalink_id_t linkid = DATALINK_ALL_LINKID; 4415 show_state_t state; 4416 dladm_status_t status; 4417 char *fields_str = NULL; 4418 char *all_active_fields = 4419 "link,media,state,speed,duplex,device"; 4420 char *all_inactive_fields = "link,device,media,flags"; 4421 char *all_mac_fields = "link,slot,address,inuse,client"; 4422 char *all_hwgrp_fields = "link,ringtype,rings,clients"; 4423 const ofmt_field_t *pf; 4424 ofmt_handle_t ofmt; 4425 ofmt_status_t oferr; 4426 uint_t ofmtflags = 0; 4427 4428 bzero(&state, sizeof (state)); 4429 opterr = 0; 4430 while ((option = getopt_long(argc, argv, ":pPo:mH", 4431 show_lopts, NULL)) != -1) { 4432 switch (option) { 4433 case 'p': 4434 if (p_arg) 4435 die_optdup(option); 4436 4437 p_arg = B_TRUE; 4438 break; 4439 case 'P': 4440 if (flags != DLADM_OPT_ACTIVE) 4441 die_optdup(option); 4442 4443 flags = DLADM_OPT_PERSIST; 4444 break; 4445 case 'o': 4446 o_arg = B_TRUE; 4447 fields_str = optarg; 4448 break; 4449 case 'm': 4450 m_arg = B_TRUE; 4451 break; 4452 case 'H': 4453 H_arg = B_TRUE; 4454 break; 4455 default: 4456 die_opterr(optopt, option, use); 4457 break; 4458 } 4459 } 4460 4461 if (p_arg && !o_arg) 4462 die("-p requires -o"); 4463 4464 if (m_arg && H_arg) 4465 die("-m cannot combine with -H"); 4466 4467 if (p_arg && strcasecmp(fields_str, "all") == 0) 4468 die("\"-o all\" is invalid with -p"); 4469 4470 /* get link name (optional last argument) */ 4471 if (optind == (argc-1)) { 4472 if ((status = dladm_name2info(handle, argv[optind], &linkid, 4473 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 4474 die_dlerr(status, "link %s is not valid", argv[optind]); 4475 } 4476 } else if (optind != argc) { 4477 usage(); 4478 } 4479 4480 state.ls_parsable = p_arg; 4481 state.ls_flags = flags; 4482 state.ls_donefirst = B_FALSE; 4483 state.ls_mac = m_arg; 4484 state.ls_hwgrp = H_arg; 4485 4486 if (m_arg && !(flags & DLADM_OPT_ACTIVE)) { 4487 /* 4488 * We can only display the factory MAC addresses of 4489 * active data-links. 4490 */ 4491 die("-m not compatible with -P"); 4492 } 4493 4494 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 4495 if (state.ls_mac) 4496 fields_str = all_mac_fields; 4497 else if (state.ls_hwgrp) 4498 fields_str = all_hwgrp_fields; 4499 else if (state.ls_flags & DLADM_OPT_ACTIVE) { 4500 fields_str = all_active_fields; 4501 } else { 4502 fields_str = all_inactive_fields; 4503 } 4504 } 4505 4506 if (state.ls_mac) { 4507 pf = phys_m_fields; 4508 } else if (state.ls_hwgrp) { 4509 pf = phys_h_fields; 4510 } else { 4511 pf = phys_fields; 4512 } 4513 4514 if (state.ls_parsable) 4515 ofmtflags |= OFMT_PARSABLE; 4516 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 4517 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 4518 state.ls_ofmt = ofmt; 4519 4520 if (linkid == DATALINK_ALL_LINKID) { 4521 (void) dladm_walk_datalink_id(show_phys, handle, &state, 4522 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags); 4523 } else { 4524 (void) show_phys(handle, linkid, &state); 4525 if (state.ls_status != DLADM_STATUS_OK) { 4526 die_dlerr(state.ls_status, 4527 "failed to show physical link %s", argv[optind]); 4528 } 4529 } 4530 ofmt_close(ofmt); 4531} 4532 4533static void 4534do_show_vlan(int argc, char *argv[], const char *use) 4535{ 4536 int option; 4537 uint32_t flags = DLADM_OPT_ACTIVE; 4538 boolean_t p_arg = B_FALSE; 4539 datalink_id_t linkid = DATALINK_ALL_LINKID; 4540 show_state_t state; 4541 dladm_status_t status; 4542 boolean_t o_arg = B_FALSE; 4543 char *fields_str = NULL; 4544 ofmt_handle_t ofmt; 4545 ofmt_status_t oferr; 4546 uint_t ofmtflags = 0; 4547 4548 bzero(&state, sizeof (state)); 4549 4550 opterr = 0; 4551 while ((option = getopt_long(argc, argv, ":pPo:", 4552 show_lopts, NULL)) != -1) { 4553 switch (option) { 4554 case 'p': 4555 if (p_arg) 4556 die_optdup(option); 4557 4558 p_arg = B_TRUE; 4559 break; 4560 case 'P': 4561 if (flags != DLADM_OPT_ACTIVE) 4562 die_optdup(option); 4563 4564 flags = DLADM_OPT_PERSIST; 4565 break; 4566 case 'o': 4567 o_arg = B_TRUE; 4568 fields_str = optarg; 4569 break; 4570 default: 4571 die_opterr(optopt, option, use); 4572 break; 4573 } 4574 } 4575 4576 /* get link name (optional last argument) */ 4577 if (optind == (argc-1)) { 4578 if ((status = dladm_name2info(handle, argv[optind], &linkid, 4579 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 4580 die_dlerr(status, "link %s is not valid", argv[optind]); 4581 } 4582 } else if (optind != argc) { 4583 usage(); 4584 } 4585 4586 state.ls_parsable = p_arg; 4587 state.ls_flags = flags; 4588 state.ls_donefirst = B_FALSE; 4589 4590 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 4591 fields_str = NULL; 4592 4593 if (state.ls_parsable) 4594 ofmtflags |= OFMT_PARSABLE; 4595 oferr = ofmt_open(fields_str, vlan_fields, ofmtflags, 0, &ofmt); 4596 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 4597 state.ls_ofmt = ofmt; 4598 4599 if (linkid == DATALINK_ALL_LINKID) { 4600 (void) dladm_walk_datalink_id(show_vlan, handle, &state, 4601 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags); 4602 } else { 4603 (void) show_vlan(handle, linkid, &state); 4604 if (state.ls_status != DLADM_STATUS_OK) { 4605 die_dlerr(state.ls_status, "failed to show vlan %s", 4606 argv[optind]); 4607 } 4608 } 4609 ofmt_close(ofmt); 4610} 4611 4612static void 4613do_create_vnic(int argc, char *argv[], const char *use) 4614{ 4615 datalink_id_t linkid, dev_linkid; 4616 char devname[MAXLINKNAMELEN]; 4617 char name[MAXLINKNAMELEN]; 4618 boolean_t l_arg = B_FALSE; 4619 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4620 char *altroot = NULL; 4621 int option; 4622 char *endp = NULL; 4623 dladm_status_t status; 4624 vnic_mac_addr_type_t mac_addr_type = VNIC_MAC_ADDR_TYPE_UNKNOWN; 4625 uchar_t *mac_addr = NULL; 4626 int mac_slot = -1; 4627 uint_t maclen = 0, mac_prefix_len = 0; 4628 char propstr[DLADM_STRSIZE]; 4629 dladm_arg_list_t *proplist = NULL; 4630 int vid = 0; 4631 int af = AF_UNSPEC; 4632 vrid_t vrid = VRRP_VRID_NONE; 4633 4634 opterr = 0; 4635 bzero(propstr, DLADM_STRSIZE); 4636 4637 while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:V:A:H", 4638 vnic_lopts, NULL)) != -1) { 4639 switch (option) { 4640 case 't': 4641 flags &= ~DLADM_OPT_PERSIST; 4642 break; 4643 case 'R': 4644 altroot = optarg; 4645 break; 4646 case 'l': 4647 if (strlcpy(devname, optarg, MAXLINKNAMELEN) >= 4648 MAXLINKNAMELEN) 4649 die("link name too long"); 4650 l_arg = B_TRUE; 4651 break; 4652 case 'm': 4653 if (mac_addr_type != VNIC_MAC_ADDR_TYPE_UNKNOWN) 4654 die("cannot specify -m option twice"); 4655 4656 if (strcmp(optarg, "fixed") == 0) { 4657 /* 4658 * A fixed MAC address must be specified 4659 * by its value, not by the keyword 'fixed'. 4660 */ 4661 die("'fixed' is not a valid MAC address"); 4662 } 4663 if (dladm_vnic_str2macaddrtype(optarg, 4664 &mac_addr_type) != DLADM_STATUS_OK) { 4665 mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED; 4666 /* MAC address specified by value */ 4667 mac_addr = _link_aton(optarg, (int *)&maclen); 4668 if (mac_addr == NULL) { 4669 if (maclen == (uint_t)-1) 4670 die("invalid MAC address"); 4671 else 4672 die("out of memory"); 4673 } 4674 } 4675 break; 4676 case 'n': 4677 errno = 0; 4678 mac_slot = (int)strtol(optarg, &endp, 10); 4679 if (errno != 0 || *endp != '\0') 4680 die("invalid slot number"); 4681 break; 4682 case 'p': 4683 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 4684 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 4685 DLADM_STRSIZE) 4686 die("property list too long '%s'", propstr); 4687 break; 4688 case 'r': 4689 mac_addr = _link_aton(optarg, (int *)&mac_prefix_len); 4690 if (mac_addr == NULL) { 4691 if (mac_prefix_len == (uint_t)-1) 4692 die("invalid MAC address"); 4693 else 4694 die("out of memory"); 4695 } 4696 break; 4697 case 'V': 4698 if (!str2int(optarg, (int *)&vrid) || 4699 vrid < VRRP_VRID_MIN || vrid > VRRP_VRID_MAX) { 4700 die("invalid VRRP identifier '%s'", optarg); 4701 } 4702 4703 break; 4704 case 'A': 4705 if (strcmp(optarg, "inet") == 0) 4706 af = AF_INET; 4707 else if (strcmp(optarg, "inet6") == 0) 4708 af = AF_INET6; 4709 else 4710 die("invalid address family '%s'", optarg); 4711 break; 4712 case 'v': 4713 if (vid != 0) 4714 die_optdup(option); 4715 4716 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 4717 die("invalid VLAN identifier '%s'", optarg); 4718 4719 break; 4720 case 'f': 4721 flags |= DLADM_OPT_FORCE; 4722 break; 4723 default: 4724 die_opterr(optopt, option, use); 4725 } 4726 } 4727 4728 if (mac_addr_type == VNIC_MAC_ADDR_TYPE_UNKNOWN) 4729 mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO; 4730 4731 /* 4732 * 'f' - force, flag can be specified only with 'v' - vlan. 4733 */ 4734 if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0) 4735 die("-f option can only be used with -v"); 4736 4737 if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM && 4738 mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED) 4739 usage(); 4740 4741 if (mac_addr_type == VNIC_MAC_ADDR_TYPE_VRID) { 4742 if (vrid == VRRP_VRID_NONE || af == AF_UNSPEC || 4743 mac_addr != NULL || maclen != 0 || mac_slot != -1 || 4744 mac_prefix_len != 0) { 4745 usage(); 4746 } 4747 } else if ((af != AF_UNSPEC || vrid != VRRP_VRID_NONE)) { 4748 usage(); 4749 } 4750 4751 /* check required options */ 4752 if (!l_arg) 4753 usage(); 4754 4755 if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY) 4756 usage(); 4757 4758 /* the VNIC id is the required operand */ 4759 if (optind != (argc - 1)) 4760 usage(); 4761 4762 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 4763 die("link name too long '%s'", argv[optind]); 4764 4765 if (!dladm_valid_linkname(name)) 4766 die("invalid link name '%s'", argv[optind]); 4767 4768 if (altroot != NULL) 4769 altroot_cmd(altroot, argc, argv); 4770 4771 if (dladm_name2info(handle, devname, &dev_linkid, NULL, NULL, NULL) != 4772 DLADM_STATUS_OK) 4773 die("invalid link name '%s'", devname); 4774 4775 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 4776 != DLADM_STATUS_OK) 4777 die("invalid vnic property"); 4778 4779 status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type, 4780 mac_addr, maclen, &mac_slot, mac_prefix_len, vid, vrid, af, 4781 &linkid, proplist, flags); 4782 switch (status) { 4783 case DLADM_STATUS_OK: 4784 break; 4785 4786 case DLADM_STATUS_LINKBUSY: 4787 die("VLAN over '%s' may not use default_tag ID " 4788 "(see dladm(1M))", devname); 4789 break; 4790 4791 default: 4792 die_dlerr(status, "vnic creation over %s failed", devname); 4793 } 4794 4795 dladm_free_props(proplist); 4796 free(mac_addr); 4797} 4798 4799static void 4800do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub, 4801 uint32_t flags) 4802{ 4803 boolean_t is_etherstub; 4804 dladm_vnic_attr_t attr; 4805 4806 if (dladm_vnic_info(handle, linkid, &attr, flags) != DLADM_STATUS_OK) { 4807 /* 4808 * Let the delete continue anyway. 4809 */ 4810 return; 4811 } 4812 is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID); 4813 if (is_etherstub != etherstub) { 4814 die("'%s' is not %s", name, 4815 (is_etherstub ? "a vnic" : "an etherstub")); 4816 } 4817} 4818 4819static void 4820do_delete_vnic_common(int argc, char *argv[], const char *use, 4821 boolean_t etherstub) 4822{ 4823 int option; 4824 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4825 datalink_id_t linkid; 4826 char *altroot = NULL; 4827 dladm_status_t status; 4828 4829 opterr = 0; 4830 while ((option = getopt_long(argc, argv, ":R:t", lopts, 4831 NULL)) != -1) { 4832 switch (option) { 4833 case 't': 4834 flags &= ~DLADM_OPT_PERSIST; 4835 break; 4836 case 'R': 4837 altroot = optarg; 4838 break; 4839 default: 4840 die_opterr(optopt, option, use); 4841 } 4842 } 4843 4844 /* get vnic name (required last argument) */ 4845 if (optind != (argc - 1)) 4846 usage(); 4847 4848 if (altroot != NULL) 4849 altroot_cmd(altroot, argc, argv); 4850 4851 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 4852 NULL); 4853 if (status != DLADM_STATUS_OK) 4854 die("invalid link name '%s'", argv[optind]); 4855 4856 if ((flags & DLADM_OPT_ACTIVE) != 0) { 4857 do_etherstub_check(argv[optind], linkid, etherstub, 4858 DLADM_OPT_ACTIVE); 4859 } 4860 if ((flags & DLADM_OPT_PERSIST) != 0) { 4861 do_etherstub_check(argv[optind], linkid, etherstub, 4862 DLADM_OPT_PERSIST); 4863 } 4864 4865 status = dladm_vnic_delete(handle, linkid, flags); 4866 if (status != DLADM_STATUS_OK) 4867 die_dlerr(status, "vnic deletion failed"); 4868} 4869 4870static void 4871do_delete_vnic(int argc, char *argv[], const char *use) 4872{ 4873 do_delete_vnic_common(argc, argv, use, B_FALSE); 4874} 4875 4876/* ARGSUSED */ 4877static void 4878do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan) 4879{ 4880 datalink_id_t linkid = DATALINK_ALL_LINKID; 4881 dladm_status_t status; 4882 char *type; 4883 4884 type = vlan ? "vlan" : "vnic"; 4885 4886 /* 4887 * get the id or the name of the vnic/vlan (optional last argument) 4888 */ 4889 if (argc == 2) { 4890 status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL, 4891 NULL); 4892 if (status != DLADM_STATUS_OK) 4893 goto done; 4894 4895 } else if (argc > 2) { 4896 usage(); 4897 } 4898 4899 if (vlan) 4900 status = dladm_vlan_up(handle, linkid); 4901 else 4902 status = dladm_vnic_up(handle, linkid, 0); 4903 4904done: 4905 if (status != DLADM_STATUS_OK) { 4906 if (argc == 2) { 4907 die_dlerr(status, 4908 "could not bring up %s '%s'", type, argv[1]); 4909 } else { 4910 die_dlerr(status, "could not bring %ss up", type); 4911 } 4912 } 4913} 4914 4915static void 4916do_up_vnic(int argc, char *argv[], const char *use) 4917{ 4918 do_up_vnic_common(argc, argv, use, B_FALSE); 4919} 4920 4921static void 4922dump_vnics_head(const char *dev) 4923{ 4924 if (strlen(dev)) 4925 (void) printf("%s", dev); 4926 4927 (void) printf("\tipackets rbytes opackets obytes "); 4928 4929 if (strlen(dev)) 4930 (void) printf("%%ipkts %%opkts\n"); 4931 else 4932 (void) printf("\n"); 4933} 4934 4935static void 4936dump_vnic_stat(const char *name, datalink_id_t vnic_id, 4937 show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats) 4938{ 4939 pktsum_t diff_stats; 4940 pktsum_t *old_stats = &state->vs_prevstats[vnic_id]; 4941 4942 dladm_stats_diff(&diff_stats, vnic_stats, old_stats); 4943 4944 (void) printf("%s", name); 4945 4946 (void) printf("\t%-10llu", diff_stats.ipackets); 4947 (void) printf("%-12llu", diff_stats.rbytes); 4948 (void) printf("%-10llu", diff_stats.opackets); 4949 (void) printf("%-12llu", diff_stats.obytes); 4950 4951 if (tot_stats) { 4952 if (tot_stats->ipackets == 0) { 4953 (void) printf("\t-"); 4954 } else { 4955 (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 4956 (double)tot_stats->ipackets * 100); 4957 } 4958 if (tot_stats->opackets == 0) { 4959 (void) printf("\t-"); 4960 } else { 4961 (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 4962 (double)tot_stats->opackets * 100); 4963 } 4964 } 4965 (void) printf("\n"); 4966 4967 *old_stats = *vnic_stats; 4968} 4969 4970/* 4971 * Called from the walker dladm_vnic_walk_sys() for each vnic to display 4972 * vnic information or statistics. 4973 */ 4974static dladm_status_t 4975print_vnic(show_vnic_state_t *state, datalink_id_t linkid) 4976{ 4977 dladm_vnic_attr_t attr, *vnic = &attr; 4978 dladm_status_t status; 4979 boolean_t is_etherstub; 4980 char devname[MAXLINKNAMELEN]; 4981 char vnic_name[MAXLINKNAMELEN]; 4982 char mstr[MAXMACADDRLEN * 3]; 4983 vnic_fields_buf_t vbuf; 4984 4985 if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) != 4986 DLADM_STATUS_OK) 4987 return (status); 4988 4989 is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID); 4990 if (state->vs_etherstub != is_etherstub) { 4991 /* 4992 * Want all etherstub but it's not one, or want 4993 * non-etherstub and it's one. 4994 */ 4995 return (DLADM_STATUS_OK); 4996 } 4997 4998 if (state->vs_link_id != DATALINK_ALL_LINKID) { 4999 if (state->vs_link_id != vnic->va_link_id) 5000 return (DLADM_STATUS_OK); 5001 } 5002 5003 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, 5004 NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK) 5005 return (DLADM_STATUS_BADARG); 5006 5007 bzero(devname, sizeof (devname)); 5008 if (!is_etherstub && 5009 dladm_datalink_id2info(handle, vnic->va_link_id, NULL, NULL, 5010 NULL, devname, sizeof (devname)) != DLADM_STATUS_OK) 5011 (void) sprintf(devname, "?"); 5012 5013 state->vs_found = B_TRUE; 5014 if (state->vs_stats) { 5015 /* print vnic statistics */ 5016 pktsum_t vnic_stats; 5017 5018 if (state->vs_firstonly) { 5019 if (state->vs_donefirst) 5020 return (0); 5021 state->vs_donefirst = B_TRUE; 5022 } 5023 5024 if (!state->vs_printstats) { 5025 /* 5026 * get vnic statistics and add to the sum for the 5027 * named device. 5028 */ 5029 get_link_stats(vnic_name, &vnic_stats); 5030 dladm_stats_total(&state->vs_totalstats, &vnic_stats, 5031 &state->vs_prevstats[vnic->va_vnic_id]); 5032 } else { 5033 /* get and print vnic statistics */ 5034 get_link_stats(vnic_name, &vnic_stats); 5035 dump_vnic_stat(vnic_name, linkid, state, &vnic_stats, 5036 &state->vs_totalstats); 5037 } 5038 return (DLADM_STATUS_OK); 5039 } else { 5040 (void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link), 5041 "%s", vnic_name); 5042 5043 if (!is_etherstub) { 5044 5045 (void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over), 5046 "%s", devname); 5047 (void) snprintf(vbuf.vnic_speed, 5048 sizeof (vbuf.vnic_speed), "%u", 5049 (uint_t)((get_ifspeed(vnic_name, B_TRUE)) 5050 / 1000000ull)); 5051 5052 switch (vnic->va_mac_addr_type) { 5053 case VNIC_MAC_ADDR_TYPE_FIXED: 5054 case VNIC_MAC_ADDR_TYPE_PRIMARY: 5055 (void) snprintf(vbuf.vnic_macaddrtype, 5056 sizeof (vbuf.vnic_macaddrtype), 5057 gettext("fixed")); 5058 break; 5059 case VNIC_MAC_ADDR_TYPE_RANDOM: 5060 (void) snprintf(vbuf.vnic_macaddrtype, 5061 sizeof (vbuf.vnic_macaddrtype), 5062 gettext("random")); 5063 break; 5064 case VNIC_MAC_ADDR_TYPE_FACTORY: 5065 (void) snprintf(vbuf.vnic_macaddrtype, 5066 sizeof (vbuf.vnic_macaddrtype), 5067 gettext("factory, slot %d"), 5068 vnic->va_mac_slot); 5069 break; 5070 case VNIC_MAC_ADDR_TYPE_VRID: 5071 (void) snprintf(vbuf.vnic_macaddrtype, 5072 sizeof (vbuf.vnic_macaddrtype), 5073 gettext("vrrp, %d/%s"), 5074 vnic->va_vrid, vnic->va_af == AF_INET ? 5075 "inet" : "inet6"); 5076 break; 5077 } 5078 5079 if (strlen(vbuf.vnic_macaddrtype) > 0) { 5080 (void) snprintf(vbuf.vnic_macaddr, 5081 sizeof (vbuf.vnic_macaddr), "%s", 5082 dladm_aggr_macaddr2str(vnic->va_mac_addr, 5083 mstr)); 5084 } 5085 5086 (void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid), 5087 "%d", vnic->va_vid); 5088 } 5089 5090 ofmt_print(state->vs_ofmt, &vbuf); 5091 5092 return (DLADM_STATUS_OK); 5093 } 5094} 5095 5096/* ARGSUSED */ 5097static int 5098show_vnic(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5099{ 5100 show_vnic_state_t *state = arg; 5101 5102 state->vs_status = print_vnic(state, linkid); 5103 return (DLADM_WALK_CONTINUE); 5104} 5105 5106static void 5107do_show_vnic_common(int argc, char *argv[], const char *use, 5108 boolean_t etherstub) 5109{ 5110 int option; 5111 boolean_t s_arg = B_FALSE; 5112 boolean_t i_arg = B_FALSE; 5113 boolean_t l_arg = B_FALSE; 5114 uint32_t interval = 0, flags = DLADM_OPT_ACTIVE; 5115 datalink_id_t linkid = DATALINK_ALL_LINKID; 5116 datalink_id_t dev_linkid = DATALINK_ALL_LINKID; 5117 show_vnic_state_t state; 5118 dladm_status_t status; 5119 boolean_t o_arg = B_FALSE; 5120 char *fields_str = NULL; 5121 const ofmt_field_t *pf; 5122 char *all_e_fields = "link"; 5123 ofmt_handle_t ofmt; 5124 ofmt_status_t oferr; 5125 uint_t ofmtflags = 0; 5126 5127 bzero(&state, sizeof (state)); 5128 opterr = 0; 5129 while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts, 5130 NULL)) != -1) { 5131 switch (option) { 5132 case 'p': 5133 state.vs_parsable = B_TRUE; 5134 break; 5135 case 'P': 5136 flags = DLADM_OPT_PERSIST; 5137 break; 5138 case 'l': 5139 if (etherstub) 5140 die("option not supported for this command"); 5141 5142 if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >= 5143 MAXLINKNAMELEN) 5144 die("link name too long"); 5145 5146 l_arg = B_TRUE; 5147 break; 5148 case 's': 5149 if (s_arg) { 5150 die("the option -s cannot be specified " 5151 "more than once"); 5152 } 5153 s_arg = B_TRUE; 5154 break; 5155 case 'i': 5156 if (i_arg) { 5157 die("the option -i cannot be specified " 5158 "more than once"); 5159 } 5160 i_arg = B_TRUE; 5161 if (!dladm_str2interval(optarg, &interval)) 5162 die("invalid interval value '%s'", optarg); 5163 break; 5164 case 'o': 5165 o_arg = B_TRUE; 5166 fields_str = optarg; 5167 break; 5168 default: 5169 die_opterr(optopt, option, use); 5170 } 5171 } 5172 5173 if (i_arg && !s_arg) 5174 die("the option -i can be used only with -s"); 5175 5176 /* get vnic ID (optional last argument) */ 5177 if (optind == (argc - 1)) { 5178 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 5179 NULL, NULL); 5180 if (status != DLADM_STATUS_OK) { 5181 die_dlerr(status, "invalid vnic name '%s'", 5182 argv[optind]); 5183 } 5184 (void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN); 5185 } else if (optind != argc) { 5186 usage(); 5187 } 5188 5189 if (l_arg) { 5190 status = dladm_name2info(handle, state.vs_link, &dev_linkid, 5191 NULL, NULL, NULL); 5192 if (status != DLADM_STATUS_OK) { 5193 die_dlerr(status, "invalid link name '%s'", 5194 state.vs_link); 5195 } 5196 } 5197 5198 state.vs_vnic_id = linkid; 5199 state.vs_link_id = dev_linkid; 5200 state.vs_etherstub = etherstub; 5201 state.vs_found = B_FALSE; 5202 state.vs_flags = flags; 5203 5204 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 5205 if (etherstub) 5206 fields_str = all_e_fields; 5207 } 5208 pf = vnic_fields; 5209 5210 if (state.vs_parsable) 5211 ofmtflags |= OFMT_PARSABLE; 5212 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 5213 ofmt_check(oferr, state.vs_parsable, ofmt, die, warn); 5214 state.vs_ofmt = ofmt; 5215 5216 if (s_arg) { 5217 /* Display vnic statistics */ 5218 vnic_stats(&state, interval); 5219 ofmt_close(ofmt); 5220 return; 5221 } 5222 5223 /* Display vnic information */ 5224 state.vs_donefirst = B_FALSE; 5225 5226 if (linkid == DATALINK_ALL_LINKID) { 5227 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 5228 DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB, 5229 DATALINK_ANY_MEDIATYPE, flags); 5230 } else { 5231 (void) show_vnic(handle, linkid, &state); 5232 if (state.vs_status != DLADM_STATUS_OK) { 5233 ofmt_close(ofmt); 5234 die_dlerr(state.vs_status, "failed to show vnic '%s'", 5235 state.vs_vnic); 5236 } 5237 } 5238 ofmt_close(ofmt); 5239} 5240 5241static void 5242do_show_vnic(int argc, char *argv[], const char *use) 5243{ 5244 do_show_vnic_common(argc, argv, use, B_FALSE); 5245} 5246 5247static void 5248do_create_etherstub(int argc, char *argv[], const char *use) 5249{ 5250 uint32_t flags; 5251 char *altroot = NULL; 5252 int option; 5253 dladm_status_t status; 5254 char name[MAXLINKNAMELEN]; 5255 uchar_t mac_addr[ETHERADDRL]; 5256 5257 name[0] = '\0'; 5258 bzero(mac_addr, sizeof (mac_addr)); 5259 flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5260 5261 opterr = 0; 5262 while ((option = getopt_long(argc, argv, "tR:", 5263 etherstub_lopts, NULL)) != -1) { 5264 switch (option) { 5265 case 't': 5266 flags &= ~DLADM_OPT_PERSIST; 5267 break; 5268 case 'R': 5269 altroot = optarg; 5270 break; 5271 default: 5272 die_opterr(optopt, option, use); 5273 } 5274 } 5275 5276 /* the etherstub id is the required operand */ 5277 if (optind != (argc - 1)) 5278 usage(); 5279 5280 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 5281 die("link name too long '%s'", argv[optind]); 5282 5283 if (!dladm_valid_linkname(name)) 5284 die("invalid link name '%s'", argv[optind]); 5285 5286 if (altroot != NULL) 5287 altroot_cmd(altroot, argc, argv); 5288 5289 status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID, 5290 VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, 5291 VRRP_VRID_NONE, AF_UNSPEC, NULL, NULL, flags); 5292 if (status != DLADM_STATUS_OK) 5293 die_dlerr(status, "etherstub creation failed"); 5294} 5295 5296static void 5297do_delete_etherstub(int argc, char *argv[], const char *use) 5298{ 5299 do_delete_vnic_common(argc, argv, use, B_TRUE); 5300} 5301 5302/* ARGSUSED */ 5303static void 5304do_show_etherstub(int argc, char *argv[], const char *use) 5305{ 5306 do_show_vnic_common(argc, argv, use, B_TRUE); 5307} 5308 5309/* ARGSUSED */ 5310static void 5311do_up_simnet(int argc, char *argv[], const char *use) 5312{ 5313 (void) dladm_simnet_up(handle, DATALINK_ALL_LINKID, 0); 5314} 5315 5316static void 5317do_create_simnet(int argc, char *argv[], const char *use) 5318{ 5319 uint32_t flags; 5320 char *altroot = NULL; 5321 char *media = NULL; 5322 uint32_t mtype = DL_ETHER; 5323 int option; 5324 dladm_status_t status; 5325 char name[MAXLINKNAMELEN]; 5326 5327 name[0] = '\0'; 5328 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5329 5330 opterr = 0; 5331 while ((option = getopt_long(argc, argv, ":tR:m:", 5332 simnet_lopts, NULL)) != -1) { 5333 switch (option) { 5334 case 't': 5335 flags &= ~DLADM_OPT_PERSIST; 5336 break; 5337 case 'R': 5338 altroot = optarg; 5339 break; 5340 case 'm': 5341 media = optarg; 5342 break; 5343 default: 5344 die_opterr(optopt, option, use); 5345 } 5346 } 5347 5348 /* the simnet id is the required operand */ 5349 if (optind != (argc - 1)) 5350 usage(); 5351 5352 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 5353 die("link name too long '%s'", argv[optind]); 5354 5355 if (!dladm_valid_linkname(name)) 5356 die("invalid link name '%s'", name); 5357 5358 if (media != NULL) { 5359 mtype = dladm_str2media(media); 5360 if (mtype != DL_ETHER && mtype != DL_WIFI) 5361 die("media type '%s' is not supported", media); 5362 } 5363 5364 if (altroot != NULL) 5365 altroot_cmd(altroot, argc, argv); 5366 5367 status = dladm_simnet_create(handle, name, mtype, flags); 5368 if (status != DLADM_STATUS_OK) 5369 die_dlerr(status, "simnet creation failed"); 5370} 5371 5372static void 5373do_delete_simnet(int argc, char *argv[], const char *use) 5374{ 5375 int option; 5376 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5377 datalink_id_t linkid; 5378 char *altroot = NULL; 5379 dladm_status_t status; 5380 dladm_simnet_attr_t slinfo; 5381 5382 opterr = 0; 5383 while ((option = getopt_long(argc, argv, ":tR:", simnet_lopts, 5384 NULL)) != -1) { 5385 switch (option) { 5386 case 't': 5387 flags &= ~DLADM_OPT_PERSIST; 5388 break; 5389 case 'R': 5390 altroot = optarg; 5391 break; 5392 default: 5393 die_opterr(optopt, option, use); 5394 } 5395 } 5396 5397 /* get simnet name (required last argument) */ 5398 if (optind != (argc - 1)) 5399 usage(); 5400 5401 if (!dladm_valid_linkname(argv[optind])) 5402 die("invalid link name '%s'", argv[optind]); 5403 5404 if (altroot != NULL) 5405 altroot_cmd(altroot, argc, argv); 5406 5407 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 5408 NULL); 5409 if (status != DLADM_STATUS_OK) 5410 die("simnet '%s' not found", argv[optind]); 5411 5412 if ((status = dladm_simnet_info(handle, linkid, &slinfo, 5413 flags)) != DLADM_STATUS_OK) 5414 die_dlerr(status, "failed to retrieve simnet information"); 5415 5416 status = dladm_simnet_delete(handle, linkid, flags); 5417 if (status != DLADM_STATUS_OK) 5418 die_dlerr(status, "simnet deletion failed"); 5419} 5420 5421static void 5422do_modify_simnet(int argc, char *argv[], const char *use) 5423{ 5424 int option; 5425 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 5426 datalink_id_t linkid; 5427 datalink_id_t peer_linkid; 5428 char *altroot = NULL; 5429 dladm_status_t status; 5430 boolean_t p_arg = B_FALSE; 5431 5432 opterr = 0; 5433 while ((option = getopt_long(argc, argv, ":tR:p:", simnet_lopts, 5434 NULL)) != -1) { 5435 switch (option) { 5436 case 't': 5437 flags &= ~DLADM_OPT_PERSIST; 5438 break; 5439 case 'R': 5440 altroot = optarg; 5441 break; 5442 case 'p': 5443 if (p_arg) 5444 die_optdup(option); 5445 p_arg = B_TRUE; 5446 if (strcasecmp(optarg, "none") == 0) 5447 peer_linkid = DATALINK_INVALID_LINKID; 5448 else if (dladm_name2info(handle, optarg, &peer_linkid, 5449 NULL, NULL, NULL) != DLADM_STATUS_OK) 5450 die("invalid peer link name '%s'", optarg); 5451 break; 5452 default: 5453 die_opterr(optopt, option, use); 5454 } 5455 } 5456 5457 /* get simnet name (required last argument) */ 5458 if (optind != (argc - 1)) 5459 usage(); 5460 5461 /* Nothing to do if no peer link argument */ 5462 if (!p_arg) 5463 return; 5464 5465 if (altroot != NULL) 5466 altroot_cmd(altroot, argc, argv); 5467 5468 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 5469 NULL); 5470 if (status != DLADM_STATUS_OK) 5471 die("invalid link name '%s'", argv[optind]); 5472 5473 status = dladm_simnet_modify(handle, linkid, peer_linkid, flags); 5474 if (status != DLADM_STATUS_OK) 5475 die_dlerr(status, "simnet modification failed"); 5476} 5477 5478static dladm_status_t 5479print_simnet(show_state_t *state, datalink_id_t linkid) 5480{ 5481 dladm_simnet_attr_t slinfo; 5482 uint32_t flags; 5483 dladm_status_t status; 5484 simnet_fields_buf_t slbuf; 5485 char mstr[ETHERADDRL * 3]; 5486 5487 bzero(&slbuf, sizeof (slbuf)); 5488 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL, 5489 slbuf.simnet_name, sizeof (slbuf.simnet_name))) 5490 != DLADM_STATUS_OK) 5491 return (status); 5492 5493 if (!(state->ls_flags & flags)) 5494 return (DLADM_STATUS_NOTFOUND); 5495 5496 if ((status = dladm_simnet_info(handle, linkid, &slinfo, 5497 state->ls_flags)) != DLADM_STATUS_OK) 5498 return (status); 5499 5500 if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID && 5501 (status = dladm_datalink_id2info(handle, slinfo.sna_peer_link_id, 5502 NULL, NULL, NULL, slbuf.simnet_otherlink, 5503 sizeof (slbuf.simnet_otherlink))) != 5504 DLADM_STATUS_OK) 5505 return (status); 5506 5507 if (slinfo.sna_mac_len > sizeof (slbuf.simnet_macaddr)) 5508 return (DLADM_STATUS_BADVAL); 5509 5510 (void) strlcpy(slbuf.simnet_macaddr, 5511 dladm_aggr_macaddr2str(slinfo.sna_mac_addr, mstr), 5512 sizeof (slbuf.simnet_macaddr)); 5513 (void) dladm_media2str(slinfo.sna_type, slbuf.simnet_media); 5514 5515 ofmt_print(state->ls_ofmt, &slbuf); 5516 return (status); 5517} 5518 5519/* ARGSUSED */ 5520static int 5521show_simnet(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5522{ 5523 show_state_t *state = arg; 5524 5525 state->ls_status = print_simnet(state, linkid); 5526 return (DLADM_WALK_CONTINUE); 5527} 5528 5529static void 5530do_show_simnet(int argc, char *argv[], const char *use) 5531{ 5532 int option; 5533 uint32_t flags = DLADM_OPT_ACTIVE; 5534 boolean_t p_arg = B_FALSE; 5535 datalink_id_t linkid = DATALINK_ALL_LINKID; 5536 show_state_t state; 5537 dladm_status_t status; 5538 boolean_t o_arg = B_FALSE; 5539 ofmt_handle_t ofmt; 5540 ofmt_status_t oferr; 5541 char *all_fields = "link,media,macaddress,otherlink"; 5542 char *fields_str = all_fields; 5543 uint_t ofmtflags = 0; 5544 5545 bzero(&state, sizeof (state)); 5546 5547 opterr = 0; 5548 while ((option = getopt_long(argc, argv, ":pPo:", 5549 show_lopts, NULL)) != -1) { 5550 switch (option) { 5551 case 'p': 5552 if (p_arg) 5553 die_optdup(option); 5554 5555 p_arg = B_TRUE; 5556 state.ls_parsable = p_arg; 5557 break; 5558 case 'P': 5559 if (flags != DLADM_OPT_ACTIVE) 5560 die_optdup(option); 5561 5562 flags = DLADM_OPT_PERSIST; 5563 break; 5564 case 'o': 5565 o_arg = B_TRUE; 5566 fields_str = optarg; 5567 break; 5568 default: 5569 die_opterr(optopt, option, use); 5570 break; 5571 } 5572 } 5573 5574 if (p_arg && !o_arg) 5575 die("-p requires -o"); 5576 5577 if (strcasecmp(fields_str, "all") == 0) { 5578 if (p_arg) 5579 die("\"-o all\" is invalid with -p"); 5580 fields_str = all_fields; 5581 } 5582 5583 /* get link name (optional last argument) */ 5584 if (optind == (argc-1)) { 5585 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5586 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5587 die_dlerr(status, "link %s is not valid", argv[optind]); 5588 } 5589 } else if (optind != argc) { 5590 usage(); 5591 } 5592 5593 state.ls_flags = flags; 5594 state.ls_donefirst = B_FALSE; 5595 if (state.ls_parsable) 5596 ofmtflags |= OFMT_PARSABLE; 5597 oferr = ofmt_open(fields_str, simnet_fields, ofmtflags, 0, &ofmt); 5598 ofmt_check(oferr, state.ls_parsable, ofmt, die, warn); 5599 state.ls_ofmt = ofmt; 5600 5601 if (linkid == DATALINK_ALL_LINKID) { 5602 (void) dladm_walk_datalink_id(show_simnet, handle, &state, 5603 DATALINK_CLASS_SIMNET, DATALINK_ANY_MEDIATYPE, flags); 5604 } else { 5605 (void) show_simnet(handle, linkid, &state); 5606 if (state.ls_status != DLADM_STATUS_OK) { 5607 ofmt_close(ofmt); 5608 die_dlerr(state.ls_status, "failed to show simnet %s", 5609 argv[optind]); 5610 } 5611 } 5612 ofmt_close(ofmt); 5613} 5614 5615static void 5616link_stats(datalink_id_t linkid, uint_t interval, char *fields_str, 5617 show_state_t *state) 5618{ 5619 ofmt_handle_t ofmt; 5620 ofmt_status_t oferr; 5621 uint_t ofmtflags = 0; 5622 5623 if (state->ls_parsable) 5624 ofmtflags |= OFMT_PARSABLE; 5625 oferr = ofmt_open(fields_str, link_s_fields, ofmtflags, 0, &ofmt); 5626 ofmt_check(oferr, state->ls_parsable, ofmt, die, warn); 5627 state->ls_ofmt = ofmt; 5628 5629 /* 5630 * If an interval is specified, continuously show the stats 5631 * only for the first MAC port. 5632 */ 5633 state->ls_firstonly = (interval != 0); 5634 5635 for (;;) { 5636 state->ls_donefirst = B_FALSE; 5637 if (linkid == DATALINK_ALL_LINKID) { 5638 (void) dladm_walk_datalink_id(show_link_stats, handle, 5639 state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 5640 DLADM_OPT_ACTIVE); 5641 } else { 5642 (void) show_link_stats(handle, linkid, state); 5643 } 5644 5645 if (interval == 0) 5646 break; 5647 5648 (void) fflush(stdout); 5649 (void) sleep(interval); 5650 } 5651 ofmt_close(ofmt); 5652} 5653 5654static void 5655aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) 5656{ 5657 /* 5658 * If an interval is specified, continuously show the stats 5659 * only for the first group. 5660 */ 5661 state->gs_firstonly = (interval != 0); 5662 5663 for (;;) { 5664 state->gs_donefirst = B_FALSE; 5665 if (linkid == DATALINK_ALL_LINKID) 5666 (void) dladm_walk_datalink_id(show_aggr, handle, state, 5667 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 5668 DLADM_OPT_ACTIVE); 5669 else 5670 (void) show_aggr(handle, linkid, state); 5671 5672 if (interval == 0) 5673 break; 5674 5675 (void) fflush(stdout); 5676 (void) sleep(interval); 5677 } 5678} 5679 5680/* ARGSUSED */ 5681static void 5682vnic_stats(show_vnic_state_t *sp, uint32_t interval) 5683{ 5684 show_vnic_state_t state; 5685 boolean_t specific_link, specific_dev; 5686 5687 /* Display vnic statistics */ 5688 dump_vnics_head(sp->vs_link); 5689 5690 bzero(&state, sizeof (state)); 5691 state.vs_stats = B_TRUE; 5692 state.vs_vnic_id = sp->vs_vnic_id; 5693 state.vs_link_id = sp->vs_link_id; 5694 5695 /* 5696 * If an interval is specified, and a vnic ID is not specified, 5697 * continuously show the stats only for the first vnic. 5698 */ 5699 specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID); 5700 specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID); 5701 5702 for (;;) { 5703 /* Get stats for each vnic */ 5704 state.vs_found = B_FALSE; 5705 state.vs_donefirst = B_FALSE; 5706 state.vs_printstats = B_FALSE; 5707 state.vs_flags = DLADM_OPT_ACTIVE; 5708 5709 if (!specific_link) { 5710 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 5711 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 5712 DLADM_OPT_ACTIVE); 5713 } else { 5714 (void) show_vnic(handle, sp->vs_vnic_id, &state); 5715 if (state.vs_status != DLADM_STATUS_OK) { 5716 die_dlerr(state.vs_status, 5717 "failed to show vnic '%s'", sp->vs_vnic); 5718 } 5719 } 5720 5721 if (specific_link && !state.vs_found) 5722 die("non-existent vnic '%s'", sp->vs_vnic); 5723 if (specific_dev && !state.vs_found) 5724 die("device %s has no vnics", sp->vs_link); 5725 5726 /* Show totals */ 5727 if ((specific_link | specific_dev) && !interval) { 5728 (void) printf("Total"); 5729 (void) printf("\t%-10llu", 5730 state.vs_totalstats.ipackets); 5731 (void) printf("%-12llu", 5732 state.vs_totalstats.rbytes); 5733 (void) printf("%-10llu", 5734 state.vs_totalstats.opackets); 5735 (void) printf("%-12llu\n", 5736 state.vs_totalstats.obytes); 5737 } 5738 5739 /* Show stats for each vnic */ 5740 state.vs_donefirst = B_FALSE; 5741 state.vs_printstats = B_TRUE; 5742 5743 if (!specific_link) { 5744 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 5745 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 5746 DLADM_OPT_ACTIVE); 5747 } else { 5748 (void) show_vnic(handle, sp->vs_vnic_id, &state); 5749 if (state.vs_status != DLADM_STATUS_OK) { 5750 die_dlerr(state.vs_status, 5751 "failed to show vnic '%s'", sp->vs_vnic); 5752 } 5753 } 5754 5755 if (interval == 0) 5756 break; 5757 5758 (void) fflush(stdout); 5759 (void) sleep(interval); 5760 } 5761} 5762 5763static void 5764get_mac_stats(const char *dev, pktsum_t *stats) 5765{ 5766 kstat_ctl_t *kcp; 5767 kstat_t *ksp; 5768 char module[DLPI_LINKNAME_MAX]; 5769 uint_t instance; 5770 5771 5772 bzero(stats, sizeof (*stats)); 5773 5774 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 5775 return; 5776 5777 if ((kcp = kstat_open()) == NULL) { 5778 warn("kstat open operation failed"); 5779 return; 5780 } 5781 5782 ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL); 5783 if (ksp != NULL) 5784 dladm_get_stats(kcp, ksp, stats); 5785 5786 (void) kstat_close(kcp); 5787 5788} 5789 5790static void 5791get_link_stats(const char *link, pktsum_t *stats) 5792{ 5793 kstat_ctl_t *kcp; 5794 kstat_t *ksp; 5795 5796 bzero(stats, sizeof (*stats)); 5797 5798 if ((kcp = kstat_open()) == NULL) { 5799 warn("kstat_open operation failed"); 5800 return; 5801 } 5802 5803 ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL); 5804 5805 if (ksp != NULL) 5806 dladm_get_stats(kcp, ksp, stats); 5807 5808 (void) kstat_close(kcp); 5809} 5810 5811static int 5812query_kstat(char *module, int instance, const char *name, const char *stat, 5813 uint8_t type, void *val) 5814{ 5815 kstat_ctl_t *kcp; 5816 kstat_t *ksp; 5817 5818 if ((kcp = kstat_open()) == NULL) { 5819 warn("kstat open operation failed"); 5820 return (-1); 5821 } 5822 5823 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 5824 /* 5825 * The kstat query could fail if the underlying MAC 5826 * driver was already detached. 5827 */ 5828 goto bail; 5829 } 5830 5831 if (kstat_read(kcp, ksp, NULL) == -1) { 5832 warn("kstat read failed"); 5833 goto bail; 5834 } 5835 5836 if (dladm_kstat_value(ksp, stat, type, val) < 0) 5837 goto bail; 5838 5839 (void) kstat_close(kcp); 5840 return (0); 5841 5842bail: 5843 (void) kstat_close(kcp); 5844 return (-1); 5845} 5846 5847static int 5848get_one_kstat(const char *name, const char *stat, uint8_t type, 5849 void *val, boolean_t islink) 5850{ 5851 char module[DLPI_LINKNAME_MAX]; 5852 uint_t instance; 5853 5854 if (islink) { 5855 return (query_kstat("link", 0, name, stat, type, val)); 5856 } else { 5857 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS) 5858 return (-1); 5859 5860 return (query_kstat(module, instance, "mac", stat, type, val)); 5861 } 5862} 5863 5864static uint64_t 5865get_ifspeed(const char *name, boolean_t islink) 5866{ 5867 uint64_t ifspeed = 0; 5868 5869 (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64, 5870 &ifspeed, islink); 5871 5872 return (ifspeed);