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