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