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 * Copyright 2021 OmniOS Community Edition (OmniOSce) Association. 27 */ 28 29 #include <stdio.h> 30 #include <ctype.h> 31 #include <dlfcn.h> 32 #include <locale.h> 33 #include <signal.h> 34 #include <stdarg.h> 35 #include <stdlib.h> 36 #include <fcntl.h> 37 #include <string.h> 38 #include <stropts.h> 39 #include <sys/stat.h> 40 #include <errno.h> 41 #include <kstat.h> 42 #include <strings.h> 43 #include <getopt.h> 44 #include <unistd.h> 45 #include <priv.h> 46 #include <limits.h> 47 #include <termios.h> 48 #include <pwd.h> 49 #include <auth_attr.h> 50 #include <auth_list.h> 51 #include <libintl.h> 52 #include <libdevinfo.h> 53 #include <libdlpi.h> 54 #include <libdladm.h> 55 #include <libdllink.h> 56 #include <libdlstat.h> 57 #include <libdlaggr.h> 58 #include <libdlwlan.h> 59 #include <libdlvlan.h> 60 #include <libdlvnic.h> 61 #include <libdlib.h> 62 #include <libdlether.h> 63 #include <libdliptun.h> 64 #include <libdlsim.h> 65 #include <libdlbridge.h> 66 #include <libinetutil.h> 67 #include <libvrrpadm.h> 68 #include <bsm/adt.h> 69 #include <bsm/adt_event.h> 70 #include <libdlvnic.h> 71 #include <sys/types.h> 72 #include <sys/socket.h> 73 #include <sys/ib/ib_types.h> 74 #include <sys/processor.h> 75 #include <netinet/in.h> 76 #include <arpa/inet.h> 77 #include <net/if_types.h> 78 #include <stddef.h> 79 #include <stp_in.h> 80 #include <ofmt.h> 81 82 #define MAXPORT 256 83 #define MAXVNIC 256 84 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) 85 #define MAXLINELEN 1024 86 #define SMF_UPGRADE_FILE "/var/svc/profile/upgrade" 87 #define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink" 88 #define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)" 89 #define DLADM_DEFAULT_COL 80 90 91 /* 92 * used by the wifi show-* commands to set up ofmt_field_t structures. 93 */ 94 #define WIFI_CMD_SCAN 0x00000001 95 #define WIFI_CMD_SHOW 0x00000002 96 #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 97 98 /* No larger than pktsum_t */ 99 typedef struct brsum_s { 100 uint64_t drops; 101 uint64_t forward_dir; 102 uint64_t forward_mb; 103 uint64_t forward_unk; 104 uint64_t recv; 105 uint64_t sent; 106 } brsum_t; 107 108 /* No larger than pktsum_t */ 109 typedef struct brlsum_s { 110 uint32_t cfgbpdu; 111 uint32_t tcnbpdu; 112 uint32_t rstpbpdu; 113 uint32_t txbpdu; 114 uint64_t drops; 115 uint64_t recv; 116 uint64_t xmit; 117 } brlsum_t; 118 119 typedef struct show_state { 120 boolean_t ls_firstonly; 121 boolean_t ls_donefirst; 122 pktsum_t ls_prevstats; 123 uint32_t ls_flags; 124 dladm_status_t ls_status; 125 ofmt_handle_t ls_ofmt; 126 boolean_t ls_parsable; 127 boolean_t ls_mac; 128 boolean_t ls_hwgrp; 129 } show_state_t; 130 131 typedef struct show_grp_state { 132 pktsum_t gs_prevstats[MAXPORT]; 133 uint32_t gs_flags; 134 dladm_status_t gs_status; 135 boolean_t gs_parsable; 136 boolean_t gs_lacp; 137 boolean_t gs_extended; 138 boolean_t gs_stats; 139 boolean_t gs_firstonly; 140 boolean_t gs_donefirst; 141 ofmt_handle_t gs_ofmt; 142 } show_grp_state_t; 143 144 typedef struct show_vnic_state { 145 datalink_id_t vs_vnic_id; 146 datalink_id_t vs_link_id; 147 char vs_vnic[MAXLINKNAMELEN]; 148 char vs_link[MAXLINKNAMELEN]; 149 boolean_t vs_parsable; 150 boolean_t vs_found; 151 boolean_t vs_firstonly; 152 boolean_t vs_donefirst; 153 boolean_t vs_stats; 154 boolean_t vs_printstats; 155 pktsum_t vs_totalstats; 156 pktsum_t vs_prevstats[MAXVNIC]; 157 boolean_t vs_etherstub; 158 dladm_status_t vs_status; 159 uint32_t vs_flags; 160 ofmt_handle_t vs_ofmt; 161 } show_vnic_state_t; 162 163 typedef struct show_part_state { 164 datalink_id_t ps_over_id; 165 char ps_part[MAXLINKNAMELEN]; 166 boolean_t ps_parsable; 167 boolean_t ps_found; 168 dladm_status_t ps_status; 169 uint32_t ps_flags; 170 ofmt_handle_t ps_ofmt; 171 } show_part_state_t; 172 173 typedef struct show_ib_state { 174 datalink_id_t is_link_id; 175 char is_link[MAXLINKNAMELEN]; 176 boolean_t is_parsable; 177 dladm_status_t is_status; 178 uint32_t is_flags; 179 ofmt_handle_t is_ofmt; 180 } show_ib_state_t; 181 182 typedef struct show_usage_state_s { 183 boolean_t us_plot; 184 boolean_t us_parsable; 185 boolean_t us_printheader; 186 boolean_t us_first; 187 boolean_t us_showall; 188 ofmt_handle_t us_ofmt; 189 } show_usage_state_t; 190 191 /* 192 * callback functions for printing output and error diagnostics. 193 */ 194 static ofmt_cb_t print_default_cb, print_link_stats_cb, print_linkprop_cb; 195 static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb; 196 static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb; 197 static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb; 198 static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb; 199 200 typedef void cmdfunc_t(int, char **, const char *); 201 202 static cmdfunc_t do_help; 203 static cmdfunc_t do_show_link, do_show_wifi, do_show_phys; 204 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 205 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr; 206 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 207 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 208 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 209 static cmdfunc_t do_init_linkprop, do_init_secobj; 210 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan; 211 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys; 212 static cmdfunc_t do_show_linkmap; 213 static cmdfunc_t do_show_ether; 214 static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic; 215 static cmdfunc_t do_up_vnic; 216 static cmdfunc_t do_create_part, do_delete_part, do_show_part, do_show_ib; 217 static cmdfunc_t do_up_part; 218 static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub; 219 static cmdfunc_t do_create_simnet, do_modify_simnet; 220 static cmdfunc_t do_delete_simnet, do_show_simnet, do_up_simnet; 221 static cmdfunc_t do_show_usage; 222 static cmdfunc_t do_create_bridge, do_modify_bridge, do_delete_bridge; 223 static cmdfunc_t do_add_bridge, do_remove_bridge, do_show_bridge; 224 static cmdfunc_t do_create_iptun, do_modify_iptun, do_delete_iptun; 225 static cmdfunc_t do_show_iptun, do_up_iptun, do_down_iptun; 226 227 static void do_up_vnic_common(int, char **, const char *, boolean_t); 228 229 static int show_part(dladm_handle_t, datalink_id_t, void *); 230 231 static void altroot_cmd(char *, int, char **); 232 static int show_linkprop_onelink(dladm_handle_t, datalink_id_t, void *); 233 234 static void link_stats(datalink_id_t, uint_t, char *, show_state_t *); 235 static void aggr_stats(datalink_id_t, show_grp_state_t *, uint_t); 236 static void vnic_stats(show_vnic_state_t *, uint32_t); 237 238 static int get_one_kstat(const char *, const char *, uint8_t, 239 void *, boolean_t); 240 static void get_mac_stats(const char *, pktsum_t *); 241 static void get_link_stats(const char *, pktsum_t *); 242 static uint64_t get_ifspeed(const char *, boolean_t); 243 static const char *get_linkstate(const char *, boolean_t, char *); 244 static const char *get_linkduplex(const char *, boolean_t, char *); 245 246 static iptun_type_t iptun_gettypebyname(char *); 247 static const char *iptun_gettypebyvalue(iptun_type_t); 248 static dladm_status_t print_iptun(dladm_handle_t, datalink_id_t, 249 show_state_t *); 250 static int print_iptun_walker(dladm_handle_t, datalink_id_t, void *); 251 252 static int show_etherprop(dladm_handle_t, datalink_id_t, void *); 253 static void show_ether_xprop(void *, dladm_ether_info_t *); 254 static boolean_t link_is_ether(const char *, datalink_id_t *); 255 256 static boolean_t str2int(const char *, int *); 257 static void die(const char *, ...); 258 static void die_optdup(int); 259 static void die_opterr(int, int, const char *); 260 static void die_dlerr(dladm_status_t, const char *, ...); 261 static void warn(const char *, ...); 262 static void warn_dlerr(dladm_status_t, const char *, ...); 263 264 typedef struct cmd { 265 char *c_name; 266 cmdfunc_t *c_fn; 267 const char *c_usage; 268 } cmd_t; 269 270 static cmd_t cmds[] = { 271 { "help", do_help, NULL }, 272 { "rename-link", do_rename_link, 273 " rename-link <oldlink> <newlink>" }, 274 { "show-link", do_show_link, 275 " show-link [-pP] [-o <field>,..] [-s [-i <interval>]] " 276 "[<link>]\n" }, 277 { "create-aggr", do_create_aggr, 278 " create-aggr [-t] [-P <policy>] [-L <mode>] [-T <time>] " 279 "[-u <address>]\n" 280 "\t\t -l <link> [-l <link>...] <link>" }, 281 { "delete-aggr", do_delete_aggr, 282 " delete-aggr [-t] <link>" }, 283 { "add-aggr", do_add_aggr, 284 " add-aggr [-t] -l <link> [-l <link>...] <link>" }, 285 { "remove-aggr", do_remove_aggr, 286 " remove-aggr [-t] -l <link> [-l <link>...] <link>" }, 287 { "modify-aggr", do_modify_aggr, 288 " modify-aggr [-t] [-P <policy>] [-L <mode>] [-T <time>] " 289 "[-u <address>]\n" 290 "\t\t <link>" }, 291 { "show-aggr", do_show_aggr, 292 " show-aggr [-pPLx] [-o <field>,..] [-s [-i <interval>]] " 293 "[<link>]\n" }, 294 { "up-aggr", do_up_aggr, NULL }, 295 { "scan-wifi", do_scan_wifi, 296 " scan-wifi [-p] [-o <field>,...] [<link>]" }, 297 { "connect-wifi", do_connect_wifi, 298 " connect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...] " 299 "[-s wep|wpa]\n" 300 "\t\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g] " 301 "[-T <time>]\n" 302 "\t\t [<link>]" }, 303 { "disconnect-wifi", do_disconnect_wifi, 304 " disconnect-wifi [-a] [<link>]" }, 305 { "show-wifi", do_show_wifi, 306 " show-wifi [-p] [-o <field>,...] [<link>]\n" }, 307 { "set-linkprop", do_set_linkprop, 308 " set-linkprop [-t] -p <prop>=<value>[,...] <name>" }, 309 { "reset-linkprop", do_reset_linkprop, 310 " reset-linkprop [-t] [-p <prop>,...] <name>" }, 311 { "show-linkprop", do_show_linkprop, 312 " show-linkprop [-cP] [-o <field>,...] [-p <prop>,...] " 313 "<name>\n" }, 314 { "show-ether", do_show_ether, 315 " show-ether [-px][-o <field>,...] <link>\n" }, 316 { "create-secobj", do_create_secobj, 317 " create-secobj [-t] [-f <file>] -c <class> <secobj>" }, 318 { "delete-secobj", do_delete_secobj, 319 " delete-secobj [-t] <secobj>[,...]" }, 320 { "show-secobj", do_show_secobj, 321 " show-secobj [-pP] [-o <field>,...] [<secobj>,...]\n" }, 322 { "init-linkprop", do_init_linkprop, NULL }, 323 { "init-secobj", do_init_secobj, NULL }, 324 { "create-vlan", do_create_vlan, 325 " create-vlan [-ft] -l <link> -v <vid> [link]" }, 326 { "delete-vlan", do_delete_vlan, 327 " delete-vlan [-t] <link>" }, 328 { "show-vlan", do_show_vlan, 329 " show-vlan [-pP] [-o <field>,..] [<link>]\n" }, 330 { "up-vlan", do_up_vlan, NULL }, 331 { "create-iptun", do_create_iptun, 332 " create-iptun [-t] -T <type> " 333 "[-a {local|remote}=<addr>,...] <link>]" }, 334 { "delete-iptun", do_delete_iptun, 335 " delete-iptun [-t] <link>" }, 336 { "modify-iptun", do_modify_iptun, 337 " modify-iptun [-t] -a {local|remote}=<addr>,... <link>" }, 338 { "show-iptun", do_show_iptun, 339 " show-iptun [-pP] [-o <field>,..] [<link>]\n" }, 340 { "up-iptun", do_up_iptun, NULL }, 341 { "down-iptun", do_down_iptun, NULL }, 342 { "delete-phys", do_delete_phys, 343 " delete-phys <link>" }, 344 { "show-phys", do_show_phys, 345 " show-phys [-m | -H | -P] [[-p] [-o <field>[,...]] " 346 "[<link>]\n" }, 347 { "init-phys", do_init_phys, NULL }, 348 { "show-linkmap", do_show_linkmap, NULL }, 349 { "create-vnic", do_create_vnic, 350 " create-vnic [-t] -l <link> [-m <value> | auto |\n" 351 "\t\t {factory [-n <slot-id>]} | {random [-r <prefix>]} |\n" 352 "\t\t {vrrp -V <vrid> -A {inet | inet6}} [-v <vid> [-f]]\n" 353 "\t\t [-p <prop>=<value>[,...]] <vnic-link>" }, 354 { "delete-vnic", do_delete_vnic, 355 " delete-vnic [-t] <vnic-link>" }, 356 { "show-vnic", do_show_vnic, 357 " show-vnic [-pP] [-l <link>] [-s [-i <interval>]] " 358 "[<link>]\n" }, 359 { "up-vnic", do_up_vnic, NULL }, 360 { "create-part", do_create_part, 361 " create-part [-t] [-f] -l <link> [-P <pkey>]\n" 362 "\t\t [-R <root-dir>] <part-link>" }, 363 { "delete-part", do_delete_part, 364 " delete-part [-t] [-R <root-dir>] <part-link>"}, 365 { "show-part", do_show_part, 366 " show-part [-pP] [-o <field>,...][-l <linkover>]\n" 367 "\t\t [<part-link>]" }, 368 { "show-ib", do_show_ib, 369 " show-ib [-p] [-o <field>,...] [<link>]\n" }, 370 { "up-part", do_up_part, NULL }, 371 { "create-etherstub", do_create_etherstub, 372 " create-etherstub [-t] <link>" }, 373 { "delete-etherstub", do_delete_etherstub, 374 " delete-etherstub [-t] <link>" }, 375 { "show-etherstub", do_show_etherstub, 376 " show-etherstub [-t] [<link>]\n" }, 377 { "create-simnet", do_create_simnet, NULL }, 378 { "modify-simnet", do_modify_simnet, NULL }, 379 { "delete-simnet", do_delete_simnet, NULL }, 380 { "show-simnet", do_show_simnet, NULL }, 381 { "up-simnet", do_up_simnet, NULL }, 382 { "create-bridge", do_create_bridge, 383 " create-bridge [-R <root-dir>] [-P <protect>] " 384 "[-p <priority>]\n" 385 "\t\t [-m <max-age>] [-h <hello-time>] [-d <forward-delay>]\n" 386 "\t\t [-f <force-protocol>] [-l <link>]... <bridge>" }, 387 { "modify-bridge", do_modify_bridge, 388 " modify-bridge [-R <root-dir>] [-P <protect>] " 389 "[-p <priority>]\n" 390 "\t\t [-m <max-age>] [-h <hello-time>] [-d <forward-delay>]\n" 391 "\t\t [-f <force-protocol>] <bridge>" }, 392 { "delete-bridge", do_delete_bridge, 393 " delete-bridge [-R <root-dir>] <bridge>" }, 394 { "add-bridge", do_add_bridge, 395 " add-bridge [-R <root-dir>] -l <link> [-l <link>]... " 396 "<bridge>" }, 397 { "remove-bridge", do_remove_bridge, 398 " remove-bridge [-R <root-dir>] -l <link> [-l <link>]... " 399 "<bridge>" }, 400 { "show-bridge", do_show_bridge, 401 " show-bridge [-p] [-o <field>,...] [-s [-i <interval>]] " 402 "[<bridge>]\n" 403 " show-bridge -l [-p] [-o <field>,...] [-s [-i <interval>]]" 404 " <bridge>\n" 405 " show-bridge -f [-p] [-o <field>,...] [-s [-i <interval>]]" 406 " <bridge>\n" 407 " show-bridge -t [-p] [-o <field>,...] [-s [-i <interval>]]" 408 " <bridge>\n" }, 409 { "show-usage", do_show_usage, 410 " show-usage [-a] [-d | -F <format>] " 411 "[-s <DD/MM/YYYY,HH:MM:SS>]\n" 412 "\t\t [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<link>]" } 413 }; 414 415 static const struct option lopts[] = { 416 {"vlan-id", required_argument, 0, 'v'}, 417 {"output", required_argument, 0, 'o'}, 418 {"dev", required_argument, 0, 'd'}, 419 {"policy", required_argument, 0, 'P'}, 420 {"lacp-mode", required_argument, 0, 'L'}, 421 {"lacp-timer", required_argument, 0, 'T'}, 422 {"unicast", required_argument, 0, 'u'}, 423 {"temporary", no_argument, 0, 't'}, 424 {"root-dir", required_argument, 0, 'R'}, 425 {"link", required_argument, 0, 'l'}, 426 {"forcible", no_argument, 0, 'f'}, 427 {"bw-limit", required_argument, 0, 'b'}, 428 {"mac-address", required_argument, 0, 'm'}, 429 {"slot", required_argument, 0, 'n'}, 430 { NULL, 0, NULL, 0 } 431 }; 432 433 static const struct option show_lopts[] = { 434 {"statistics", no_argument, 0, 's'}, 435 {"continuous", no_argument, 0, 'S'}, 436 {"interval", required_argument, 0, 'i'}, 437 {"parsable", no_argument, 0, 'p'}, 438 {"parseable", no_argument, 0, 'p'}, 439 {"extended", no_argument, 0, 'x'}, 440 {"output", required_argument, 0, 'o'}, 441 {"persistent", no_argument, 0, 'P'}, 442 {"lacp", no_argument, 0, 'L'}, 443 { NULL, 0, NULL, 0 } 444 }; 445 446 static const struct option iptun_lopts[] = { 447 {"output", required_argument, 0, 'o'}, 448 {"tunnel-type", required_argument, 0, 'T'}, 449 {"address", required_argument, 0, 'a'}, 450 {"root-dir", required_argument, 0, 'R'}, 451 {"parsable", no_argument, 0, 'p'}, 452 {"parseable", no_argument, 0, 'p'}, 453 {"persistent", no_argument, 0, 'P'}, 454 { NULL, 0, NULL, 0 } 455 }; 456 457 static char * const iptun_addropts[] = { 458 #define IPTUN_LOCAL 0 459 "local", 460 #define IPTUN_REMOTE 1 461 "remote", 462 NULL}; 463 464 static const struct { 465 const char *type_name; 466 iptun_type_t type_value; 467 } iptun_types[] = { 468 {"ipv4", IPTUN_TYPE_IPV4}, 469 {"ipv6", IPTUN_TYPE_IPV6}, 470 {"6to4", IPTUN_TYPE_6TO4}, 471 {NULL, 0} 472 }; 473 474 static const struct option prop_longopts[] = { 475 {"temporary", no_argument, 0, 't' }, 476 {"output", required_argument, 0, 'o' }, 477 {"root-dir", required_argument, 0, 'R' }, 478 {"prop", required_argument, 0, 'p' }, 479 {"parsable", no_argument, 0, 'c' }, 480 {"parseable", no_argument, 0, 'c' }, 481 {"persistent", no_argument, 0, 'P' }, 482 { NULL, 0, NULL, 0 } 483 }; 484 485 static const struct option wifi_longopts[] = { 486 {"parsable", no_argument, 0, 'p' }, 487 {"parseable", no_argument, 0, 'p' }, 488 {"output", required_argument, 0, 'o' }, 489 {"essid", required_argument, 0, 'e' }, 490 {"bsstype", required_argument, 0, 'b' }, 491 {"mode", required_argument, 0, 'm' }, 492 {"key", required_argument, 0, 'k' }, 493 {"sec", required_argument, 0, 's' }, 494 {"auth", required_argument, 0, 'a' }, 495 {"create-ibss", required_argument, 0, 'c' }, 496 {"timeout", required_argument, 0, 'T' }, 497 {"all-links", no_argument, 0, 'a' }, 498 {"temporary", no_argument, 0, 't' }, 499 {"root-dir", required_argument, 0, 'R' }, 500 {"persistent", no_argument, 0, 'P' }, 501 {"file", required_argument, 0, 'f' }, 502 { NULL, 0, NULL, 0 } 503 }; 504 505 static const struct option showeth_lopts[] = { 506 {"parsable", no_argument, 0, 'p' }, 507 {"parseable", no_argument, 0, 'p' }, 508 {"extended", no_argument, 0, 'x' }, 509 {"output", required_argument, 0, 'o' }, 510 { NULL, 0, NULL, 0 } 511 }; 512 513 static const struct option vnic_lopts[] = { 514 {"temporary", no_argument, 0, 't' }, 515 {"root-dir", required_argument, 0, 'R' }, 516 {"dev", required_argument, 0, 'd' }, 517 {"mac-address", required_argument, 0, 'm' }, 518 {"cpus", required_argument, 0, 'c' }, 519 {"bw-limit", required_argument, 0, 'b' }, 520 {"slot", required_argument, 0, 'n' }, 521 {"mac-prefix", required_argument, 0, 'r' }, 522 {"vrid", required_argument, 0, 'V' }, 523 {"address-family", required_argument, 0, 'A' }, 524 { NULL, 0, NULL, 0 } 525 }; 526 527 static const struct option part_lopts[] = { 528 {"temporary", no_argument, 0, 't' }, 529 {"pkey", required_argument, 0, 'P' }, 530 {"link", required_argument, 0, 'l' }, 531 {"force", no_argument, 0, 'f' }, 532 {"root-dir", required_argument, 0, 'R' }, 533 {"prop", required_argument, 0, 'p' }, 534 { NULL, 0, NULL, 0 } 535 }; 536 537 static const struct option show_part_lopts[] = { 538 {"parsable", no_argument, 0, 'p' }, 539 {"parseable", no_argument, 0, 'p' }, 540 {"link", required_argument, 0, 'l' }, 541 {"persistent", no_argument, 0, 'P' }, 542 {"output", required_argument, 0, 'o' }, 543 { NULL, 0, NULL, 0 } 544 }; 545 546 static const struct option etherstub_lopts[] = { 547 {"temporary", no_argument, 0, 't' }, 548 {"root-dir", required_argument, 0, 'R' }, 549 { NULL, 0, NULL, 0 } 550 }; 551 552 static const struct option usage_opts[] = { 553 {"file", required_argument, 0, 'f' }, 554 {"format", required_argument, 0, 'F' }, 555 {"start", required_argument, 0, 's' }, 556 {"stop", required_argument, 0, 'e' }, 557 { NULL, 0, NULL, 0 } 558 }; 559 560 static const struct option simnet_lopts[] = { 561 {"temporary", no_argument, 0, 't' }, 562 {"root-dir", required_argument, 0, 'R' }, 563 {"media", required_argument, 0, 'm' }, 564 {"peer", required_argument, 0, 'p' }, 565 { NULL, 0, NULL, 0 } 566 }; 567 568 static const struct option bridge_lopts[] = { 569 { "protect", required_argument, 0, 'P' }, 570 { "root-dir", required_argument, 0, 'R' }, 571 { "forward-delay", required_argument, 0, 'd' }, 572 { "force-protocol", required_argument, 0, 'f' }, 573 { "hello-time", required_argument, 0, 'h' }, 574 { "link", required_argument, 0, 'l' }, 575 { "max-age", required_argument, 0, 'm' }, 576 { "priority", required_argument, 0, 'p' }, 577 { NULL, 0, NULL, 0 } 578 }; 579 580 static const struct option bridge_show_lopts[] = { 581 { "forwarding", no_argument, 0, 'f' }, 582 { "interval", required_argument, 0, 'i' }, 583 { "link", no_argument, 0, 'l' }, 584 { "output", required_argument, 0, 'o' }, 585 { "parsable", no_argument, 0, 'p' }, 586 { "parseable", no_argument, 0, 'p' }, 587 { "statistics", no_argument, 0, 's' }, 588 { "trill", no_argument, 0, 't' }, 589 { NULL, 0, NULL, 0 } 590 }; 591 592 /* 593 * structures for 'dladm show-ether' 594 */ 595 static const char *ptype[] = {LEI_ATTR_NAMES}; 596 597 typedef struct ether_fields_buf_s 598 { 599 char eth_link[15]; 600 char eth_ptype[8]; 601 char eth_state[8]; 602 char eth_autoneg[5]; 603 char eth_spdx[31]; 604 char eth_pause[6]; 605 char eth_rem_fault[16]; 606 } ether_fields_buf_t; 607 608 static const ofmt_field_t ether_fields[] = { 609 /* name, field width, offset callback */ 610 { "LINK", 16, 611 offsetof(ether_fields_buf_t, eth_link), print_default_cb}, 612 { "PTYPE", 9, 613 offsetof(ether_fields_buf_t, eth_ptype), print_default_cb}, 614 { "STATE", 9, 615 offsetof(ether_fields_buf_t, eth_state), 616 print_default_cb}, 617 { "AUTO", 6, 618 offsetof(ether_fields_buf_t, eth_autoneg), print_default_cb}, 619 { "SPEED-DUPLEX", 32, 620 offsetof(ether_fields_buf_t, eth_spdx), print_default_cb}, 621 { "PAUSE", 7, 622 offsetof(ether_fields_buf_t, eth_pause), print_default_cb}, 623 { "REM_FAULT", 17, 624 offsetof(ether_fields_buf_t, eth_rem_fault), print_default_cb}, 625 {NULL, 0, 626 0, NULL}} 627 ; 628 629 typedef struct print_ether_state { 630 const char *es_link; 631 boolean_t es_parsable; 632 boolean_t es_header; 633 boolean_t es_extended; 634 ofmt_handle_t es_ofmt; 635 } print_ether_state_t; 636 637 /* 638 * structures for 'dladm show-link -s' (print statistics) 639 */ 640 typedef enum { 641 LINK_S_LINK, 642 LINK_S_IPKTS, 643 LINK_S_RBYTES, 644 LINK_S_IERRORS, 645 LINK_S_OPKTS, 646 LINK_S_OBYTES, 647 LINK_S_OERRORS 648 } link_s_field_index_t; 649 650 static const ofmt_field_t link_s_fields[] = { 651 /* name, field width, index, callback */ 652 { "LINK", 15, LINK_S_LINK, print_link_stats_cb}, 653 { "IPACKETS", 10, LINK_S_IPKTS, print_link_stats_cb}, 654 { "RBYTES", 8, LINK_S_RBYTES, print_link_stats_cb}, 655 { "IERRORS", 10, LINK_S_IERRORS, print_link_stats_cb}, 656 { "OPACKETS", 12, LINK_S_OPKTS, print_link_stats_cb}, 657 { "OBYTES", 12, LINK_S_OBYTES, print_link_stats_cb}, 658 { "OERRORS", 8, LINK_S_OERRORS, print_link_stats_cb}, 659 { NULL, 0, 0, NULL}}; 660 661 typedef struct link_args_s { 662 char *link_s_link; 663 pktsum_t *link_s_psum; 664 } link_args_t; 665 666 /* 667 * buffer used by print functions for show-{link,phys,vlan} commands. 668 */ 669 typedef struct link_fields_buf_s { 670 char link_name[MAXLINKNAMELEN]; 671 char link_class[DLADM_STRSIZE]; 672 char link_mtu[11]; 673 char link_state[DLADM_STRSIZE]; 674 char link_bridge[MAXLINKNAMELEN * MAXPORT]; 675 char link_over[MAXLINKNAMELEN * MAXPORT]; 676 char link_phys_state[DLADM_STRSIZE]; 677 char link_phys_media[DLADM_STRSIZE]; 678 char link_phys_speed[DLADM_STRSIZE]; 679 char link_phys_duplex[DLPI_LINKNAME_MAX]; 680 char link_phys_device[DLPI_LINKNAME_MAX]; 681 char link_flags[6]; 682 char link_vlan_vid[6]; 683 } link_fields_buf_t; 684 685 /* 686 * structures for 'dladm show-link' 687 */ 688 static const ofmt_field_t link_fields[] = { 689 /* name, field width, index, callback */ 690 { "LINK", 12, 691 offsetof(link_fields_buf_t, link_name), print_default_cb}, 692 { "CLASS", 10, 693 offsetof(link_fields_buf_t, link_class), print_default_cb}, 694 { "MTU", 7, 695 offsetof(link_fields_buf_t, link_mtu), print_default_cb}, 696 { "STATE", 9, 697 offsetof(link_fields_buf_t, link_state), print_default_cb}, 698 { "BRIDGE", 11, 699 offsetof(link_fields_buf_t, link_bridge), print_default_cb}, 700 { "OVER", 30, 701 offsetof(link_fields_buf_t, link_over), print_default_cb}, 702 { NULL, 0, 0, NULL}} 703 ; 704 705 /* 706 * structures for 'dladm show-aggr' 707 */ 708 typedef struct laggr_fields_buf_s { 709 char laggr_name[DLPI_LINKNAME_MAX]; 710 char laggr_policy[9]; 711 char laggr_addrpolicy[ETHERADDRL * 3 + 3]; 712 char laggr_lacpactivity[14]; 713 char laggr_lacptimer[DLADM_STRSIZE]; 714 char laggr_flags[7]; 715 } laggr_fields_buf_t; 716 717 typedef struct laggr_args_s { 718 int laggr_lport; /* -1 indicates the aggr itself */ 719 const char *laggr_link; 720 dladm_aggr_grp_attr_t *laggr_ginfop; 721 dladm_status_t *laggr_status; 722 pktsum_t *laggr_pktsumtot; /* -s only */ 723 pktsum_t *laggr_diffstats; /* -s only */ 724 boolean_t laggr_parsable; 725 } laggr_args_t; 726 727 static const ofmt_field_t laggr_fields[] = { 728 /* name, field width, offset, callback */ 729 { "LINK", 16, 730 offsetof(laggr_fields_buf_t, laggr_name), print_default_cb}, 731 { "POLICY", 9, 732 offsetof(laggr_fields_buf_t, laggr_policy), print_default_cb}, 733 { "ADDRPOLICY", ETHERADDRL * 3 + 3, 734 offsetof(laggr_fields_buf_t, laggr_addrpolicy), print_default_cb}, 735 { "LACPACTIVITY", 14, 736 offsetof(laggr_fields_buf_t, laggr_lacpactivity), print_default_cb}, 737 { "LACPTIMER", 12, 738 offsetof(laggr_fields_buf_t, laggr_lacptimer), print_default_cb}, 739 { "FLAGS", 8, 740 offsetof(laggr_fields_buf_t, laggr_flags), print_default_cb}, 741 { NULL, 0, 0, NULL}} 742 ; 743 744 /* 745 * structures for 'dladm show-aggr -x'. 746 */ 747 typedef enum { 748 AGGR_X_LINK, 749 AGGR_X_PORT, 750 AGGR_X_SPEED, 751 AGGR_X_DUPLEX, 752 AGGR_X_STATE, 753 AGGR_X_ADDRESS, 754 AGGR_X_PORTSTATE 755 } aggr_x_field_index_t; 756 757 static const ofmt_field_t aggr_x_fields[] = { 758 /* name, field width, index callback */ 759 { "LINK", 12, AGGR_X_LINK, print_xaggr_cb}, 760 { "PORT", 15, AGGR_X_PORT, print_xaggr_cb}, 761 { "SPEED", 5, AGGR_X_SPEED, print_xaggr_cb}, 762 { "DUPLEX", 10, AGGR_X_DUPLEX, print_xaggr_cb}, 763 { "STATE", 10, AGGR_X_STATE, print_xaggr_cb}, 764 { "ADDRESS", 19, AGGR_X_ADDRESS, print_xaggr_cb}, 765 { "PORTSTATE", 16, AGGR_X_PORTSTATE, print_xaggr_cb}, 766 { NULL, 0, 0, NULL}} 767 ; 768 769 /* 770 * structures for 'dladm show-aggr -s'. 771 */ 772 typedef enum { 773 AGGR_S_LINK, 774 AGGR_S_PORT, 775 AGGR_S_IPKTS, 776 AGGR_S_RBYTES, 777 AGGR_S_OPKTS, 778 AGGR_S_OBYTES, 779 AGGR_S_IPKTDIST, 780 AGGR_S_OPKTDIST 781 } aggr_s_field_index_t; 782 783 static const ofmt_field_t aggr_s_fields[] = { 784 { "LINK", 12, AGGR_S_LINK, print_aggr_stats_cb}, 785 { "PORT", 10, AGGR_S_PORT, print_aggr_stats_cb}, 786 { "IPACKETS", 8, AGGR_S_IPKTS, print_aggr_stats_cb}, 787 { "RBYTES", 8, AGGR_S_RBYTES, print_aggr_stats_cb}, 788 { "OPACKETS", 8, AGGR_S_OPKTS, print_aggr_stats_cb}, 789 { "OBYTES", 8, AGGR_S_OBYTES, print_aggr_stats_cb}, 790 { "IPKTDIST", 9, AGGR_S_IPKTDIST, print_aggr_stats_cb}, 791 { "OPKTDIST", 15, AGGR_S_OPKTDIST, print_aggr_stats_cb}, 792 { NULL, 0, 0, NULL}} 793 ; 794 795 /* 796 * structures for 'dladm show-aggr -L'. 797 */ 798 typedef enum { 799 AGGR_L_LINK, 800 AGGR_L_PORT, 801 AGGR_L_AGGREGATABLE, 802 AGGR_L_SYNC, 803 AGGR_L_COLL, 804 AGGR_L_DIST, 805 AGGR_L_DEFAULTED, 806 AGGR_L_EXPIRED 807 } aggr_l_field_index_t; 808 809 static const ofmt_field_t aggr_l_fields[] = { 810 /* name, field width, index */ 811 { "LINK", 12, AGGR_L_LINK, print_lacp_cb}, 812 { "PORT", 13, AGGR_L_PORT, print_lacp_cb}, 813 { "AGGREGATABLE", 13, AGGR_L_AGGREGATABLE, print_lacp_cb}, 814 { "SYNC", 5, AGGR_L_SYNC, print_lacp_cb}, 815 { "COLL", 5, AGGR_L_COLL, print_lacp_cb}, 816 { "DIST", 5, AGGR_L_DIST, print_lacp_cb}, 817 { "DEFAULTED", 10, AGGR_L_DEFAULTED, print_lacp_cb}, 818 { "EXPIRED", 15, AGGR_L_EXPIRED, print_lacp_cb}, 819 { NULL, 0, 0, NULL}} 820 ; 821 822 /* 823 * structures for 'dladm show-phys' 824 */ 825 826 static const ofmt_field_t phys_fields[] = { 827 /* name, field width, offset */ 828 { "LINK", 13, 829 offsetof(link_fields_buf_t, link_name), print_default_cb}, 830 { "MEDIA", 21, 831 offsetof(link_fields_buf_t, link_phys_media), print_default_cb}, 832 { "STATE", 11, 833 offsetof(link_fields_buf_t, link_phys_state), print_default_cb}, 834 { "SPEED", 7, 835 offsetof(link_fields_buf_t, link_phys_speed), print_default_cb}, 836 { "DUPLEX", 10, 837 offsetof(link_fields_buf_t, link_phys_duplex), print_default_cb}, 838 { "DEVICE", 13, 839 offsetof(link_fields_buf_t, link_phys_device), print_default_cb}, 840 { "FLAGS", 7, 841 offsetof(link_fields_buf_t, link_flags), print_default_cb}, 842 { NULL, 0, 0, NULL}} 843 ; 844 845 /* 846 * structures for 'dladm show-phys -m' 847 */ 848 849 typedef enum { 850 PHYS_M_LINK, 851 PHYS_M_SLOT, 852 PHYS_M_ADDRESS, 853 PHYS_M_INUSE, 854 PHYS_M_CLIENT 855 } phys_m_field_index_t; 856 857 static const ofmt_field_t phys_m_fields[] = { 858 /* name, field width, offset */ 859 { "LINK", 13, PHYS_M_LINK, print_phys_one_mac_cb}, 860 { "SLOT", 9, PHYS_M_SLOT, print_phys_one_mac_cb}, 861 { "ADDRESS", 19, PHYS_M_ADDRESS, print_phys_one_mac_cb}, 862 { "INUSE", 5, PHYS_M_INUSE, print_phys_one_mac_cb}, 863 { "CLIENT", 13, PHYS_M_CLIENT, print_phys_one_mac_cb}, 864 { NULL, 0, 0, NULL}} 865 ; 866 867 /* 868 * structures for 'dladm show-phys -H' 869 */ 870 871 typedef enum { 872 PHYS_H_LINK, 873 PHYS_H_RINGTYPE, 874 PHYS_H_RINGS, 875 PHYS_H_CLIENTS 876 } phys_h_field_index_t; 877 878 #define RINGSTRLEN 21 879 880 static const ofmt_field_t phys_h_fields[] = { 881 { "LINK", 13, PHYS_H_LINK, print_phys_one_hwgrp_cb}, 882 { "RINGTYPE", 9, PHYS_H_RINGTYPE, print_phys_one_hwgrp_cb}, 883 { "RINGS", RINGSTRLEN, PHYS_H_RINGS, print_phys_one_hwgrp_cb}, 884 { "CLIENTS", 24, PHYS_H_CLIENTS, print_phys_one_hwgrp_cb}, 885 { NULL, 0, 0, NULL}} 886 ; 887 888 /* 889 * structures for 'dladm show-vlan' 890 */ 891 static const ofmt_field_t vlan_fields[] = { 892 { "LINK", 16, 893 offsetof(link_fields_buf_t, link_name), print_default_cb}, 894 { "VID", 9, 895 offsetof(link_fields_buf_t, link_vlan_vid), print_default_cb}, 896 { "OVER", 13, 897 offsetof(link_fields_buf_t, link_over), print_default_cb}, 898 { "FLAGS", 7, 899 offsetof(link_fields_buf_t, link_flags), print_default_cb}, 900 { NULL, 0, 0, NULL}} 901 ; 902 903 /* 904 * structures common to 'dladm scan-wifi' and 'dladm show-wifi' 905 * callback will be determined in parse_wifi_fields. 906 */ 907 static ofmt_field_t wifi_common_fields[] = { 908 { "LINK", 11, 0, NULL}, 909 { "ESSID", 20, DLADM_WLAN_ATTR_ESSID, NULL}, 910 { "BSSID", 18, DLADM_WLAN_ATTR_BSSID, NULL}, 911 { "IBSSID", 18, DLADM_WLAN_ATTR_BSSID, NULL}, 912 { "MODE", 7, DLADM_WLAN_ATTR_MODE, NULL}, 913 { "SPEED", 7, DLADM_WLAN_ATTR_SPEED, NULL}, 914 { "BSSTYPE", 9, DLADM_WLAN_ATTR_BSSTYPE, NULL}, 915 { "SEC", 7, DLADM_WLAN_ATTR_SECMODE, NULL}, 916 { "STRENGTH", 11, DLADM_WLAN_ATTR_STRENGTH, NULL}, 917 { NULL, 0, 0, NULL}}; 918 919 /* 920 * the 'show-wifi' command supports all the fields in wifi_common_fields 921 * plus the AUTH and STATUS fields. 922 */ 923 static ofmt_field_t wifi_show_fields[A_CNT(wifi_common_fields) + 2] = { 924 { "AUTH", 9, DLADM_WLAN_ATTR_AUTH, NULL}, 925 { "STATUS", 18, DLADM_WLAN_LINKATTR_STATUS, print_wifi_status_cb}, 926 /* copy wifi_common_fields here */ 927 }; 928 929 static char *all_scan_wifi_fields = 930 "link,essid,bssid,sec,strength,mode,speed,bsstype"; 931 static char *all_show_wifi_fields = 932 "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 933 static char *def_scan_wifi_fields = 934 "link,essid,bssid,sec,strength,mode,speed"; 935 static char *def_show_wifi_fields = 936 "link,status,essid,sec,strength,mode,speed"; 937 938 /* 939 * structures for 'dladm show-linkprop' 940 */ 941 typedef enum { 942 LINKPROP_LINK, 943 LINKPROP_PROPERTY, 944 LINKPROP_PERM, 945 LINKPROP_VALUE, 946 LINKPROP_DEFAULT, 947 LINKPROP_POSSIBLE 948 } linkprop_field_index_t; 949 950 static const ofmt_field_t linkprop_fields[] = { 951 /* name, field width, index */ 952 { "LINK", 13, LINKPROP_LINK, print_linkprop_cb}, 953 { "PROPERTY", 16, LINKPROP_PROPERTY, print_linkprop_cb}, 954 { "PERM", 5, LINKPROP_PERM, print_linkprop_cb}, 955 { "VALUE", 15, LINKPROP_VALUE, print_linkprop_cb}, 956 { "DEFAULT", 15, LINKPROP_DEFAULT, print_linkprop_cb}, 957 { "POSSIBLE", 20, LINKPROP_POSSIBLE, print_linkprop_cb}, 958 { NULL, 0, 0, NULL}} 959 ; 960 961 #define MAX_PROP_LINE 512 962 963 typedef struct show_linkprop_state { 964 char ls_link[MAXLINKNAMELEN]; 965 char *ls_line; 966 char **ls_propvals; 967 dladm_arg_list_t *ls_proplist; 968 boolean_t ls_parsable; 969 boolean_t ls_persist; 970 boolean_t ls_header; 971 dladm_status_t ls_status; 972 dladm_status_t ls_retstatus; 973 ofmt_handle_t ls_ofmt; 974 } show_linkprop_state_t; 975 976 typedef struct set_linkprop_state { 977 const char *ls_name; 978 boolean_t ls_reset; 979 boolean_t ls_temp; 980 dladm_status_t ls_status; 981 } set_linkprop_state_t; 982 983 typedef struct linkprop_args_s { 984 show_linkprop_state_t *ls_state; 985 char *ls_propname; 986 datalink_id_t ls_linkid; 987 } linkprop_args_t; 988 989 /* 990 * structures for 'dladm show-secobj' 991 */ 992 typedef struct secobj_fields_buf_s { 993 char ss_obj_name[DLADM_SECOBJ_VAL_MAX]; 994 char ss_class[20]; 995 char ss_val[30]; 996 } secobj_fields_buf_t; 997 998 static const ofmt_field_t secobj_fields[] = { 999 { "OBJECT", 21, 1000 offsetof(secobj_fields_buf_t, ss_obj_name), print_default_cb}, 1001 { "CLASS", 21, 1002 offsetof(secobj_fields_buf_t, ss_class), print_default_cb}, 1003 { "VALUE", 31, 1004 offsetof(secobj_fields_buf_t, ss_val), print_default_cb}, 1005 { NULL, 0, 0, NULL}} 1006 ; 1007 1008 /* 1009 * structures for 'dladm show-vnic' 1010 */ 1011 typedef struct vnic_fields_buf_s 1012 { 1013 char vnic_link[DLPI_LINKNAME_MAX]; 1014 char vnic_over[DLPI_LINKNAME_MAX]; 1015 char vnic_speed[6]; 1016 char vnic_macaddr[18]; 1017 char vnic_macaddrtype[19]; 1018 char vnic_vid[6]; 1019 } vnic_fields_buf_t; 1020 1021 static const ofmt_field_t vnic_fields[] = { 1022 { "LINK", 13, 1023 offsetof(vnic_fields_buf_t, vnic_link), print_default_cb}, 1024 { "OVER", 13, 1025 offsetof(vnic_fields_buf_t, vnic_over), print_default_cb}, 1026 { "SPEED", 7, 1027 offsetof(vnic_fields_buf_t, vnic_speed), print_default_cb}, 1028 { "MACADDRESS", 18, 1029 offsetof(vnic_fields_buf_t, vnic_macaddr), print_default_cb}, 1030 { "MACADDRTYPE", 20, 1031 offsetof(vnic_fields_buf_t, vnic_macaddrtype), print_default_cb}, 1032 { "VID", 7, 1033 offsetof(vnic_fields_buf_t, vnic_vid), print_default_cb}, 1034 { NULL, 0, 0, NULL}} 1035 ; 1036 1037 /* 1038 * structures for 'dladm show-ib' 1039 */ 1040 typedef struct ib_fields_buf_s 1041 { 1042 char ib_link[DLPI_LINKNAME_MAX]; 1043 char ib_hcaguid[17]; 1044 char ib_portguid[17]; 1045 char ib_portnum[4]; 1046 char ib_state[6]; 1047 char ib_pkeys[MAXPKEYSTRSZ]; 1048 } ib_fields_buf_t; 1049 1050 static const ofmt_field_t ib_fields[] = { 1051 { "LINK", 13, 1052 offsetof(ib_fields_buf_t, ib_link), print_default_cb}, 1053 { "HCAGUID", IBGUIDSTRLEN, 1054 offsetof(ib_fields_buf_t, ib_hcaguid), print_default_cb}, 1055 { "PORTGUID", IBGUIDSTRLEN, 1056 offsetof(ib_fields_buf_t, ib_portguid), print_default_cb}, 1057 { "PORT", IBPORTSTRLEN, 1058 offsetof(ib_fields_buf_t, ib_portnum), print_default_cb}, 1059 { "STATE", 7, 1060 offsetof(ib_fields_buf_t, ib_state), print_default_cb}, 1061 { "PKEYS", 18, 1062 offsetof(ib_fields_buf_t, ib_pkeys), print_default_cb}, 1063 { NULL, 0, 0, NULL}}; 1064 1065 /* 1066 * structures for 'dladm show-part' 1067 */ 1068 typedef struct part_fields_buf_s 1069 { 1070 char part_link[DLPI_LINKNAME_MAX]; 1071 char part_pkey[5]; 1072 char part_over[DLPI_LINKNAME_MAX]; 1073 char part_state[8]; 1074 char part_flags[5]; 1075 } part_fields_buf_t; 1076 1077 static const ofmt_field_t part_fields[] = { 1078 { "LINK", 13, 1079 offsetof(part_fields_buf_t, part_link), print_default_cb}, 1080 { "PKEY", MAXPKEYLEN, 1081 offsetof(part_fields_buf_t, part_pkey), print_default_cb}, 1082 { "OVER", 13, 1083 offsetof(part_fields_buf_t, part_over), print_default_cb}, 1084 { "STATE", 9, 1085 offsetof(part_fields_buf_t, part_state), print_default_cb}, 1086 { "FLAGS", 5, 1087 offsetof(part_fields_buf_t, part_flags), print_default_cb}, 1088 { NULL, 0, 0, NULL}}; 1089 1090 /* 1091 * structures for 'dladm show-simnet' 1092 */ 1093 typedef struct simnet_fields_buf_s 1094 { 1095 char simnet_name[DLPI_LINKNAME_MAX]; 1096 char simnet_media[DLADM_STRSIZE]; 1097 char simnet_macaddr[18]; 1098 char simnet_otherlink[DLPI_LINKNAME_MAX]; 1099 } simnet_fields_buf_t; 1100 1101 static const ofmt_field_t simnet_fields[] = { 1102 { "LINK", 12, 1103 offsetof(simnet_fields_buf_t, simnet_name), print_default_cb}, 1104 { "MEDIA", 20, 1105 offsetof(simnet_fields_buf_t, simnet_media), print_default_cb}, 1106 { "MACADDRESS", 18, 1107 offsetof(simnet_fields_buf_t, simnet_macaddr), print_default_cb}, 1108 { "OTHERLINK", 12, 1109 offsetof(simnet_fields_buf_t, simnet_otherlink), print_default_cb}, 1110 { NULL, 0, 0, NULL}} 1111 ; 1112 1113 /* 1114 * structures for 'dladm show-usage' 1115 */ 1116 1117 typedef struct usage_fields_buf_s { 1118 char usage_link[12]; 1119 char usage_duration[10]; 1120 char usage_ipackets[9]; 1121 char usage_rbytes[10]; 1122 char usage_opackets[9]; 1123 char usage_obytes[10]; 1124 char usage_bandwidth[15]; 1125 } usage_fields_buf_t; 1126 1127 static const ofmt_field_t usage_fields[] = { 1128 { "LINK", 13, 1129 offsetof(usage_fields_buf_t, usage_link), print_default_cb}, 1130 { "DURATION", 11, 1131 offsetof(usage_fields_buf_t, usage_duration), print_default_cb}, 1132 { "IPACKETS", 10, 1133 offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb}, 1134 { "RBYTES", 11, 1135 offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb}, 1136 { "OPACKETS", 10, 1137 offsetof(usage_fields_buf_t, usage_opackets), print_default_cb}, 1138 { "OBYTES", 11, 1139 offsetof(usage_fields_buf_t, usage_obytes), print_default_cb}, 1140 { "BANDWIDTH", 16, 1141 offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb}, 1142 { NULL, 0, 0, NULL}} 1143 ; 1144 1145 1146 /* 1147 * structures for 'dladm show-usage link' 1148 */ 1149 1150 typedef struct usage_l_fields_buf_s { 1151 char usage_l_link[12]; 1152 char usage_l_stime[13]; 1153 char usage_l_etime[13]; 1154 char usage_l_rbytes[8]; 1155 char usage_l_obytes[8]; 1156 char usage_l_bandwidth[15]; 1157 } usage_l_fields_buf_t; 1158 1159 static const ofmt_field_t usage_l_fields[] = { 1160 /* name, field width, offset */ 1161 { "LINK", 13, 1162 offsetof(usage_l_fields_buf_t, usage_l_link), print_default_cb}, 1163 { "START", 14, 1164 offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb}, 1165 { "END", 14, 1166 offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb}, 1167 { "RBYTES", 9, 1168 offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb}, 1169 { "OBYTES", 9, 1170 offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb}, 1171 { "BANDWIDTH", 16, 1172 offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb}, 1173 { NULL, 0, 0, NULL}} 1174 ; 1175 1176 /* IPTUN_*FLAG_INDEX values are indices into iptun_flags below. */ 1177 enum { IPTUN_SFLAG_INDEX, IPTUN_IFLAG_INDEX, IPTUN_NUM_FLAGS }; 1178 1179 /* 1180 * structures for 'dladm show-iptun' 1181 */ 1182 typedef struct iptun_fields_buf_s { 1183 char iptun_name[MAXLINKNAMELEN]; 1184 char iptun_type[5]; 1185 char iptun_laddr[NI_MAXHOST]; 1186 char iptun_raddr[NI_MAXHOST]; 1187 char iptun_flags[IPTUN_NUM_FLAGS + 1]; 1188 } iptun_fields_buf_t; 1189 1190 static const ofmt_field_t iptun_fields[] = { 1191 { "LINK", 16, 1192 offsetof(iptun_fields_buf_t, iptun_name), print_default_cb }, 1193 { "TYPE", 6, 1194 offsetof(iptun_fields_buf_t, iptun_type), print_default_cb }, 1195 { "FLAGS", 7, 1196 offsetof(iptun_fields_buf_t, iptun_flags), print_default_cb }, 1197 { "LOCAL", 20, 1198 offsetof(iptun_fields_buf_t, iptun_laddr), print_default_cb }, 1199 { "REMOTE", 20, 1200 offsetof(iptun_fields_buf_t, iptun_raddr), print_default_cb }, 1201 { NULL, 0, 0, NULL} 1202 }; 1203 1204 /* 1205 * structures for 'dladm show-bridge'. These are based on sections 14.8.1.1.3 1206 * and 14.8.1.2.2 of IEEE 802.1D-2004. 1207 */ 1208 typedef struct bridge_fields_buf_s { 1209 char bridge_name[MAXLINKNAMELEN]; /* 14.4.1.2.3(b) */ 1210 char bridge_protect[7]; /* stp or trill */ 1211 char bridge_address[24]; /* 17.18.3, 7.12.5, 14.4.1.2.3(a) */ 1212 char bridge_priority[7]; /* 17.18.3 9.2.5 - only upper 4 bits */ 1213 char bridge_bmaxage[7]; /* 17.18.4 configured */ 1214 char bridge_bhellotime[7]; /* 17.18.4 configured */ 1215 char bridge_bfwddelay[7]; /* 17.18.4 configured */ 1216 char bridge_forceproto[3]; /* 17.13.4 configured */ 1217 char bridge_tctime[12]; /* 14.8.1.1.3(b) */ 1218 char bridge_tccount[12]; /* 17.17.8 */ 1219 char bridge_tchange[12]; /* 17.17.8 */ 1220 char bridge_desroot[24]; /* 17.18.6 priority "/" MAC */ 1221 char bridge_rootcost[12]; /* 17.18.6 */ 1222 char bridge_rootport[12]; /* 17.18.6 */ 1223 char bridge_maxage[7]; /* 17.18.7 for root */ 1224 char bridge_hellotime[7]; /* 17.13.6 for root */ 1225 char bridge_fwddelay[7]; /* 17.13.5 for root */ 1226 char bridge_holdtime[12]; /* 17.13.12 for root */ 1227 } bridge_fields_buf_t; 1228 1229 static ofmt_field_t bridge_fields[] = { 1230 /* name, field width, offset, callback */ 1231 { "BRIDGE", 12, 1232 offsetof(bridge_fields_buf_t, bridge_name), print_default_cb }, 1233 { "PROTECT", 8, 1234 offsetof(bridge_fields_buf_t, bridge_protect), print_default_cb }, 1235 { "ADDRESS", 19, 1236 offsetof(bridge_fields_buf_t, bridge_address), print_default_cb }, 1237 { "PRIORITY", 9, 1238 offsetof(bridge_fields_buf_t, bridge_priority), print_default_cb }, 1239 { "BMAXAGE", 8, 1240 offsetof(bridge_fields_buf_t, bridge_bmaxage), print_default_cb }, 1241 { "BHELLOTIME", 11, 1242 offsetof(bridge_fields_buf_t, bridge_bhellotime), print_default_cb }, 1243 { "BFWDDELAY", 10, 1244 offsetof(bridge_fields_buf_t, bridge_bfwddelay), print_default_cb }, 1245 { "FORCEPROTO", 11, 1246 offsetof(bridge_fields_buf_t, bridge_forceproto), print_default_cb }, 1247 { "TCTIME", 10, 1248 offsetof(bridge_fields_buf_t, bridge_tctime), print_default_cb }, 1249 { "TCCOUNT", 10, 1250 offsetof(bridge_fields_buf_t, bridge_tccount), print_default_cb }, 1251 { "TCHANGE", 10, 1252 offsetof(bridge_fields_buf_t, bridge_tchange), print_default_cb }, 1253 { "DESROOT", 23, 1254 offsetof(bridge_fields_buf_t, bridge_desroot), print_default_cb }, 1255 { "ROOTCOST", 11, 1256 offsetof(bridge_fields_buf_t, bridge_rootcost), print_default_cb }, 1257 { "ROOTPORT", 11, 1258 offsetof(bridge_fields_buf_t, bridge_rootport), print_default_cb }, 1259 { "MAXAGE", 8, 1260 offsetof(bridge_fields_buf_t, bridge_maxage), print_default_cb }, 1261 { "HELLOTIME", 10, 1262 offsetof(bridge_fields_buf_t, bridge_hellotime), print_default_cb }, 1263 { "FWDDELAY", 9, 1264 offsetof(bridge_fields_buf_t, bridge_fwddelay), print_default_cb }, 1265 { "HOLDTIME", 9, 1266 offsetof(bridge_fields_buf_t, bridge_holdtime), print_default_cb }, 1267 { NULL, 0, 0, NULL}}; 1268 1269 /* 1270 * structures for 'dladm show-bridge -l'. These are based on 14.4.1.2.3 and 1271 * 14.8.2.1.3 of IEEE 802.1D-2004. 1272 */ 1273 typedef struct bridge_link_fields_buf_s { 1274 char bridgel_link[MAXLINKNAMELEN]; 1275 char bridgel_index[7]; /* 14.4.1.2.3(d1) */ 1276 char bridgel_state[11]; /* 14.8.2.1.3(b) */ 1277 char bridgel_uptime[7]; /* 14.8.2.1.3(a) */ 1278 char bridgel_opercost[7] /* 14.8.2.1.3(d) */; 1279 char bridgel_operp2p[4]; /* 14.8.2.1.3(p) */ 1280 char bridgel_operedge[4]; /* 14.8.2.1.3(k) */ 1281 char bridgel_desroot[23]; /* 14.8.2.1.3(e) */ 1282 char bridgel_descost[12]; /* 14.8.2.1.3(f) */ 1283 char bridgel_desbridge[23]; /* 14.8.2.1.3(g) */ 1284 char bridgel_desport[7]; /* 14.8.2.1.3(h) */ 1285 char bridgel_tcack[4]; /* 14.8.2.1.3(i) */ 1286 } bridge_link_fields_buf_t; 1287 1288 static ofmt_field_t bridge_link_fields[] = { 1289 /* name, field width, offset, callback */ 1290 { "LINK", 12, 1291 offsetof(bridge_link_fields_buf_t, bridgel_link), print_default_cb }, 1292 { "INDEX", 8, 1293 offsetof(bridge_link_fields_buf_t, bridgel_index), print_default_cb }, 1294 { "STATE", 12, 1295 offsetof(bridge_link_fields_buf_t, bridgel_state), print_default_cb }, 1296 { "UPTIME", 8, 1297 offsetof(bridge_link_fields_buf_t, bridgel_uptime), print_default_cb }, 1298 { "OPERCOST", 9, 1299 offsetof(bridge_link_fields_buf_t, bridgel_opercost), print_default_cb }, 1300 { "OPERP2P", 8, 1301 offsetof(bridge_link_fields_buf_t, bridgel_operp2p), print_default_cb }, 1302 { "OPEREDGE", 9, 1303 offsetof(bridge_link_fields_buf_t, bridgel_operedge), print_default_cb }, 1304 { "DESROOT", 22, 1305 offsetof(bridge_link_fields_buf_t, bridgel_desroot), print_default_cb }, 1306 { "DESCOST", 11, 1307 offsetof(bridge_link_fields_buf_t, bridgel_descost), print_default_cb }, 1308 { "DESBRIDGE", 22, 1309 offsetof(bridge_link_fields_buf_t, bridgel_desbridge), print_default_cb }, 1310 { "DESPORT", 8, 1311 offsetof(bridge_link_fields_buf_t, bridgel_desport), print_default_cb }, 1312 { "TCACK", 6, 1313 offsetof(bridge_link_fields_buf_t, bridgel_tcack), print_default_cb }, 1314 { NULL, 0, 0, NULL}}; 1315 1316 /* 1317 * structures for 'dladm show-bridge -s'. These are not based on IEEE 1318 * 802.1D-2004. 1319 */ 1320 #define ULONG_DIG (((sizeof (ulong_t) * NBBY) * 3 / 10) + 1) 1321 #define UINT64_DIG (((sizeof (uint64_t) * NBBY) * 3 / 10) + 1) 1322 typedef struct bridge_statfields_buf_s { 1323 char bridges_name[MAXLINKNAMELEN]; 1324 char bridges_drops[UINT64_DIG]; 1325 char bridges_forwards[UINT64_DIG]; 1326 char bridges_mbcast[UINT64_DIG]; 1327 char bridges_unknown[UINT64_DIG]; 1328 char bridges_recv[UINT64_DIG]; 1329 char bridges_sent[UINT64_DIG]; 1330 } bridge_statfields_buf_t; 1331 1332 static ofmt_field_t bridge_statfields[] = { 1333 /* name, field width, offset, callback */ 1334 { "BRIDGE", 12, 1335 offsetof(bridge_statfields_buf_t, bridges_name), print_default_cb }, 1336 { "DROPS", 12, 1337 offsetof(bridge_statfields_buf_t, bridges_drops), print_default_cb }, 1338 { "FORWARDS", 12, 1339 offsetof(bridge_statfields_buf_t, bridges_forwards), print_default_cb }, 1340 { "MBCAST", 12, 1341 offsetof(bridge_statfields_buf_t, bridges_mbcast), print_default_cb }, 1342 { "UNKNOWN", 12, 1343 offsetof(bridge_statfields_buf_t, bridges_unknown), print_default_cb }, 1344 { "RECV", 12, 1345 offsetof(bridge_statfields_buf_t, bridges_recv), print_default_cb }, 1346 { "SENT", 12, 1347 offsetof(bridge_statfields_buf_t, bridges_sent), print_default_cb }, 1348 { NULL, 0, 0, NULL}}; 1349 1350 /* 1351 * structures for 'dladm show-bridge -s -l'. These are based in part on 1352 * section 14.6.1.1.3 of IEEE 802.1D-2004. 1353 */ 1354 typedef struct bridge_link_statfields_buf_s { 1355 char bridgels_link[MAXLINKNAMELEN]; 1356 char bridgels_cfgbpdu[ULONG_DIG]; 1357 char bridgels_tcnbpdu[ULONG_DIG]; 1358 char bridgels_rstpbpdu[ULONG_DIG]; 1359 char bridgels_txbpdu[ULONG_DIG]; 1360 char bridgels_drops[UINT64_DIG]; /* 14.6.1.1.3(d) */ 1361 char bridgels_recv[UINT64_DIG]; /* 14.6.1.1.3(a) */ 1362 char bridgels_xmit[UINT64_DIG]; /* 14.6.1.1.3(c) */ 1363 } bridge_link_statfields_buf_t; 1364 1365 static ofmt_field_t bridge_link_statfields[] = { 1366 /* name, field width, offset, callback */ 1367 { "LINK", 12, 1368 offsetof(bridge_link_statfields_buf_t, bridgels_link), print_default_cb }, 1369 { "CFGBPDU", 9, 1370 offsetof(bridge_link_statfields_buf_t, bridgels_cfgbpdu), 1371 print_default_cb }, 1372 { "TCNBPDU", 9, 1373 offsetof(bridge_link_statfields_buf_t, bridgels_tcnbpdu), 1374 print_default_cb }, 1375 { "RSTPBPDU", 9, 1376 offsetof(bridge_link_statfields_buf_t, bridgels_rstpbpdu), 1377 print_default_cb }, 1378 { "TXBPDU", 9, 1379 offsetof(bridge_link_statfields_buf_t, bridgels_txbpdu), print_default_cb }, 1380 { "DROPS", 9, 1381 offsetof(bridge_link_statfields_buf_t, bridgels_drops), print_default_cb }, 1382 { "RECV", 9, 1383 offsetof(bridge_link_statfields_buf_t, bridgels_recv), print_default_cb }, 1384 { "XMIT", 9, 1385 offsetof(bridge_link_statfields_buf_t, bridgels_xmit), print_default_cb }, 1386 { NULL, 0, 0, NULL}}; 1387 1388 /* 1389 * structures for 'dladm show-bridge -f'. These are based in part on 1390 * section 14.7.6.3.3 of IEEE 802.1D-2004. 1391 */ 1392 typedef struct bridge_fwd_fields_buf_s { 1393 char bridgef_dest[18]; /* 14.7.6.3.3(a) */ 1394 char bridgef_age[8]; 1395 char bridgef_flags[6]; 1396 char bridgef_output[MAXLINKNAMELEN]; /* 14.7.6.3.3(c) */ 1397 } bridge_fwd_fields_buf_t; 1398 1399 static ofmt_field_t bridge_fwd_fields[] = { 1400 /* name, field width, offset, callback */ 1401 { "DEST", 17, 1402 offsetof(bridge_fwd_fields_buf_t, bridgef_dest), print_default_cb }, 1403 { "AGE", 7, 1404 offsetof(bridge_fwd_fields_buf_t, bridgef_age), print_default_cb }, 1405 { "FLAGS", 6, 1406 offsetof(bridge_fwd_fields_buf_t, bridgef_flags), print_default_cb }, 1407 { "OUTPUT", 12, 1408 offsetof(bridge_fwd_fields_buf_t, bridgef_output), print_default_cb }, 1409 { NULL, 0, 0, NULL}}; 1410 1411 /* 1412 * structures for 'dladm show-bridge -t'. 1413 */ 1414 typedef struct bridge_trill_fields_buf_s { 1415 char bridget_nick[6]; 1416 char bridget_flags[6]; 1417 char bridget_link[MAXLINKNAMELEN]; 1418 char bridget_nexthop[18]; 1419 } bridge_trill_fields_buf_t; 1420 1421 static ofmt_field_t bridge_trill_fields[] = { 1422 /* name, field width, offset, callback */ 1423 { "NICK", 5, 1424 offsetof(bridge_trill_fields_buf_t, bridget_nick), print_default_cb }, 1425 { "FLAGS", 6, 1426 offsetof(bridge_trill_fields_buf_t, bridget_flags), print_default_cb }, 1427 { "LINK", 12, 1428 offsetof(bridge_trill_fields_buf_t, bridget_link), print_default_cb }, 1429 { "NEXTHOP", 17, 1430 offsetof(bridge_trill_fields_buf_t, bridget_nexthop), print_default_cb }, 1431 { NULL, 0, 0, NULL}}; 1432 1433 static char *progname; 1434 static sig_atomic_t signalled; 1435 1436 /* 1437 * Handle to libdladm. Opened in main() before the sub-command 1438 * specific function is called. 1439 */ 1440 static dladm_handle_t handle = NULL; 1441 1442 #define DLADM_ETHERSTUB_NAME "etherstub" 1443 #define DLADM_IS_ETHERSTUB(id) (id == DATALINK_INVALID_LINKID) 1444 1445 static void 1446 usage_text(void) 1447 { 1448 int i; 1449 cmd_t *cmdp; 1450 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ..." 1451 "\n")); 1452 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 1453 cmdp = &cmds[i]; 1454 if (cmdp->c_usage != NULL) 1455 (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage)); 1456 } 1457 } 1458 1459 static void 1460 usage(void) 1461 { 1462 usage_text(); 1463 1464 /* close dladm handle if it was opened */ 1465 if (handle != NULL) 1466 dladm_close(handle); 1467 1468 exit(EXIT_FAILURE); 1469 } 1470 1471 static void 1472 do_help(int argc __unused, char *argv[] __unused, const char *use __unused) 1473 { 1474 usage_text(); 1475 } 1476 1477 int 1478 main(int argc, char *argv[]) 1479 { 1480 int i; 1481 cmd_t *cmdp; 1482 dladm_status_t status; 1483 1484 (void) setlocale(LC_ALL, ""); 1485 #if !defined(TEXT_DOMAIN) 1486 #define TEXT_DOMAIN "SYS_TEST" 1487 #endif 1488 (void) textdomain(TEXT_DOMAIN); 1489 1490 if ((progname = strrchr(argv[0], '/')) == NULL) 1491 progname = argv[0]; 1492 else 1493 progname++; 1494 1495 if (argc < 2) { 1496 argv[1] = "show-link"; 1497 argc = 2; 1498 } 1499 1500 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 1501 cmdp = &cmds[i]; 1502 if (strcmp(argv[1], cmdp->c_name) == 0) { 1503 /* Open the libdladm handle */ 1504 if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) { 1505 die_dlerr(status, 1506 "could not open /dev/dld"); 1507 } 1508 1509 cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage); 1510 1511 dladm_close(handle); 1512 return (EXIT_SUCCESS); 1513 } 1514 } 1515 1516 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 1517 progname, argv[1]); 1518 usage(); 1519 return (EXIT_FAILURE); 1520 } 1521 1522 /*ARGSUSED*/ 1523 static int 1524 show_usage_date(dladm_usage_t *usage, void *arg) 1525 { 1526 show_usage_state_t *state = (show_usage_state_t *)arg; 1527 time_t stime; 1528 char timebuf[20]; 1529 dladm_status_t status; 1530 uint32_t flags; 1531 1532 /* 1533 * Only show usage information for existing links unless '-a' 1534 * is specified. 1535 */ 1536 if (!state->us_showall) { 1537 if ((status = dladm_name2info(handle, usage->du_name, 1538 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1539 return (status); 1540 } 1541 if ((flags & DLADM_OPT_ACTIVE) == 0) 1542 return (DLADM_STATUS_LINKINVAL); 1543 } 1544 1545 stime = usage->du_stime; 1546 (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y", 1547 localtime(&stime)); 1548 (void) printf("%s\n", timebuf); 1549 1550 return (DLADM_STATUS_OK); 1551 } 1552 1553 static int 1554 show_usage_time(dladm_usage_t *usage, void *arg) 1555 { 1556 show_usage_state_t *state = (show_usage_state_t *)arg; 1557 char buf[DLADM_STRSIZE]; 1558 usage_l_fields_buf_t ubuf; 1559 time_t time; 1560 double bw; 1561 dladm_status_t status; 1562 uint32_t flags; 1563 1564 /* 1565 * Only show usage information for existing links unless '-a' 1566 * is specified. 1567 */ 1568 if (!state->us_showall) { 1569 if ((status = dladm_name2info(handle, usage->du_name, 1570 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1571 return (status); 1572 } 1573 if ((flags & DLADM_OPT_ACTIVE) == 0) 1574 return (DLADM_STATUS_LINKINVAL); 1575 } 1576 1577 if (state->us_plot) { 1578 if (!state->us_printheader) { 1579 if (state->us_first) { 1580 (void) printf("# Time"); 1581 state->us_first = B_FALSE; 1582 } 1583 (void) printf(" %s", usage->du_name); 1584 if (usage->du_last) { 1585 (void) printf("\n"); 1586 state->us_first = B_TRUE; 1587 state->us_printheader = B_TRUE; 1588 } 1589 } else { 1590 if (state->us_first) { 1591 time = usage->du_etime; 1592 (void) strftime(buf, sizeof (buf), "%T", 1593 localtime(&time)); 1594 state->us_first = B_FALSE; 1595 (void) printf("%s", buf); 1596 } 1597 bw = (double)usage->du_bandwidth/1000; 1598 (void) printf(" %.2f", bw); 1599 if (usage->du_last) { 1600 (void) printf("\n"); 1601 state->us_first = B_TRUE; 1602 } 1603 } 1604 return (DLADM_STATUS_OK); 1605 } 1606 1607 bzero(&ubuf, sizeof (ubuf)); 1608 1609 (void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s", 1610 usage->du_name); 1611 time = usage->du_stime; 1612 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1613 (void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s", 1614 buf); 1615 time = usage->du_etime; 1616 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1617 (void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s", 1618 buf); 1619 (void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes), 1620 "%llu", usage->du_rbytes); 1621 (void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes), 1622 "%llu", usage->du_obytes); 1623 (void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth), 1624 "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1625 1626 ofmt_print(state->us_ofmt, &ubuf); 1627 return (DLADM_STATUS_OK); 1628 } 1629 1630 static int 1631 show_usage_res(dladm_usage_t *usage, void *arg) 1632 { 1633 show_usage_state_t *state = (show_usage_state_t *)arg; 1634 char buf[DLADM_STRSIZE]; 1635 usage_fields_buf_t ubuf; 1636 dladm_status_t status; 1637 uint32_t flags; 1638 1639 /* 1640 * Only show usage information for existing links unless '-a' 1641 * is specified. 1642 */ 1643 if (!state->us_showall) { 1644 if ((status = dladm_name2info(handle, usage->du_name, 1645 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1646 return (status); 1647 } 1648 if ((flags & DLADM_OPT_ACTIVE) == 0) 1649 return (DLADM_STATUS_LINKINVAL); 1650 } 1651 1652 bzero(&ubuf, sizeof (ubuf)); 1653 1654 (void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s", 1655 usage->du_name); 1656 (void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration), 1657 "%llu", usage->du_duration); 1658 (void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets), 1659 "%llu", usage->du_ipackets); 1660 (void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes), 1661 "%llu", usage->du_rbytes); 1662 (void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets), 1663 "%llu", usage->du_opackets); 1664 (void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes), 1665 "%llu", usage->du_obytes); 1666 (void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth), 1667 "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1668 1669 ofmt_print(state->us_ofmt, &ubuf); 1670 1671 return (DLADM_STATUS_OK); 1672 } 1673 1674 static boolean_t 1675 valid_formatspec(char *formatspec_str) 1676 { 1677 if (strcmp(formatspec_str, "gnuplot") == 0) 1678 return (B_TRUE); 1679 return (B_FALSE); 1680 1681 } 1682 1683 /*ARGSUSED*/ 1684 static void 1685 do_show_usage(int argc, char *argv[], const char *use) 1686 { 1687 char *file = NULL; 1688 int opt; 1689 dladm_status_t status; 1690 boolean_t d_arg = B_FALSE; 1691 char *stime = NULL; 1692 char *etime = NULL; 1693 char *resource = NULL; 1694 show_usage_state_t state; 1695 boolean_t o_arg = B_FALSE; 1696 boolean_t F_arg = B_FALSE; 1697 char *fields_str = NULL; 1698 char *formatspec_str = NULL; 1699 char *all_l_fields = 1700 "link,start,end,rbytes,obytes,bandwidth"; 1701 ofmt_handle_t ofmt; 1702 ofmt_status_t oferr; 1703 uint_t ofmtflags = 0; 1704 1705 bzero(&state, sizeof (show_usage_state_t)); 1706 state.us_parsable = B_FALSE; 1707 state.us_printheader = B_FALSE; 1708 state.us_plot = B_FALSE; 1709 state.us_first = B_TRUE; 1710 1711 while ((opt = getopt_long(argc, argv, "das:e:o:f:F:", 1712 usage_opts, NULL)) != -1) { 1713 switch (opt) { 1714 case 'd': 1715 d_arg = B_TRUE; 1716 break; 1717 case 'a': 1718 state.us_showall = B_TRUE; 1719 break; 1720 case 'f': 1721 file = optarg; 1722 break; 1723 case 's': 1724 stime = optarg; 1725 break; 1726 case 'e': 1727 etime = optarg; 1728 break; 1729 case 'o': 1730 o_arg = B_TRUE; 1731 fields_str = optarg; 1732 break; 1733 case 'F': 1734 state.us_plot = F_arg = B_TRUE; 1735 formatspec_str = optarg; 1736 break; 1737 default: 1738 die_opterr(optopt, opt, use); 1739 break; 1740 } 1741 } 1742 1743 if (file == NULL) 1744 die("show-usage requires a file"); 1745 1746 if (optind == (argc-1)) { 1747 uint32_t flags; 1748 1749 resource = argv[optind]; 1750 if (!state.us_showall && 1751 (((status = dladm_name2info(handle, resource, NULL, &flags, 1752 NULL, NULL)) != DLADM_STATUS_OK) || 1753 ((flags & DLADM_OPT_ACTIVE) == 0))) { 1754 die("invalid link: '%s'", resource); 1755 } 1756 } 1757 1758 if (F_arg && d_arg) 1759 die("incompatible -d and -F options"); 1760 1761 if (F_arg && valid_formatspec(formatspec_str) == B_FALSE) 1762 die("Format specifier %s not supported", formatspec_str); 1763 1764 if (state.us_parsable) 1765 ofmtflags |= OFMT_PARSABLE; 1766 1767 if (resource == NULL && stime == NULL && etime == NULL) { 1768 oferr = ofmt_open(fields_str, usage_fields, ofmtflags, 0, 1769 &ofmt); 1770 } else { 1771 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 1772 fields_str = all_l_fields; 1773 oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags, 0, 1774 &ofmt); 1775 1776 } 1777 ofmt_check(oferr, state.us_parsable, ofmt, die, warn); 1778 state.us_ofmt = ofmt; 1779 1780 if (d_arg) { 1781 /* Print log dates */ 1782 status = dladm_usage_dates(show_usage_date, 1783 DLADM_LOGTYPE_LINK, file, resource, &state); 1784 } else if (resource == NULL && stime == NULL && etime == NULL && 1785 !F_arg) { 1786 /* Print summary */ 1787 status = dladm_usage_summary(show_usage_res, 1788 DLADM_LOGTYPE_LINK, file, &state); 1789 } else if (resource != NULL) { 1790 /* Print log entries for named resource */ 1791 status = dladm_walk_usage_res(show_usage_time, 1792 DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state); 1793 } else { 1794 /* Print time and information for each link */ 1795 status = dladm_walk_usage_time(show_usage_time, 1796 DLADM_LOGTYPE_LINK, file, stime, etime, &state); 1797 } 1798 1799 if (status != DLADM_STATUS_OK) 1800 die_dlerr(status, "show-usage"); 1801 ofmt_close(ofmt); 1802 } 1803 1804 static void 1805 do_create_aggr(int argc, char *argv[], const char *use) 1806 { 1807 int option; 1808 int key = 0; 1809 uint32_t policy = AGGR_POLICY_L4; 1810 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 1811 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 1812 dladm_aggr_port_attr_db_t port[MAXPORT]; 1813 uint_t n, ndev, nlink; 1814 uint8_t mac_addr[ETHERADDRL]; 1815 boolean_t mac_addr_fixed = B_FALSE; 1816 boolean_t P_arg = B_FALSE; 1817 boolean_t l_arg = B_FALSE; 1818 boolean_t u_arg = B_FALSE; 1819 boolean_t T_arg = B_FALSE; 1820 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1821 char *altroot = NULL; 1822 char name[MAXLINKNAMELEN]; 1823 char *devs[MAXPORT]; 1824 char *links[MAXPORT]; 1825 dladm_status_t status; 1826 dladm_status_t pstatus; 1827 char propstr[DLADM_STRSIZE]; 1828 dladm_arg_list_t *proplist = NULL; 1829 int i; 1830 datalink_id_t linkid; 1831 1832 ndev = nlink = opterr = 0; 1833 bzero(propstr, DLADM_STRSIZE); 1834 1835 while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:", 1836 lopts, NULL)) != -1) { 1837 switch (option) { 1838 case 'd': 1839 if (ndev + nlink >= MAXPORT) 1840 die("too many ports specified"); 1841 1842 devs[ndev++] = optarg; 1843 break; 1844 case 'P': 1845 if (P_arg) 1846 die_optdup(option); 1847 1848 P_arg = B_TRUE; 1849 if (!dladm_aggr_str2policy(optarg, &policy)) 1850 die("invalid policy '%s'", optarg); 1851 break; 1852 case 'u': 1853 if (u_arg) 1854 die_optdup(option); 1855 1856 u_arg = B_TRUE; 1857 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 1858 mac_addr)) 1859 die("invalid MAC address '%s'", optarg); 1860 break; 1861 case 'l': 1862 if (isdigit(optarg[strlen(optarg) - 1])) { 1863 1864 /* 1865 * Ended with digit, possibly a link name. 1866 */ 1867 if (ndev + nlink >= MAXPORT) 1868 die("too many ports specified"); 1869 1870 links[nlink++] = optarg; 1871 break; 1872 } 1873 /* FALLTHROUGH */ 1874 case 'L': 1875 if (l_arg) 1876 die_optdup(option); 1877 1878 l_arg = B_TRUE; 1879 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 1880 die("invalid LACP mode '%s'", optarg); 1881 break; 1882 case 'T': 1883 if (T_arg) 1884 die_optdup(option); 1885 1886 T_arg = B_TRUE; 1887 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 1888 die("invalid LACP timer value '%s'", optarg); 1889 break; 1890 case 't': 1891 flags &= ~DLADM_OPT_PERSIST; 1892 break; 1893 case 'f': 1894 flags |= DLADM_OPT_FORCE; 1895 break; 1896 case 'R': 1897 altroot = optarg; 1898 break; 1899 case 'p': 1900 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 1901 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 1902 DLADM_STRSIZE) 1903 die("property list too long '%s'", propstr); 1904 break; 1905 1906 default: 1907 die_opterr(optopt, option, use); 1908 break; 1909 } 1910 } 1911 1912 if (ndev + nlink == 0) 1913 usage(); 1914 1915 /* get key value or the aggregation name (required last argument) */ 1916 if (optind != (argc-1)) 1917 usage(); 1918 1919 if (!str2int(argv[optind], &key)) { 1920 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= 1921 MAXLINKNAMELEN) { 1922 die("link name too long '%s'", argv[optind]); 1923 } 1924 1925 if (!dladm_valid_linkname(name)) 1926 die("invalid link name '%s'", argv[optind]); 1927 } else { 1928 (void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key); 1929 } 1930 1931 if (altroot != NULL) 1932 altroot_cmd(altroot, argc, argv); 1933 1934 for (n = 0; n < ndev; n++) { 1935 if ((status = dladm_dev2linkid(handle, devs[n], 1936 &port[n].lp_linkid)) != DLADM_STATUS_OK) { 1937 die_dlerr(status, "invalid dev name '%s'", devs[n]); 1938 } 1939 } 1940 1941 for (n = 0; n < nlink; n++) { 1942 if ((status = dladm_name2info(handle, links[n], 1943 &port[ndev + n].lp_linkid, NULL, NULL, NULL)) != 1944 DLADM_STATUS_OK) { 1945 die_dlerr(status, "invalid link name '%s'", links[n]); 1946 } 1947 } 1948 1949 status = dladm_aggr_create(handle, name, key, ndev + nlink, port, 1950 policy, mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, 1951 lacp_timer, flags); 1952 if (status != DLADM_STATUS_OK) 1953 goto done; 1954 1955 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 1956 != DLADM_STATUS_OK) 1957 die("invalid aggregation property"); 1958 1959 if (proplist == NULL) 1960 return; 1961 1962 status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL); 1963 if (status != DLADM_STATUS_OK) 1964 goto done; 1965 1966 for (i = 0; i < proplist->al_count; i++) { 1967 dladm_arg_info_t *aip = &proplist->al_info[i]; 1968 1969 pstatus = dladm_set_linkprop(handle, linkid, aip->ai_name, 1970 aip->ai_val, aip->ai_count, flags); 1971 1972 if (pstatus != DLADM_STATUS_OK) { 1973 die_dlerr(pstatus, 1974 "aggr creation succeeded but " 1975 "could not set property '%s'", aip->ai_name); 1976 } 1977 } 1978 done: 1979 dladm_free_props(proplist); 1980 if (status != DLADM_STATUS_OK) { 1981 if (status == DLADM_STATUS_NONOTIF) { 1982 die("not all links have link up/down detection; must " 1983 "use -f (see dladm(1M))"); 1984 } else { 1985 die_dlerr(status, "create operation failed"); 1986 } 1987 } 1988 } 1989 1990 /* 1991 * arg is either the key or the aggr name. Validate it and convert it to 1992 * the linkid if altroot is NULL. 1993 */ 1994 static dladm_status_t 1995 i_dladm_aggr_get_linkid(const char *altroot, const char *arg, 1996 datalink_id_t *linkidp, uint32_t flags) 1997 { 1998 int key = 0; 1999 char *aggr = NULL; 2000 dladm_status_t status; 2001 2002 if (!str2int(arg, &key)) 2003 aggr = (char *)arg; 2004 2005 if (aggr == NULL && key == 0) 2006 return (DLADM_STATUS_LINKINVAL); 2007 2008 if (altroot != NULL) 2009 return (DLADM_STATUS_OK); 2010 2011 if (aggr != NULL) { 2012 status = dladm_name2info(handle, aggr, linkidp, NULL, NULL, 2013 NULL); 2014 } else { 2015 status = dladm_key2linkid(handle, key, linkidp, flags); 2016 } 2017 2018 return (status); 2019 } 2020 2021 static void 2022 do_delete_aggr(int argc, char *argv[], const char *use) 2023 { 2024 int option; 2025 char *altroot = NULL; 2026 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 2027 dladm_status_t status; 2028 datalink_id_t linkid; 2029 2030 opterr = 0; 2031 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 2032 switch (option) { 2033 case 't': 2034 flags &= ~DLADM_OPT_PERSIST; 2035 break; 2036 case 'R': 2037 altroot = optarg; 2038 break; 2039 default: 2040 die_opterr(optopt, option, use); 2041 break; 2042 } 2043 } 2044 2045 /* get key value or the aggregation name (required last argument) */ 2046 if (optind != (argc-1)) 2047 usage(); 2048 2049 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 2050 if (status != DLADM_STATUS_OK) 2051 goto done; 2052 2053 if (altroot != NULL) 2054 altroot_cmd(altroot, argc, argv); 2055 2056 status = dladm_aggr_delete(handle, linkid, flags); 2057 done: 2058 if (status != DLADM_STATUS_OK) 2059 die_dlerr(status, "delete operation failed"); 2060 } 2061 2062 static void 2063 do_add_aggr(int argc, char *argv[], const char *use) 2064 { 2065 int option; 2066 uint_t n, ndev, nlink; 2067 char *altroot = NULL; 2068 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 2069 datalink_id_t linkid; 2070 dladm_status_t status; 2071 dladm_aggr_port_attr_db_t port[MAXPORT]; 2072 char *devs[MAXPORT]; 2073 char *links[MAXPORT]; 2074 2075 ndev = nlink = opterr = 0; 2076 while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts, 2077 NULL)) != -1) { 2078 switch (option) { 2079 case 'd': 2080 if (ndev + nlink >= MAXPORT) 2081 die("too many ports specified"); 2082 2083 devs[ndev++] = optarg; 2084 break; 2085 case 'l': 2086 if (ndev + nlink >= MAXPORT) 2087 die("too many ports specified"); 2088 2089 links[nlink++] = optarg; 2090 break; 2091 case 't': 2092 flags &= ~DLADM_OPT_PERSIST; 2093 break; 2094 case 'f': 2095 flags |= DLADM_OPT_FORCE; 2096 break; 2097 case 'R': 2098 altroot = optarg; 2099 break; 2100 default: 2101 die_opterr(optopt, option, use); 2102 break; 2103 } 2104 } 2105 2106 if (ndev + nlink == 0) 2107 usage(); 2108 2109 /* get key value or the aggregation name (required last argument) */ 2110 if (optind != (argc-1)) 2111 usage(); 2112 2113 if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, 2114 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) != 2115 DLADM_STATUS_OK) { 2116 goto done; 2117 } 2118 2119 if (altroot != NULL) 2120 altroot_cmd(altroot, argc, argv); 2121 2122 for (n = 0; n < ndev; n++) { 2123 if ((status = dladm_dev2linkid(handle, devs[n], 2124 &(port[n].lp_linkid))) != DLADM_STATUS_OK) { 2125 die_dlerr(status, "invalid <dev> '%s'", devs[n]); 2126 } 2127 } 2128 2129 for (n = 0; n < nlink; n++) { 2130 if ((status = dladm_name2info(handle, links[n], 2131 &port[n + ndev].lp_linkid, NULL, NULL, NULL)) != 2132 DLADM_STATUS_OK) { 2133 die_dlerr(status, "invalid <link> '%s'", links[n]); 2134 } 2135 } 2136 2137 status = dladm_aggr_add(handle, linkid, ndev + nlink, port, flags); 2138 done: 2139 if (status != DLADM_STATUS_OK) { 2140 /* 2141 * checking DLADM_STATUS_NOTSUP is a temporary workaround 2142 * and should be removed once 6399681 is fixed. 2143 */ 2144 if (status == DLADM_STATUS_NOTSUP) { 2145 die("add operation failed: link capabilities don't " 2146 "match"); 2147 } else if (status == DLADM_STATUS_NONOTIF) { 2148 die("not all links have link up/down detection; must " 2149 "use -f (see dladm(1M))"); 2150 } else { 2151 die_dlerr(status, "add operation failed"); 2152 } 2153 } 2154 } 2155 2156 static void 2157 do_remove_aggr(int argc, char *argv[], const char *use) 2158 { 2159 int option; 2160 dladm_aggr_port_attr_db_t port[MAXPORT]; 2161 uint_t n, ndev, nlink; 2162 char *devs[MAXPORT]; 2163 char *links[MAXPORT]; 2164 char *altroot = NULL; 2165 uint32_t flags; 2166 datalink_id_t linkid; 2167 dladm_status_t status; 2168 2169 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 2170 ndev = nlink = opterr = 0; 2171 while ((option = getopt_long(argc, argv, ":d:l:R:t", 2172 lopts, NULL)) != -1) { 2173 switch (option) { 2174 case 'd': 2175 if (ndev + nlink >= MAXPORT) 2176 die("too many ports specified"); 2177 2178 devs[ndev++] = optarg; 2179 break; 2180 case 'l': 2181 if (ndev + nlink >= MAXPORT) 2182 die("too many ports specified"); 2183 2184 links[nlink++] = optarg; 2185 break; 2186 case 't': 2187 flags &= ~DLADM_OPT_PERSIST; 2188 break; 2189 case 'R': 2190 altroot = optarg; 2191 break; 2192 default: 2193 die_opterr(optopt, option, use); 2194 break; 2195 } 2196 } 2197 2198 if (ndev + nlink == 0) 2199 usage(); 2200 2201 /* get key value or the aggregation name (required last argument) */ 2202 if (optind != (argc-1)) 2203 usage(); 2204 2205 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 2206 if (status != DLADM_STATUS_OK) 2207 goto done; 2208 2209 if (altroot != NULL) 2210 altroot_cmd(altroot, argc, argv); 2211 2212 for (n = 0; n < ndev; n++) { 2213 if ((status = dladm_dev2linkid(handle, devs[n], 2214 &(port[n].lp_linkid))) != DLADM_STATUS_OK) { 2215 die_dlerr(status, "invalid <dev> '%s'", devs[n]); 2216 } 2217 } 2218 2219 for (n = 0; n < nlink; n++) { 2220 if ((status = dladm_name2info(handle, links[n], 2221 &port[n + ndev].lp_linkid, NULL, NULL, NULL)) != 2222 DLADM_STATUS_OK) { 2223 die_dlerr(status, "invalid <link> '%s'", links[n]); 2224 } 2225 } 2226 2227 status = dladm_aggr_remove(handle, linkid, ndev + nlink, port, flags); 2228 done: 2229 if (status != DLADM_STATUS_OK) 2230 die_dlerr(status, "remove operation failed"); 2231 } 2232 2233 static void 2234 do_modify_aggr(int argc, char *argv[], const char *use) 2235 { 2236 int option; 2237 uint32_t policy = AGGR_POLICY_L4; 2238 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 2239 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 2240 uint8_t mac_addr[ETHERADDRL]; 2241 boolean_t mac_addr_fixed = B_FALSE; 2242 uint8_t modify_mask = 0; 2243 char *altroot = NULL; 2244 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 2245 datalink_id_t linkid; 2246 dladm_status_t status; 2247 2248 opterr = 0; 2249 while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts, 2250 NULL)) != -1) { 2251 switch (option) { 2252 case 'P': 2253 if (modify_mask & DLADM_AGGR_MODIFY_POLICY) 2254 die_optdup(option); 2255 2256 modify_mask |= DLADM_AGGR_MODIFY_POLICY; 2257 2258 if (!dladm_aggr_str2policy(optarg, &policy)) 2259 die("invalid policy '%s'", optarg); 2260 break; 2261 case 'u': 2262 if (modify_mask & DLADM_AGGR_MODIFY_MAC) 2263 die_optdup(option); 2264 2265 modify_mask |= DLADM_AGGR_MODIFY_MAC; 2266 2267 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 2268 mac_addr)) 2269 die("invalid MAC address '%s'", optarg); 2270 break; 2271 case 'l': 2272 case 'L': 2273 if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE) 2274 die_optdup(option); 2275 2276 modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE; 2277 2278 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 2279 die("invalid LACP mode '%s'", optarg); 2280 break; 2281 case 'T': 2282 if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER) 2283 die_optdup(option); 2284 2285 modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER; 2286 2287 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 2288 die("invalid LACP timer value '%s'", optarg); 2289 break; 2290 case 't': 2291 flags &= ~DLADM_OPT_PERSIST; 2292 break; 2293 case 'R': 2294 altroot = optarg; 2295 break; 2296 default: 2297 die_opterr(optopt, option, use); 2298 break; 2299 } 2300 } 2301 2302 if (modify_mask == 0) 2303 die("at least one of the -PulT options must be specified"); 2304 2305 /* get key value or the aggregation name (required last argument) */ 2306 if (optind != (argc-1)) 2307 usage(); 2308 2309 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 2310 if (status != DLADM_STATUS_OK) 2311 goto done; 2312 2313 if (altroot != NULL) 2314 altroot_cmd(altroot, argc, argv); 2315 2316 status = dladm_aggr_modify(handle, linkid, modify_mask, policy, 2317 mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, lacp_timer, 2318 flags); 2319 2320 done: 2321 if (status != DLADM_STATUS_OK) 2322 die_dlerr(status, "modify operation failed"); 2323 } 2324 2325 /*ARGSUSED*/ 2326 static void 2327 do_up_aggr(int argc, char *argv[], const char *use) 2328 { 2329 datalink_id_t linkid = DATALINK_ALL_LINKID; 2330 dladm_status_t status; 2331 2332 /* 2333 * get the key or the name of the aggregation (optional last argument) 2334 */ 2335 if (argc == 2) { 2336 if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid, 2337 DLADM_OPT_PERSIST)) != DLADM_STATUS_OK) 2338 goto done; 2339 } else if (argc > 2) { 2340 usage(); 2341 } 2342 2343 status = dladm_aggr_up(handle, linkid); 2344 done: 2345 if (status != DLADM_STATUS_OK) { 2346 if (argc == 2) { 2347 die_dlerr(status, 2348 "could not bring up aggregation '%s'", argv[1]); 2349 } else { 2350 die_dlerr(status, "could not bring aggregations up"); 2351 } 2352 } 2353 } 2354 2355 static void 2356 do_create_vlan(int argc, char *argv[], const char *use) 2357 { 2358 char *link = NULL; 2359 char drv[DLPI_LINKNAME_MAX]; 2360 uint_t ppa; 2361 datalink_id_t linkid; 2362 datalink_id_t dev_linkid; 2363 int vid = 0; 2364 int option; 2365 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2366 char *altroot = NULL; 2367 char vlan[MAXLINKNAMELEN]; 2368 char propstr[DLADM_STRSIZE]; 2369 dladm_arg_list_t *proplist = NULL; 2370 dladm_status_t status; 2371 2372 opterr = 0; 2373 bzero(propstr, DLADM_STRSIZE); 2374 2375 while ((option = getopt_long(argc, argv, ":tfR:l:v:p:", 2376 lopts, NULL)) != -1) { 2377 switch (option) { 2378 case 'v': 2379 if (vid != 0) 2380 die_optdup(option); 2381 2382 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 2383 die("invalid VLAN identifier '%s'", optarg); 2384 2385 break; 2386 case 'l': 2387 if (link != NULL) 2388 die_optdup(option); 2389 2390 link = optarg; 2391 break; 2392 case 't': 2393 flags &= ~DLADM_OPT_PERSIST; 2394 break; 2395 case 'R': 2396 altroot = optarg; 2397 break; 2398 case 'p': 2399 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 2400 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 2401 DLADM_STRSIZE) 2402 die("property list too long '%s'", propstr); 2403 break; 2404 case 'f': 2405 flags |= DLADM_OPT_FORCE; 2406 break; 2407 default: 2408 die_opterr(optopt, option, use); 2409 break; 2410 } 2411 } 2412 2413 /* get vlan name if there is any */ 2414 if ((vid == 0) || (link == NULL) || (argc - optind > 1)) 2415 usage(); 2416 2417 if (optind == (argc - 1)) { 2418 if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >= 2419 MAXLINKNAMELEN) { 2420 die("vlan name too long '%s'", argv[optind]); 2421 } 2422 } else { 2423 if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) || 2424 (ppa >= 1000) || 2425 (dlpi_makelink(vlan, drv, vid * 1000 + ppa) != 2426 DLPI_SUCCESS)) { 2427 die("invalid link name '%s'", link); 2428 } 2429 } 2430 2431 if (altroot != NULL) 2432 altroot_cmd(altroot, argc, argv); 2433 2434 if (dladm_name2info(handle, link, &dev_linkid, NULL, NULL, NULL) != 2435 DLADM_STATUS_OK) { 2436 die("invalid link name '%s'", link); 2437 } 2438 2439 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 2440 != DLADM_STATUS_OK) 2441 die("invalid vlan property"); 2442 2443 status = dladm_vlan_create(handle, vlan, dev_linkid, vid, proplist, 2444 flags, &linkid); 2445 switch (status) { 2446 case DLADM_STATUS_OK: 2447 break; 2448 2449 case DLADM_STATUS_NOTSUP: 2450 die("VLAN over '%s' may require lowered MTU; must use -f (see " 2451 "dladm(1M))", link); 2452 break; 2453 2454 case DLADM_STATUS_LINKBUSY: 2455 die("VLAN over '%s' may not use default_tag ID " 2456 "(see dladm(1M))", link); 2457 break; 2458 2459 default: 2460 die_dlerr(status, "create operation failed"); 2461 } 2462 } 2463 2464 static void 2465 do_delete_vlan(int argc, char *argv[], const char *use) 2466 { 2467 int option; 2468 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2469 char *altroot = NULL; 2470 datalink_id_t linkid; 2471 dladm_status_t status; 2472 2473 opterr = 0; 2474 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 2475 switch (option) { 2476 case 't': 2477 flags &= ~DLADM_OPT_PERSIST; 2478 break; 2479 case 'R': 2480 altroot = optarg; 2481 break; 2482 default: 2483 die_opterr(optopt, option, use); 2484 break; 2485 } 2486 } 2487 2488 /* get VLAN link name (required last argument) */ 2489 if (optind != (argc - 1)) 2490 usage(); 2491 2492 if (altroot != NULL) 2493 altroot_cmd(altroot, argc, argv); 2494 2495 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 2496 NULL); 2497 if (status != DLADM_STATUS_OK) 2498 goto done; 2499 2500 status = dladm_vlan_delete(handle, linkid, flags); 2501 done: 2502 if (status != DLADM_STATUS_OK) 2503 die_dlerr(status, "delete operation failed"); 2504 } 2505 2506 /*ARGSUSED*/ 2507 static void 2508 do_up_vlan(int argc, char *argv[], const char *use) 2509 { 2510 do_up_vnic_common(argc, argv, use, B_TRUE); 2511 } 2512 2513 static void 2514 do_rename_link(int argc, char *argv[], const char *use) 2515 { 2516 int option; 2517 char *link1, *link2; 2518 char *altroot = NULL; 2519 dladm_status_t status; 2520 2521 opterr = 0; 2522 while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) { 2523 switch (option) { 2524 case 'R': 2525 altroot = optarg; 2526 break; 2527 default: 2528 die_opterr(optopt, option, use); 2529 break; 2530 } 2531 } 2532 2533 /* get link1 and link2 name (required the last 2 arguments) */ 2534 if (optind != (argc - 2)) 2535 usage(); 2536 2537 if (altroot != NULL) 2538 altroot_cmd(altroot, argc, argv); 2539 2540 link1 = argv[optind++]; 2541 link2 = argv[optind]; 2542 if ((status = dladm_rename_link(handle, link1, link2)) != 2543 DLADM_STATUS_OK) 2544 die_dlerr(status, "rename operation failed"); 2545 } 2546 2547 /*ARGSUSED*/ 2548 static void 2549 do_delete_phys(int argc, char *argv[], const char *use) 2550 { 2551 datalink_id_t linkid = DATALINK_ALL_LINKID; 2552 dladm_status_t status; 2553 2554 /* get link name (required the last argument) */ 2555 if (argc > 2) 2556 usage(); 2557 2558 if (argc == 2) { 2559 if ((status = dladm_name2info(handle, argv[1], &linkid, NULL, 2560 NULL, NULL)) != DLADM_STATUS_OK) 2561 die_dlerr(status, "cannot delete '%s'", argv[1]); 2562 } 2563 2564 if ((status = dladm_phys_delete(handle, linkid)) != DLADM_STATUS_OK) { 2565 if (argc == 2) 2566 die_dlerr(status, "cannot delete '%s'", argv[1]); 2567 else 2568 die_dlerr(status, "delete operation failed"); 2569 } 2570 } 2571 2572 /*ARGSUSED*/ 2573 static int 2574 i_dladm_walk_linkmap(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2575 { 2576 char name[MAXLINKNAMELEN]; 2577 char mediabuf[DLADM_STRSIZE]; 2578 char classbuf[DLADM_STRSIZE]; 2579 datalink_class_t class; 2580 uint32_t media; 2581 uint32_t flags; 2582 2583 if (dladm_datalink_id2info(dh, linkid, &flags, &class, &media, name, 2584 MAXLINKNAMELEN) == DLADM_STATUS_OK) { 2585 (void) dladm_class2str(class, classbuf); 2586 (void) dladm_media2str(media, mediabuf); 2587 (void) printf("%-12s%8d %-12s%-20s %6d\n", name, 2588 linkid, classbuf, mediabuf, flags); 2589 } 2590 return (DLADM_WALK_CONTINUE); 2591 } 2592 2593 /*ARGSUSED*/ 2594 static void 2595 do_show_linkmap(int argc, char *argv[], const char *use) 2596 { 2597 if (argc != 1) 2598 die("invalid arguments"); 2599 2600 (void) printf("%-12s%8s %-12s%-20s %6s\n", "NAME", "LINKID", 2601 "CLASS", "MEDIA", "FLAGS"); 2602 2603 (void) dladm_walk_datalink_id(i_dladm_walk_linkmap, handle, NULL, 2604 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 2605 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2606 } 2607 2608 /* 2609 * Delete inactive physical links. 2610 */ 2611 /*ARGSUSED*/ 2612 static int 2613 purge_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2614 { 2615 datalink_class_t class; 2616 uint32_t flags; 2617 2618 if (dladm_datalink_id2info(dh, linkid, &flags, &class, NULL, NULL, 0) 2619 != DLADM_STATUS_OK) { 2620 return (DLADM_WALK_CONTINUE); 2621 } 2622 2623 if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE)) 2624 (void) dladm_phys_delete(dh, linkid); 2625 2626 return (DLADM_WALK_CONTINUE); 2627 } 2628 2629 /*ARGSUSED*/ 2630 static void 2631 do_init_phys(int argc, char *argv[], const char *use) 2632 { 2633 di_node_t devtree; 2634 2635 if (argc > 1) 2636 usage(); 2637 2638 /* 2639 * Force all the devices to attach, therefore all the network physical 2640 * devices can be known to the dlmgmtd daemon. 2641 */ 2642 if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL) 2643 di_fini(devtree); 2644 2645 (void) dladm_walk_datalink_id(purge_phys, handle, NULL, 2646 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 2647 } 2648 2649 /* 2650 * Print the active topology information. 2651 */ 2652 void 2653 print_link_topology(show_state_t *state, datalink_id_t linkid, 2654 datalink_class_t class, link_fields_buf_t *lbuf) 2655 { 2656 uint32_t flags = state->ls_flags; 2657 dladm_status_t status; 2658 char tmpbuf[MAXLINKNAMELEN]; 2659 2660 lbuf->link_over[0] = '\0'; 2661 lbuf->link_bridge[0] = '\0'; 2662 2663 switch (class) { 2664 case DATALINK_CLASS_AGGR: 2665 case DATALINK_CLASS_PHYS: 2666 case DATALINK_CLASS_ETHERSTUB: 2667 status = dladm_bridge_getlink(handle, linkid, lbuf->link_bridge, 2668 sizeof (lbuf->link_bridge)); 2669 if (status != DLADM_STATUS_OK && 2670 status != DLADM_STATUS_NOTFOUND) 2671 (void) strcpy(lbuf->link_bridge, "?"); 2672 break; 2673 } 2674 2675 switch (class) { 2676 case DATALINK_CLASS_VLAN: { 2677 dladm_vlan_attr_t vinfo; 2678 2679 if (dladm_vlan_info(handle, linkid, &vinfo, flags) != 2680 DLADM_STATUS_OK) { 2681 (void) strcpy(lbuf->link_over, "?"); 2682 break; 2683 } 2684 if (dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, NULL, 2685 NULL, lbuf->link_over, sizeof (lbuf->link_over)) != 2686 DLADM_STATUS_OK) 2687 (void) strcpy(lbuf->link_over, "?"); 2688 break; 2689 } 2690 case DATALINK_CLASS_AGGR: { 2691 dladm_aggr_grp_attr_t ginfo; 2692 int i; 2693 2694 if (dladm_aggr_info(handle, linkid, &ginfo, flags) != 2695 DLADM_STATUS_OK || ginfo.lg_nports == 0) { 2696 (void) strcpy(lbuf->link_over, "?"); 2697 break; 2698 } 2699 for (i = 0; i < ginfo.lg_nports; i++) { 2700 if (dladm_datalink_id2info(handle, 2701 ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, 2702 tmpbuf, sizeof (tmpbuf)) != DLADM_STATUS_OK) { 2703 (void) strcpy(lbuf->link_over, "?"); 2704 break; 2705 } 2706 (void) strlcat(lbuf->link_over, tmpbuf, 2707 sizeof (lbuf->link_over)); 2708 if (i != (ginfo.lg_nports - 1)) { 2709 (void) strlcat(lbuf->link_over, ",", 2710 sizeof (lbuf->link_over)); 2711 } 2712 } 2713 free(ginfo.lg_ports); 2714 break; 2715 } 2716 case DATALINK_CLASS_VNIC: { 2717 dladm_vnic_attr_t vinfo; 2718 2719 if (dladm_vnic_info(handle, linkid, &vinfo, flags) != 2720 DLADM_STATUS_OK) { 2721 (void) strcpy(lbuf->link_over, "?"); 2722 break; 2723 } 2724 if (dladm_datalink_id2info(handle, vinfo.va_link_id, NULL, NULL, 2725 NULL, lbuf->link_over, sizeof (lbuf->link_over)) != 2726 DLADM_STATUS_OK) 2727 (void) strcpy(lbuf->link_over, "?"); 2728 break; 2729 } 2730 2731 case DATALINK_CLASS_PART: { 2732 dladm_part_attr_t pinfo; 2733 2734 if (dladm_part_info(handle, linkid, &pinfo, flags) != 2735 DLADM_STATUS_OK) { 2736 (void) strcpy(lbuf->link_over, "?"); 2737 break; 2738 } 2739 if (dladm_datalink_id2info(handle, pinfo.dia_physlinkid, NULL, 2740 NULL, NULL, lbuf->link_over, sizeof (lbuf->link_over)) != 2741 DLADM_STATUS_OK) 2742 (void) strcpy(lbuf->link_over, "?"); 2743 break; 2744 } 2745 2746 case DATALINK_CLASS_BRIDGE: { 2747 datalink_id_t *dlp; 2748 uint_t i, nports; 2749 2750 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, 2751 NULL, tmpbuf, sizeof (tmpbuf)) != DLADM_STATUS_OK) { 2752 (void) strcpy(lbuf->link_over, "?"); 2753 break; 2754 } 2755 if (tmpbuf[0] != '\0') 2756 tmpbuf[strlen(tmpbuf) - 1] = '\0'; 2757 dlp = dladm_bridge_get_portlist(tmpbuf, &nports); 2758 if (dlp == NULL) { 2759 (void) strcpy(lbuf->link_over, "?"); 2760 break; 2761 } 2762 for (i = 0; i < nports; i++) { 2763 if (dladm_datalink_id2info(handle, dlp[i], NULL, 2764 NULL, NULL, tmpbuf, sizeof (tmpbuf)) != 2765 DLADM_STATUS_OK) { 2766 (void) strcpy(lbuf->link_over, "?"); 2767 break; 2768 } 2769 (void) strlcat(lbuf->link_over, tmpbuf, 2770 sizeof (lbuf->link_over)); 2771 if (i != nports - 1) { 2772 (void) strlcat(lbuf->link_over, ",", 2773 sizeof (lbuf->link_over)); 2774 } 2775 } 2776 dladm_bridge_free_portlist(dlp); 2777 break; 2778 } 2779 2780 case DATALINK_CLASS_SIMNET: { 2781 dladm_simnet_attr_t slinfo; 2782 2783 if (dladm_simnet_info(handle, linkid, &slinfo, flags) != 2784 DLADM_STATUS_OK) { 2785 (void) strcpy(lbuf->link_over, "?"); 2786 break; 2787 } 2788 if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID) { 2789 if (dladm_datalink_id2info(handle, 2790 slinfo.sna_peer_link_id, NULL, NULL, NULL, 2791 lbuf->link_over, sizeof (lbuf->link_over)) != 2792 DLADM_STATUS_OK) 2793 (void) strcpy(lbuf->link_over, "?"); 2794 } 2795 break; 2796 } 2797 } 2798 } 2799 2800 static dladm_status_t 2801 print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf) 2802 { 2803 char link[MAXLINKNAMELEN]; 2804 datalink_class_t class; 2805 uint_t mtu; 2806 uint32_t flags; 2807 dladm_status_t status; 2808 2809 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 2810 NULL, link, sizeof (link))) != DLADM_STATUS_OK) { 2811 goto done; 2812 } 2813 2814 if (!(state->ls_flags & flags)) { 2815 status = DLADM_STATUS_NOTFOUND; 2816 goto done; 2817 } 2818 2819 (void) snprintf(lbuf->link_name, sizeof (lbuf->link_name), 2820 "%s", link); 2821 (void) dladm_class2str(class, lbuf->link_class); 2822 2823 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2824 dladm_attr_t dlattr; 2825 2826 if (class == DATALINK_CLASS_PHYS) { 2827 dladm_phys_attr_t dpa; 2828 dlpi_handle_t dh; 2829 dlpi_info_t dlinfo; 2830 2831 if ((status = dladm_phys_info(handle, linkid, &dpa, 2832 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2833 goto done; 2834 } 2835 2836 if (!dpa.dp_novanity) 2837 goto link_mtu; 2838 2839 /* 2840 * This is a physical link that does not have 2841 * vanity naming support. 2842 */ 2843 if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) != 2844 DLPI_SUCCESS) { 2845 status = DLADM_STATUS_NOTFOUND; 2846 goto done; 2847 } 2848 2849 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 2850 dlpi_close(dh); 2851 status = DLADM_STATUS_BADARG; 2852 goto done; 2853 } 2854 2855 dlpi_close(dh); 2856 mtu = dlinfo.di_max_sdu; 2857 } else { 2858 link_mtu: 2859 status = dladm_info(handle, linkid, &dlattr); 2860 if (status != DLADM_STATUS_OK) 2861 goto done; 2862 mtu = dlattr.da_max_sdu; 2863 } 2864 2865 (void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu), 2866 "%u", mtu); 2867 (void) get_linkstate(link, B_TRUE, lbuf->link_state); 2868 } 2869 2870 print_link_topology(state, linkid, class, lbuf); 2871 done: 2872 return (status); 2873 } 2874 2875 /* ARGSUSED */ 2876 static int 2877 show_link(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2878 { 2879 show_state_t *state = (show_state_t *)arg; 2880 dladm_status_t status; 2881 link_fields_buf_t lbuf; 2882 2883 /* 2884 * first get all the link attributes into lbuf; 2885 */ 2886 bzero(&lbuf, sizeof (link_fields_buf_t)); 2887 if ((status = print_link(state, linkid, &lbuf)) == DLADM_STATUS_OK) 2888 ofmt_print(state->ls_ofmt, &lbuf); 2889 state->ls_status = status; 2890 return (DLADM_WALK_CONTINUE); 2891 } 2892 2893 static boolean_t 2894 print_link_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2895 { 2896 link_args_t *largs = ofarg->ofmt_cbarg; 2897 pktsum_t *diff_stats = largs->link_s_psum; 2898 2899 switch (ofarg->ofmt_id) { 2900 case LINK_S_LINK: 2901 (void) snprintf(buf, bufsize, "%s", largs->link_s_link); 2902 break; 2903 case LINK_S_IPKTS: 2904 (void) snprintf(buf, bufsize, "%llu", diff_stats->ipackets); 2905 break; 2906 case LINK_S_RBYTES: 2907 (void) snprintf(buf, bufsize, "%llu", diff_stats->rbytes); 2908 break; 2909 case LINK_S_IERRORS: 2910 (void) snprintf(buf, bufsize, "%u", diff_stats->ierrors); 2911 break; 2912 case LINK_S_OPKTS: 2913 (void) snprintf(buf, bufsize, "%llu", diff_stats->opackets); 2914 break; 2915 case LINK_S_OBYTES: 2916 (void) snprintf(buf, bufsize, "%llu", diff_stats->obytes); 2917 break; 2918 case LINK_S_OERRORS: 2919 (void) snprintf(buf, bufsize, "%u", diff_stats->oerrors); 2920 break; 2921 default: 2922 die("invalid input"); 2923 break; 2924 } 2925 return (B_TRUE); 2926 } 2927 2928 static int 2929 show_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2930 { 2931 char link[DLPI_LINKNAME_MAX]; 2932 datalink_class_t class; 2933 show_state_t *state = arg; 2934 pktsum_t stats, diff_stats; 2935 dladm_phys_attr_t dpa; 2936 link_args_t largs; 2937 2938 if (state->ls_firstonly) { 2939 if (state->ls_donefirst) 2940 return (DLADM_WALK_CONTINUE); 2941 state->ls_donefirst = B_TRUE; 2942 } else { 2943 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 2944 } 2945 2946 if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, link, 2947 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2948 return (DLADM_WALK_CONTINUE); 2949 } 2950 2951 if (class == DATALINK_CLASS_PHYS) { 2952 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) != 2953 DLADM_STATUS_OK) { 2954 return (DLADM_WALK_CONTINUE); 2955 } 2956 if (dpa.dp_novanity) 2957 get_mac_stats(dpa.dp_dev, &stats); 2958 else 2959 get_link_stats(link, &stats); 2960 } else { 2961 get_link_stats(link, &stats); 2962 } 2963 dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats); 2964 2965 largs.link_s_link = link; 2966 largs.link_s_psum = &diff_stats; 2967 ofmt_print(state->ls_ofmt, &largs); 2968 2969 state->ls_prevstats = stats; 2970 return (DLADM_WALK_CONTINUE); 2971 } 2972 2973 2974 static dladm_status_t 2975 print_aggr_info(show_grp_state_t *state, const char *link, 2976 dladm_aggr_grp_attr_t *ginfop) 2977 { 2978 char addr_str[ETHERADDRL * 3]; 2979 laggr_fields_buf_t lbuf; 2980 2981 (void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name), 2982 "%s", link); 2983 2984 (void) dladm_aggr_policy2str(ginfop->lg_policy, 2985 lbuf.laggr_policy); 2986 2987 if (ginfop->lg_mac_fixed) { 2988 (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); 2989 (void) snprintf(lbuf.laggr_addrpolicy, 2990 sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str); 2991 } else { 2992 (void) snprintf(lbuf.laggr_addrpolicy, 2993 sizeof (lbuf.laggr_addrpolicy), "auto"); 2994 } 2995 2996 (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, 2997 lbuf.laggr_lacpactivity); 2998 (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, 2999 lbuf.laggr_lacptimer); 3000 (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----", 3001 ginfop->lg_force ? 'f' : '-'); 3002 3003 ofmt_print(state->gs_ofmt, &lbuf); 3004 3005 return (DLADM_STATUS_OK); 3006 } 3007 3008 static boolean_t 3009 print_xaggr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3010 { 3011 const laggr_args_t *l = ofarg->ofmt_cbarg; 3012 boolean_t is_port = (l->laggr_lport >= 0); 3013 char tmpbuf[DLADM_STRSIZE]; 3014 const char *objname; 3015 dladm_aggr_port_attr_t *portp = NULL; 3016 dladm_phys_attr_t dpa; 3017 3018 if (is_port) { 3019 portp = &(l->laggr_ginfop->lg_ports[l->laggr_lport]); 3020 if (dladm_phys_info(handle, portp->lp_linkid, &dpa, 3021 DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) 3022 objname = "?"; 3023 else 3024 objname = dpa.dp_dev; 3025 } else { 3026 objname = l->laggr_link; 3027 } 3028 3029 switch (ofarg->ofmt_id) { 3030 case AGGR_X_LINK: 3031 (void) snprintf(buf, bufsize, "%s", 3032 (is_port && !l->laggr_parsable ? " " : l->laggr_link)); 3033 break; 3034 case AGGR_X_PORT: 3035 if (is_port) { 3036 if (dladm_datalink_id2info(handle, portp->lp_linkid, 3037 NULL, NULL, NULL, buf, bufsize) != DLADM_STATUS_OK) 3038 (void) sprintf(buf, "?"); 3039 } 3040 break; 3041 3042 case AGGR_X_SPEED: 3043 (void) snprintf(buf, bufsize, "%uMb", 3044 (uint_t)((get_ifspeed(objname, !is_port)) / 1000000ull)); 3045 break; 3046 3047 case AGGR_X_DUPLEX: 3048 (void) get_linkduplex(objname, !is_port, tmpbuf); 3049 (void) strlcpy(buf, tmpbuf, bufsize); 3050 break; 3051 3052 case AGGR_X_STATE: 3053 (void) get_linkstate(objname, !is_port, tmpbuf); 3054 (void) strlcpy(buf, tmpbuf, bufsize); 3055 break; 3056 case AGGR_X_ADDRESS: 3057 (void) dladm_aggr_macaddr2str( 3058 (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac), 3059 tmpbuf); 3060 (void) strlcpy(buf, tmpbuf, bufsize); 3061 break; 3062 case AGGR_X_PORTSTATE: 3063 if (is_port) { 3064 (void) dladm_aggr_portstate2str(portp->lp_state, 3065 tmpbuf); 3066 (void) strlcpy(buf, tmpbuf, bufsize); 3067 } 3068 break; 3069 } 3070 err: 3071 *(l->laggr_status) = DLADM_STATUS_OK; 3072 return (B_TRUE); 3073 } 3074 3075 static dladm_status_t 3076 print_aggr_extended(show_grp_state_t *state, const char *link, 3077 dladm_aggr_grp_attr_t *ginfop) 3078 { 3079 int i; 3080 dladm_status_t status; 3081 laggr_args_t largs; 3082 3083 largs.laggr_lport = -1; 3084 largs.laggr_link = link; 3085 largs.laggr_ginfop = ginfop; 3086 largs.laggr_status = &status; 3087 largs.laggr_parsable = state->gs_parsable; 3088 3089 ofmt_print(state->gs_ofmt, &largs); 3090 3091 if (status != DLADM_STATUS_OK) 3092 goto done; 3093 3094 for (i = 0; i < ginfop->lg_nports; i++) { 3095 largs.laggr_lport = i; 3096 ofmt_print(state->gs_ofmt, &largs); 3097 if (status != DLADM_STATUS_OK) 3098 goto done; 3099 } 3100 3101 status = DLADM_STATUS_OK; 3102 done: 3103 return (status); 3104 } 3105 3106 static boolean_t 3107 print_lacp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3108 { 3109 const laggr_args_t *l = ofarg->ofmt_cbarg; 3110 int portnum; 3111 boolean_t is_port = (l->laggr_lport >= 0); 3112 dladm_aggr_port_attr_t *portp; 3113 aggr_lacp_state_t *lstate; 3114 3115 if (!is_port) 3116 return (B_FALSE); /* cannot happen! */ 3117 3118 portnum = l->laggr_lport; 3119 portp = &(l->laggr_ginfop->lg_ports[portnum]); 3120 lstate = &(portp->lp_lacp_state); 3121 3122 switch (ofarg->ofmt_id) { 3123 case AGGR_L_LINK: 3124 (void) snprintf(buf, bufsize, "%s", 3125 (portnum > 0 ? "" : l->laggr_link)); 3126 break; 3127 3128 case AGGR_L_PORT: 3129 if (dladm_datalink_id2info(handle, portp->lp_linkid, NULL, NULL, 3130 NULL, buf, bufsize) != DLADM_STATUS_OK) 3131 (void) sprintf(buf, "?"); 3132 break; 3133 3134 case AGGR_L_AGGREGATABLE: 3135 (void) snprintf(buf, bufsize, "%s", 3136 (lstate->bit.aggregation ? "yes" : "no")); 3137 break; 3138 3139 case AGGR_L_SYNC: 3140 (void) snprintf(buf, bufsize, "%s", 3141 (lstate->bit.sync ? "yes" : "no")); 3142 break; 3143 3144 case AGGR_L_COLL: 3145 (void) snprintf(buf, bufsize, "%s", 3146 (lstate->bit.collecting ? "yes" : "no")); 3147 break; 3148 3149 case AGGR_L_DIST: 3150 (void) snprintf(buf, bufsize, "%s", 3151 (lstate->bit.distributing ? "yes" : "no")); 3152 break; 3153 3154 case AGGR_L_DEFAULTED: 3155 (void) snprintf(buf, bufsize, "%s", 3156 (lstate->bit.defaulted ? "yes" : "no")); 3157 break; 3158 3159 case AGGR_L_EXPIRED: 3160 (void) snprintf(buf, bufsize, "%s", 3161 (lstate->bit.expired ? "yes" : "no")); 3162 break; 3163 } 3164 3165 *(l->laggr_status) = DLADM_STATUS_OK; 3166 return (B_TRUE); 3167 } 3168 3169 static dladm_status_t 3170 print_aggr_lacp(show_grp_state_t *state, const char *link, 3171 dladm_aggr_grp_attr_t *ginfop) 3172 { 3173 int i; 3174 dladm_status_t status; 3175 laggr_args_t largs; 3176 3177 largs.laggr_link = link; 3178 largs.laggr_ginfop = ginfop; 3179 largs.laggr_status = &status; 3180 3181 for (i = 0; i < ginfop->lg_nports; i++) { 3182 largs.laggr_lport = i; 3183 ofmt_print(state->gs_ofmt, &largs); 3184 if (status != DLADM_STATUS_OK) 3185 goto done; 3186 } 3187 3188 status = DLADM_STATUS_OK; 3189 done: 3190 return (status); 3191 } 3192 3193 static boolean_t 3194 print_aggr_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3195 { 3196 const laggr_args_t *l = ofarg->ofmt_cbarg; 3197 int portnum; 3198 boolean_t is_port = (l->laggr_lport >= 0); 3199 dladm_aggr_port_attr_t *portp; 3200 dladm_status_t *stat, status; 3201 pktsum_t *diff_stats = NULL; 3202 3203 stat = l->laggr_status; 3204 *stat = DLADM_STATUS_OK; 3205 3206 if (is_port) { 3207 portnum = l->laggr_lport; 3208 portp = &(l->laggr_ginfop->lg_ports[portnum]); 3209 3210 if ((status = dladm_datalink_id2info(handle, 3211 portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) != 3212 DLADM_STATUS_OK) { 3213 goto err; 3214 } 3215 diff_stats = l->laggr_diffstats; 3216 if (diff_stats == NULL) { 3217 status = DLADM_STATUS_BADVAL; 3218 goto err; 3219 } 3220 } 3221 3222 switch (ofarg->ofmt_id) { 3223 case AGGR_S_LINK: 3224 (void) snprintf(buf, bufsize, "%s", 3225 (is_port ? "" : l->laggr_link)); 3226 break; 3227 case AGGR_S_PORT: 3228 /* 3229 * if (is_port), buf has port name. Otherwise we print 3230 * STR_UNDEF_VAL 3231 */ 3232 break; 3233 3234 case AGGR_S_IPKTS: 3235 if (is_port) { 3236 (void) snprintf(buf, bufsize, "%llu", 3237 diff_stats->ipackets); 3238 } else { 3239 (void) snprintf(buf, bufsize, "%llu", 3240 l->laggr_pktsumtot->ipackets); 3241 } 3242 break; 3243 3244 case AGGR_S_RBYTES: 3245 if (is_port) { 3246 (void) snprintf(buf, bufsize, "%llu", 3247 diff_stats->rbytes); 3248 } else { 3249 (void) snprintf(buf, bufsize, "%llu", 3250 l->laggr_pktsumtot->rbytes); 3251 } 3252 break; 3253 3254 case AGGR_S_OPKTS: 3255 if (is_port) { 3256 (void) snprintf(buf, bufsize, "%llu", 3257 diff_stats->opackets); 3258 } else { 3259 (void) snprintf(buf,