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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <ctype.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 <termios.h> 43 #include <pwd.h> 44 #include <auth_attr.h> 45 #include <auth_list.h> 46 #include <libintl.h> 47 #include <libdevinfo.h> 48 #include <libdlpi.h> 49 #include <libdladm.h> 50 #include <libdllink.h> 51 #include <libdlstat.h> 52 #include <libdlaggr.h> 53 #include <libdlwlan.h> 54 #include <libdlvlan.h> 55 #include <libdlvnic.h> 56 #include <libdlether.h> 57 #include <libdlsim.h> 58 #include <libinetutil.h> 59 #include <bsm/adt.h> 60 #include <bsm/adt_event.h> 61 #include <libdlvnic.h> 62 #include <sys/types.h> 63 #include <sys/socket.h> 64 #include <sys/processor.h> 65 #include <netinet/in.h> 66 #include <arpa/inet.h> 67 #include <net/if_types.h> 68 #include <stddef.h> 69 #include <ofmt.h> 70 71 #define MAXPORT 256 72 #define MAXVNIC 256 73 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) 74 #define MAXLINELEN 1024 75 #define SMF_UPGRADE_FILE "/var/svc/profile/upgrade" 76 #define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink" 77 #define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)" 78 #define DLADM_DEFAULT_COL 80 79 80 /* 81 * used by the wifi show-* commands to set up ofmt_field_t structures. 82 */ 83 #define WIFI_CMD_SCAN 0x00000001 84 #define WIFI_CMD_SHOW 0x00000002 85 #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 86 87 typedef struct show_state { 88 boolean_t ls_firstonly; 89 boolean_t ls_donefirst; 90 pktsum_t ls_prevstats; 91 uint32_t ls_flags; 92 dladm_status_t ls_status; 93 ofmt_handle_t ls_ofmt; 94 boolean_t ls_parsable; 95 boolean_t ls_mac; 96 boolean_t ls_hwgrp; 97 } show_state_t; 98 99 typedef struct show_grp_state { 100 pktsum_t gs_prevstats[MAXPORT]; 101 uint32_t gs_flags; 102 dladm_status_t gs_status; 103 boolean_t gs_parsable; 104 boolean_t gs_lacp; 105 boolean_t gs_extended; 106 boolean_t gs_stats; 107 boolean_t gs_firstonly; 108 boolean_t gs_donefirst; 109 ofmt_handle_t gs_ofmt; 110 } show_grp_state_t; 111 112 typedef struct show_vnic_state { 113 datalink_id_t vs_vnic_id; 114 datalink_id_t vs_link_id; 115 char vs_vnic[MAXLINKNAMELEN]; 116 char vs_link[MAXLINKNAMELEN]; 117 boolean_t vs_parsable; 118 boolean_t vs_found; 119 boolean_t vs_firstonly; 120 boolean_t vs_donefirst; 121 boolean_t vs_stats; 122 boolean_t vs_printstats; 123 pktsum_t vs_totalstats; 124 pktsum_t vs_prevstats[MAXVNIC]; 125 boolean_t vs_etherstub; 126 dladm_status_t vs_status; 127 uint32_t vs_flags; 128 ofmt_handle_t vs_ofmt; 129 } show_vnic_state_t; 130 131 typedef struct show_usage_state_s { 132 boolean_t us_plot; 133 boolean_t us_parsable; 134 boolean_t us_printheader; 135 boolean_t us_first; 136 boolean_t us_showall; 137 ofmt_handle_t us_ofmt; 138 } show_usage_state_t; 139 140 /* 141 * callback functions for printing output and error diagnostics. 142 */ 143 static ofmt_cb_t print_default_cb, print_link_stats_cb, print_linkprop_cb; 144 static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb; 145 static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb; 146 static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb; 147 static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb; 148 static void dladm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t); 149 150 typedef void cmdfunc_t(int, char **, const char *); 151 152 static cmdfunc_t do_show_link, do_show_wifi, do_show_phys; 153 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 154 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr; 155 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 156 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 157 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 158 static cmdfunc_t do_init_linkprop, do_init_secobj; 159 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan; 160 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys; 161 static cmdfunc_t do_show_linkmap; 162 static cmdfunc_t do_show_ether; 163 static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic; 164 static cmdfunc_t do_up_vnic; 165 static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub; 166 static cmdfunc_t do_create_simnet, do_modify_simnet; 167 static cmdfunc_t do_delete_simnet, do_show_simnet, do_up_simnet; 168 static cmdfunc_t do_show_usage; 169 170 static void do_up_vnic_common(int, char **, const char *, boolean_t); 171 172 static void altroot_cmd(char *, int, char **); 173 static int show_linkprop_onelink(dladm_handle_t, datalink_id_t, void *); 174 175 static void link_stats(datalink_id_t, uint_t, char *, show_state_t *); 176 static void aggr_stats(datalink_id_t, show_grp_state_t *, uint_t); 177 static void vnic_stats(show_vnic_state_t *, uint32_t); 178 179 static int get_one_kstat(const char *, const char *, uint8_t, 180 void *, boolean_t); 181 static void get_mac_stats(const char *, pktsum_t *); 182 static void get_link_stats(const char *, pktsum_t *); 183 static uint64_t get_ifspeed(const char *, boolean_t); 184 static const char *get_linkstate(const char *, boolean_t, char *); 185 static const char *get_linkduplex(const char *, boolean_t, char *); 186 187 static int show_etherprop(dladm_handle_t, datalink_id_t, void *); 188 static void show_ether_xprop(void *, dladm_ether_info_t *); 189 static boolean_t link_is_ether(const char *, datalink_id_t *); 190 191 static boolean_t str2int(const char *, int *); 192 static void die(const char *, ...); 193 static void die_optdup(int); 194 static void die_opterr(int, int, const char *); 195 static void die_dlerr(dladm_status_t, const char *, ...); 196 static void warn(const char *, ...); 197 static void warn_dlerr(dladm_status_t, const char *, ...); 198 199 typedef struct cmd { 200 char *c_name; 201 cmdfunc_t *c_fn; 202 const char *c_usage; 203 } cmd_t; 204 205 static cmd_t cmds[] = { 206 { "rename-link", do_rename_link, 207 " rename-link <oldlink> <newlink>" }, 208 { "show-link", do_show_link, 209 " show-link [-pP] [-o <field>,..] [-s [-i <interval>]] " 210 "[<link>]\n" }, 211 { "create-aggr", do_create_aggr, 212 " create-aggr [-t] [-P <policy>] [-L <mode>] [-T <time>] " 213 "[-u <address>]\n" 214 "\t\t -l <link> [-l <link>...] <link>" }, 215 { "delete-aggr", do_delete_aggr, 216 " delete-aggr [-t] <link>" }, 217 { "add-aggr", do_add_aggr, 218 " add-aggr [-t] -l <link> [-l <link>...] <link>" }, 219 { "remove-aggr", do_remove_aggr, 220 " remove-aggr [-t] -l <link> [-l <link>...] <link>" }, 221 { "modify-aggr", do_modify_aggr, 222 " modify-aggr [-t] [-P <policy>] [-L <mode>] [-T <time>] " 223 "[-u <address>]\n" 224 "\t\t <link>" }, 225 { "show-aggr", do_show_aggr, 226 " show-aggr [-pPLx] [-o <field>,..] [-s [-i <interval>]] " 227 "[<link>]\n" }, 228 { "up-aggr", do_up_aggr, NULL }, 229 { "scan-wifi", do_scan_wifi, 230 " scan-wifi [-p] [-o <field>,...] [<link>]" }, 231 { "connect-wifi", do_connect_wifi, 232 " connect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...] " 233 "[-s wep|wpa]\n" 234 "\t\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g] " 235 "[-T <time>]\n" 236 "\t\t [<link>]" }, 237 { "disconnect-wifi", do_disconnect_wifi, 238 " disconnect-wifi [-a] [<link>]" }, 239 { "show-wifi", do_show_wifi, 240 " show-wifi [-p] [-o <field>,...] [<link>]\n" }, 241 { "set-linkprop", do_set_linkprop, 242 " set-linkprop [-t] -p <prop>=<value>[,...] <name>" }, 243 { "reset-linkprop", do_reset_linkprop, 244 " reset-linkprop [-t] [-p <prop>,...] <name>" }, 245 { "show-linkprop", do_show_linkprop, 246 " show-linkprop [-cP] [-o <field>,...] [-p <prop>,...] " 247 "<name>\n" }, 248 { "show-ether", do_show_ether, 249 " show-ether [-px][-o <field>,...] <link>\n" }, 250 { "create-secobj", do_create_secobj, 251 " create-secobj [-t] [-f <file>] -c <class> <secobj>" }, 252 { "delete-secobj", do_delete_secobj, 253 " delete-secobj [-t] <secobj>[,...]" }, 254 { "show-secobj", do_show_secobj, 255 " show-secobj [-pP] [-o <field>,...] [<secobj>,...]\n" }, 256 { "init-linkprop", do_init_linkprop, NULL }, 257 { "init-secobj", do_init_secobj, NULL }, 258 { "create-vlan", do_create_vlan, 259 " create-vlan [-ft] -l <link> -v <vid> [link]" }, 260 { "delete-vlan", do_delete_vlan, 261 " delete-vlan [-t] <link>" }, 262 { "show-vlan", do_show_vlan, 263 " show-vlan [-pP] [-o <field>,..] [<link>]\n" }, 264 { "up-vlan", do_up_vlan, NULL }, 265 { "delete-phys", do_delete_phys, 266 " delete-phys <link>" }, 267 { "show-phys", do_show_phys, 268 " show-phys [-pP] [-o <field>,..] [-H] [<link>]\n"}, 269 { "init-phys", do_init_phys, NULL }, 270 { "show-linkmap", do_show_linkmap, NULL }, 271 { "create-vnic", do_create_vnic, 272 " create-vnic [-t] -l <link> [-m <value> | auto |\n" 273 "\t\t {factory [-n <slot-id>]} | {random [-r <prefix>]}]\n" 274 "\t\t [-v <vid> [-f]] [-p <prop>=<value>[,...]] [-H] " 275 "<vnic-link>" }, 276 { "delete-vnic", do_delete_vnic, 277 " delete-vnic [-t] <vnic-link>" }, 278 { "show-vnic", do_show_vnic, 279 " show-vnic [-pP] [-l <link>] [-s [-i <interval>]] " 280 "[<link>]\n" }, 281 { "up-vnic", do_up_vnic, NULL }, 282 { "create-etherstub", do_create_etherstub, 283 " create-etherstub [-t] <link>" }, 284 { "delete-etherstub", do_delete_etherstub, 285 " delete-etherstub [-t] <link>" }, 286 { "show-etherstub", do_show_etherstub, 287 " show-etherstub [-t] [<link>]\n" }, 288 { "create-simnet", do_create_simnet, 289 " create-simnet [-t] [-m <media>] <link>" }, 290 { "modify-simnet", do_modify_simnet, 291 " modify-simnet [-t] [-p <peer>] <link>" }, 292 { "delete-simnet", do_delete_simnet, 293 " delete-simnet [-t] <link>" }, 294 { "show-simnet", do_show_simnet, 295 " show-simnet [-pP] [-o <field>,...] [<link>]\n" }, 296 { "up-simnet", do_up_simnet, NULL }, 297 { "show-usage", do_show_usage, 298 " show-usage [-a] [-d | -F <format>] " 299 "[-s <DD/MM/YYYY,HH:MM:SS>]\n" 300 "\t\t [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<link>]" } 301 }; 302 303 static const struct option lopts[] = { 304 {"vlan-id", required_argument, 0, 'v'}, 305 {"output", required_argument, 0, 'o'}, 306 {"dev", required_argument, 0, 'd'}, 307 {"policy", required_argument, 0, 'P'}, 308 {"lacp-mode", required_argument, 0, 'L'}, 309 {"lacp-timer", required_argument, 0, 'T'}, 310 {"unicast", required_argument, 0, 'u'}, 311 {"temporary", no_argument, 0, 't'}, 312 {"root-dir", required_argument, 0, 'R'}, 313 {"link", required_argument, 0, 'l'}, 314 {"forcible", no_argument, 0, 'f'}, 315 {"bw-limit", required_argument, 0, 'b'}, 316 {"mac-address", required_argument, 0, 'm'}, 317 {"slot", required_argument, 0, 'n'}, 318 { 0, 0, 0, 0 } 319 }; 320 321 static const struct option show_lopts[] = { 322 {"statistics", no_argument, 0, 's'}, 323 {"continuous", no_argument, 0, 'S'}, 324 {"interval", required_argument, 0, 'i'}, 325 {"parsable", no_argument, 0, 'p'}, 326 {"parseable", no_argument, 0, 'p'}, 327 {"extended", no_argument, 0, 'x'}, 328 {"output", required_argument, 0, 'o'}, 329 {"persistent", no_argument, 0, 'P'}, 330 {"lacp", no_argument, 0, 'L'}, 331 { 0, 0, 0, 0 } 332 }; 333 334 static const struct option prop_longopts[] = { 335 {"temporary", no_argument, 0, 't' }, 336 {"output", required_argument, 0, 'o' }, 337 {"root-dir", required_argument, 0, 'R' }, 338 {"prop", required_argument, 0, 'p' }, 339 {"parsable", no_argument, 0, 'c' }, 340 {"parseable", no_argument, 0, 'c' }, 341 {"persistent", no_argument, 0, 'P' }, 342 { 0, 0, 0, 0 } 343 }; 344 345 static const struct option wifi_longopts[] = { 346 {"parsable", no_argument, 0, 'p' }, 347 {"parseable", no_argument, 0, 'p' }, 348 {"output", required_argument, 0, 'o' }, 349 {"essid", required_argument, 0, 'e' }, 350 {"bsstype", required_argument, 0, 'b' }, 351 {"mode", required_argument, 0, 'm' }, 352 {"key", required_argument, 0, 'k' }, 353 {"sec", required_argument, 0, 's' }, 354 {"auth", required_argument, 0, 'a' }, 355 {"create-ibss", required_argument, 0, 'c' }, 356 {"timeout", required_argument, 0, 'T' }, 357 {"all-links", no_argument, 0, 'a' }, 358 {"temporary", no_argument, 0, 't' }, 359 {"root-dir", required_argument, 0, 'R' }, 360 {"persistent", no_argument, 0, 'P' }, 361 {"file", required_argument, 0, 'f' }, 362 { 0, 0, 0, 0 } 363 }; 364 static const struct option showeth_lopts[] = { 365 {"parsable", no_argument, 0, 'p' }, 366 {"parseable", no_argument, 0, 'p' }, 367 {"extended", no_argument, 0, 'x' }, 368 {"output", required_argument, 0, 'o' }, 369 { 0, 0, 0, 0 } 370 }; 371 372 static const struct option vnic_lopts[] = { 373 {"temporary", no_argument, 0, 't' }, 374 {"root-dir", required_argument, 0, 'R' }, 375 {"dev", required_argument, 0, 'd' }, 376 {"mac-address", required_argument, 0, 'm' }, 377 {"cpus", required_argument, 0, 'c' }, 378 {"bw-limit", required_argument, 0, 'b' }, 379 {"slot", required_argument, 0, 'n' }, 380 {"mac-prefix", required_argument, 0, 'r' }, 381 { 0, 0, 0, 0 } 382 }; 383 384 static const struct option etherstub_lopts[] = { 385 {"temporary", no_argument, 0, 't' }, 386 {"root-dir", required_argument, 0, 'R' }, 387 { 0, 0, 0, 0 } 388 }; 389 390 static const struct option usage_opts[] = { 391 {"file", required_argument, 0, 'f' }, 392 {"format", required_argument, 0, 'F' }, 393 {"start", required_argument, 0, 's' }, 394 {"stop", required_argument, 0, 'e' }, 395 { 0, 0, 0, 0 } 396 }; 397 398 static const struct option simnet_lopts[] = { 399 {"temporary", no_argument, 0, 't' }, 400 {"root-dir", required_argument, 0, 'R' }, 401 {"media", required_argument, 0, 'm' }, 402 {"peer", required_argument, 0, 'p' }, 403 { 0, 0, 0, 0 } 404 }; 405 406 /* 407 * structures for 'dladm show-ether' 408 */ 409 static const char *ptype[] = {LEI_ATTR_NAMES}; 410 411 typedef struct ether_fields_buf_s 412 { 413 char eth_link[15]; 414 char eth_ptype[8]; 415 char eth_state[8]; 416 char eth_autoneg[5]; 417 char eth_spdx[31]; 418 char eth_pause[6]; 419 char eth_rem_fault[16]; 420 } ether_fields_buf_t; 421 422 static ofmt_field_t ether_fields[] = { 423 /* name, field width, offset callback */ 424 { "LINK", 16, 425 offsetof(ether_fields_buf_t, eth_link), print_default_cb}, 426 { "PTYPE", 9, 427 offsetof(ether_fields_buf_t, eth_ptype), print_default_cb}, 428 { "STATE", 9, 429 offsetof(ether_fields_buf_t, eth_state), 430 print_default_cb}, 431 { "AUTO", 6, 432 offsetof(ether_fields_buf_t, eth_autoneg), print_default_cb}, 433 { "SPEED-DUPLEX", 32, 434 offsetof(ether_fields_buf_t, eth_spdx), print_default_cb}, 435 { "PAUSE", 7, 436 offsetof(ether_fields_buf_t, eth_pause), print_default_cb}, 437 { "REM_FAULT", 17, 438 offsetof(ether_fields_buf_t, eth_rem_fault), print_default_cb}, 439 {NULL, 0, 440 0, NULL}} 441 ; 442 443 typedef struct print_ether_state { 444 const char *es_link; 445 boolean_t es_parsable; 446 boolean_t es_header; 447 boolean_t es_extended; 448 ofmt_handle_t es_ofmt; 449 } print_ether_state_t; 450 451 /* 452 * structures for 'dladm show-link -s' (print statistics) 453 */ 454 typedef enum { 455 LINK_S_LINK, 456 LINK_S_IPKTS, 457 LINK_S_RBYTES, 458 LINK_S_IERRORS, 459 LINK_S_OPKTS, 460 LINK_S_OBYTES, 461 LINK_S_OERRORS 462 } link_s_field_index_t; 463 464 static ofmt_field_t link_s_fields[] = { 465 /* name, field width, index, callback */ 466 { "LINK", 15, LINK_S_LINK, print_link_stats_cb}, 467 { "IPACKETS", 10, LINK_S_IPKTS, print_link_stats_cb}, 468 { "RBYTES", 8, LINK_S_RBYTES, print_link_stats_cb}, 469 { "IERRORS", 10, LINK_S_IERRORS, print_link_stats_cb}, 470 { "OPACKETS", 12, LINK_S_OPKTS, print_link_stats_cb}, 471 { "OBYTES", 12, LINK_S_OBYTES, print_link_stats_cb}, 472 { "OERRORS", 8, LINK_S_OERRORS, print_link_stats_cb}} 473 ; 474 475 typedef struct link_args_s { 476 char *link_s_link; 477 pktsum_t *link_s_psum; 478 } link_args_t; 479 480 /* 481 * buffer used by print functions for show-{link,phys,vlan} commands. 482 */ 483 typedef struct link_fields_buf_s { 484 char link_name[MAXLINKNAMELEN]; 485 char link_class[DLADM_STRSIZE]; 486 char link_mtu[11]; 487 char link_state[DLADM_STRSIZE]; 488 char link_over[MAXLINKNAMELEN]; 489 char link_phys_state[DLADM_STRSIZE]; 490 char link_phys_media[DLADM_STRSIZE]; 491 char link_phys_speed[DLADM_STRSIZE]; 492 char link_phys_duplex[DLPI_LINKNAME_MAX]; 493 char link_phys_device[DLPI_LINKNAME_MAX]; 494 char link_flags[6]; 495 char link_vlan_vid[6]; 496 } link_fields_buf_t; 497 498 /* 499 * structures for 'dladm show-link' 500 */ 501 static ofmt_field_t link_fields[] = { 502 /* name, field width, index, callback */ 503 { "LINK", 12, 504 offsetof(link_fields_buf_t, link_name), print_default_cb}, 505 { "CLASS", 9, 506 offsetof(link_fields_buf_t, link_class), print_default_cb}, 507 { "MTU", 7, 508 offsetof(link_fields_buf_t, link_mtu), print_default_cb}, 509 { "STATE", 9, 510 offsetof(link_fields_buf_t, link_state), print_default_cb}, 511 { "OVER", DLPI_LINKNAME_MAX, 512 offsetof(link_fields_buf_t, link_over), print_default_cb}, 513 { NULL, 0, 0, NULL}} 514 ; 515 516 /* 517 * structures for 'dladm show-aggr' 518 */ 519 typedef struct laggr_fields_buf_s { 520 char laggr_name[DLPI_LINKNAME_MAX]; 521 char laggr_policy[9]; 522 char laggr_addrpolicy[ETHERADDRL * 3 + 3]; 523 char laggr_lacpactivity[14]; 524 char laggr_lacptimer[DLADM_STRSIZE]; 525 char laggr_flags[7]; 526 } laggr_fields_buf_t; 527 528 typedef struct laggr_args_s { 529 int laggr_lport; /* -1 indicates the aggr itself */ 530 const char *laggr_link; 531 dladm_aggr_grp_attr_t *laggr_ginfop; 532 dladm_status_t *laggr_status; 533 pktsum_t *laggr_pktsumtot; /* -s only */ 534 pktsum_t *laggr_diffstats; /* -s only */ 535 boolean_t laggr_parsable; 536 } laggr_args_t; 537 538 static ofmt_field_t laggr_fields[] = { 539 /* name, field width, offset, callback */ 540 { "LINK", 16, 541 offsetof(laggr_fields_buf_t, laggr_name), print_default_cb}, 542 { "POLICY", 9, 543 offsetof(laggr_fields_buf_t, laggr_policy), print_default_cb}, 544 { "ADDRPOLICY", ETHERADDRL * 3 + 3, 545 offsetof(laggr_fields_buf_t, laggr_addrpolicy), print_default_cb}, 546 { "LACPACTIVITY", 14, 547 offsetof(laggr_fields_buf_t, laggr_lacpactivity), print_default_cb}, 548 { "LACPTIMER", 12, 549 offsetof(laggr_fields_buf_t, laggr_lacptimer), print_default_cb}, 550 { "FLAGS", 8, 551 offsetof(laggr_fields_buf_t, laggr_flags), print_default_cb}, 552 { NULL, 0, 0, NULL}} 553 ; 554 555 /* 556 * structures for 'dladm show-aggr -x'. 557 */ 558 typedef enum { 559 AGGR_X_LINK, 560 AGGR_X_PORT, 561 AGGR_X_SPEED, 562 AGGR_X_DUPLEX, 563 AGGR_X_STATE, 564 AGGR_X_ADDRESS, 565 AGGR_X_PORTSTATE 566 } aggr_x_field_index_t; 567 568 static ofmt_field_t aggr_x_fields[] = { 569 /* name, field width, index callback */ 570 { "LINK", 12, AGGR_X_LINK, print_xaggr_cb}, 571 { "PORT", 15, AGGR_X_PORT, print_xaggr_cb}, 572 { "SPEED", 5, AGGR_X_SPEED, print_xaggr_cb}, 573 { "DUPLEX", 10, AGGR_X_DUPLEX, print_xaggr_cb}, 574 { "STATE", 10, AGGR_X_STATE, print_xaggr_cb}, 575 { "ADDRESS", 19, AGGR_X_ADDRESS, print_xaggr_cb}, 576 { "PORTSTATE", 16, AGGR_X_PORTSTATE, print_xaggr_cb}, 577 { NULL, 0, 0, NULL}} 578 ; 579 580 /* 581 * structures for 'dladm show-aggr -s'. 582 */ 583 typedef enum { 584 AGGR_S_LINK, 585 AGGR_S_PORT, 586 AGGR_S_IPKTS, 587 AGGR_S_RBYTES, 588 AGGR_S_OPKTS, 589 AGGR_S_OBYTES, 590 AGGR_S_IPKTDIST, 591 AGGR_S_OPKTDIST 592 } aggr_s_field_index_t; 593 594 static ofmt_field_t aggr_s_fields[] = { 595 { "LINK", 12, AGGR_S_LINK, print_aggr_stats_cb}, 596 { "PORT", 10, AGGR_S_PORT, print_aggr_stats_cb}, 597 { "IPACKETS", 8, AGGR_S_IPKTS, print_aggr_stats_cb}, 598 { "RBYTES", 8, AGGR_S_RBYTES, print_aggr_stats_cb}, 599 { "OPACKETS", 8, AGGR_S_OPKTS, print_aggr_stats_cb}, 600 { "OBYTES", 8, AGGR_S_OBYTES, print_aggr_stats_cb}, 601 { "IPKTDIST", 9, AGGR_S_IPKTDIST, print_aggr_stats_cb}, 602 { "OPKTDIST", 15, AGGR_S_OPKTDIST, print_aggr_stats_cb}, 603 { NULL, 0, 0, NULL}} 604 ; 605 606 /* 607 * structures for 'dladm show-aggr -L'. 608 */ 609 typedef enum { 610 AGGR_L_LINK, 611 AGGR_L_PORT, 612 AGGR_L_AGGREGATABLE, 613 AGGR_L_SYNC, 614 AGGR_L_COLL, 615 AGGR_L_DIST, 616 AGGR_L_DEFAULTED, 617 AGGR_L_EXPIRED 618 } aggr_l_field_index_t; 619 620 static ofmt_field_t aggr_l_fields[] = { 621 /* name, field width, index */ 622 { "LINK", 12, AGGR_L_LINK, print_lacp_cb}, 623 { "PORT", 13, AGGR_L_PORT, print_lacp_cb}, 624 { "AGGREGATABLE", 13, AGGR_L_AGGREGATABLE, print_lacp_cb}, 625 { "SYNC", 5, AGGR_L_SYNC, print_lacp_cb}, 626 { "COLL", 5, AGGR_L_COLL, print_lacp_cb}, 627 { "DIST", 5, AGGR_L_DIST, print_lacp_cb}, 628 { "DEFAULTED", 10, AGGR_L_DEFAULTED, print_lacp_cb}, 629 { "EXPIRED", 15, AGGR_L_EXPIRED, print_lacp_cb}, 630 { NULL, 0, 0, NULL}} 631 ; 632 633 /* 634 * structures for 'dladm show-phys' 635 */ 636 637 static ofmt_field_t phys_fields[] = { 638 /* name, field width, offset */ 639 { "LINK", 13, 640 offsetof(link_fields_buf_t, link_name), print_default_cb}, 641 { "MEDIA", 21, 642 offsetof(link_fields_buf_t, link_phys_media), print_default_cb}, 643 { "STATE", 11, 644 offsetof(link_fields_buf_t, link_phys_state), print_default_cb}, 645 { "SPEED", 7, 646 offsetof(link_fields_buf_t, link_phys_speed), print_default_cb}, 647 { "DUPLEX", 10, 648 offsetof(link_fields_buf_t, link_phys_duplex), print_default_cb}, 649 { "DEVICE", 13, 650 offsetof(link_fields_buf_t, link_phys_device), print_default_cb}, 651 { "FLAGS", 7, 652 offsetof(link_fields_buf_t, link_flags), print_default_cb}, 653 { NULL, 0, NULL, 0}} 654 ; 655 656 /* 657 * structures for 'dladm show-phys -m' 658 */ 659 660 typedef enum { 661 PHYS_M_LINK, 662 PHYS_M_SLOT, 663 PHYS_M_ADDRESS, 664 PHYS_M_INUSE, 665 PHYS_M_CLIENT 666 } phys_m_field_index_t; 667 668 static ofmt_field_t phys_m_fields[] = { 669 /* name, field width, offset */ 670 { "LINK", 13, PHYS_M_LINK, print_phys_one_mac_cb}, 671 { "SLOT", 9, PHYS_M_SLOT, print_phys_one_mac_cb}, 672 { "ADDRESS", 19, PHYS_M_ADDRESS, print_phys_one_mac_cb}, 673 { "INUSE", 5, PHYS_M_INUSE, print_phys_one_mac_cb}, 674 { "CLIENT", 13, PHYS_M_CLIENT, print_phys_one_mac_cb}, 675 { NULL, 0, 0, NULL}} 676 ; 677 678 /* 679 * structures for 'dladm show-phys -H' 680 */ 681 682 typedef enum { 683 PHYS_H_LINK, 684 PHYS_H_GROUP, 685 PHYS_H_GRPTYPE, 686 PHYS_H_RINGS, 687 PHYS_H_CLIENTS 688 } phys_h_field_index_t; 689 690 static ofmt_field_t phys_h_fields[] = { 691 { "LINK", 13, PHYS_H_LINK, print_phys_one_hwgrp_cb}, 692 { "GROUP", 9, PHYS_H_GROUP, print_phys_one_hwgrp_cb}, 693 { "GROUPTYPE", 7, PHYS_H_GRPTYPE, print_phys_one_hwgrp_cb}, 694 { "RINGS", 17, PHYS_H_RINGS, print_phys_one_hwgrp_cb}, 695 { "CLIENTS", 21, PHYS_H_CLIENTS, print_phys_one_hwgrp_cb}, 696 { NULL, 0, 0, NULL}} 697 ; 698 699 /* 700 * structures for 'dladm show-vlan' 701 */ 702 static ofmt_field_t vlan_fields[] = { 703 { "LINK", 16, 704 offsetof(link_fields_buf_t, link_name), print_default_cb}, 705 { "VID", 9, 706 offsetof(link_fields_buf_t, link_vlan_vid), print_default_cb}, 707 { "OVER", 13, 708 offsetof(link_fields_buf_t, link_over), print_default_cb}, 709 { "FLAGS", 7, 710 offsetof(link_fields_buf_t, link_flags), print_default_cb}, 711 { NULL, 0, 0, NULL}} 712 ; 713 714 /* 715 * structures common to 'dladm scan-wifi' and 'dladm show-wifi' 716 * callback will be determined in parse_wifi_fields. 717 */ 718 static ofmt_field_t wifi_common_fields[] = { 719 { "LINK", 11, 0, NULL}, 720 { "ESSID", 20, DLADM_WLAN_ATTR_ESSID, NULL}, 721 { "BSSID", 18, DLADM_WLAN_ATTR_BSSID, NULL}, 722 { "IBSSID", 18, DLADM_WLAN_ATTR_BSSID, NULL}, 723 { "MODE", 7, DLADM_WLAN_ATTR_MODE, NULL}, 724 { "SPEED", 7, DLADM_WLAN_ATTR_SPEED, NULL}, 725 { "BSSTYPE", 9, DLADM_WLAN_ATTR_BSSTYPE, NULL}, 726 { "SEC", 7, DLADM_WLAN_ATTR_SECMODE, NULL}, 727 { "STRENGTH", 11, DLADM_WLAN_ATTR_STRENGTH, NULL}, 728 { NULL, 0, 0, NULL}}; 729 730 /* 731 * the 'show-wifi' command supports all the fields in wifi_common_fields 732 * plus the AUTH and STATUS fields. 733 */ 734 static ofmt_field_t wifi_show_fields[A_CNT(wifi_common_fields) + 2] = { 735 { "AUTH", 9, DLADM_WLAN_ATTR_AUTH, NULL}, 736 { "STATUS", 18, DLADM_WLAN_LINKATTR_STATUS, print_wifi_status_cb}, 737 /* copy wifi_common_fields here */ 738 }; 739 740 static char *all_scan_wifi_fields = 741 "link,essid,bssid,sec,strength,mode,speed,bsstype"; 742 static char *all_show_wifi_fields = 743 "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 744 static char *def_scan_wifi_fields = 745 "link,essid,bssid,sec,strength,mode,speed"; 746 static char *def_show_wifi_fields = 747 "link,status,essid,sec,strength,mode,speed"; 748 749 /* 750 * structures for 'dladm show-linkprop' 751 */ 752 typedef enum { 753 LINKPROP_LINK, 754 LINKPROP_PROPERTY, 755 LINKPROP_PERM, 756 LINKPROP_VALUE, 757 LINKPROP_DEFAULT, 758 LINKPROP_POSSIBLE 759 } linkprop_field_index_t; 760 761 static ofmt_field_t linkprop_fields[] = { 762 /* name, field width, index */ 763 { "LINK", 13, LINKPROP_LINK, print_linkprop_cb}, 764 { "PROPERTY", 16, LINKPROP_PROPERTY, print_linkprop_cb}, 765 { "PERM", 5, LINKPROP_PERM, print_linkprop_cb}, 766 { "VALUE", 15, LINKPROP_VALUE, print_linkprop_cb}, 767 { "DEFAULT", 15, LINKPROP_DEFAULT, print_linkprop_cb}, 768 { "POSSIBLE", 21, LINKPROP_POSSIBLE, print_linkprop_cb}, 769 { NULL, 0, 0, NULL}} 770 ; 771 772 #define MAX_PROP_LINE 512 773 774 typedef struct show_linkprop_state { 775 char ls_link[MAXLINKNAMELEN]; 776 char *ls_line; 777 char **ls_propvals; 778 dladm_arg_list_t *ls_proplist; 779 boolean_t ls_parsable; 780 boolean_t ls_persist; 781 boolean_t ls_header; 782 dladm_status_t ls_status; 783 dladm_status_t ls_retstatus; 784 ofmt_handle_t ls_ofmt; 785 } show_linkprop_state_t; 786 787 typedef struct set_linkprop_state { 788 const char *ls_name; 789 boolean_t ls_reset; 790 boolean_t ls_temp; 791 dladm_status_t ls_status; 792 } set_linkprop_state_t; 793 794 typedef struct linkprop_args_s { 795 show_linkprop_state_t *ls_state; 796 char *ls_propname; 797 datalink_id_t ls_linkid; 798 } linkprop_args_t; 799 800 /* 801 * structures for 'dladm show-secobj' 802 */ 803 typedef struct secobj_fields_buf_s { 804 char ss_obj_name[DLADM_SECOBJ_VAL_MAX]; 805 char ss_class[20]; 806 char ss_val[30]; 807 } secobj_fields_buf_t; 808 809 static ofmt_field_t secobj_fields[] = { 810 { "OBJECT", 21, 811 offsetof(secobj_fields_buf_t, ss_obj_name), print_default_cb}, 812 { "CLASS", 21, 813 offsetof(secobj_fields_buf_t, ss_class), print_default_cb}, 814 { "VALUE", 31, 815 offsetof(secobj_fields_buf_t, ss_val), print_default_cb}, 816 { NULL, 0, 0, NULL}} 817 ; 818 819 /* 820 * structures for 'dladm show-vnic' 821 */ 822 typedef struct vnic_fields_buf_s 823 { 824 char vnic_link[DLPI_LINKNAME_MAX]; 825 char vnic_over[DLPI_LINKNAME_MAX]; 826 char vnic_speed[6]; 827 char vnic_macaddr[18]; 828 char vnic_macaddrtype[19]; 829 char vnic_vid[6]; 830 } vnic_fields_buf_t; 831 832 static ofmt_field_t vnic_fields[] = { 833 { "LINK", 13, 834 offsetof(vnic_fields_buf_t, vnic_link), print_default_cb}, 835 { "OVER", 13, 836 offsetof(vnic_fields_buf_t, vnic_over), print_default_cb}, 837 { "SPEED", 7, 838 offsetof(vnic_fields_buf_t, vnic_speed), print_default_cb}, 839 { "MACADDRESS", 18, 840 offsetof(vnic_fields_buf_t, vnic_macaddr), print_default_cb}, 841 { "MACADDRTYPE", 20, 842 offsetof(vnic_fields_buf_t, vnic_macaddrtype), print_default_cb}, 843 { "VID", 7, 844 offsetof(vnic_fields_buf_t, vnic_vid), print_default_cb}, 845 { NULL, 0, 0, NULL}} 846 ; 847 848 /* 849 * structures for 'dladm show-simnet' 850 */ 851 typedef struct simnet_fields_buf_s 852 { 853 char simnet_name[DLPI_LINKNAME_MAX]; 854 char simnet_media[DLADM_STRSIZE]; 855 char simnet_macaddr[18]; 856 char simnet_otherlink[DLPI_LINKNAME_MAX]; 857 } simnet_fields_buf_t; 858 859 static ofmt_field_t simnet_fields[] = { 860 { "LINK", 12, 861 offsetof(simnet_fields_buf_t, simnet_name), print_default_cb}, 862 { "MEDIA", 20, 863 offsetof(simnet_fields_buf_t, simnet_media), print_default_cb}, 864 { "MACADDRESS", 18, 865 offsetof(simnet_fields_buf_t, simnet_macaddr), print_default_cb}, 866 { "OTHERLINK", 12, 867 offsetof(simnet_fields_buf_t, simnet_otherlink), print_default_cb}, 868 { NULL, 0, 0, NULL}} 869 ; 870 871 /* 872 * structures for 'dladm show-usage' 873 */ 874 875 typedef struct usage_fields_buf_s { 876 char usage_link[12]; 877 char usage_duration[10]; 878 char usage_ipackets[9]; 879 char usage_rbytes[10]; 880 char usage_opackets[9]; 881 char usage_obytes[10]; 882 char usage_bandwidth[14]; 883 } usage_fields_buf_t; 884 885 static ofmt_field_t usage_fields[] = { 886 { "LINK", 13, 887 offsetof(usage_fields_buf_t, usage_link), print_default_cb}, 888 { "DURATION", 11, 889 offsetof(usage_fields_buf_t, usage_duration), print_default_cb}, 890 { "IPACKETS", 10, 891 offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb}, 892 { "RBYTES", 11, 893 offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb}, 894 { "OPACKETS", 10, 895 offsetof(usage_fields_buf_t, usage_opackets), print_default_cb}, 896 { "OBYTES", 11, 897 offsetof(usage_fields_buf_t, usage_obytes), print_default_cb}, 898 { "BANDWIDTH", 15, 899 offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb}, 900 { NULL, 0, 0, NULL}} 901 ; 902 903 904 /* 905 * structures for 'dladm show-usage link' 906 */ 907 908 typedef struct usage_l_fields_buf_s { 909 char usage_l_link[12]; 910 char usage_l_stime[13]; 911 char usage_l_etime[13]; 912 char usage_l_rbytes[8]; 913 char usage_l_obytes[8]; 914 char usage_l_bandwidth[14]; 915 } usage_l_fields_buf_t; 916 917 static ofmt_field_t usage_l_fields[] = { 918 /* name, field width, offset */ 919 { "LINK", 13, 920 offsetof(usage_l_fields_buf_t, usage_l_link), print_default_cb}, 921 { "START", 14, 922 offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb}, 923 { "END", 14, 924 offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb}, 925 { "RBYTES", 9, 926 offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb}, 927 { "OBYTES", 9, 928 offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb}, 929 { "BANDWIDTH", 15, 930 offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb}, 931 { NULL, 0, 0, NULL}} 932 ; 933 934 static char *progname; 935 static sig_atomic_t signalled; 936 937 /* 938 * Handle to libdladm. Opened in main() before the sub-command 939 * specific function is called. 940 */ 941 static dladm_handle_t handle = NULL; 942 943 #define DLADM_ETHERSTUB_NAME "etherstub" 944 #define DLADM_IS_ETHERSTUB(id) (id == DATALINK_INVALID_LINKID) 945 946 static void 947 usage(void) 948 { 949 int i; 950 cmd_t *cmdp; 951 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ..." 952 "\n")); 953 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 954 cmdp = &cmds[i]; 955 if (cmdp->c_usage != NULL) 956 (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage)); 957 } 958 959 /* close dladm handle if it was opened */ 960 if (handle != NULL) 961 dladm_close(handle); 962 963 exit(1); 964 } 965 966 int 967 main(int argc, char *argv[]) 968 { 969 int i; 970 cmd_t *cmdp; 971 dladm_status_t status; 972 973 (void) setlocale(LC_ALL, ""); 974 #if !defined(TEXT_DOMAIN) 975 #define TEXT_DOMAIN "SYS_TEST" 976 #endif 977 (void) textdomain(TEXT_DOMAIN); 978 979 progname = argv[0]; 980 981 if (argc < 2) 982 usage(); 983 984 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 985 cmdp = &cmds[i]; 986 if (strcmp(argv[1], cmdp->c_name) == 0) { 987 /* Open the libdladm handle */ 988 if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) { 989 die_dlerr(status, 990 "could not open /dev/dld"); 991 } 992 993 cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage); 994 995 dladm_close(handle); 996 exit(0); 997 } 998 } 999 1000 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 1001 progname, argv[1]); 1002 usage(); 1003 1004 return (0); 1005 } 1006 1007 /*ARGSUSED*/ 1008 static int 1009 show_usage_date(dladm_usage_t *usage, void *arg) 1010 { 1011 show_usage_state_t *state = (show_usage_state_t *)arg; 1012 time_t stime; 1013 char timebuf[20]; 1014 dladm_status_t status; 1015 uint32_t flags; 1016 1017 /* 1018 * Only show usage information for existing links unless '-a' 1019 * is specified. 1020 */ 1021 if (!state->us_showall) { 1022 if ((status = dladm_name2info(handle, usage->du_name, 1023 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1024 return (status); 1025 } 1026 if ((flags & DLADM_OPT_ACTIVE) == 0) 1027 return (DLADM_STATUS_LINKINVAL); 1028 } 1029 1030 stime = usage->du_stime; 1031 (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y", 1032 localtime(&stime)); 1033 (void) printf("%s\n", timebuf); 1034 1035 return (DLADM_STATUS_OK); 1036 } 1037 1038 static int 1039 show_usage_time(dladm_usage_t *usage, void *arg) 1040 { 1041 show_usage_state_t *state = (show_usage_state_t *)arg; 1042 char buf[DLADM_STRSIZE]; 1043 usage_l_fields_buf_t ubuf; 1044 time_t time; 1045 double bw; 1046 dladm_status_t status; 1047 uint32_t flags; 1048 1049 /* 1050 * Only show usage information for existing links unless '-a' 1051 * is specified. 1052 */ 1053 if (!state->us_showall) { 1054 if ((status = dladm_name2info(handle, usage->du_name, 1055 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1056 return (status); 1057 } 1058 if ((flags & DLADM_OPT_ACTIVE) == 0) 1059 return (DLADM_STATUS_LINKINVAL); 1060 } 1061 1062 if (state->us_plot) { 1063 if (!state->us_printheader) { 1064 if (state->us_first) { 1065 (void) printf("# Time"); 1066 state->us_first = B_FALSE; 1067 } 1068 (void) printf(" %s", usage->du_name); 1069 if (usage->du_last) { 1070 (void) printf("\n"); 1071 state->us_first = B_TRUE; 1072 state->us_printheader = B_TRUE; 1073 } 1074 } else { 1075 if (state->us_first) { 1076 time = usage->du_etime; 1077 (void) strftime(buf, sizeof (buf), "%T", 1078 localtime(&time)); 1079 state->us_first = B_FALSE; 1080 (void) printf("%s", buf); 1081 } 1082 bw = (double)usage->du_bandwidth/1000; 1083 (void) printf(" %.2f", bw); 1084 if (usage->du_last) { 1085 (void) printf("\n"); 1086 state->us_first = B_TRUE; 1087 } 1088 } 1089 return (DLADM_STATUS_OK); 1090 } 1091 1092 bzero(&ubuf, sizeof (ubuf)); 1093 1094 (void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s", 1095 usage->du_name); 1096 time = usage->du_stime; 1097 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1098 (void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s", 1099 buf); 1100 time = usage->du_etime; 1101 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1102 (void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s", 1103 buf); 1104 (void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes), 1105 "%llu", usage->du_rbytes); 1106 (void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes), 1107 "%llu", usage->du_obytes); 1108 (void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth), 1109 "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1110 1111 ofmt_print(state->us_ofmt, &ubuf); 1112 return (DLADM_STATUS_OK); 1113 } 1114 1115 static int 1116 show_usage_res(dladm_usage_t *usage, void *arg) 1117 { 1118 show_usage_state_t *state = (show_usage_state_t *)arg; 1119 char buf[DLADM_STRSIZE]; 1120 usage_fields_buf_t ubuf; 1121 dladm_status_t status; 1122 uint32_t flags; 1123 1124 /* 1125 * Only show usage information for existing links unless '-a' 1126 * is specified. 1127 */ 1128 if (!state->us_showall) { 1129 if ((status = dladm_name2info(handle, usage->du_name, 1130 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1131 return (status); 1132 } 1133 if ((flags & DLADM_OPT_ACTIVE) == 0) 1134 return (DLADM_STATUS_LINKINVAL); 1135 } 1136 1137 bzero(&ubuf, sizeof (ubuf)); 1138 1139 (void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s", 1140 usage->du_name); 1141 (void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration), 1142 "%llu", usage->du_duration); 1143 (void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets), 1144 "%llu", usage->du_ipackets); 1145 (void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes), 1146 "%llu", usage->du_rbytes); 1147 (void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets), 1148 "%llu", usage->du_opackets); 1149 (void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes), 1150 "%llu", usage->du_obytes); 1151 (void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth), 1152 "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1153 1154 ofmt_print(state->us_ofmt, &ubuf); 1155 1156 return (DLADM_STATUS_OK); 1157 } 1158 1159 static boolean_t 1160 valid_formatspec(char *formatspec_str) 1161 { 1162 if (strcmp(formatspec_str, "gnuplot") == 0) 1163 return (B_TRUE); 1164 return (B_FALSE); 1165 1166 } 1167 1168 /*ARGSUSED*/ 1169 static void 1170 do_show_usage(int argc, char *argv[], const char *use) 1171 { 1172 char *file = NULL; 1173 int opt; 1174 dladm_status_t status; 1175 boolean_t d_arg = B_FALSE; 1176 char *stime = NULL; 1177 char *etime = NULL; 1178 char *resource = NULL; 1179 show_usage_state_t state; 1180 boolean_t o_arg = B_FALSE; 1181 boolean_t F_arg = B_FALSE; 1182 char *fields_str = NULL; 1183 char *formatspec_str = NULL; 1184 char *all_l_fields = 1185 "link,start,end,rbytes,obytes,bandwidth"; 1186 ofmt_handle_t ofmt; 1187 ofmt_status_t oferr; 1188 uint_t ofmtflags = 0; 1189 1190 bzero(&state, sizeof (show_usage_state_t)); 1191 state.us_parsable = B_FALSE; 1192 state.us_printheader = B_FALSE; 1193 state.us_plot = B_FALSE; 1194 state.us_first = B_TRUE; 1195 1196 while ((opt = getopt_long(argc, argv, "das:e:o:f:F:", 1197 usage_opts, NULL)) != -1) { 1198 switch (opt) { 1199 case 'd': 1200 d_arg = B_TRUE; 1201 break; 1202 case 'a': 1203 state.us_showall = B_TRUE; 1204 break; 1205 case 'f': 1206 file = optarg; 1207 break; 1208 case 's': 1209 stime = optarg; 1210 break; 1211 case 'e': 1212 etime = optarg; 1213 break; 1214 case 'o': 1215 o_arg = B_TRUE; 1216 fields_str = optarg; 1217 break; 1218 case 'F': 1219 state.us_plot = F_arg = B_TRUE; 1220 formatspec_str = optarg; 1221 break; 1222 default: 1223 die_opterr(optopt, opt, use); 1224 break; 1225 } 1226 } 1227 1228 if (file == NULL) 1229 die("show-usage requires a file"); 1230 1231 if (optind == (argc-1)) { 1232 uint32_t flags; 1233 1234 resource = argv[optind]; 1235 if (!state.us_showall && 1236 (((status = dladm_name2info(handle, resource, NULL, &flags, 1237 NULL, NULL)) != DLADM_STATUS_OK) || 1238 ((flags & DLADM_OPT_ACTIVE) == 0))) { 1239 die("invalid link: '%s'", resource); 1240 } 1241 } 1242 1243 if (F_arg && d_arg) 1244 die("incompatible -d and -F options"); 1245 1246 if (F_arg && valid_formatspec(formatspec_str) == B_FALSE) 1247 die("Format specifier %s not supported", formatspec_str); 1248 1249 if (state.us_parsable) 1250 ofmtflags |= OFMT_PARSABLE; 1251 1252 if (resource == NULL && stime == NULL && etime == NULL) { 1253 oferr = ofmt_open(fields_str, usage_fields, ofmtflags, 0, 1254 &ofmt); 1255 } else { 1256 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 1257 fields_str = all_l_fields; 1258 oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags, 0, 1259 &ofmt); 1260 1261 } 1262 dladm_ofmt_check(oferr, state.us_parsable, ofmt); 1263 state.us_ofmt = ofmt; 1264 1265 if (d_arg) { 1266 /* Print log dates */ 1267 status = dladm_usage_dates(show_usage_date, 1268 DLADM_LOGTYPE_LINK, file, resource, &state); 1269 } else if (resource == NULL && stime == NULL && etime == NULL && 1270 !F_arg) { 1271 /* Print summary */ 1272 status = dladm_usage_summary(show_usage_res, 1273 DLADM_LOGTYPE_LINK, file, &state); 1274 } else if (resource != NULL) { 1275 /* Print log entries for named resource */ 1276 status = dladm_walk_usage_res(show_usage_time, 1277 DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state); 1278 } else { 1279 /* Print time and information for each link */ 1280 status = dladm_walk_usage_time(show_usage_time, 1281 DLADM_LOGTYPE_LINK, file, stime, etime, &state); 1282 } 1283 1284 if (status != DLADM_STATUS_OK) 1285 die_dlerr(status, "show-usage"); 1286 ofmt_close(ofmt); 1287 } 1288 1289 static void 1290 do_create_aggr(int argc, char *argv[], const char *use) 1291 { 1292 int option; 1293 int key = 0; 1294 uint32_t policy = AGGR_POLICY_L4; 1295 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 1296 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 1297 dladm_aggr_port_attr_db_t port[MAXPORT]; 1298 uint_t n, ndev, nlink; 1299 uint8_t mac_addr[ETHERADDRL]; 1300 boolean_t mac_addr_fixed = B_FALSE; 1301 boolean_t P_arg = B_FALSE; 1302 boolean_t l_arg = B_FALSE; 1303 boolean_t u_arg = B_FALSE; 1304 boolean_t T_arg = B_FALSE; 1305 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1306 char *altroot = NULL; 1307 char name[MAXLINKNAMELEN]; 1308 char *devs[MAXPORT]; 1309 char *links[MAXPORT]; 1310 dladm_status_t status; 1311 dladm_status_t pstatus; 1312 char propstr[DLADM_STRSIZE]; 1313 dladm_arg_list_t *proplist = NULL; 1314 int i; 1315 datalink_id_t linkid; 1316 1317 ndev = nlink = opterr = 0; 1318 bzero(propstr, DLADM_STRSIZE); 1319 1320 while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:", 1321 lopts, NULL)) != -1) { 1322 switch (option) { 1323 case 'd': 1324 if (ndev + nlink >= MAXPORT) 1325 die("too many ports specified"); 1326 1327 devs[ndev++] = optarg; 1328 break; 1329 case 'P': 1330 if (P_arg) 1331 die_optdup(option); 1332 1333 P_arg = B_TRUE; 1334 if (!dladm_aggr_str2policy(optarg, &policy)) 1335 die("invalid policy '%s'", optarg); 1336 break; 1337 case 'u': 1338 if (u_arg) 1339 die_optdup(option); 1340 1341 u_arg = B_TRUE; 1342 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 1343 mac_addr)) 1344 die("invalid MAC address '%s'", optarg); 1345 break; 1346 case 'l': 1347 if (isdigit(optarg[strlen(optarg) - 1])) { 1348 1349 /* 1350 * Ended with digit, possibly a link name. 1351 */ 1352 if (ndev + nlink >= MAXPORT) 1353 die("too many ports specified"); 1354 1355 links[nlink++] = optarg; 1356 break; 1357 } 1358 /* FALLTHROUGH */ 1359 case 'L': 1360 if (l_arg) 1361 die_optdup(option); 1362 1363 l_arg = B_TRUE; 1364 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 1365 die("invalid LACP mode '%s'", optarg); 1366 break; 1367 case 'T': 1368 if (T_arg) 1369 die_optdup(option); 1370 1371 T_arg = B_TRUE; 1372 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 1373 die("invalid LACP timer value '%s'", optarg); 1374 break; 1375 case 't': 1376 flags &= ~DLADM_OPT_PERSIST; 1377 break; 1378 case 'f': 1379 flags |= DLADM_OPT_FORCE; 1380 break; 1381 case 'R': 1382 altroot = optarg; 1383 break; 1384 case 'p': 1385 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 1386 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 1387 DLADM_STRSIZE) 1388 die("property list too long '%s'", propstr); 1389 break; 1390 1391 default: 1392 die_opterr(optopt, option, use); 1393 break; 1394 } 1395 } 1396 1397 if (ndev + nlink == 0) 1398 usage(); 1399 1400 /* get key value or the aggregation name (required last argument) */ 1401 if (optind != (argc-1)) 1402 usage(); 1403 1404 if (!str2int(argv[optind], &key)) { 1405 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= 1406 MAXLINKNAMELEN) { 1407 die("link name too long '%s'", argv[optind]); 1408 } 1409 1410 if (!dladm_valid_linkname(name)) 1411 die("invalid link name '%s'", argv[optind]); 1412 } else { 1413 (void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key); 1414 } 1415 1416 if (altroot != NULL) 1417 altroot_cmd(altroot, argc, argv); 1418 1419 for (n = 0; n < ndev; n++) { 1420 if ((status = dladm_dev2linkid(handle, devs[n], 1421 &port[n].lp_linkid)) != DLADM_STATUS_OK) { 1422 die_dlerr(status, "invalid dev name '%s'", devs[n]); 1423 } 1424 } 1425 1426 for (n = 0; n < nlink; n++) { 1427 if ((status = dladm_name2info(handle, links[n], 1428 &port[ndev + n].lp_linkid, NULL, NULL, NULL)) != 1429 DLADM_STATUS_OK) { 1430 die_dlerr(status, "invalid link name '%s'", links[n]); 1431 } 1432 } 1433 1434 status = dladm_aggr_create(handle, name, key, ndev + nlink, port, 1435 policy, mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, 1436 lacp_timer, flags); 1437 if (status != DLADM_STATUS_OK) 1438 goto done; 1439 1440 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 1441 != DLADM_STATUS_OK) 1442 die("invalid aggregation property"); 1443 1444 if (proplist == NULL) 1445 return; 1446 1447 status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL); 1448 if (status != DLADM_STATUS_OK) 1449 goto done; 1450 1451 for (i = 0; i < proplist->al_count; i++) { 1452 dladm_arg_info_t *aip = &proplist->al_info[i]; 1453 1454 pstatus = dladm_set_linkprop(handle, linkid, aip->ai_name, 1455 aip->ai_val, aip->ai_count, flags); 1456 1457 if (pstatus != DLADM_STATUS_OK) { 1458 die_dlerr(pstatus, 1459 "aggr creation succeeded but " 1460 "could not set property '%s'", aip->ai_name); 1461 } 1462 } 1463 done: 1464 dladm_free_props(proplist); 1465 if (status != DLADM_STATUS_OK) { 1466 if (status == DLADM_STATUS_NONOTIF) { 1467 die_dlerr(status, "not all links have link up/down " 1468 "detection; must use -f (see dladm(1M))\n"); 1469 } else { 1470 die_dlerr(status, "create operation failed"); 1471 } 1472 } 1473 } 1474 1475 /* 1476 * arg is either the key or the aggr name. Validate it and convert it to 1477 * the linkid if altroot is NULL. 1478 */ 1479 static dladm_status_t 1480 i_dladm_aggr_get_linkid(const char *altroot, const char *arg, 1481 datalink_id_t *linkidp, uint32_t flags) 1482 { 1483 int key = 0; 1484 char *aggr = NULL; 1485 dladm_status_t status; 1486 1487 if (!str2int(arg, &key)) 1488 aggr = (char *)arg; 1489 1490 if (aggr == NULL && key == 0) 1491 return (DLADM_STATUS_LINKINVAL); 1492 1493 if (altroot != NULL) 1494 return (DLADM_STATUS_OK); 1495 1496 if (aggr != NULL) { 1497 status = dladm_name2info(handle, aggr, linkidp, NULL, NULL, 1498 NULL); 1499 } else { 1500 status = dladm_key2linkid(handle, key, linkidp, flags); 1501 } 1502 1503 return (status); 1504 } 1505 1506 static void 1507 do_delete_aggr(int argc, char *argv[], const char *use) 1508 { 1509 int option; 1510 char *altroot = NULL; 1511 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1512 dladm_status_t status; 1513 datalink_id_t linkid; 1514 1515 opterr = 0; 1516 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 1517 switch (option) { 1518 case 't': 1519 flags &= ~DLADM_OPT_PERSIST; 1520 break; 1521 case 'R': 1522 altroot = optarg; 1523 break; 1524 default: 1525 die_opterr(optopt, option, use); 1526 break; 1527 } 1528 } 1529 1530 /* get key value or the aggregation name (required last argument) */ 1531 if (optind != (argc-1)) 1532 usage(); 1533 1534 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1535 if (status != DLADM_STATUS_OK) 1536 goto done; 1537 1538 if (altroot != NULL) 1539 altroot_cmd(altroot, argc, argv); 1540 1541 status = dladm_aggr_delete(handle, linkid, flags); 1542 done: 1543 if (status != DLADM_STATUS_OK) 1544 die_dlerr(status, "delete operation failed"); 1545 } 1546 1547 static void 1548 do_add_aggr(int argc, char *argv[], const char *use) 1549 { 1550 int option; 1551 uint_t n, ndev, nlink; 1552 char *altroot = NULL; 1553 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1554 datalink_id_t linkid; 1555 dladm_status_t status; 1556 dladm_aggr_port_attr_db_t port[MAXPORT]; 1557 char *devs[MAXPORT]; 1558 char *links[MAXPORT]; 1559 1560 ndev = nlink = opterr = 0; 1561 while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts, 1562 NULL)) != -1) { 1563 switch (option) { 1564 case 'd': 1565 if (ndev + nlink >= MAXPORT) 1566 die("too many ports specified"); 1567 1568 devs[ndev++] = optarg; 1569 break; 1570 case 'l': 1571 if (ndev + nlink >= MAXPORT) 1572 die("too many ports specified"); 1573 1574 links[nlink++] = optarg; 1575 break; 1576 case 't': 1577 flags &= ~DLADM_OPT_PERSIST; 1578 break; 1579 case 'f': 1580 flags |= DLADM_OPT_FORCE; 1581 break; 1582 case 'R': 1583 altroot = optarg; 1584 break; 1585 default: 1586 die_opterr(optopt, option, use); 1587 break; 1588 } 1589 } 1590 1591 if (ndev + nlink == 0) 1592 usage(); 1593 1594 /* get key value or the aggregation name (required last argument) */ 1595 if (optind != (argc-1)) 1596 usage(); 1597 1598 if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, 1599 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) != 1600 DLADM_STATUS_OK) { 1601 goto done; 1602 } 1603 1604 if (altroot != NULL) 1605 altroot_cmd(altroot, argc, argv); 1606 1607 for (n = 0; n < ndev; n++) { 1608 if ((status = dladm_dev2linkid(handle, devs[n], 1609 &(port[n].lp_linkid))) != DLADM_STATUS_OK) { 1610 die_dlerr(status, "invalid <dev> '%s'", devs[n]); 1611 } 1612 } 1613 1614 for (n = 0; n < nlink; n++) { 1615 if ((status = dladm_name2info(handle, links[n], 1616 &port[n + ndev].lp_linkid, NULL, NULL, NULL)) != 1617 DLADM_STATUS_OK) { 1618 die_dlerr(status, "invalid <link> '%s'", links[n]); 1619 } 1620 } 1621 1622 status = dladm_aggr_add(handle, linkid, ndev + nlink, port, flags); 1623 done: 1624 if (status != DLADM_STATUS_OK) { 1625 /* 1626 * checking DLADM_STATUS_NOTSUP is a temporary workaround 1627 * and should be removed once 6399681 is fixed. 1628 */ 1629 if (status == DLADM_STATUS_NOTSUP) { 1630 (void) fprintf(stderr, 1631 gettext("%s: add operation failed: %s\n"), 1632 progname, 1633 gettext("link capabilities don't match")); 1634 dladm_close(handle); 1635 exit(ENOTSUP); 1636 } else if (status == DLADM_STATUS_NONOTIF) { 1637 die_dlerr(status, "not all links have link up/down " 1638 "detection; must use -f (see dladm(1M))\n"); 1639 } else { 1640 die_dlerr(status, "add operation failed"); 1641 } 1642 } 1643 } 1644 1645 static void 1646 do_remove_aggr(int argc, char *argv[], const char *use) 1647 { 1648 int option; 1649 dladm_aggr_port_attr_db_t port[MAXPORT]; 1650 uint_t n, ndev, nlink; 1651 char *devs[MAXPORT]; 1652 char *links[MAXPORT]; 1653 char *altroot = NULL; 1654 uint32_t flags; 1655 datalink_id_t linkid; 1656 dladm_status_t status; 1657 1658 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1659 ndev = nlink = opterr = 0; 1660 while ((option = getopt_long(argc, argv, ":d:l:R:t", 1661 lopts, NULL)) != -1) { 1662 switch (option) { 1663 case 'd': 1664 if (ndev + nlink >= MAXPORT) 1665 die("too many ports specified"); 1666 1667 devs[ndev++] = optarg; 1668 break; 1669 case 'l': 1670 if (ndev + nlink >= MAXPORT) 1671 die("too many ports specified"); 1672 1673 links[nlink++] = optarg; 1674 break; 1675 case 't': 1676 flags &= ~DLADM_OPT_PERSIST; 1677 break; 1678 case 'R': 1679 altroot = optarg; 1680 break; 1681 default: 1682 die_opterr(optopt, option, use); 1683 break; 1684 } 1685 } 1686 1687 if (ndev + nlink == 0) 1688 usage(); 1689 1690 /* get key value or the aggregation name (required last argument) */ 1691 if (optind != (argc-1)) 1692 usage(); 1693 1694 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1695 if (status != DLADM_STATUS_OK) 1696 goto done; 1697 1698 if (altroot != NULL) 1699 altroot_cmd(altroot, argc, argv); 1700 1701 for (n = 0; n < ndev; n++) { 1702 if ((status = dladm_dev2linkid(handle, devs[n], 1703 &(port[n].lp_linkid))) != DLADM_STATUS_OK) { 1704 die_dlerr(status, "invalid <dev> '%s'", devs[n]); 1705 } 1706 } 1707 1708 for (n = 0; n < nlink; n++) { 1709 if ((status = dladm_name2info(handle, links[n], 1710 &port[n + ndev].lp_linkid, NULL, NULL, NULL)) != 1711 DLADM_STATUS_OK) { 1712 die_dlerr(status, "invalid <link> '%s'", links[n]); 1713 } 1714 } 1715 1716 status = dladm_aggr_remove(handle, linkid, ndev + nlink, port, flags); 1717 done: 1718 if (status != DLADM_STATUS_OK) 1719 die_dlerr(status, "remove operation failed"); 1720 } 1721 1722 static void 1723 do_modify_aggr(int argc, char *argv[], const char *use) 1724 { 1725 int option; 1726 uint32_t policy = AGGR_POLICY_L4; 1727 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 1728 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 1729 uint8_t mac_addr[ETHERADDRL]; 1730 boolean_t mac_addr_fixed = B_FALSE; 1731 uint8_t modify_mask = 0; 1732 char *altroot = NULL; 1733 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1734 datalink_id_t linkid; 1735 dladm_status_t status; 1736 1737 opterr = 0; 1738 while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts, 1739 NULL)) != -1) { 1740 switch (option) { 1741 case 'P': 1742 if (modify_mask & DLADM_AGGR_MODIFY_POLICY) 1743 die_optdup(option); 1744 1745 modify_mask |= DLADM_AGGR_MODIFY_POLICY; 1746 1747 if (!dladm_aggr_str2policy(optarg, &policy)) 1748 die("invalid policy '%s'", optarg); 1749 break; 1750 case 'u': 1751 if (modify_mask & DLADM_AGGR_MODIFY_MAC) 1752 die_optdup(option); 1753 1754 modify_mask |= DLADM_AGGR_MODIFY_MAC; 1755 1756 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 1757 mac_addr)) 1758 die("invalid MAC address '%s'", optarg); 1759 break; 1760 case 'l': 1761 case 'L': 1762 if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE) 1763 die_optdup(option); 1764 1765 modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE; 1766 1767 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 1768 die("invalid LACP mode '%s'", optarg); 1769 break; 1770 case 'T': 1771 if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER) 1772 die_optdup(option); 1773 1774 modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER; 1775 1776 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 1777 die("invalid LACP timer value '%s'", optarg); 1778 break; 1779 case 't': 1780 flags &= ~DLADM_OPT_PERSIST; 1781 break; 1782 case 'R': 1783 altroot = optarg; 1784 break; 1785 default: 1786 die_opterr(optopt, option, use); 1787 break; 1788 } 1789 } 1790 1791 if (modify_mask == 0) 1792 die("at least one of the -PulT options must be specified"); 1793 1794 /* get key value or the aggregation name (required last argument) */ 1795 if (optind != (argc-1)) 1796 usage(); 1797 1798 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1799 if (status != DLADM_STATUS_OK) 1800 goto done; 1801 1802 if (altroot != NULL) 1803 altroot_cmd(altroot, argc, argv); 1804 1805 status = dladm_aggr_modify(handle, linkid, modify_mask, policy, 1806 mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, lacp_timer, 1807 flags); 1808 1809 done: 1810 if (status != DLADM_STATUS_OK) 1811 die_dlerr(status, "modify operation failed"); 1812 } 1813 1814 /*ARGSUSED*/ 1815 static void 1816 do_up_aggr(int argc, char *argv[], const char *use) 1817 { 1818 datalink_id_t linkid = DATALINK_ALL_LINKID; 1819 dladm_status_t status; 1820 1821 /* 1822 * get the key or the name of the aggregation (optional last argument) 1823 */ 1824 if (argc == 2) { 1825 if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid, 1826 DLADM_OPT_PERSIST)) != DLADM_STATUS_OK) 1827 goto done; 1828 } else if (argc > 2) { 1829 usage(); 1830 } 1831 1832 status = dladm_aggr_up(handle, linkid); 1833 done: 1834 if (status != DLADM_STATUS_OK) { 1835 if (argc == 2) { 1836 die_dlerr(status, 1837 "could not bring up aggregation '%s'", argv[1]); 1838 } else { 1839 die_dlerr(status, "could not bring aggregations up"); 1840 } 1841 } 1842 } 1843 1844 static void 1845 do_create_vlan(int argc, char *argv[], const char *use) 1846 { 1847 char *link = NULL; 1848 char drv[DLPI_LINKNAME_MAX]; 1849 uint_t ppa; 1850 datalink_id_t linkid; 1851 datalink_id_t dev_linkid; 1852 int vid = 0; 1853 int option; 1854 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 1855 char *altroot = NULL; 1856 char vlan[MAXLINKNAMELEN]; 1857 char propstr[DLADM_STRSIZE]; 1858 dladm_arg_list_t *proplist = NULL; 1859 dladm_status_t status; 1860 1861 opterr = 0; 1862 bzero(propstr, DLADM_STRSIZE); 1863 1864 while ((option = getopt_long(argc, argv, ":tfR:l:v:p:", 1865 lopts, NULL)) != -1) { 1866 switch (option) { 1867 case 'v': 1868 if (vid != 0) 1869 die_optdup(option); 1870 1871 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 1872 die("invalid VLAN identifier '%s'", optarg); 1873 1874 break; 1875 case 'l': 1876 if (link != NULL) 1877 die_optdup(option); 1878 1879 link = optarg; 1880 break; 1881 case 't': 1882 flags &= ~DLADM_OPT_PERSIST; 1883 break; 1884 case 'R': 1885 altroot = optarg; 1886 break; 1887 case 'p': 1888 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 1889 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 1890 DLADM_STRSIZE) 1891 die("property list too long '%s'", propstr); 1892 break; 1893 case 'f': 1894 flags |= DLADM_OPT_FORCE; 1895 break; 1896 default: 1897 die_opterr(optopt, option, use); 1898 break; 1899 } 1900 } 1901 1902 /* get vlan name if there is any */ 1903 if ((vid == 0) || (link == NULL) || (argc - optind > 1)) 1904 usage(); 1905 1906 if (optind == (argc - 1)) { 1907 if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >= 1908 MAXLINKNAMELEN) { 1909 die("vlan name too long '%s'", argv[optind]); 1910 } 1911 } else { 1912 if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) || 1913 (ppa >= 1000) || 1914 (dlpi_makelink(vlan, drv, vid * 1000 + ppa) != 1915 DLPI_SUCCESS)) { 1916 die("invalid link name '%s'", link); 1917 } 1918 } 1919 1920 if (altroot != NULL) 1921 altroot_cmd(altroot, argc, argv); 1922 1923 if (dladm_name2info(handle, link, &dev_linkid, NULL, NULL, NULL) != 1924 DLADM_STATUS_OK) { 1925 die("invalid link name '%s'", link); 1926 } 1927 1928 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 1929 != DLADM_STATUS_OK) 1930 die("invalid vlan property"); 1931 1932 if ((status = dladm_vlan_create(handle, vlan, dev_linkid, vid, proplist, 1933 flags, &linkid)) != DLADM_STATUS_OK) { 1934 die_dlerr(status, "create operation over %s failed", link); 1935 } 1936 } 1937 1938 static void 1939 do_delete_vlan(int argc, char *argv[], const char *use) 1940 { 1941 int option; 1942 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 1943 char *altroot = NULL; 1944 datalink_id_t linkid; 1945 dladm_status_t status; 1946 1947 opterr = 0; 1948 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 1949 switch (option) { 1950 case 't': 1951 flags &= ~DLADM_OPT_PERSIST; 1952 break; 1953 case 'R': 1954 altroot = optarg; 1955 break; 1956 default: 1957 die_opterr(optopt, option, use); 1958 break; 1959 } 1960 } 1961 1962 /* get VLAN link name (required last argument) */ 1963 if (optind != (argc - 1)) 1964 usage(); 1965 1966 if (altroot != NULL) 1967 altroot_cmd(altroot, argc, argv); 1968 1969 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 1970 NULL); 1971 if (status != DLADM_STATUS_OK) 1972 goto done; 1973 1974 status = dladm_vlan_delete(handle, linkid, flags); 1975 done: 1976 if (status != DLADM_STATUS_OK) 1977 die_dlerr(status, "delete operation failed"); 1978 } 1979 1980 /*ARGSUSED*/ 1981 static void 1982 do_up_vlan(int argc, char *argv[], const char *use) 1983 { 1984 do_up_vnic_common(argc, argv, use, B_TRUE); 1985 } 1986 1987 static void 1988 do_rename_link(int argc, char *argv[], const char *use) 1989 { 1990 int option; 1991 char *link1, *link2; 1992 char *altroot = NULL; 1993 dladm_status_t status; 1994 1995 opterr = 0; 1996 while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) { 1997 switch (option) { 1998 case 'R': 1999 altroot = optarg; 2000 break; 2001 default: 2002 die_opterr(optopt, option, use); 2003 break; 2004 } 2005 } 2006 2007 /* get link1 and link2 name (required the last 2 arguments) */ 2008 if (optind != (argc - 2)) 2009 usage(); 2010 2011 if (altroot != NULL) 2012 altroot_cmd(altroot, argc, argv); 2013 2014 link1 = argv[optind++]; 2015 link2 = argv[optind]; 2016 if ((status = dladm_rename_link(handle, link1, link2)) != 2017 DLADM_STATUS_OK) 2018 die_dlerr(status, "rename operation failed"); 2019 } 2020 2021 /*ARGSUSED*/ 2022 static void 2023 do_delete_phys(int argc, char *argv[], const char *use) 2024 { 2025 datalink_id_t linkid = DATALINK_ALL_LINKID; 2026 dladm_status_t status; 2027 2028 /* get link name (required the last argument) */ 2029 if (argc > 2) 2030 usage(); 2031 2032 if (argc == 2) { 2033 if ((status = dladm_name2info(handle, argv[1], &linkid, NULL, 2034 NULL, NULL)) != DLADM_STATUS_OK) 2035 die_dlerr(status, "cannot delete '%s'", argv[1]); 2036 } 2037 2038 if ((status = dladm_phys_delete(handle, linkid)) != DLADM_STATUS_OK) { 2039 if (argc == 2) 2040 die_dlerr(status, "cannot delete '%s'", argv[1]); 2041 else 2042 die_dlerr(status, "delete operation failed"); 2043 } 2044 } 2045 2046 /*ARGSUSED*/ 2047 static int 2048 i_dladm_walk_linkmap(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2049 { 2050 char name[MAXLINKNAMELEN]; 2051 char mediabuf[DLADM_STRSIZE]; 2052 char classbuf[DLADM_STRSIZE]; 2053 datalink_class_t class; 2054 uint32_t media; 2055 uint32_t flags; 2056 2057 if (dladm_datalink_id2info(dh, linkid, &flags, &class, &media, name, 2058 MAXLINKNAMELEN) == DLADM_STATUS_OK) { 2059 (void) dladm_class2str(class, classbuf); 2060 (void) dladm_media2str(media, mediabuf); 2061 (void) printf("%-12s%8d %-12s%-20s %6d\n", name, 2062 linkid, classbuf, mediabuf, flags); 2063 } 2064 return (DLADM_WALK_CONTINUE); 2065 } 2066 2067 /*ARGSUSED*/ 2068 static void 2069 do_show_linkmap(int argc, char *argv[], const char *use) 2070 { 2071 if (argc != 1) 2072 die("invalid arguments"); 2073 2074 (void) printf("%-12s%8s %-12s%-20s %6s\n", "NAME", "LINKID", 2075 "CLASS", "MEDIA", "FLAGS"); 2076 2077 (void) dladm_walk_datalink_id(i_dladm_walk_linkmap, handle, NULL, 2078 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 2079 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2080 } 2081 2082 /* 2083 * Delete inactive physical links. 2084 */ 2085 /*ARGSUSED*/ 2086 static int 2087 purge_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2088 { 2089 datalink_class_t class; 2090 uint32_t flags; 2091 2092 if (dladm_datalink_id2info(dh, linkid, &flags, &class, NULL, NULL, 0) 2093 != DLADM_STATUS_OK) { 2094 return (DLADM_WALK_CONTINUE); 2095 } 2096 2097 if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE)) 2098 (void) dladm_phys_delete(dh, linkid); 2099 2100 return (DLADM_WALK_CONTINUE); 2101 } 2102 2103 /*ARGSUSED*/ 2104 static void 2105 do_init_phys(int argc, char *argv[], const char *use) 2106 { 2107 di_node_t devtree; 2108 2109 if (argc > 1) 2110 usage(); 2111 2112 /* 2113 * Force all the devices to attach, therefore all the network physical 2114 * devices can be known to the dlmgmtd daemon. 2115 */ 2116 if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL) 2117 di_fini(devtree); 2118 2119 (void) dladm_walk_datalink_id(purge_phys, handle, NULL, 2120 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 2121 } 2122 2123 2124 /* 2125 * Print the active topology information. 2126 */ 2127 static dladm_status_t 2128 print_link_topology(show_state_t *state, datalink_id_t linkid, 2129 datalink_class_t class, link_fields_buf_t *lbuf) 2130 { 2131 uint32_t flags = state->ls_flags; 2132 dladm_status_t status = DLADM_STATUS_OK; 2133 char tmpbuf[MAXLINKNAMELEN]; 2134 2135 lbuf->link_over[0] = '\0'; 2136 2137 switch (class) { 2138 case DATALINK_CLASS_VLAN: { 2139 dladm_vlan_attr_t vinfo; 2140 2141 status = dladm_vlan_info(handle, linkid, &vinfo, flags); 2142 if (status != DLADM_STATUS_OK) 2143 break; 2144 status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, 2145 NULL, NULL, lbuf->link_over, sizeof (lbuf->link_over)); 2146 break; 2147 } 2148 2149 case DATALINK_CLASS_AGGR: { 2150 dladm_aggr_grp_attr_t ginfo; 2151 int i; 2152 2153 status = dladm_aggr_info(handle, linkid, &ginfo, flags); 2154 if (status != DLADM_STATUS_OK) 2155 break; 2156 2157 if (ginfo.lg_nports == 0) { 2158 status = DLADM_STATUS_BADVAL; 2159 break; 2160 } 2161 for (i = 0; i < ginfo.lg_nports; i++) { 2162 status = dladm_datalink_id2info(handle, 2163 ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, 2164 tmpbuf, sizeof (tmpbuf)); 2165 if (status != DLADM_STATUS_OK) { 2166 free(ginfo.lg_ports); 2167 break; 2168 } 2169 (void) strlcat(lbuf->link_over, tmpbuf, 2170 sizeof (lbuf->link_over)); 2171 if (i != (ginfo.lg_nports - 1)) { 2172 (void) strlcat(lbuf->link_over, " ", 2173 sizeof (lbuf->link_over)); 2174 } 2175 } 2176 free(ginfo.lg_ports); 2177 break; 2178 } 2179 2180 case DATALINK_CLASS_VNIC: { 2181 dladm_vnic_attr_t vinfo; 2182 2183 status = dladm_vnic_info(handle, linkid, &vinfo, flags); 2184 if (status == DLADM_STATUS_OK) 2185 status = dladm_datalink_id2info(handle, 2186 vinfo.va_link_id, NULL, NULL, NULL, lbuf->link_over, 2187 sizeof (lbuf->link_over)); 2188 break; 2189 } 2190 2191 case DATALINK_CLASS_SIMNET: { 2192 dladm_simnet_attr_t slinfo; 2193 2194 status = dladm_simnet_info(handle, linkid, &slinfo, flags); 2195 if (status == DLADM_STATUS_OK && 2196 slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID) 2197 status = dladm_datalink_id2info(handle, 2198 slinfo.sna_peer_link_id, NULL, NULL, NULL, 2199 lbuf->link_over, sizeof (lbuf->link_over)); 2200 break; 2201 } 2202 } 2203 2204 return (status); 2205 } 2206 2207 static dladm_status_t 2208 print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf) 2209 { 2210 char link[MAXLINKNAMELEN]; 2211 datalink_class_t class; 2212 uint_t mtu; 2213 uint32_t flags; 2214 dladm_status_t status; 2215 2216 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 2217 NULL, link, sizeof (link))) != DLADM_STATUS_OK) { 2218 goto done; 2219 } 2220 2221 if (!(state->ls_flags & flags)) { 2222 status = DLADM_STATUS_NOTFOUND; 2223 goto done; 2224 } 2225 2226 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2227 dladm_attr_t dlattr; 2228 2229 if (class == DATALINK_CLASS_PHYS) { 2230 dladm_phys_attr_t dpa; 2231 dlpi_handle_t dh; 2232 dlpi_info_t dlinfo; 2233 2234 if ((status = dladm_phys_info(handle, linkid, &dpa, 2235 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2236 goto done; 2237 } 2238 2239 if (!dpa.dp_novanity) 2240 goto link_mtu; 2241 2242 /* 2243 * This is a physical link that does not have 2244 * vanity naming support. 2245 */ 2246 if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) != 2247 DLPI_SUCCESS) { 2248 status = DLADM_STATUS_NOTFOUND; 2249 goto done; 2250 } 2251 2252 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 2253 dlpi_close(dh); 2254 status = DLADM_STATUS_BADARG; 2255 goto done; 2256 } 2257 2258 dlpi_close(dh); 2259 mtu = dlinfo.di_max_sdu; 2260 } else { 2261 link_mtu: 2262 status = dladm_info(handle, linkid, &dlattr); 2263 if (status != DLADM_STATUS_OK) 2264 goto done; 2265 mtu = dlattr.da_max_sdu; 2266 } 2267 } 2268 2269 (void) snprintf(lbuf->link_name, sizeof (lbuf->link_name), 2270 "%s", link); 2271 (void) dladm_class2str(class, lbuf->link_class); 2272 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2273 (void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu), 2274 "%u", mtu); 2275 (void) get_linkstate(link, B_TRUE, lbuf->link_state); 2276 } 2277 2278 status = print_link_topology(state, linkid, class, lbuf); 2279 if (status != DLADM_STATUS_OK) 2280 goto done; 2281 2282 done: 2283 return (status); 2284 } 2285 2286 /* ARGSUSED */ 2287 static int 2288 show_link(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2289 { 2290 show_state_t *state = (show_state_t *)arg; 2291 dladm_status_t status; 2292 link_fields_buf_t lbuf; 2293 2294 /* 2295 * first get all the link attributes into lbuf; 2296 */ 2297 bzero(&lbuf, sizeof (link_fields_buf_t)); 2298 status = print_link(state, linkid, &lbuf); 2299 2300 if (status != DLADM_STATUS_OK) 2301 goto done; 2302 2303 ofmt_print(state->ls_ofmt, &lbuf); 2304 2305 done: 2306 state->ls_status = status; 2307 return (DLADM_WALK_CONTINUE); 2308 } 2309 2310 static boolean_t 2311 print_link_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2312 { 2313 link_args_t *largs = ofarg->ofmt_cbarg; 2314 pktsum_t *diff_stats = largs->link_s_psum; 2315 2316 switch (ofarg->ofmt_id) { 2317 case LINK_S_LINK: 2318 (void) snprintf(buf, bufsize, "%s", largs->link_s_link); 2319 break; 2320 case LINK_S_IPKTS: 2321 (void) snprintf(buf, bufsize, "%llu", diff_stats->ipackets); 2322 break; 2323 case LINK_S_RBYTES: 2324 (void) snprintf(buf, bufsize, "%llu", diff_stats->rbytes); 2325 break; 2326 case LINK_S_IERRORS: 2327 (void) snprintf(buf, bufsize, "%u", diff_stats->ierrors); 2328 break; 2329 case LINK_S_OPKTS: 2330 (void) snprintf(buf, bufsize, "%llu", diff_stats->opackets); 2331 break; 2332 case LINK_S_OBYTES: 2333 (void) snprintf(buf, bufsize, "%llu", diff_stats->obytes); 2334 break; 2335 case LINK_S_OERRORS: 2336 (void) snprintf(buf, bufsize, "%u", diff_stats->oerrors); 2337 break; 2338 default: 2339 die("invalid input"); 2340 break; 2341 } 2342 return (B_TRUE); 2343 } 2344 2345 static int 2346 show_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2347 { 2348 char link[DLPI_LINKNAME_MAX]; 2349 datalink_class_t class; 2350 show_state_t *state = (show_state_t *)arg; 2351 pktsum_t stats, diff_stats; 2352 dladm_phys_attr_t dpa; 2353 link_args_t largs; 2354 2355 if (state->ls_firstonly) { 2356 if (state->ls_donefirst) 2357 return (DLADM_WALK_CONTINUE); 2358 state->ls_donefirst = B_TRUE; 2359 } else { 2360 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 2361 } 2362 2363 if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, link, 2364 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2365 return (DLADM_WALK_CONTINUE); 2366 } 2367 2368 if (class == DATALINK_CLASS_PHYS) { 2369 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) != 2370 DLADM_STATUS_OK) { 2371 return (DLADM_WALK_CONTINUE); 2372 } 2373 if (dpa.dp_novanity) 2374 get_mac_stats(dpa.dp_dev, &stats); 2375 else 2376 get_link_stats(link, &stats); 2377 } else { 2378 get_link_stats(link, &stats); 2379 } 2380 dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats); 2381 2382 largs.link_s_link = link; 2383 largs.link_s_psum = &diff_stats; 2384 ofmt_print(state->ls_ofmt, &largs); 2385 2386 state->ls_prevstats = stats; 2387 return (DLADM_WALK_CONTINUE); 2388 } 2389 2390 2391 static dladm_status_t 2392 print_aggr_info(show_grp_state_t *state, const char *link, 2393 dladm_aggr_grp_attr_t *ginfop) 2394 { 2395 char addr_str[ETHERADDRL * 3]; 2396 laggr_fields_buf_t lbuf; 2397 2398 (void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name), 2399 "%s", link); 2400 2401 (void) dladm_aggr_policy2str(ginfop->lg_policy, 2402 lbuf.laggr_policy); 2403 2404 if (ginfop->lg_mac_fixed) { 2405 (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); 2406 (void) snprintf(lbuf.laggr_addrpolicy, 2407 sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str); 2408 } else { 2409 (void) snprintf(lbuf.laggr_addrpolicy, 2410 sizeof (lbuf.laggr_addrpolicy), "auto"); 2411 } 2412 2413 2414 (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, 2415 lbuf.laggr_lacpactivity); 2416 (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, 2417 lbuf.laggr_lacptimer); 2418 (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----", 2419 ginfop->lg_force ? 'f' : '-'); 2420 2421 ofmt_print(state->gs_ofmt, &lbuf); 2422 2423 return (DLADM_STATUS_OK); 2424 } 2425 2426 static boolean_t 2427 print_xaggr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2428 { 2429 const laggr_args_t *l = ofarg->ofmt_cbarg; 2430 int portnum; 2431 boolean_t is_port = (l->laggr_lport >= 0); 2432 static char tmpbuf[DLADM_STRSIZE]; 2433 dladm_aggr_port_attr_t *portp; 2434 dladm_phys_attr_t dpa; 2435 dladm_status_t *stat, status = DLADM_STATUS_OK; 2436 2437 stat = l->laggr_status; 2438 2439 if (is_port) { 2440 portnum = l->laggr_lport; 2441 portp = &(l->laggr_ginfop->lg_ports[portnum]); 2442 if ((status = dladm_datalink_id2info(handle, 2443 portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) != 2444 DLADM_STATUS_OK) { 2445 goto err; 2446 } 2447 2448 if ((status = dladm_phys_info(handle, portp->lp_linkid, 2449 &dpa, DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2450 goto err; 2451 } 2452 } 2453 2454 switch (ofarg->ofmt_id) { 2455 case AGGR_X_LINK: 2456 (void) snprintf(buf, bufsize, "%s", 2457 (is_port && !l->laggr_parsable ? " " : l->laggr_link)); 2458 break; 2459 case AGGR_X_PORT: 2460 if (is_port) 2461 break; 2462 *stat = DLADM_STATUS_OK; 2463 return (B_TRUE); 2464 2465 case AGGR_X_SPEED: 2466 if (is_port) { 2467 (void) snprintf(buf, bufsize, "%uMb", 2468 (uint_t)((get_ifspeed(dpa.dp_dev, 2469 B_FALSE)) / 1000000ull)); 2470 } else { 2471 (void) snprintf(buf, bufsize, "%uMb", 2472 (uint_t)((get_ifspeed(l->laggr_link, 2473 B_TRUE)) / 1000000ull)); 2474 } 2475 break; 2476 2477 case AGGR_X_DUPLEX: 2478 if (is_port) 2479 (void) get_linkduplex(dpa.dp_dev, B_FALSE, tmpbuf); 2480 else 2481 (void) get_linkduplex(l->laggr_link, B_TRUE, tmpbuf); 2482 (void) strlcpy(buf, tmpbuf, bufsize); 2483 break; 2484 2485 case AGGR_X_STATE: 2486 if (is_port) 2487 (void) get_linkstate(dpa.dp_dev, B_FALSE, tmpbuf); 2488 else 2489 (void) get_linkstate(l->laggr_link, B_TRUE, tmpbuf); 2490 (void) strlcpy(buf, tmpbuf, bufsize); 2491 break; 2492 case AGGR_X_ADDRESS: 2493 (void) dladm_aggr_macaddr2str( 2494 (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac), 2495 tmpbuf); 2496 (void) strlcpy(buf, tmpbuf, bufsize); 2497 break; 2498 case AGGR_X_PORTSTATE: 2499 if (is_port) { 2500 (void) dladm_aggr_portstate2str(portp->lp_state, 2501 tmpbuf); 2502 (void) strlcpy(buf, tmpbuf, bufsize); 2503 } 2504 break; 2505 } 2506 err: 2507 *stat = status; 2508 return (B_TRUE); 2509 } 2510 2511 static dladm_status_t 2512 print_aggr_extended(show_grp_state_t *state, const char *link, 2513 dladm_aggr_grp_attr_t *ginfop) 2514 { 2515 int i; 2516 dladm_status_t status; 2517 laggr_args_t largs; 2518 2519 largs.laggr_lport = -1; 2520 largs.laggr_link = link; 2521 largs.laggr_ginfop = ginfop; 2522 largs.laggr_status = &status; 2523 largs.laggr_parsable = state->gs_parsable; 2524 2525 ofmt_print(state->gs_ofmt, &largs); 2526 2527 if (status != DLADM_STATUS_OK) 2528 goto done; 2529 2530 for (i = 0; i < ginfop->lg_nports; i++) { 2531 largs.laggr_lport = i; 2532 ofmt_print(state->gs_ofmt, &largs); 2533 if (status != DLADM_STATUS_OK) 2534 goto done; 2535 } 2536 2537 status = DLADM_STATUS_OK; 2538 done: 2539 return (status); 2540 } 2541 2542 static boolean_t 2543 print_lacp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2544 { 2545 const laggr_args_t *l = ofarg->ofmt_cbarg; 2546 int portnum; 2547 boolean_t is_port = (l->laggr_lport >= 0); 2548 dladm_aggr_port_attr_t *portp; 2549 dladm_status_t *stat, status; 2550 aggr_lacp_state_t *lstate; 2551 2552 if (!is_port) { 2553 return (B_FALSE); /* cannot happen! */ 2554 } 2555 2556 stat = l->laggr_status; 2557 2558 portnum = l->laggr_lport; 2559 portp = &(l->laggr_ginfop->lg_ports[portnum]); 2560 2561 if ((status = dladm_datalink_id2info(handle, portp->lp_linkid, 2562 NULL, NULL, NULL, buf, bufsize)) != DLADM_STATUS_OK) { 2563 goto err; 2564 } 2565 lstate = &(portp->lp_lacp_state); 2566 2567 switch (ofarg->ofmt_id) { 2568 case AGGR_L_LINK: 2569 (void) snprintf(buf, bufsize, "%s", 2570 (portnum > 0 ? "" : l->laggr_link)); 2571 break; 2572 2573 case AGGR_L_PORT: 2574 /* 2575 * buf already contains portname as a result of the 2576 * earlier call to dladm_datalink_id2info(). 2577 */ 2578 break; 2579 2580 case AGGR_L_AGGREGATABLE: 2581 (void) snprintf(buf, bufsize, "%s", 2582 (lstate->bit.aggregation ? "yes" : "no")); 2583 break; 2584 2585 case AGGR_L_SYNC: 2586 (void) snprintf(buf, bufsize, "%s", 2587 (lstate->bit.sync ? "yes" : "no")); 2588 break; 2589 2590 case AGGR_L_COLL: 2591 (void) snprintf(buf, bufsize, "%s", 2592 (lstate->bit.collecting ? "yes" : "no")); 2593 break; 2594 2595 case AGGR_L_DIST: 2596 (void) snprintf(buf, bufsize, "%s", 2597 (lstate->bit.distributing ? "yes" : "no")); 2598 break; 2599 2600 case AGGR_L_DEFAULTED: 2601 (void) snprintf(buf, bufsize, "%s", 2602 (lstate->bit.defaulted ? "yes" : "no")); 2603 break; 2604 2605 case AGGR_L_EXPIRED: 2606 (void) snprintf(buf, bufsize, "%s", 2607 (lstate->bit.expired ? "yes" : "no")); 2608 break; 2609 } 2610 2611 *stat = DLADM_STATUS_OK; 2612 return (B_TRUE); 2613 2614 err: 2615 *stat = status; 2616 return (B_TRUE); 2617 } 2618 2619 static dladm_status_t 2620 print_aggr_lacp(show_grp_state_t *state, const char *link, 2621 dladm_aggr_grp_attr_t *ginfop) 2622 { 2623 int i; 2624 dladm_status_t status; 2625 laggr_args_t largs; 2626 2627 largs.laggr_link = link; 2628 largs.laggr_ginfop = ginfop; 2629 largs.laggr_status = &status; 2630 2631 for (i = 0; i < ginfop->lg_nports; i++) { 2632 largs.laggr_lport = i; 2633 ofmt_print(state->gs_ofmt, &largs); 2634 if (status != DLADM_STATUS_OK) 2635 goto done; 2636 } 2637 2638 status = DLADM_STATUS_OK; 2639 done: 2640 return (status); 2641 } 2642 2643 static boolean_t 2644 print_aggr_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2645 { 2646 const laggr_args_t *l = ofarg->ofmt_cbarg; 2647 int portnum; 2648 boolean_t is_port = (l->laggr_lport >= 0); 2649 dladm_aggr_port_attr_t *portp; 2650 dladm_status_t *stat, status; 2651 pktsum_t *diff_stats; 2652 2653 stat = l->laggr_status; 2654 *stat = DLADM_STATUS_OK; 2655 2656 if (is_port) { 2657 portnum = l->laggr_lport; 2658 portp = &(l->laggr_ginfop->lg_ports[portnum]); 2659 2660 if ((status = dladm_datalink_id2info(handle, 2661 portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) != 2662 DLADM_STATUS_OK) { 2663 goto err; 2664 } 2665 diff_stats = l->laggr_diffstats; 2666 } 2667 2668 switch (ofarg->ofmt_id) { 2669 case AGGR_S_LINK: 2670 (void) snprintf(buf, bufsize, "%s", 2671 (is_port ? "" : l->laggr_link)); 2672 break; 2673 case AGGR_S_PORT: 2674 /* 2675 * if (is_port), buf has port name. Otherwise we print 2676 * STR_UNDEF_VAL 2677 */ 2678 break; 2679 2680 case AGGR_S_IPKTS: 2681 if (is_port) { 2682 (void) snprintf(buf, bufsize, "%llu", 2683 diff_stats->ipackets); 2684 } else { 2685 (void) snprintf(buf, bufsize, "%llu", 2686 l->laggr_pktsumtot->ipackets); 2687 } 2688 break; 2689 2690 case AGGR_S_RBYTES: 2691 if (is_port) { 2692 (void) snprintf(buf, bufsize, "%llu", 2693 diff_stats->rbytes); 2694 } else { 2695 (void) snprintf(buf, bufsize, "%llu", 2696 l->laggr_pktsumtot->rbytes); 2697 } 2698 break; 2699 2700 case AGGR_S_OPKTS: 2701 if (is_port) { 2702 (void) snprintf(buf, bufsize, "%llu", 2703 diff_stats->opackets); 2704 } else { 2705 (void) snprintf(buf, bufsize, "%llu", 2706 l->laggr_pktsumtot->opackets); 2707 } 2708 break; 2709 case AGGR_S_OBYTES: 2710 if (is_port) { 2711 (void) snprintf(buf, bufsize, "%llu", 2712 diff_stats->obytes); 2713 } else { 2714 (void) snprintf(buf, bufsize, "%llu", 2715 l->laggr_pktsumtot->obytes); 2716 } 2717 break; 2718 2719 case AGGR_S_IPKTDIST: 2720 if (is_port) { 2721 (void) snprintf(buf, bufsize, "%-6.1f", 2722 (double)diff_stats->ipackets/ 2723 (double)l->laggr_pktsumtot->ipackets * 100); 2724 } 2725 break; 2726 case AGGR_S_OPKTDIST: 2727 if (is_port) { 2728 (void) snprintf(buf, bufsize, "%-6.1f", 2729 (double)diff_stats->opackets/ 2730 (double)l->laggr_pktsumtot->opackets * 100); 2731 } 2732 break; 2733 } 2734 return (B_TRUE); 2735 2736 err: 2737 *stat = status; 2738 return (B_TRUE); 2739 } 2740 2741 static dladm_status_t 2742 print_aggr_stats(show_grp_state_t *state, const char *link, 2743 dladm_aggr_grp_attr_t *ginfop) 2744 { 2745 dladm_phys_attr_t dpa; 2746 dladm_aggr_port_attr_t *portp; 2747 pktsum_t pktsumtot, *port_stat; 2748 dladm_status_t status; 2749 int i; 2750 laggr_args_t largs; 2751 2752 /* sum the ports statistics */ 2753 bzero(&pktsumtot, sizeof (pktsumtot)); 2754 2755 /* Allocate memory to keep stats of each port */ 2756 port_stat = malloc(ginfop->lg_nports * sizeof (pktsum_t)); 2757 if (port_stat == NULL) { 2758 /* Bail out; no memory */ 2759 return (DLADM_STATUS_NOMEM); 2760 } 2761 2762 2763 for (i = 0; i < ginfop->lg_nports; i++) { 2764 2765 portp = &(ginfop->lg_ports[i]); 2766 if ((status = dladm_phys_info(handle, portp->lp_linkid, &dpa, 2767 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2768 goto done; 2769 } 2770 2771 get_mac_stats(dpa.dp_dev, &port_stat[i]); 2772 2773 /* 2774 * Let's re-use gs_prevstats[] to store the difference of the 2775 * counters since last use. We will store the new stats from 2776 * port_stat[] once we have the stats displayed. 2777 */ 2778 2779 dladm_stats_diff(&state->gs_prevstats[i], &port_stat[i], 2780 &state->gs_prevstats[i]); 2781 dladm_stats_total(&pktsumtot, &pktsumtot, 2782 &state->gs_prevstats[i]); 2783 } 2784 2785 largs.laggr_lport = -1; 2786 largs.laggr_link = link; 2787 largs.laggr_ginfop = ginfop; 2788 largs.laggr_status = &status; 2789 largs.laggr_pktsumtot = &pktsumtot; 2790 2791 ofmt_print(state->gs_ofmt, &largs); 2792 2793 if (status != DLADM_STATUS_OK) 2794 goto done; 2795 2796 for (i = 0; i < ginfop->lg_nports; i++) { 2797 largs.laggr_lport = i; 2798 largs.laggr_diffstats = &state->gs_prevstats[i]; 2799 ofmt_print(state->gs_ofmt, &largs); 2800 if (status != DLADM_STATUS_OK) 2801 goto done; 2802 } 2803 2804 status = DLADM_STATUS_OK; 2805 for (i = 0; i < ginfop->lg_nports; i++) 2806 state->gs_prevstats[i] = port_stat[i]; 2807 2808 done: 2809 free(port_stat); 2810 return (status); 2811 } 2812 2813 static dladm_status_t 2814 print_aggr(show_grp_state_t *state, datalink_id_t linkid) 2815 { 2816 char link[MAXLINKNAMELEN]; 2817 dladm_aggr_grp_attr_t ginfo; 2818 uint32_t flags; 2819 dladm_status_t status; 2820 2821 bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t)); 2822 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 2823 NULL, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 2824 return (status); 2825 } 2826 2827 if (!(state->gs_flags & flags)) 2828 return (DLADM_STATUS_NOTFOUND); 2829 2830 status = dladm_aggr_info(handle, linkid, &ginfo, state->gs_flags); 2831 if (status != DLADM_STATUS_OK) 2832 return (status); 2833 2834 if (state->gs_lacp) 2835 status = print_aggr_lacp(state, link, &ginfo); 2836 else if (state->gs_extended) 2837 status = print_aggr_extended(state, link, &ginfo); 2838 else if (state->gs_stats) 2839 status = print_aggr_stats(state, link, &ginfo); 2840 else 2841 status = print_aggr_info(state, link, &ginfo); 2842 2843 done: 2844 free(ginfo.lg_ports); 2845 return (status); 2846 } 2847 2848 /* ARGSUSED */ 2849 static int 2850 show_aggr(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2851 { 2852 show_grp_state_t *state = arg; 2853 2854 state->gs_status = print_aggr(state, linkid); 2855 return (DLADM_WALK_CONTINUE); 2856 } 2857 2858 static void 2859 do_show_link(int argc, char *argv[], const char *use) 2860 { 2861 int option; 2862 boolean_t s_arg = B_FALSE; 2863 boolean_t S_arg = B_FALSE; 2864 boolean_t i_arg = B_FALSE; 2865 uint32_t flags = DLADM_OPT_ACTIVE; 2866 boolean_t p_arg = B_FALSE; 2867 datalink_id_t linkid = DATALINK_ALL_LINKID; 2868 char linkname[MAXLINKNAMELEN]; 2869 uint32_t interval = 0; 2870 show_state_t state; 2871 dladm_status_t status; 2872 boolean_t o_arg = B_FALSE; 2873 char *fields_str = NULL; 2874 char *all_active_fields = "link,class,mtu,state,over"; 2875 char *all_inactive_fields = "link,class,over"; 2876 char *allstat_fields = 2877 "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; 2878 ofmt_handle_t ofmt; 2879 ofmt_status_t oferr; 2880 uint_t ofmtflags = 0; 2881 2882 bzero(&state, sizeof (state)); 2883 2884 opterr = 0; 2885 while ((option = getopt_long(argc, argv, ":pPsSi:o:", 2886 show_lopts, NULL)) != -1) { 2887 switch (option) { 2888 case 'p': 2889 if (p_arg) 2890 die_optdup(option); 2891 2892 p_arg = B_TRUE; 2893 break; 2894 case 's': 2895 if (s_arg) 2896 die_optdup(option); 2897 2898 s_arg = B_TRUE; 2899 break; 2900 case 'P': 2901 if (flags != DLADM_OPT_ACTIVE) 2902 die_optdup(option); 2903 2904 flags = DLADM_OPT_PERSIST; 2905 break; 2906 case 'S': 2907 if (S_arg) 2908 die_optdup(option); 2909 2910 S_arg = B_TRUE; 2911 break; 2912 case 'o': 2913 o_arg = B_TRUE; 2914 fields_str = optarg; 2915 break; 2916 case 'i': 2917 if (i_arg) 2918 die_optdup(option); 2919 2920 i_arg = B_TRUE; 2921 if (!dladm_str2interval(optarg, &interval)) 2922 die("invalid interval value '%s'", optarg); 2923 break; 2924 default: 2925 die_opterr(optopt, option, use); 2926 break; 2927 } 2928 } 2929 2930 if (i_arg && !(s_arg || S_arg)) 2931 die("the option -i can be used only with -s or -S"); 2932 2933 if (s_arg && S_arg) 2934 die("the -s option cannot be used with -S"); 2935 2936 if (s_arg && flags != DLADM_OPT_ACTIVE) 2937 die("the option -P cannot be used with -s"); 2938 2939 if (S_arg && (p_arg || flags != DLADM_OPT_ACTIVE)) 2940 die("the option -%c cannot be used with -S", p_arg ? 'p' : 'P'); 2941 2942 /* get link name (optional last argument) */ 2943 if (optind == (argc-1)) { 2944 uint32_t f; 2945 2946 if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN) 2947 >= MAXLINKNAMELEN) { 2948 (void) fprintf(stderr, 2949 gettext("%s: link name too long\n"), 2950 progname); 2951 dladm_close(handle); 2952 exit(1); 2953 } 2954 if ((status = dladm_name2info(handle, linkname, &linkid, &f, 2955 NULL, NULL)) != DLADM_STATUS_OK) { 2956 die_dlerr(status, "link %s is not valid", linkname); 2957 } 2958 2959 if (!(f & flags)) { 2960 die_dlerr(DLADM_STATUS_BADARG, "link %s is %s", 2961 argv[optind], flags == DLADM_OPT_PERSIST ? 2962 "a temporary link" : "temporarily removed"); 2963 } 2964 } else if (optind != argc) { 2965 usage(); 2966 } 2967 2968 if (p_arg && !o_arg) 2969 die("-p requires -o"); 2970 2971 if (S_arg) { 2972 dladm_continuous(handle, linkid, NULL, interval, LINK_REPORT); 2973 return; 2974 } 2975 2976 if (p_arg && strcasecmp(fields_str, "all") == 0) 2977 die("\"-o all\" is invalid with -p"); 2978 2979 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 2980 if (s_arg) 2981 fields_str = allstat_fields; 2982 else if (flags & DLADM_OPT_ACTIVE) 2983 fields_str = all_active_fields; 2984 else 2985 fields_str = all_inactive_fields; 2986 } 2987 2988 state.ls_parsable = p_arg; 2989 state.ls_flags = flags; 2990 state.ls_donefirst = B_FALSE; 2991 2992 if (s_arg) { 2993 link_stats(linkid, interval, fields_str, &state); 2994 return; 2995 } 2996 if (state.ls_parsable) 2997 ofmtflags |= OFMT_PARSABLE; 2998 oferr = ofmt_open(fields_str, link_fields, ofmtflags, 0, &ofmt); 2999 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 3000 state.ls_ofmt = ofmt; 3001 3002 if (linkid == DATALINK_ALL_LINKID) { 3003 (void) dladm_walk_datalink_id(show_link, handle, &state, 3004 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 3005 } else { 3006 (void) show_link(handle, linkid, &state); 3007 if (state.ls_status != DLADM_STATUS_OK) { 3008 die_dlerr(state.ls_status, "failed to show link %s", 3009 argv[optind]); 3010 } 3011 } 3012 ofmt_close(ofmt); 3013 } 3014 3015 static void 3016 do_show_aggr(int argc, char *argv[], const char *use) 3017 { 3018 boolean_t L_arg = B_FALSE; 3019 boolean_t s_arg = B_FALSE; 3020 boolean_t i_arg = B_FALSE; 3021 boolean_t p_arg = B_FALSE; 3022 boolean_t x_arg = B_FALSE; 3023 show_grp_state_t state; 3024 uint32_t flags = DLADM_OPT_ACTIVE; 3025 datalink_id_t linkid = DATALINK_ALL_LINKID; 3026 int option; 3027 uint32_t interval = 0; 3028 int key; 3029 dladm_status_t status; 3030 boolean_t o_arg = B_FALSE; 3031 char *fields_str = NULL; 3032 char *all_fields = 3033 "link,policy,addrpolicy,lacpactivity,lacptimer,flags"; 3034 char *all_lacp_fields = 3035 "link,port,aggregatable,sync,coll,dist,defaulted,expired"; 3036 char *all_stats_fields = 3037 "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist"; 3038 char *all_extended_fields = 3039 "link,port,speed,duplex,state,address,portstate"; 3040 ofmt_field_t *pf; 3041 ofmt_handle_t ofmt; 3042 ofmt_status_t oferr; 3043 uint_t ofmtflags = 0; 3044 3045 opterr = 0; 3046 while ((option = getopt_long(argc, argv, ":LpPxsi:o:", 3047 show_lopts, NULL)) != -1) { 3048 switch (option) { 3049 case 'L': 3050 if (L_arg) 3051 die_optdup(option); 3052 3053 L_arg = B_TRUE; 3054 break; 3055 case 'p': 3056 if (p_arg) 3057 die_optdup(option); 3058 3059 p_arg = B_TRUE; 3060 break; 3061 case 'x': 3062 if (x_arg) 3063 die_optdup(option); 3064 3065 x_arg = B_TRUE; 3066 break; 3067 case 'P': 3068 if (flags != DLADM_OPT_ACTIVE) 3069 die_optdup(option); 3070 3071 flags = DLADM_OPT_PERSIST; 3072 break; 3073 case 's': 3074 if (s_arg) 3075 die_optdup(option); 3076 3077 s_arg = B_TRUE; 3078 break; 3079 case 'o': 3080 o_arg = B_TRUE; 3081 fields_str = optarg; 3082 break; 3083 case 'i': 3084 if (i_arg) 3085 die_optdup(option); 3086 3087 i_arg = B_TRUE; 3088 if (!dladm_str2interval(optarg, &interval)) 3089 die("invalid interval value '%s'", optarg); 3090 break; 3091 default: 3092 die_opterr(optopt, option, use); 3093 break; 3094 } 3095 } 3096 3097 if (p_arg && !o_arg) 3098 die("-p requires -o"); 3099 3100 if (p_arg && strcasecmp(fields_str, "all") == 0) 3101 die("\"-o all\" is invalid with -p"); 3102 3103 if (i_arg && !s_arg) 3104 die("the option -i can be used only with -s"); 3105 3106 if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) { 3107 die("the option -%c cannot be used with -s", 3108 L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P'))); 3109 } 3110 3111 if (L_arg && flags != DLADM_OPT_ACTIVE) 3112 die("the option -P cannot be used with -L"); 3113 3114 if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE)) 3115 die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P'); 3116 3117 /* get aggregation key or aggrname (optional last argument) */ 3118 if (optind == (argc-1)) { 3119 if (!str2int(argv[optind], &key)) { 3120 status = dladm_name2info(handle, argv[optind], 3121 &linkid, NULL, NULL, NULL); 3122 } else { 3123 status = dladm_key2linkid(handle, (uint16_t)key, 3124 &linkid, DLADM_OPT_ACTIVE); 3125 } 3126 3127 if (status != DLADM_STATUS_OK) 3128 die("non-existent aggregation '%s'", argv[optind]); 3129 3130 } else if (optind != argc) { 3131 usage(); 3132 } 3133 3134 bzero(&state, sizeof (state)); 3135 state.gs_lacp = L_arg; 3136 state.gs_stats = s_arg; 3137 state.gs_flags = flags; 3138 state.gs_parsable = p_arg; 3139 state.gs_extended = x_arg; 3140 3141 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3142 if (state.gs_lacp) 3143 fields_str = all_lacp_fields; 3144 else if (state.gs_stats) 3145 fields_str = all_stats_fields; 3146 else if (state.gs_extended) 3147 fields_str = all_extended_fields; 3148 else 3149 fields_str = all_fields; 3150 } 3151 3152 if (state.gs_lacp) { 3153 pf = aggr_l_fields; 3154 } else if (state.gs_stats) { 3155 pf = aggr_s_fields; 3156 } else if (state.gs_extended) { 3157 pf = aggr_x_fields; 3158 } else { 3159 pf = laggr_fields; 3160 } 3161 3162 if (state.gs_parsable) 3163 ofmtflags |= OFMT_PARSABLE; 3164 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 3165 dladm_ofmt_check(oferr, state.gs_parsable, ofmt); 3166 state.gs_ofmt = ofmt; 3167 3168 if (s_arg) { 3169 aggr_stats(linkid, &state, interval); 3170 ofmt_close(ofmt); 3171 return; 3172 } 3173 3174 if (linkid == DATALINK_ALL_LINKID) { 3175 (void) dladm_walk_datalink_id(show_aggr, handle, &state, 3176 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); 3177 } else { 3178 (void) show_aggr(handle, linkid, &state); 3179 if (state.gs_status != DLADM_STATUS_OK) { 3180 die_dlerr(state.gs_status, "failed to show aggr %s", 3181 argv[optind]); 3182 } 3183 } 3184 ofmt_close(ofmt); 3185 } 3186 3187 static dladm_status_t 3188 print_phys_default(show_state_t *state, datalink_id_t linkid, 3189 const char *link, uint32_t flags, uint32_t media) 3190 { 3191 dladm_phys_attr_t dpa; 3192 dladm_status_t status; 3193 link_fields_buf_t pattr; 3194 3195 status = dladm_phys_info(handle, linkid, &dpa, state->ls_flags); 3196 if (status != DLADM_STATUS_OK) 3197 goto done; 3198 3199 (void) snprintf(pattr.link_phys_device, 3200 sizeof (pattr.link_phys_device), "%s", dpa.dp_dev); 3201 (void) dladm_media2str(media, pattr.link_phys_media); 3202 if (state->ls_flags == DLADM_OPT_ACTIVE) { 3203 boolean_t islink; 3204 3205 if (!dpa.dp_novanity) { 3206 (void) strlcpy(pattr.link_name, link, 3207 sizeof (pattr.link_name)); 3208 islink = B_TRUE; 3209 } else { 3210 /* 3211 * This is a physical link that does not have 3212 * vanity naming support. 3213 */ 3214 (void) strlcpy(pattr.link_name, dpa.dp_dev, 3215 sizeof (pattr.link_name)); 3216 islink = B_FALSE; 3217 } 3218 3219 (void) get_linkstate(pattr.link_name, islink, 3220 pattr.link_phys_state); 3221 (void) snprintf(pattr.link_phys_speed, 3222 sizeof (pattr.link_phys_speed), "%u", 3223 (uint_t)((get_ifspeed(pattr.link_name, 3224 islink)) / 1000000ull)); 3225 (void) get_linkduplex(pattr.link_name, islink, 3226 pattr.link_phys_duplex); 3227 } else { 3228 (void) snprintf(pattr.link_name, sizeof (pattr.link_name), 3229 "%s", link); 3230 (void) snprintf(pattr.link_flags, sizeof (pattr.link_flags), 3231 "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r'); 3232 } 3233 3234 ofmt_print(state->ls_ofmt, &pattr); 3235 3236 done: 3237 return (status); 3238 } 3239 3240 typedef struct { 3241 show_state_t *ms_state; 3242 char *ms_link; 3243 dladm_macaddr_attr_t *ms_mac_attr; 3244 } print_phys_mac_state_t; 3245 3246 /* 3247 * callback for ofmt_print() 3248 */ 3249 static boolean_t 3250 print_phys_one_mac_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3251 { 3252 print_phys_mac_state_t *mac_state = ofarg->ofmt_cbarg; 3253 dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr; 3254 boolean_t is_primary = (attr->ma_slot == 0); 3255 boolean_t is_parsable = mac_state->ms_state->ls_parsable; 3256 3257 switch (ofarg->ofmt_id) { 3258 case PHYS_M_LINK: 3259 (void) snprintf(buf, bufsize, "%s", 3260 (is_primary || is_parsable) ? mac_state->ms_link : " "); 3261 break; 3262 case PHYS_M_SLOT: 3263 if (is_primary) 3264 (void) snprintf(buf, bufsize, gettext("primary")); 3265 else 3266 (void) snprintf(buf, bufsize, "%d", attr->ma_slot); 3267 break; 3268 case PHYS_M_ADDRESS: 3269 (void) dladm_aggr_macaddr2str(attr->ma_addr, buf); 3270 break; 3271 case PHYS_M_INUSE: 3272 (void) snprintf(buf, bufsize, "%s", 3273 attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") : 3274 gettext("no")); 3275 break; 3276 case PHYS_M_CLIENT: 3277 /* 3278 * CR 6678526: resolve link id to actual link name if 3279 * it is valid. 3280 */ 3281 (void) snprintf(buf, bufsize, "%s", attr->ma_client_name); 3282 break; 3283 } 3284 3285 return (B_TRUE); 3286 } 3287 3288 typedef struct { 3289 show_state_t *hs_state; 3290 char *hs_link; 3291 dladm_hwgrp_attr_t *hs_grp_attr; 3292 } print_phys_hwgrp_state_t; 3293 3294 static boolean_t 3295 print_phys_one_hwgrp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3296 { 3297 print_phys_hwgrp_state_t *hg_state = ofarg->ofmt_cbarg; 3298 dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr; 3299 3300 switch (ofarg->ofmt_id) { 3301 case PHYS_H_LINK: 3302 (void) snprintf(buf, bufsize, "%s", attr->hg_link_name); 3303 break; 3304 case PHYS_H_GROUP: 3305 (void) snprintf(buf, bufsize, "%d", attr->hg_grp_num); 3306 break; 3307 case PHYS_H_GRPTYPE: 3308 (void) snprintf(buf, bufsize, "%s", 3309 attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX"); 3310 break; 3311 case PHYS_H_RINGS: 3312 (void) snprintf(buf, bufsize, "%d", attr->hg_n_rings); 3313 break; 3314 case PHYS_H_CLIENTS: 3315 if (attr->hg_client_names[0] == '\0') { 3316 (void) snprintf(buf, bufsize, "--"); 3317 } else { 3318 (void) snprintf(buf, bufsize, "%s ", 3319 attr->hg_client_names); 3320 } 3321 break; 3322 } 3323 3324 return (B_TRUE); 3325 } 3326 3327 /* 3328 * callback for dladm_walk_macaddr, invoked for each MAC address slot 3329 */ 3330 static boolean_t 3331 print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr) 3332 { 3333 print_phys_mac_state_t *mac_state = arg; 3334 show_state_t *state = mac_state->ms_state; 3335 3336 mac_state->ms_mac_attr = attr; 3337 ofmt_print(state->ls_ofmt, mac_state); 3338 3339 return (B_TRUE); 3340 } 3341 3342 /* 3343 * invoked by show-phys -m for each physical data-link 3344 */ 3345 static dladm_status_t 3346 print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link) 3347 { 3348 print_phys_mac_state_t mac_state; 3349 3350 mac_state.ms_state = state; 3351 mac_state.ms_link = link; 3352 3353 return (dladm_walk_macaddr(handle, linkid, &mac_state, 3354 print_phys_mac_callback)); 3355 } 3356 3357 /* 3358 * callback for dladm_walk_hwgrp, invoked for each MAC hwgrp 3359 */ 3360 static boolean_t 3361 print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr) 3362 { 3363 print_phys_hwgrp_state_t *hwgrp_state = arg; 3364 show_state_t *state = hwgrp_state->hs_state; 3365 3366 hwgrp_state->hs_grp_attr = attr; 3367 ofmt_print(state->ls_ofmt, hwgrp_state); 3368 3369 return (B_TRUE); 3370 } 3371 3372 /* invoked by show-phys -H for each physical data-link */ 3373 static dladm_status_t 3374 print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link) 3375 { 3376 print_phys_hwgrp_state_t hwgrp_state; 3377 3378 hwgrp_state.hs_state = state; 3379 hwgrp_state.hs_link = link; 3380 return (dladm_walk_hwgrp(handle, linkid, &hwgrp_state, 3381 print_phys_hwgrp_callback)); 3382 } 3383 3384 static dladm_status_t 3385 print_phys(show_state_t *state, datalink_id_t linkid) 3386 { 3387 char link[MAXLINKNAMELEN]; 3388 uint32_t flags; 3389 dladm_status_t status; 3390 datalink_class_t class; 3391 uint32_t media; 3392 3393 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 3394 &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 3395 goto done; 3396 } 3397 3398 if (class != DATALINK_CLASS_PHYS) { 3399 status = DLADM_STATUS_BADARG; 3400 goto done; 3401 } 3402 3403 if (!(state->ls_flags & flags)) { 3404 status = DLADM_STATUS_NOTFOUND; 3405 goto done; 3406 } 3407 3408 if (state->ls_mac) 3409 status = print_phys_mac(state, linkid, link); 3410 else if (state->ls_hwgrp) 3411 status = print_phys_hwgrp(state, linkid, link); 3412 else 3413 status = print_phys_default(state, linkid, link, flags, media); 3414 3415 done: 3416 return (status); 3417 } 3418 3419 /* ARGSUSED */ 3420 static int 3421 show_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg) 3422 { 3423 show_state_t *state = arg; 3424 3425 state->ls_status = print_phys(state, linkid); 3426 return (DLADM_WALK_CONTINUE); 3427 } 3428 3429 /* 3430 * Print the active topology information. 3431 */ 3432 static dladm_status_t 3433 print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l) 3434 { 3435 dladm_vlan_attr_t vinfo; 3436 uint32_t flags; 3437 dladm_status_t status; 3438 3439 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL, 3440 l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) { 3441 goto done; 3442 } 3443 3444 if (!(state->ls_flags & flags)) { 3445 status = DLADM_STATUS_NOTFOUND; 3446 goto done; 3447 } 3448 3449 if ((status = dladm_vlan_info(handle, linkid, &vinfo, 3450 state->ls_flags)) != DLADM_STATUS_OK || 3451 (status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, 3452 NULL, NULL, l->link_over, sizeof (l->link_over))) != 3453 DLADM_STATUS_OK) { 3454 goto done; 3455 } 3456 3457 (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d", 3458 vinfo.dv_vid); 3459 (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----", 3460 vinfo.dv_force ? 'f' : '-'); 3461 3462 done: 3463 return (status); 3464 } 3465 3466 /* ARGSUSED */ 3467 static int 3468 show_vlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 3469 { 3470 show_state_t *state = arg; 3471 dladm_status_t status; 3472 link_fields_buf_t lbuf; 3473 3474 bzero(&lbuf, sizeof (link_fields_buf_t)); 3475 status = print_vlan(state, linkid, &lbuf); 3476 if (status != DLADM_STATUS_OK) 3477 goto done; 3478 3479 ofmt_print(state->ls_ofmt, &lbuf); 3480 3481 done: 3482 state->ls_status = status; 3483 return (DLADM_WALK_CONTINUE); 3484 } 3485 3486 static void 3487 do_show_phys(int argc, char *argv[], const char *use) 3488 { 3489 int option; 3490 uint32_t flags = DLADM_OPT_ACTIVE; 3491 boolean_t p_arg = B_FALSE; 3492 boolean_t o_arg = B_FALSE; 3493 boolean_t m_arg = B_FALSE; 3494 boolean_t H_arg = B_FALSE; 3495 datalink_id_t linkid = DATALINK_ALL_LINKID; 3496 show_state_t state; 3497 dladm_status_t status; 3498 char *fields_str = NULL; 3499 char *all_active_fields = 3500 "link,media,state,speed,duplex,device"; 3501 char *all_inactive_fields = "link,device,media,flags"; 3502 char *all_mac_fields = "link,slot,address,inuse,client"; 3503 char *all_hwgrp_fields = 3504 "link,group,grouptype,rings,clients"; 3505 ofmt_field_t *pf; 3506 ofmt_handle_t ofmt; 3507 ofmt_status_t oferr; 3508 uint_t ofmtflags = 0; 3509 3510 bzero(&state, sizeof (state)); 3511 opterr = 0; 3512 while ((option = getopt_long(argc, argv, ":pPo:mH", 3513 show_lopts, NULL)) != -1) { 3514 switch (option) { 3515 case 'p': 3516 if (p_arg) 3517 die_optdup(option); 3518 3519 p_arg = B_TRUE; 3520 break; 3521 case 'P': 3522 if (flags != DLADM_OPT_ACTIVE) 3523 die_optdup(option); 3524 3525 flags = DLADM_OPT_PERSIST; 3526 break; 3527 case 'o': 3528 o_arg = B_TRUE; 3529 fields_str = optarg; 3530 break; 3531 case 'm': 3532 m_arg = B_TRUE; 3533 break; 3534 case 'H': 3535 H_arg = B_TRUE; 3536 break; 3537 default: 3538 die_opterr(optopt, option, use); 3539 break; 3540 } 3541 } 3542 3543 if (p_arg && !o_arg) 3544 die("-p requires -o"); 3545 3546 if (m_arg && H_arg) 3547 die("-m cannot combine with -H"); 3548 3549 if (p_arg && strcasecmp(fields_str, "all") == 0) 3550 die("\"-o all\" is invalid with -p"); 3551 3552 /* get link name (optional last argument) */ 3553 if (optind == (argc-1)) { 3554 if ((status = dladm_name2info(handle, argv[optind], &linkid, 3555 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 3556 die_dlerr(status, "link %s is not valid", argv[optind]); 3557 } 3558 } else if (optind != argc) { 3559 usage(); 3560 } 3561 3562 state.ls_parsable = p_arg; 3563 state.ls_flags = flags; 3564 state.ls_donefirst = B_FALSE; 3565 state.ls_mac = m_arg; 3566 state.ls_hwgrp = H_arg; 3567 3568 if (m_arg && !(flags & DLADM_OPT_ACTIVE)) { 3569 /* 3570 * We can only display the factory MAC addresses of 3571 * active data-links. 3572 */ 3573 die("-m not compatible with -P"); 3574 } 3575 3576 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3577 if (state.ls_mac) 3578 fields_str = all_mac_fields; 3579 else if (state.ls_hwgrp) 3580 fields_str = all_hwgrp_fields; 3581 else if (state.ls_flags & DLADM_OPT_ACTIVE) { 3582 fields_str = all_active_fields; 3583 } else { 3584 fields_str = all_inactive_fields; 3585 } 3586 } 3587 3588 if (state.ls_mac) { 3589 pf = phys_m_fields; 3590 } else if (state.ls_hwgrp) { 3591 pf = phys_h_fields; 3592 } else { 3593 pf = phys_fields; 3594 } 3595 3596 if (state.ls_parsable) 3597 ofmtflags |= OFMT_PARSABLE; 3598 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 3599 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 3600 state.ls_ofmt = ofmt; 3601 3602 if (linkid == DATALINK_ALL_LINKID) { 3603 (void) dladm_walk_datalink_id(show_phys, handle, &state, 3604 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags); 3605 } else { 3606 (void) show_phys(handle, linkid, &state); 3607 if (state.ls_status != DLADM_STATUS_OK) { 3608 die_dlerr(state.ls_status, 3609 "failed to show physical link %s", argv[optind]); 3610 } 3611 } 3612 ofmt_close(ofmt); 3613 } 3614 3615 static void 3616 do_show_vlan(int argc, char *argv[], const char *use) 3617 { 3618 int option; 3619 uint32_t flags = DLADM_OPT_ACTIVE; 3620 boolean_t p_arg = B_FALSE; 3621 datalink_id_t linkid = DATALINK_ALL_LINKID; 3622 show_state_t state; 3623 dladm_status_t status; 3624 boolean_t o_arg = B_FALSE; 3625 char *fields_str = NULL; 3626 ofmt_handle_t ofmt; 3627 ofmt_status_t oferr; 3628 uint_t ofmtflags = 0; 3629 3630 bzero(&state, sizeof (state)); 3631 3632 opterr = 0; 3633 while ((option = getopt_long(argc, argv, ":pPo:", 3634 show_lopts, NULL)) != -1) { 3635 switch (option) { 3636 case 'p': 3637 if (p_arg) 3638 die_optdup(option); 3639 3640 p_arg = B_TRUE; 3641 break; 3642 case 'P': 3643 if (flags != DLADM_OPT_ACTIVE) 3644 die_optdup(option); 3645 3646 flags = DLADM_OPT_PERSIST; 3647 break; 3648 case 'o': 3649 o_arg = B_TRUE; 3650 fields_str = optarg; 3651 break; 3652 default: 3653 die_opterr(optopt, option, use); 3654 break; 3655 } 3656 } 3657 3658 /* get link name (optional last argument) */ 3659 if (optind == (argc-1)) { 3660 if ((status = dladm_name2info(handle, argv[optind], &linkid, 3661 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 3662 die_dlerr(status, "link %s is not valid", argv[optind]); 3663 } 3664 } else if (optind != argc) { 3665 usage(); 3666 } 3667 3668 state.ls_parsable = p_arg; 3669 state.ls_flags = flags; 3670 state.ls_donefirst = B_FALSE; 3671 3672 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 3673 fields_str = NULL; 3674 3675 if (state.ls_parsable) 3676 ofmtflags |= OFMT_PARSABLE; 3677 oferr = ofmt_open(fields_str, vlan_fields, ofmtflags, 0, &ofmt); 3678 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 3679 state.ls_ofmt = ofmt; 3680 3681 if (linkid == DATALINK_ALL_LINKID) { 3682 (void) dladm_walk_datalink_id(show_vlan, handle, &state, 3683 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags); 3684 } else { 3685 (void) show_vlan(handle, linkid, &state); 3686 if (state.ls_status != DLADM_STATUS_OK) { 3687 die_dlerr(state.ls_status, "failed to show vlan %s", 3688 argv[optind]); 3689 } 3690 } 3691 ofmt_close(ofmt); 3692 } 3693 3694 static void 3695 do_create_vnic(int argc, char *argv[], const char *use) 3696 { 3697 datalink_id_t linkid, dev_linkid; 3698 char devname[MAXLINKNAMELEN]; 3699 char name[MAXLINKNAMELEN]; 3700 boolean_t l_arg = B_FALSE; 3701 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 3702 char *altroot = NULL; 3703 int option; 3704 char *endp = NULL; 3705 dladm_status_t status; 3706 vnic_mac_addr_type_t mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO; 3707 uchar_t *mac_addr; 3708 int mac_slot = -1, maclen = 0, mac_prefix_len = 0; 3709 char propstr[DLADM_STRSIZE]; 3710 dladm_arg_list_t *proplist = NULL; 3711 int vid = 0; 3712 3713 opterr = 0; 3714 bzero(propstr, DLADM_STRSIZE); 3715 3716 while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:H", 3717 vnic_lopts, NULL)) != -1) { 3718 switch (option) { 3719 case 't': 3720 flags &= ~DLADM_OPT_PERSIST; 3721 break; 3722 case 'R': 3723 altroot = optarg; 3724 break; 3725 case 'l': 3726 if (strlcpy(devname, optarg, MAXLINKNAMELEN) >= 3727 MAXLINKNAMELEN) 3728 die("link name too long"); 3729 l_arg = B_TRUE; 3730 break; 3731 case 'm': 3732 if (strcmp(optarg, "fixed") == 0) { 3733 /* 3734 * A fixed MAC address must be specified 3735 * by its value, not by the keyword 'fixed'. 3736 */ 3737 die("'fixed' is not a valid MAC address"); 3738 } 3739 if (dladm_vnic_str2macaddrtype(optarg, 3740 &mac_addr_type) != DLADM_STATUS_OK) { 3741 mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED; 3742 /* MAC address specified by value */ 3743 mac_addr = _link_aton(optarg, &maclen); 3744 if (mac_addr == NULL) { 3745 if (maclen == -1) 3746 die("invalid MAC address"); 3747 else 3748 die("out of memory"); 3749 } 3750 } 3751 break; 3752 case 'n': 3753 errno = 0; 3754 mac_slot = (int)strtol(optarg, &endp, 10); 3755 if (errno != 0 || *endp != '\0') 3756 die("invalid slot number"); 3757 break; 3758 case 'p': 3759 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 3760 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 3761 DLADM_STRSIZE) 3762 die("property list too long '%s'", propstr); 3763 break; 3764 case 'r': 3765 mac_addr = _link_aton(optarg, &mac_prefix_len); 3766 if (mac_addr == NULL) { 3767 if (mac_prefix_len == -1) 3768 die("invalid MAC address"); 3769 else 3770 die("out of memory"); 3771 } 3772 break; 3773 case 'v': 3774 if (vid != 0) 3775 die_optdup(option); 3776 3777 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 3778 die("invalid VLAN identifier '%s'", optarg); 3779 3780 break; 3781 case 'f': 3782 flags |= DLADM_OPT_FORCE; 3783 break; 3784 case 'H': 3785 flags |= DLADM_OPT_HWRINGS; 3786 break; 3787 default: 3788 die_opterr(optopt, option, use); 3789 } 3790 } 3791 3792 /* 3793 * 'f' - force, flag can be specified only with 'v' - vlan. 3794 */ 3795 if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0) 3796 die("-f option can only be used with -v"); 3797 3798 if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM && 3799 mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED) 3800 usage(); 3801 3802 /* check required options */ 3803 if (!l_arg) 3804 usage(); 3805 3806 if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY) 3807 usage(); 3808 3809 /* the VNIC id is the required operand */ 3810 if (optind != (argc - 1)) 3811 usage(); 3812 3813 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 3814 die("link name too long '%s'", argv[optind]); 3815 3816 if (!dladm_valid_linkname(name)) 3817 die("invalid link name '%s'", argv[optind]); 3818 3819 if (altroot != NULL) 3820 altroot_cmd(altroot, argc, argv); 3821 3822 if (dladm_name2info(handle, devname, &dev_linkid, NULL, NULL, NULL) != 3823 DLADM_STATUS_OK) 3824 die("invalid link name '%s'", devname); 3825 3826 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 3827 != DLADM_STATUS_OK) 3828 die("invalid vnic property"); 3829 3830 status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type, 3831 mac_addr, maclen, &mac_slot, mac_prefix_len, vid, &linkid, proplist, 3832 flags); 3833 if (status != DLADM_STATUS_OK) 3834 die_dlerr(status, "vnic creation over %s failed", devname); 3835 3836 dladm_free_props(proplist); 3837 } 3838 3839 static void 3840 do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub, 3841 uint32_t flags) 3842 { 3843 boolean_t is_etherstub; 3844 dladm_vnic_attr_t attr; 3845 3846 if (dladm_vnic_info(handle, linkid, &attr, flags) != DLADM_STATUS_OK) { 3847 /* 3848 * Let the delete continue anyway. 3849 */ 3850 return; 3851 } 3852 is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID); 3853 if (is_etherstub != etherstub) { 3854 die("'%s' is not %s", name, 3855 (is_etherstub ? "a vnic" : "an etherstub")); 3856 } 3857 } 3858 3859 static void 3860 do_delete_vnic_common(int argc, char *argv[], const char *use, 3861 boolean_t etherstub) 3862 { 3863 int option; 3864 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 3865 datalink_id_t linkid; 3866 char *altroot = NULL; 3867 dladm_status_t status; 3868 3869 opterr = 0; 3870 while ((option = getopt_long(argc, argv, ":R:t", lopts, 3871 NULL)) != -1) { 3872 switch (option) { 3873 case 't': 3874 flags &= ~DLADM_OPT_PERSIST; 3875 break; 3876 case 'R': 3877 altroot = optarg; 3878 break; 3879 default: 3880 die_opterr(optopt, option, use); 3881 } 3882 } 3883 3884 /* get vnic name (required last argument) */ 3885 if (optind != (argc - 1)) 3886 usage(); 3887 3888 if (altroot != NULL) 3889 altroot_cmd(altroot, argc, argv); 3890 3891 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 3892 NULL); 3893 if (status != DLADM_STATUS_OK) 3894 die("invalid link name '%s'", argv[optind]); 3895 3896 if ((flags & DLADM_OPT_ACTIVE) != 0) { 3897 do_etherstub_check(argv[optind], linkid, etherstub, 3898 DLADM_OPT_ACTIVE); 3899 } 3900 if ((flags & DLADM_OPT_PERSIST) != 0) { 3901 do_etherstub_check(argv[optind], linkid, etherstub, 3902 DLADM_OPT_PERSIST); 3903 } 3904 3905 status = dladm_vnic_delete(handle, linkid, flags); 3906 if (status != DLADM_STATUS_OK) 3907 die_dlerr(status, "vnic deletion failed"); 3908 } 3909 3910 static void 3911 do_delete_vnic(int argc, char *argv[], const char *use) 3912 { 3913 do_delete_vnic_common(argc, argv, use, B_FALSE); 3914 } 3915 3916 /* ARGSUSED */ 3917 static void 3918 do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan) 3919 { 3920 datalink_id_t linkid = DATALINK_ALL_LINKID; 3921 dladm_status_t status; 3922 char *type; 3923 3924 type = vlan ? "vlan" : "vnic"; 3925 3926 /* 3927 * get the id or the name of the vnic/vlan (optional last argument) 3928 */ 3929 if (argc == 2) { 3930 status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL, 3931 NULL); 3932 if (status != DLADM_STATUS_OK) 3933 goto done; 3934 3935 } else if (argc > 2) { 3936 usage(); 3937 } 3938 3939 if (vlan) 3940 status = dladm_vlan_up(handle, linkid); 3941 else 3942 status = dladm_vnic_up(handle, linkid, 0); 3943 3944 done: 3945 if (status != DLADM_STATUS_OK) { 3946 if (argc == 2) { 3947 die_dlerr(status, 3948 "could not bring up %s '%s'", type, argv[1]); 3949 } else { 3950 die_dlerr(status, "could not bring %ss up", type); 3951 } 3952 } 3953 } 3954 3955 static void 3956 do_up_vnic(int argc, char *argv[], const char *use) 3957 { 3958 do_up_vnic_common(argc, argv, use, B_FALSE); 3959 } 3960 3961 static void 3962 dump_vnics_head(const char *dev) 3963 { 3964 if (strlen(dev)) 3965 (void) printf("%s", dev); 3966 3967 (void) printf("\tipackets rbytes opackets obytes "); 3968 3969 if (strlen(dev)) 3970 (void) printf("%%ipkts %%opkts\n"); 3971 else 3972 (void) printf("\n"); 3973 } 3974 3975 static void 3976 dump_vnic_stat(const char *name, datalink_id_t vnic_id, 3977 show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats) 3978 { 3979 pktsum_t diff_stats; 3980 pktsum_t *old_stats = &state->vs_prevstats[vnic_id]; 3981 3982 dladm_stats_diff(&diff_stats, vnic_stats, old_stats); 3983 3984 (void) printf("%s", name); 3985 3986 (void) printf("\t%-10llu", diff_stats.ipackets); 3987 (void) printf("%-12llu", diff_stats.rbytes); 3988 (void) printf("%-10llu", diff_stats.opackets); 3989 (void) printf("%-12llu", diff_stats.obytes); 3990 3991 if (tot_stats) { 3992 if (tot_stats->ipackets == 0) { 3993 (void) printf("\t-"); 3994 } else { 3995 (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 3996 (double)tot_stats->ipackets * 100); 3997 } 3998 if (tot_stats->opackets == 0) { 3999 (void) printf("\t-"); 4000 } else { 4001 (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 4002 (double)tot_stats->opackets * 100); 4003 } 4004 } 4005 (void) printf("\n"); 4006 4007 *old_stats = *vnic_stats; 4008 } 4009 4010 /* 4011 * Called from the walker dladm_vnic_walk_sys() for each vnic to display 4012 * vnic information or statistics. 4013 */ 4014 static dladm_status_t 4015 print_vnic(show_vnic_state_t *state, datalink_id_t linkid) 4016 { 4017 dladm_vnic_attr_t attr, *vnic = &attr; 4018 dladm_status_t status; 4019 boolean_t is_etherstub; 4020 char devname[MAXLINKNAMELEN]; 4021 char vnic_name[MAXLINKNAMELEN]; 4022 char mstr[MAXMACADDRLEN * 3]; 4023 vnic_fields_buf_t vbuf; 4024 4025 if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) != 4026 DLADM_STATUS_OK) 4027 return (status); 4028 4029 is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID); 4030 if (state->vs_etherstub != is_etherstub) { 4031 /* 4032 * Want all etherstub but it's not one, or want 4033 * non-etherstub and it's one. 4034 */ 4035 return (DLADM_STATUS_OK); 4036 } 4037 4038 if (state->vs_link_id != DATALINK_ALL_LINKID) { 4039 if (state->vs_link_id != vnic->va_link_id) 4040 return (DLADM_STATUS_OK); 4041 } 4042 4043 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, 4044 NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK) 4045 return (DLADM_STATUS_BADARG); 4046 4047 bzero(devname, sizeof (devname)); 4048 if (!is_etherstub && 4049 dladm_datalink_id2info(handle, vnic->va_link_id, NULL, NULL, 4050 NULL, devname, sizeof (devname)) != DLADM_STATUS_OK) 4051 return (DLADM_STATUS_BADARG); 4052 4053 state->vs_found = B_TRUE; 4054 if (state->vs_stats) { 4055 /* print vnic statistics */ 4056 pktsum_t vnic_stats; 4057 4058 if (state->vs_firstonly) { 4059 if (state->vs_donefirst) 4060 return (0); 4061 state->vs_donefirst = B_TRUE; 4062 } 4063 4064 if (!state->vs_printstats) { 4065 /* 4066 * get vnic statistics and add to the sum for the 4067 * named device. 4068 */ 4069 get_link_stats(vnic_name, &vnic_stats); 4070 dladm_stats_total(&state->vs_totalstats, &vnic_stats, 4071 &state->vs_prevstats[vnic->va_vnic_id]); 4072 } else { 4073 /* get and print vnic statistics */ 4074 get_link_stats(vnic_name, &vnic_stats); 4075 dump_vnic_stat(vnic_name, linkid, state, &vnic_stats, 4076 &state->vs_totalstats); 4077 } 4078 return (DLADM_STATUS_OK); 4079 } else { 4080 (void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link), 4081 "%s", vnic_name); 4082 4083 if (!is_etherstub) { 4084 4085 (void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over), 4086 "%s", devname); 4087 (void) snprintf(vbuf.vnic_speed, 4088 sizeof (vbuf.vnic_speed), "%u", 4089 (uint_t)((get_ifspeed(vnic_name, B_TRUE)) 4090 / 1000000ull)); 4091 4092 switch (vnic->va_mac_addr_type) { 4093 case VNIC_MAC_ADDR_TYPE_FIXED: 4094 case VNIC_MAC_ADDR_TYPE_PRIMARY: 4095 (void) snprintf(vbuf.vnic_macaddrtype, 4096 sizeof (vbuf.vnic_macaddrtype), 4097 gettext("fixed")); 4098 break; 4099 case VNIC_MAC_ADDR_TYPE_RANDOM: 4100 (void) snprintf(vbuf.vnic_macaddrtype, 4101 sizeof (vbuf.vnic_macaddrtype), 4102 gettext("random")); 4103 break; 4104 case VNIC_MAC_ADDR_TYPE_FACTORY: 4105 (void) snprintf(vbuf.vnic_macaddrtype, 4106 sizeof (vbuf.vnic_macaddrtype), 4107 gettext("factory, slot %d"), 4108 vnic->va_mac_slot); 4109 break; 4110 } 4111 4112 if (strlen(vbuf.vnic_macaddrtype) > 0) { 4113 (void) snprintf(vbuf.vnic_macaddr, 4114 sizeof (vbuf.vnic_macaddr), "%s", 4115 dladm_aggr_macaddr2str(vnic->va_mac_addr, 4116 mstr)); 4117 } 4118 4119 (void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid), 4120 "%d", vnic->va_vid); 4121 } 4122 4123 ofmt_print(state->vs_ofmt, &vbuf); 4124 4125 return (DLADM_STATUS_OK); 4126 } 4127 } 4128 4129 /* ARGSUSED */ 4130 static int 4131 show_vnic(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4132 { 4133 show_vnic_state_t *state = arg; 4134 4135 state->vs_status = print_vnic(state, linkid); 4136 return (DLADM_WALK_CONTINUE); 4137 } 4138 4139 static void 4140 do_show_vnic_common(int argc, char *argv[], const char *use, 4141 boolean_t etherstub) 4142 { 4143 int option; 4144 boolean_t s_arg = B_FALSE; 4145 boolean_t i_arg = B_FALSE; 4146 boolean_t l_arg = B_FALSE; 4147 uint32_t interval = 0, flags = DLADM_OPT_ACTIVE; 4148 datalink_id_t linkid = DATALINK_ALL_LINKID; 4149 datalink_id_t dev_linkid = DATALINK_ALL_LINKID; 4150 show_vnic_state_t state; 4151 dladm_status_t status; 4152 boolean_t o_arg = B_FALSE; 4153 char *fields_str = NULL; 4154 ofmt_field_t *pf; 4155 char *all_e_fields = "link"; 4156 ofmt_handle_t ofmt; 4157 ofmt_status_t oferr; 4158 uint_t ofmtflags = 0; 4159 4160 bzero(&state, sizeof (state)); 4161 opterr = 0; 4162 while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts, 4163 NULL)) != -1) { 4164 switch (option) { 4165 case 'p': 4166 state.vs_parsable = B_TRUE; 4167 break; 4168 case 'P': 4169 flags = DLADM_OPT_PERSIST; 4170 break; 4171 case 'l': 4172 if (etherstub) 4173 die("option not supported for this command"); 4174 4175 if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >= 4176 MAXLINKNAMELEN) 4177 die("link name too long"); 4178 4179 l_arg = B_TRUE; 4180 break; 4181 case 's': 4182 if (s_arg) { 4183 die("the option -s cannot be specified " 4184 "more than once"); 4185 } 4186 s_arg = B_TRUE; 4187 break; 4188 case 'i': 4189 if (i_arg) { 4190 die("the option -i cannot be specified " 4191 "more than once"); 4192 } 4193 i_arg = B_TRUE; 4194 if (!dladm_str2interval(optarg, &interval)) 4195 die("invalid interval value '%s'", optarg); 4196 break; 4197 case 'o': 4198 o_arg = B_TRUE; 4199 fields_str = optarg; 4200 break; 4201 default: 4202 die_opterr(optopt, option, use); 4203 } 4204 } 4205 4206 if (i_arg && !s_arg) 4207 die("the option -i can be used only with -s"); 4208 4209 /* get vnic ID (optional last argument) */ 4210 if (optind == (argc - 1)) { 4211 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 4212 NULL, NULL); 4213 if (status != DLADM_STATUS_OK) { 4214 die_dlerr(status, "invalid vnic name '%s'", 4215 argv[optind]); 4216 } 4217 (void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN); 4218 } else if (optind != argc) { 4219 usage(); 4220 } 4221 4222 if (l_arg) { 4223 status = dladm_name2info(handle, state.vs_link, &dev_linkid, 4224 NULL, NULL, NULL); 4225 if (status != DLADM_STATUS_OK) { 4226 die_dlerr(status, "invalid link name '%s'", 4227 state.vs_link); 4228 } 4229 } 4230 4231 state.vs_vnic_id = linkid; 4232 state.vs_link_id = dev_linkid; 4233 state.vs_etherstub = etherstub; 4234 state.vs_found = B_FALSE; 4235 state.vs_flags = flags; 4236 4237 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 4238 if (etherstub) 4239 fields_str = all_e_fields; 4240 } 4241 pf = vnic_fields; 4242 4243 if (state.vs_parsable) 4244 ofmtflags |= OFMT_PARSABLE; 4245 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 4246 dladm_ofmt_check(oferr, state.vs_parsable, ofmt); 4247 state.vs_ofmt = ofmt; 4248 4249 if (s_arg) { 4250 /* Display vnic statistics */ 4251 vnic_stats(&state, interval); 4252 ofmt_close(ofmt); 4253 return; 4254 } 4255 4256 /* Display vnic information */ 4257 state.vs_donefirst = B_FALSE; 4258 4259 if (linkid == DATALINK_ALL_LINKID) { 4260 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4261 DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB, 4262 DATALINK_ANY_MEDIATYPE, flags); 4263 } else { 4264 (void) show_vnic(handle, linkid, &state); 4265 if (state.vs_status != DLADM_STATUS_OK) { 4266 ofmt_close(ofmt); 4267 die_dlerr(state.vs_status, "failed to show vnic '%s'", 4268 state.vs_vnic); 4269 } 4270 } 4271 ofmt_close(ofmt); 4272 } 4273 4274 static void 4275 do_show_vnic(int argc, char *argv[], const char *use) 4276 { 4277 do_show_vnic_common(argc, argv, use, B_FALSE); 4278 } 4279 4280 static void 4281 do_create_etherstub(int argc, char *argv[], const char *use) 4282 { 4283 uint32_t flags; 4284 char *altroot = NULL; 4285 int option; 4286 dladm_status_t status; 4287 char name[MAXLINKNAMELEN]; 4288 uchar_t mac_addr[ETHERADDRL]; 4289 4290 name[0] = '\0'; 4291 bzero(mac_addr, sizeof (mac_addr)); 4292 flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4293 4294 opterr = 0; 4295 while ((option = getopt_long(argc, argv, "tR:", 4296 etherstub_lopts, NULL)) != -1) { 4297 switch (option) { 4298 case 't': 4299 flags &= ~DLADM_OPT_PERSIST; 4300 break; 4301 case 'R': 4302 altroot = optarg; 4303 break; 4304 default: 4305 die_opterr(optopt, option, use); 4306 } 4307 } 4308 4309 /* the etherstub id is the required operand */ 4310 if (optind != (argc - 1)) 4311 usage(); 4312 4313 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 4314 die("link name too long '%s'", argv[optind]); 4315 4316 if (!dladm_valid_linkname(name)) 4317 die("invalid link name '%s'", argv[optind]); 4318 4319 if (altroot != NULL) 4320 altroot_cmd(altroot, argc, argv); 4321 4322 status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID, 4323 VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, NULL, 4324 NULL, flags); 4325 if (status != DLADM_STATUS_OK) 4326 die_dlerr(status, "etherstub creation failed"); 4327 } 4328 4329 static void 4330 do_delete_etherstub(int argc, char *argv[], const char *use) 4331 { 4332 do_delete_vnic_common(argc, argv, use, B_TRUE); 4333 } 4334 4335 /* ARGSUSED */ 4336 static void 4337 do_show_etherstub(int argc, char *argv[], const char *use) 4338 { 4339 do_show_vnic_common(argc, argv, use, B_TRUE); 4340 } 4341 4342 /* ARGSUSED */ 4343 static void 4344 do_up_simnet(int argc, char *argv[], const char *use) 4345 { 4346 (void) dladm_simnet_up(handle, DATALINK_ALL_LINKID, 0); 4347 } 4348 4349 static void 4350 do_create_simnet(int argc, char *argv[], const char *use) 4351 { 4352 uint32_t flags; 4353 char *altroot = NULL; 4354 char *media = NULL; 4355 uint32_t mtype = DL_ETHER; 4356 int option; 4357 dladm_status_t status; 4358 char name[MAXLINKNAMELEN]; 4359 4360 name[0] = '\0'; 4361 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4362 4363 opterr = 0; 4364 while ((option = getopt_long(argc, argv, ":tR:m:", 4365 simnet_lopts, NULL)) != -1) { 4366 switch (option) { 4367 case 't': 4368 flags &= ~DLADM_OPT_PERSIST; 4369 break; 4370 case 'R': 4371 altroot = optarg; 4372 break; 4373 case 'm': 4374 media = optarg; 4375 break; 4376 default: 4377 die_opterr(optopt, option, use); 4378 } 4379 } 4380 4381 /* the simnet id is the required operand */ 4382 if (optind != (argc - 1)) 4383 usage(); 4384 4385 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 4386 die("link name too long '%s'", argv[optind]); 4387 4388 if (!dladm_valid_linkname(name)) 4389 die("invalid link name '%s'", name); 4390 4391 if (media != NULL) { 4392 mtype = dladm_str2media(media); 4393 if (mtype != DL_ETHER && mtype != DL_WIFI) 4394 die("media type '%s' is not supported", media); 4395 } 4396 4397 if (altroot != NULL) 4398 altroot_cmd(altroot, argc, argv); 4399 4400 status = dladm_simnet_create(handle, name, mtype, flags); 4401 if (status != DLADM_STATUS_OK) 4402 die_dlerr(status, "simnet creation failed"); 4403 } 4404 4405 static void 4406 do_delete_simnet(int argc, char *argv[], const char *use) 4407 { 4408 int option; 4409 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4410 datalink_id_t linkid; 4411 char *altroot = NULL; 4412 dladm_status_t status; 4413 dladm_simnet_attr_t slinfo; 4414 4415 opterr = 0; 4416 while ((option = getopt_long(argc, argv, ":tR:", simnet_lopts, 4417 NULL)) != -1) { 4418 switch (option) { 4419 case 't': 4420 flags &= ~DLADM_OPT_PERSIST; 4421 break; 4422 case 'R': 4423 altroot = optarg; 4424 break; 4425 default: 4426 die_opterr(optopt, option, use); 4427 } 4428 } 4429 4430 /* get simnet name (required last argument) */ 4431 if (optind != (argc - 1)) 4432 usage(); 4433 4434 if (!dladm_valid_linkname(argv[optind])) 4435 die("invalid link name '%s'", argv[optind]); 4436 4437 if (altroot != NULL) 4438 altroot_cmd(altroot, argc, argv); 4439 4440 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 4441 NULL); 4442 if (status != DLADM_STATUS_OK) 4443 die("simnet '%s' not found", argv[optind]); 4444 4445 if ((status = dladm_simnet_info(handle, linkid, &slinfo, 4446 flags)) != DLADM_STATUS_OK) 4447 die_dlerr(status, "failed to retrieve simnet information"); 4448 4449 status = dladm_simnet_delete(handle, linkid, flags); 4450 if (status != DLADM_STATUS_OK) 4451 die_dlerr(status, "simnet deletion failed"); 4452 } 4453 4454 static void 4455 do_modify_simnet(int argc, char *argv[], const char *use) 4456 { 4457 int option; 4458 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4459 datalink_id_t linkid; 4460 datalink_id_t peer_linkid; 4461 char *altroot = NULL; 4462 dladm_status_t status; 4463 boolean_t p_arg = B_FALSE; 4464 4465 opterr = 0; 4466 while ((option = getopt_long(argc, argv, ":tR:p:", simnet_lopts, 4467 NULL)) != -1) { 4468 switch (option) { 4469 case 't': 4470 flags &= ~DLADM_OPT_PERSIST; 4471 break; 4472 case 'R': 4473 altroot = optarg; 4474 break; 4475 case 'p': 4476 if (p_arg) 4477 die_optdup(option); 4478 p_arg = B_TRUE; 4479 if (strcasecmp(optarg, "none") == 0) 4480 peer_linkid = DATALINK_INVALID_LINKID; 4481 else if (dladm_name2info(handle, optarg, &peer_linkid, 4482 NULL, NULL, NULL) != DLADM_STATUS_OK) 4483 die("invalid peer link name '%s'", optarg); 4484 break; 4485 default: 4486 die_opterr(optopt, option, use); 4487 } 4488 } 4489 4490 /* get simnet name (required last argument) */ 4491 if (optind != (argc - 1)) 4492 usage(); 4493 4494 /* Nothing to do if no peer link argument */ 4495 if (!p_arg) 4496 return; 4497 4498 if (altroot != NULL) 4499 altroot_cmd(altroot, argc, argv); 4500 4501 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 4502 NULL); 4503 if (status != DLADM_STATUS_OK) 4504 die("invalid link name '%s'", argv[optind]); 4505 4506 status = dladm_simnet_modify(handle, linkid, peer_linkid, flags); 4507 if (status != DLADM_STATUS_OK) 4508 die_dlerr(status, "simnet modification failed"); 4509 } 4510 4511 static dladm_status_t 4512 print_simnet(show_state_t *state, datalink_id_t linkid) 4513 { 4514 dladm_simnet_attr_t slinfo; 4515 uint32_t flags; 4516 dladm_status_t status; 4517 simnet_fields_buf_t slbuf; 4518 char mstr[ETHERADDRL * 3]; 4519 4520 bzero(&slbuf, sizeof (slbuf)); 4521 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL, 4522 slbuf.simnet_name, sizeof (slbuf.simnet_name))) 4523 != DLADM_STATUS_OK) 4524 return (status); 4525 4526 if (!(state->ls_flags & flags)) 4527 return (DLADM_STATUS_NOTFOUND); 4528 4529 if ((status = dladm_simnet_info(handle, linkid, &slinfo, 4530 state->ls_flags)) != DLADM_STATUS_OK) 4531 return (status); 4532 4533 if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID && 4534 (status = dladm_datalink_id2info(handle, slinfo.sna_peer_link_id, 4535 NULL, NULL, NULL, slbuf.simnet_otherlink, 4536 sizeof (slbuf.simnet_otherlink))) != 4537 DLADM_STATUS_OK) 4538 return (status); 4539 4540 if (slinfo.sna_mac_len > sizeof (slbuf.simnet_macaddr)) 4541 return (DLADM_STATUS_BADVAL); 4542 4543 (void) strlcpy(slbuf.simnet_macaddr, 4544 dladm_aggr_macaddr2str(slinfo.sna_mac_addr, mstr), 4545 sizeof (slbuf.simnet_macaddr)); 4546 (void) dladm_media2str(slinfo.sna_type, slbuf.simnet_media); 4547 4548 ofmt_print(state->ls_ofmt, &slbuf); 4549 return (status); 4550 } 4551 4552 /* ARGSUSED */ 4553 static int 4554 show_simnet(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4555 { 4556 show_state_t *state = arg; 4557 4558 state->ls_status = print_simnet(state, linkid); 4559 return (DLADM_WALK_CONTINUE); 4560 } 4561 4562 static void 4563 do_show_simnet(int argc, char *argv[], const char *use) 4564 { 4565 int option; 4566 uint32_t flags = DLADM_OPT_ACTIVE; 4567 boolean_t p_arg = B_FALSE; 4568 datalink_id_t linkid = DATALINK_ALL_LINKID; 4569 show_state_t state; 4570 dladm_status_t status; 4571 boolean_t o_arg = B_FALSE; 4572 ofmt_handle_t ofmt; 4573 ofmt_status_t oferr; 4574 char *all_fields = "link,media,macaddress,otherlink"; 4575 char *fields_str = all_fields; 4576 uint_t ofmtflags = 0; 4577 4578 bzero(&state, sizeof (state)); 4579 4580 opterr = 0; 4581 while ((option = getopt_long(argc, argv, ":pPo:", 4582 show_lopts, NULL)) != -1) { 4583 switch (option) { 4584 case 'p': 4585 if (p_arg) 4586 die_optdup(option); 4587 4588 p_arg = B_TRUE; 4589 state.ls_parsable = p_arg; 4590 break; 4591 case 'P': 4592 if (flags != DLADM_OPT_ACTIVE) 4593 die_optdup(option); 4594 4595 flags = DLADM_OPT_PERSIST; 4596 break; 4597 case 'o': 4598 o_arg = B_TRUE; 4599 fields_str = optarg; 4600 break; 4601 default: 4602 die_opterr(optopt, option, use); 4603 break; 4604 } 4605 } 4606 4607 if (p_arg && !o_arg) 4608 die("-p requires -o"); 4609 4610 if (strcasecmp(fields_str, "all") == 0) { 4611 if (p_arg) 4612 die("\"-o all\" is invalid with -p"); 4613 fields_str = all_fields; 4614 } 4615 4616 /* get link name (optional last argument) */ 4617 if (optind == (argc-1)) { 4618 if ((status = dladm_name2info(handle, argv[optind], &linkid, 4619 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 4620 die_dlerr(status, "link %s is not valid", argv[optind]); 4621 } 4622 } else if (optind != argc) { 4623 usage(); 4624 } 4625 4626 state.ls_flags = flags; 4627 state.ls_donefirst = B_FALSE; 4628 if (state.ls_parsable) 4629 ofmtflags |= OFMT_PARSABLE; 4630 oferr = ofmt_open(fields_str, simnet_fields, ofmtflags, 0, &ofmt); 4631 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 4632 state.ls_ofmt = ofmt; 4633 4634 if (linkid == DATALINK_ALL_LINKID) { 4635 (void) dladm_walk_datalink_id(show_simnet, handle, &state, 4636 DATALINK_CLASS_SIMNET, DATALINK_ANY_MEDIATYPE, flags); 4637 } else { 4638 (void) show_simnet(handle, linkid, &state); 4639 if (state.ls_status != DLADM_STATUS_OK) { 4640 ofmt_close(ofmt); 4641 die_dlerr(state.ls_status, "failed to show simnet %s", 4642 argv[optind]); 4643 } 4644 } 4645 ofmt_close(ofmt); 4646 } 4647 4648 static void 4649 link_stats(datalink_id_t linkid, uint_t interval, char *fields_str, 4650 show_state_t *state) 4651 { 4652 ofmt_handle_t ofmt; 4653 ofmt_status_t oferr; 4654 uint_t ofmtflags = 0; 4655 4656 if (state->ls_parsable) 4657 ofmtflags |= OFMT_PARSABLE; 4658 oferr = ofmt_open(fields_str, link_s_fields, ofmtflags, 0, &ofmt); 4659 dladm_ofmt_check(oferr, state->ls_parsable, ofmt); 4660 state->ls_ofmt = ofmt; 4661 4662 /* 4663 * If an interval is specified, continuously show the stats 4664 * only for the first MAC port. 4665 */ 4666 state->ls_firstonly = (interval != 0); 4667 4668 for (;;) { 4669 state->ls_donefirst = B_FALSE; 4670 if (linkid == DATALINK_ALL_LINKID) { 4671 (void) dladm_walk_datalink_id(show_link_stats, handle, 4672 state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 4673 DLADM_OPT_ACTIVE); 4674 } else { 4675 (void) show_link_stats(handle, linkid, state); 4676 } 4677 4678 if (interval == 0) 4679 break; 4680 4681 (void) fflush(stdout); 4682 (void) sleep(interval); 4683 } 4684 ofmt_close(ofmt); 4685 } 4686 4687 static void 4688 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) 4689 { 4690 /* 4691 * If an interval is specified, continuously show the stats 4692 * only for the first group. 4693 */ 4694 state->gs_firstonly = (interval != 0); 4695 4696 for (;;) { 4697 state->gs_donefirst = B_FALSE; 4698 if (linkid == DATALINK_ALL_LINKID) 4699 (void) dladm_walk_datalink_id(show_aggr, handle, state, 4700 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 4701 DLADM_OPT_ACTIVE); 4702 else 4703 (void) show_aggr(handle, linkid, state); 4704 4705 if (interval == 0) 4706 break; 4707 4708 (void) fflush(stdout); 4709 (void) sleep(interval); 4710 } 4711 } 4712 4713 /* ARGSUSED */ 4714 static void 4715 vnic_stats(show_vnic_state_t *sp, uint32_t interval) 4716 { 4717 show_vnic_state_t state; 4718 boolean_t specific_link, specific_dev; 4719 4720 /* Display vnic statistics */ 4721 dump_vnics_head(sp->vs_link); 4722 4723 bzero(&state, sizeof (state)); 4724 state.vs_stats = B_TRUE; 4725 state.vs_vnic_id = sp->vs_vnic_id; 4726 state.vs_link_id = sp->vs_link_id; 4727 4728 /* 4729 * If an interval is specified, and a vnic ID is not specified, 4730 * continuously show the stats only for the first vnic. 4731 */ 4732 specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID); 4733 specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID); 4734 4735 for (;;) { 4736 /* Get stats for each vnic */ 4737 state.vs_found = B_FALSE; 4738 state.vs_donefirst = B_FALSE; 4739 state.vs_printstats = B_FALSE; 4740 state.vs_flags = DLADM_OPT_ACTIVE; 4741 4742 if (!specific_link) { 4743 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4744 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 4745 DLADM_OPT_ACTIVE); 4746 } else { 4747 (void) show_vnic(handle, sp->vs_vnic_id, &state); 4748 if (state.vs_status != DLADM_STATUS_OK) { 4749 die_dlerr(state.vs_status, 4750 "failed to show vnic '%s'", sp->vs_vnic); 4751 } 4752 } 4753 4754 if (specific_link && !state.vs_found) 4755 die("non-existent vnic '%s'", sp->vs_vnic); 4756 if (specific_dev && !state.vs_found) 4757 die("device %s has no vnics", sp->vs_link); 4758 4759 /* Show totals */ 4760 if ((specific_link | specific_dev) && !interval) { 4761 (void) printf("Total"); 4762 (void) printf("\t%-10llu", 4763 state.vs_totalstats.ipackets); 4764 (void) printf("%-12llu", 4765 state.vs_totalstats.rbytes); 4766 (void) printf("%-10llu", 4767 state.vs_totalstats.opackets); 4768 (void) printf("%-12llu\n", 4769 state.vs_totalstats.obytes); 4770 } 4771 4772 /* Show stats for each vnic */ 4773 state.vs_donefirst = B_FALSE; 4774 state.vs_printstats = B_TRUE; 4775 4776 if (!specific_link) { 4777 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4778 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 4779 DLADM_OPT_ACTIVE); 4780 } else { 4781 (void) show_vnic(handle, sp->vs_vnic_id, &state); 4782 if (state.vs_status != DLADM_STATUS_OK) { 4783 die_dlerr(state.vs_status, 4784 "failed to show vnic '%s'", sp->vs_vnic); 4785 } 4786 } 4787 4788 if (interval == 0) 4789 break; 4790 4791 (void) fflush(stdout); 4792 (void) sleep(interval); 4793 } 4794 } 4795 4796 static void 4797 get_mac_stats(const char *dev, pktsum_t *stats) 4798 { 4799 kstat_ctl_t *kcp; 4800 kstat_t *ksp; 4801 char module[DLPI_LINKNAME_MAX]; 4802 uint_t instance; 4803 4804 4805 bzero(stats, sizeof (*stats)); 4806 4807 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 4808 return; 4809 4810 if ((kcp = kstat_open()) == NULL) { 4811 warn("kstat open operation failed"); 4812 return; 4813 } 4814 4815 ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL); 4816 if (ksp != NULL) 4817 dladm_get_stats(kcp, ksp, stats); 4818 4819 (void) kstat_close(kcp); 4820 4821 } 4822 4823 static void 4824 get_link_stats(const char *link, pktsum_t *stats) 4825 { 4826 kstat_ctl_t *kcp; 4827 kstat_t *ksp; 4828 4829 bzero(stats, sizeof (*stats)); 4830 4831 if ((kcp = kstat_open()) == NULL) { 4832 warn("kstat_open operation failed"); 4833 return; 4834 } 4835 4836 ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL); 4837 4838 if (ksp != NULL) 4839 dladm_get_stats(kcp, ksp, stats); 4840 4841 (void) kstat_close(kcp); 4842 } 4843 4844 static int 4845 query_kstat(char *module, int instance, const char *name, const char *stat, 4846 uint8_t type, void *val) 4847 { 4848 kstat_ctl_t *kcp; 4849 kstat_t *ksp; 4850 4851 if ((kcp = kstat_open()) == NULL) { 4852 warn("kstat open operation failed"); 4853 return (-1); 4854 } 4855 4856 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 4857 /* 4858 * The kstat query could fail if the underlying MAC 4859 * driver was already detached. 4860 */ 4861 goto bail; 4862 } 4863 4864 if (kstat_read(kcp, ksp, NULL) == -1) { 4865 warn("kstat read failed"); 4866 goto bail; 4867 } 4868 4869 if (dladm_kstat_value(ksp, stat, type, val) < 0) 4870 goto bail; 4871 4872 (void) kstat_close(kcp); 4873 return (0); 4874 4875 bail: 4876 (void) kstat_close(kcp); 4877 return (-1); 4878 } 4879 4880 static int 4881 get_one_kstat(const char *name, const char *stat, uint8_t type, 4882 void *val, boolean_t islink) 4883 { 4884 char module[DLPI_LINKNAME_MAX]; 4885 uint_t instance; 4886 4887 if (islink) { 4888 return (query_kstat("link", 0, name, stat, type, val)); 4889 } else { 4890 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS) 4891 return (-1); 4892 4893 return (query_kstat(module, instance, "mac", stat, type, val)); 4894 } 4895 } 4896 4897 static uint64_t 4898 get_ifspeed(const char *name, boolean_t islink) 4899 { 4900 uint64_t ifspeed = 0; 4901 4902 (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64, 4903 &ifspeed, islink); 4904 4905 return (ifspeed); 4906 } 4907 4908 static const char * 4909 get_linkstate(const char *name, boolean_t islink, char *buf) 4910 { 4911 link_state_t linkstate; 4912 4913 if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32, 4914 &linkstate, islink) != 0) { 4915 (void) strlcpy(buf, "?", DLADM_STRSIZE); 4916 return (buf); 4917 } 4918 return (dladm_linkstate2str(linkstate, buf)); 4919 } 4920 4921 static const char * 4922 get_linkduplex(const char *name, boolean_t islink, char *buf) 4923 { 4924 link_duplex_t linkduplex; 4925 4926 if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32, 4927 &linkduplex, islink) != 0) { 4928 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 4929 return (buf); 4930 } 4931 4932 return (dladm_linkduplex2str(linkduplex, buf)); 4933 } 4934 4935 static int 4936 parse_wifi_fields(char *str, ofmt_handle_t *ofmt, uint_t cmdtype, 4937 boolean_t parsable) 4938 { 4939 ofmt_field_t *template, *of; 4940 ofmt_cb_t *fn; 4941 ofmt_status_t oferr; 4942 4943 if (cmdtype == WIFI_CMD_SCAN) { 4944 template = wifi_common_fields; 4945 if (str == NULL) 4946 str = def_scan_wifi_fields; 4947 if (strcasecmp(str, "all") == 0) 4948 str = all_scan_wifi_fields; 4949 fn = print_wlan_attr_cb; 4950 } else if (cmdtype == WIFI_CMD_SHOW) { 4951 bcopy(wifi_common_fields, &wifi_show_fields[2], 4952 sizeof (wifi_common_fields)); 4953 template = wifi_show_fields; 4954 if (str == NULL) 4955 str = def_show_wifi_fields; 4956 if (strcasecmp(str, "all") == 0) 4957 str = all_show_wifi_fields; 4958 fn = print_link_attr_cb; 4959 } else { 4960 return (-1); 4961 } 4962 4963 for (of = template; of->of_name != NULL; of++) { 4964 if (of->of_cb == NULL) 4965 of->of_cb = fn; 4966 } 4967 4968 oferr = ofmt_open(str, template, (parsable ? OFMT_PARSABLE : 0), 4969 0, ofmt); 4970 dladm_ofmt_check(oferr, parsable, *ofmt); 4971 return (0); 4972 } 4973 4974 typedef struct print_wifi_state { 4975 char *ws_link; 4976 boolean_t ws_parsable; 4977 boolean_t ws_header; 4978 ofmt_handle_t ws_ofmt; 4979 } print_wifi_state_t; 4980 4981 typedef struct wlan_scan_args_s { 4982 print_wifi_state_t *ws_state; 4983 void *ws_attr; 4984 } wlan_scan_args_t; 4985 4986 static boolean_t 4987 print_wlan_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 4988 { 4989 wlan_scan_args_t *w = ofarg->ofmt_cbarg; 4990 print_wifi_state_t *statep = w->ws_state; 4991 dladm_wlan_attr_t *attrp = w->ws_attr; 4992 char tmpbuf[DLADM_STRSIZE]; 4993 4994 if (ofarg->ofmt_id == 0) { 4995 (void) strlcpy(buf, (char *)statep->ws_link, bufsize); 4996 return (B_TRUE); 4997 } 4998 4999 if ((ofarg->ofmt_id & attrp->wa_valid) == 0) 5000 return (B_TRUE); 5001 5002 switch (ofarg->ofmt_id) { 5003 case DLADM_WLAN_ATTR_ESSID: 5004 (void) dladm_wlan_essid2str(&attrp->wa_essid, tmpbuf); 5005 break; 5006 case DLADM_WLAN_ATTR_BSSID: 5007 (void) dladm_wlan_bssid2str(&attrp->wa_bssid, tmpbuf); 5008 break; 5009 case DLADM_WLAN_ATTR_SECMODE: 5010 (void) dladm_wlan_secmode2str(&attrp->wa_secmode, tmpbuf); 5011 break; 5012 case DLADM_WLAN_ATTR_STRENGTH: 5013 (void) dladm_wlan_strength2str(&attrp->wa_strength, tmpbuf); 5014 break; 5015 case DLADM_WLAN_ATTR_MODE: 5016 (void) dladm_wlan_mode2str(&attrp->wa_mode, tmpbuf); 5017 break; 5018 case DLADM_WLAN_ATTR_SPEED: 5019 (void) dladm_wlan_speed2str(&attrp->wa_speed, tmpbuf); 5020 (void) strlcat(tmpbuf, "Mb", sizeof (tmpbuf)); 5021 break; 5022 case DLADM_WLAN_ATTR_AUTH: 5023 (void) dladm_wlan_auth2str(&attrp->wa_auth, tmpbuf); 5024 break; 5025 case DLADM_WLAN_ATTR_BSSTYPE: 5026 (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, tmpbuf); 5027 break; 5028 } 5029 (void) strlcpy(buf, tmpbuf, bufsize); 5030 5031 return (B_TRUE); 5032 } 5033 5034 static boolean_t 5035 print_scan_results(void *arg, dladm_wlan_attr_t *attrp) 5036 { 5037 print_wifi_state_t *statep = arg; 5038 wlan_scan_args_t warg; 5039 5040 bzero(&warg, sizeof (warg)); 5041 warg.ws_state = statep; 5042 warg.ws_attr = attrp; 5043 ofmt_print(statep->ws_ofmt, &warg); 5044 return (B_TRUE); 5045 } 5046 5047 static int 5048 scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5049 { 5050 print_wifi_state_t *statep = arg; 5051 dladm_status_t status; 5052 char link[MAXLINKNAMELEN]; 5053 5054 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 5055 sizeof (link))) != DLADM_STATUS_OK) { 5056 return (DLADM_WALK_CONTINUE); 5057 } 5058 5059 statep->ws_link = link; 5060 status = dladm_wlan_scan(dh, linkid, statep, print_scan_results); 5061 if (status != DLADM_STATUS_OK) 5062 die_dlerr(status, "cannot scan link '%s'", statep->ws_link); 5063 5064 return (DLADM_WALK_CONTINUE); 5065 } 5066 5067 static boolean_t 5068 print_wifi_status_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 5069 { 5070 static char tmpbuf[DLADM_STRSIZE]; 5071 wlan_scan_args_t *w = ofarg->ofmt_cbarg; 5072 dladm_wlan_linkattr_t *attrp = w->ws_attr; 5073 5074 if ((ofarg->ofmt_id & attrp->la_valid) != 0) { 5075 (void) dladm_wlan_linkstatus2str(&attrp->la_status, tmpbuf); 5076 (void) strlcpy(buf, tmpbuf, bufsize); 5077 } 5078 return (B_TRUE); 5079 } 5080 5081 static boolean_t 5082 print_link_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 5083 { 5084 wlan_scan_args_t *w = ofarg->ofmt_cbarg, w1; 5085 print_wifi_state_t *statep = w->ws_state; 5086 dladm_wlan_linkattr_t *attrp = w->ws_attr; 5087 5088 bzero(&w1, sizeof (w1)); 5089 w1.ws_state = statep; 5090 w1.ws_attr = &attrp->la_wlan_attr; 5091 ofarg->ofmt_cbarg = &w1; 5092 return (print_wlan_attr_cb(ofarg, buf, bufsize)); 5093 } 5094 5095 static int 5096 show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5097 { 5098 print_wifi_state_t *statep = arg; 5099 dladm_wlan_linkattr_t attr; 5100 dladm_status_t status; 5101 char link[MAXLINKNAMELEN]; 5102 wlan_scan_args_t warg; 5103 5104 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 5105 sizeof (link))) != DLADM_STATUS_OK) { 5106 return (DLADM_WALK_CONTINUE); 5107 } 5108 5109 /* dladm_wlan_get_linkattr() memsets attr with 0 */ 5110 status = dladm_wlan_get_linkattr(dh, linkid, &attr); 5111 if (status != DLADM_STATUS_OK) 5112 die_dlerr(status, "cannot get link attributes for %s", link); 5113 5114 statep->ws_link = link; 5115 5116 bzero(&warg, sizeof (warg)); 5117 warg.ws_state = statep; 5118 warg.ws_attr = &attr; 5119 ofmt_print(statep->ws_ofmt, &warg); 5120 return (DLADM_WALK_CONTINUE); 5121 } 5122 5123 static void 5124 do_display_wifi(int argc, char **argv, int cmd, const char *use) 5125 { 5126 int option; 5127 char *fields_str = NULL; 5128 int (*callback)(dladm_handle_t, datalink_id_t, void *); 5129 print_wifi_state_t state; 5130 datalink_id_t linkid = DATALINK_ALL_LINKID; 5131 dladm_status_t status; 5132 5133 if (cmd == WIFI_CMD_SCAN) 5134 callback = scan_wifi; 5135 else if (cmd == WIFI_CMD_SHOW) 5136 callback = show_wifi; 5137 else 5138 return; 5139 5140 state.ws_parsable = B_FALSE; 5141 state.ws_header = B_TRUE; 5142 opterr = 0; 5143 while ((option = getopt_long(argc, argv, ":o:p", 5144 wifi_longopts, NULL)) != -1) { 5145 switch (option) { 5146 case 'o': 5147 fields_str = optarg; 5148 break; 5149 case 'p': 5150 state.ws_parsable = B_TRUE; 5151 break; 5152 default: 5153 die_opterr(optopt, option, use); 5154 } 5155 } 5156 5157 if (state.ws_parsable && fields_str == NULL) 5158 die("-p requires -o"); 5159 5160 if (state.ws_parsable && strcasecmp(fields_str, "all") == 0) 5161 die("\"-o all\" is invalid with -p"); 5162 5163 if (optind == (argc - 1)) { 5164 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5165 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5166 die_dlerr(status, "link %s is not valid", argv[optind]); 5167 } 5168 } else if (optind != argc) { 5169 usage(); 5170 } 5171 5172 if (parse_wifi_fields(fields_str, &state.ws_ofmt, cmd, 5173 state.ws_parsable) < 0) 5174 die("invalid field(s) specified"); 5175 5176 if (linkid == DATALINK_ALL_LINKID) { 5177 (void) dladm_walk_datalink_id(callback, handle, &state, 5178 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 5179 DL_WIFI, DLADM_OPT_ACTIVE); 5180 } else { 5181 (void) (*callback)(handle, linkid, &state); 5182 } 5183 ofmt_close(state.ws_ofmt); 5184 } 5185 5186 static void 5187 do_scan_wifi(int argc, char **argv, const char *use) 5188 { 5189 do_display_wifi(argc, argv, WIFI_CMD_SCAN, use); 5190 } 5191 5192 static void 5193 do_show_wifi(int argc, char **argv, const char *use) 5194 { 5195 do_display_wifi(argc, argv, WIFI_CMD_SHOW, use); 5196 } 5197 5198 typedef struct wlan_count_attr { 5199 uint_t wc_count; 5200 datalink_id_t wc_linkid; 5201 } wlan_count_attr_t; 5202 5203 /* ARGSUSED */ 5204 static int 5205 do_count_wlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5206 { 5207 wlan_count_attr_t *cp = arg; 5208 5209 if (cp->wc_count == 0) 5210 cp->wc_linkid = linkid; 5211 cp->wc_count++; 5212 return (DLADM_WALK_CONTINUE); 5213 } 5214 5215 static int 5216 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) 5217 { 5218 uint_t i; 5219 dladm_wlan_key_t *wk; 5220 int nfields = 1; 5221 char *field, *token, *lasts = NULL, c; 5222 5223 token = str; 5224 while ((c = *token++) != NULL) { 5225 if (c == ',') 5226 nfields++; 5227 } 5228 token = strdup(str); 5229 if (token == NULL) 5230 return (-1); 5231 5232 wk = malloc(nfields * sizeof (dladm_wlan_key_t)); 5233 if (wk == NULL) 5234 goto fail; 5235 5236 token = str; 5237 for (i = 0; i < nfields; i++) { 5238 char *s; 5239 dladm_secobj_class_t class; 5240 dladm_status_t status; 5241 5242 field = strtok_r(token, ",", &lasts); 5243 token = NULL; 5244 5245 (void) strlcpy(wk[i].wk_name, field, 5246 DLADM_WLAN_MAX_KEYNAME_LEN); 5247 5248 wk[i].wk_idx = 1; 5249 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 5250 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 5251 goto fail; 5252 5253 wk[i].wk_idx = (uint_t)(s[1] - '0'); 5254 *s = '\0'; 5255 } 5256 wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN; 5257 5258 status = dladm_get_secobj(handle, wk[i].wk_name, &class, 5259 wk[i].wk_val, &wk[i].wk_len, 0); 5260 if (status != DLADM_STATUS_OK) { 5261 if (status == DLADM_STATUS_NOTFOUND) { 5262 status = dladm_get_secobj(handle, wk[i].wk_name, 5263 &class, wk[i].wk_val, &wk[i].wk_len, 5264 DLADM_OPT_PERSIST); 5265 } 5266 if (status != DLADM_STATUS_OK) 5267 goto fail; 5268 } 5269 wk[i].wk_class = class; 5270 } 5271 *keys = wk; 5272 *key_countp = i; 5273 free(token); 5274 return (0); 5275 fail: 5276 free(wk); 5277 free(token); 5278 return (-1); 5279 } 5280 5281 static void 5282 do_connect_wifi(int argc, char **argv, const char *use) 5283 { 5284 int option; 5285 dladm_wlan_attr_t attr, *attrp; 5286 dladm_status_t status = DLADM_STATUS_OK; 5287 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 5288 datalink_id_t linkid = DATALINK_ALL_LINKID; 5289 dladm_wlan_key_t *keys = NULL; 5290 uint_t key_count = 0; 5291 uint_t flags = 0; 5292 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 5293 char buf[DLADM_STRSIZE]; 5294 5295 opterr = 0; 5296 (void) memset(&attr, 0, sizeof (attr)); 5297 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 5298 wifi_longopts, NULL)) != -1) { 5299 switch (option) { 5300 case 'e': 5301 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 5302 if (status != DLADM_STATUS_OK) 5303 die("invalid ESSID '%s'", optarg); 5304 5305 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 5306 /* 5307 * Try to connect without doing a scan. 5308 */ 5309 flags |= DLADM_WLAN_CONNECT_NOSCAN; 5310 break; 5311 case 'i': 5312 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 5313 if (status != DLADM_STATUS_OK) 5314 die("invalid BSSID %s", optarg); 5315 5316 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 5317 break; 5318 case 'a': 5319 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 5320 if (status != DLADM_STATUS_OK) 5321 die("invalid authentication mode '%s'", optarg); 5322 5323 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 5324 break; 5325 case 'm': 5326 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 5327 if (status != DLADM_STATUS_OK) 5328 die("invalid mode '%s'", optarg); 5329 5330 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 5331 break; 5332 case 'b': 5333 if ((status = dladm_wlan_str2bsstype(optarg, 5334 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 5335 die("invalid bsstype '%s'", optarg); 5336 } 5337 5338 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 5339 break; 5340 case 's': 5341 if ((status = dladm_wlan_str2secmode(optarg, 5342 &attr.wa_secmode)) != DLADM_STATUS_OK) { 5343 die("invalid security mode '%s'", optarg); 5344 } 5345 5346 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 5347 break; 5348 case 'k': 5349 if (parse_wlan_keys(optarg, &keys, &key_count) < 0) 5350 die("invalid key(s) '%s'", optarg); 5351 5352 if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP) 5353 keysecmode = DLADM_WLAN_SECMODE_WEP; 5354 else 5355 keysecmode = DLADM_WLAN_SECMODE_WPA; 5356 break; 5357 case 'T': 5358 if (strcasecmp(optarg, "forever") == 0) { 5359 timeout = -1; 5360 break; 5361 } 5362 if (!str2int(optarg, &timeout) || timeout < 0) 5363 die("invalid timeout value '%s'", optarg); 5364 break; 5365 case 'c': 5366 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 5367 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 5368 break; 5369 default: 5370 die_opterr(optopt, option, use); 5371 break; 5372 } 5373 } 5374 5375 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 5376 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) { 5377 die("key required for security mode '%s'", 5378 dladm_wlan_secmode2str(&attr.wa_secmode, buf)); 5379 } 5380 } else { 5381 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 5382 attr.wa_secmode != keysecmode) 5383 die("incompatible -s and -k options"); 5384 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 5385 attr.wa_secmode = keysecmode; 5386 } 5387 5388 if (optind == (argc - 1)) { 5389 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5390 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5391 die_dlerr(status, "link %s is not valid", argv[optind]); 5392 } 5393 } else if (optind != argc) { 5394 usage(); 5395 } 5396 5397 if (linkid == DATALINK_ALL_LINKID) { 5398 wlan_count_attr_t wcattr; 5399 5400 wcattr.wc_linkid = DATALINK_INVALID_LINKID; 5401 wcattr.wc_count = 0; 5402 (void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr, 5403 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 5404 DL_WIFI, DLADM_OPT_ACTIVE); 5405 if (wcattr.wc_count == 0) { 5406 die("no wifi links are available"); 5407 } else if (wcattr.wc_count > 1) { 5408 die("link name is required when more than one wifi " 5409 "link is available"); 5410 } 5411 linkid = wcattr.wc_linkid; 5412 } 5413 attrp = (attr.wa_valid == 0) ? NULL : &attr; 5414 again: 5415 if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys, 5416 key_count, flags)) != DLADM_STATUS_OK) { 5417 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 5418 /* 5419 * Try again with scanning and filtering. 5420 */ 5421 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 5422 goto again; 5423 } 5424 5425 if (status == DLADM_STATUS_NOTFOUND) { 5426 if (attr.wa_valid == 0) { 5427 die("no wifi networks are available"); 5428 } else { 5429 die("no wifi networks with the specified " 5430 "criteria are available"); 5431 } 5432 } 5433 die_dlerr(status, "cannot connect"); 5434 } 5435 free(keys); 5436 } 5437 5438 /* ARGSUSED */ 5439 static int 5440 do_all_disconnect_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5441 { 5442 dladm_status_t status; 5443 5444 status = dladm_wlan_disconnect(dh, linkid); 5445 if (status != DLADM_STATUS_OK) 5446 warn_dlerr(status, "cannot disconnect link"); 5447 5448 return (DLADM_WALK_CONTINUE); 5449 } 5450 5451 static void 5452 do_disconnect_wifi(int argc, char **argv, const char *use) 5453 { 5454 int option; 5455 datalink_id_t linkid = DATALINK_ALL_LINKID; 5456 boolean_t all_links = B_FALSE; 5457 dladm_status_t status; 5458 wlan_count_attr_t wcattr; 5459 5460 opterr = 0; 5461 while ((option = getopt_long(argc, argv, ":a", 5462 wifi_longopts, NULL)) != -1) { 5463 switch (option) { 5464 case 'a': 5465 all_links = B_TRUE; 5466 break; 5467 default: 5468 die_opterr(optopt, option, use); 5469 break; 5470 } 5471 } 5472 5473 if (optind == (argc - 1)) { 5474 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5475 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5476 die_dlerr(status, "link %s is not valid", argv[optind]); 5477 } 5478 } else if (optind != argc) { 5479 usage(); 5480 } 5481 5482 if (linkid == DATALINK_ALL_LINKID) { 5483 if (!all_links) { 5484 wcattr.wc_linkid = linkid; 5485 wcattr.wc_count = 0; 5486 (void) dladm_walk_datalink_id(do_count_wlan, handle, 5487 &wcattr, 5488 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 5489 DL_WIFI, DLADM_OPT_ACTIVE); 5490 if (wcattr.wc_count == 0) { 5491 die("no wifi links are available"); 5492 } else if (wcattr.wc_count > 1) { 5493 die("link name is required when more than " 5494 "one wifi link is available"); 5495 } 5496 linkid = wcattr.wc_linkid; 5497 } else { 5498 (void) dladm_walk_datalink_id(do_all_disconnect_wifi, 5499 handle, NULL, 5500 DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, 5501 DL_WIFI, DLADM_OPT_ACTIVE); 5502 return; 5503 } 5504 } 5505 status = dladm_wlan_disconnect(handle, linkid); 5506 if (status != DLADM_STATUS_OK) 5507 die_dlerr(status, "cannot disconnect"); 5508 } 5509 5510 static void 5511 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, 5512 const char *propname, dladm_prop_type_t type, const char *format, 5513 char **pptr) 5514 { 5515 int i; 5516 char *ptr, *lim; 5517 char buf[DLADM_STRSIZE]; 5518 char *unknown = "--", *notsup = ""; 5519 char **propvals = statep->ls_propvals; 5520 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5521 dladm_status_t status; 5522 5523 status = dladm_get_linkprop(handle, linkid, type, propname, propvals, 5524 &valcnt); 5525 if (status != DLADM_STATUS_OK) { 5526 if (status == DLADM_STATUS_TEMPONLY) { 5527 if (type == DLADM_PROP_VAL_MODIFIABLE && 5528 statep->ls_persist) { 5529 valcnt = 1; 5530 propvals = &unknown; 5531 } else { 5532 statep->ls_status = status; 5533 statep->ls_retstatus = status; 5534 return; 5535 } 5536 } else if (status == DLADM_STATUS_NOTSUP || 5537 statep->ls_persist) { 5538 valcnt = 1; 5539 if (type == DLADM_PROP_VAL_CURRENT || 5540 type == DLADM_PROP_VAL_PERM) 5541 propvals = &unknown; 5542 else 5543 propvals = ¬sup; 5544 } else if (status == DLADM_STATUS_NOTDEFINED) { 5545 propvals = ¬sup; /* STR_UNDEF_VAL */ 5546 } else { 5547 if (statep->ls_proplist && 5548 statep->ls_status == DLADM_STATUS_OK) { 5549 warn_dlerr(status, 5550 "cannot get link property '%s' for %s", 5551 propname, statep->ls_link); 5552 } 5553 statep->ls_status = status; 5554 statep->ls_retstatus = status; 5555 return; 5556 } 5557 } 5558 5559 statep->ls_status = DLADM_STATUS_OK; 5560 5561 ptr = buf; 5562 lim = buf + DLADM_STRSIZE; 5563 for (i = 0; i < valcnt; i++) { 5564 if (propvals[i][0] == '\0' && !statep->ls_parsable) 5565 ptr += snprintf(ptr, lim - ptr, "--,"); 5566 else 5567 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 5568 if (ptr >= lim) 5569 break; 5570 } 5571 if (valcnt > 0) 5572 buf[strlen(buf) - 1] = '\0'; 5573 5574 lim = statep->ls_line + MAX_PROP_LINE; 5575 if (statep->ls_parsable) { 5576 *pptr += snprintf(*pptr, lim - *pptr, 5577 "%s", buf); 5578 } else { 5579 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 5580 } 5581 } 5582 5583 static boolean_t 5584 print_linkprop_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 5585 { 5586 linkprop_args_t *arg = ofarg->ofmt_cbarg; 5587 char *propname = arg->ls_propname; 5588 show_linkprop_state_t *statep = arg->ls_state; 5589 char *ptr = statep->ls_line; 5590 char *lim = ptr + MAX_PROP_LINE; 5591 datalink_id_t linkid = arg->ls_linkid; 5592 5593 switch (ofarg->ofmt_id) { 5594 case LINKPROP_LINK: 5595 (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); 5596 break; 5597 case LINKPROP_PROPERTY: 5598 (void) snprintf(ptr, lim - ptr, "%s", propname); 5599 break; 5600 case LINKPROP_VALUE: 5601 print_linkprop(linkid, statep, propname, 5602 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 5603 DLADM_PROP_VAL_CURRENT, "%s", &ptr); 5604 /* 5605 * If we failed to query the link property, for example, query 5606 * the persistent value of a non-persistable link property, 5607 * simply skip the output. 5608 */ 5609 if (statep->ls_status != DLADM_STATUS_OK) 5610 goto skip; 5611 ptr = statep->ls_line; 5612 break; 5613 case LINKPROP_PERM: 5614 print_linkprop(linkid, statep, propname, 5615 DLADM_PROP_VAL_PERM, "%s", &ptr); 5616 if (statep->ls_status != DLADM_STATUS_OK) 5617 goto skip; 5618 ptr = statep->ls_line; 5619 break; 5620 case LINKPROP_DEFAULT: 5621 print_linkprop(linkid, statep, propname, 5622 DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 5623 if (statep->ls_status != DLADM_STATUS_OK) 5624 goto skip; 5625 ptr = statep->ls_line; 5626 break; 5627 case LINKPROP_POSSIBLE: 5628 print_linkprop(linkid, statep, propname, 5629 DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 5630 if (statep->ls_status != DLADM_STATUS_OK) 5631 goto skip; 5632 ptr = statep->ls_line; 5633 break; 5634 default: 5635 die("invalid input"); 5636 break; 5637 } 5638 (void) strlcpy(buf, ptr, bufsize); 5639 return (B_TRUE); 5640 skip: 5641 return ((statep->ls_status == DLADM_STATUS_OK) ? 5642 B_TRUE : B_FALSE); 5643 } 5644 5645 static boolean_t 5646 linkprop_is_supported(datalink_id_t linkid, const char *propname, 5647 show_linkprop_state_t *statep) 5648 { 5649 dladm_status_t status; 5650 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5651 5652 /* if used with -p flag, always print output */ 5653 if (statep->ls_proplist != NULL) 5654 return (B_TRUE); 5655 5656 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_DEFAULT, 5657 propname, statep->ls_propvals, &valcnt); 5658 5659 if (status == DLADM_STATUS_OK) 5660 return (B_TRUE); 5661 5662 /* 5663 * A system wide default value is not available for the 5664 * property. Check if current value can be retrieved. 5665 */ 5666 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT, 5667 propname, statep->ls_propvals, &valcnt); 5668 5669 return (status == DLADM_STATUS_OK); 5670 } 5671 5672 /* ARGSUSED */ 5673 static int 5674 show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname, 5675 void *arg) 5676 { 5677 show_linkprop_state_t *statep = arg; 5678 linkprop_args_t ls_arg; 5679 5680 bzero(&ls_arg, sizeof (ls_arg)); 5681 ls_arg.ls_state = statep; 5682 ls_arg.ls_propname = (char *)propname; 5683 ls_arg.ls_linkid = linkid; 5684 5685 /* 5686 * This will need to be fixed when kernel interfaces are added 5687 * to enable walking of all known private properties. For now, 5688 * we are limited to walking persistent private properties only. 5689 */ 5690 if ((propname[0] == '_') && !statep->ls_persist && 5691 (statep->ls_proplist == NULL)) 5692 return (DLADM_WALK_CONTINUE); 5693 if (!statep->ls_parsable && 5694 !linkprop_is_supported(linkid, propname, statep)) 5695 return (DLADM_WALK_CONTINUE); 5696 5697 ofmt_print(statep->ls_ofmt, &ls_arg); 5698 5699 return (DLADM_WALK_CONTINUE); 5700 } 5701 5702 static void 5703 do_show_linkprop(int argc, char **argv, const char *use) 5704 { 5705 int option; 5706 char propstr[DLADM_STRSIZE]; 5707 dladm_arg_list_t *proplist = NULL; 5708 datalink_id_t linkid = DATALINK_ALL_LINKID; 5709 show_linkprop_state_t state; 5710 uint32_t flags = DLADM_OPT_ACTIVE; 5711 dladm_status_t status; 5712 char *fields_str = NULL; 5713 ofmt_handle_t ofmt; 5714 ofmt_status_t oferr; 5715 uint_t ofmtflags = 0; 5716 5717 bzero(propstr, DLADM_STRSIZE); 5718 opterr = 0; 5719 state.ls_propvals = NULL; 5720 state.ls_line = NULL; 5721 state.ls_parsable = B_FALSE; 5722 state.ls_persist = B_FALSE; 5723 state.ls_header = B_TRUE; 5724 state.ls_retstatus = DLADM_STATUS_OK; 5725 5726 while ((option = getopt_long(argc, argv, ":p:cPo:", 5727 prop_longopts, NULL)) != -1) { 5728 switch (option) { 5729 case 'p': 5730 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 5731 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 5732 DLADM_STRSIZE) 5733 die("property list too long '%s'", propstr); 5734 break; 5735 case 'c': 5736 state.ls_parsable = B_TRUE; 5737 break; 5738 case 'P': 5739 state.ls_persist = B_TRUE; 5740 flags = DLADM_OPT_PERSIST; 5741 break; 5742 case 'o': 5743 fields_str = optarg; 5744 break; 5745 default: 5746 die_opterr(optopt, option, use); 5747 break; 5748 } 5749 } 5750 5751 if (optind == (argc - 1)) { 5752 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5753 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5754 die_dlerr(status, "link %s is not valid", argv[optind]); 5755 } 5756 } else if (optind != argc) { 5757 usage(); 5758 } 5759 5760 if (dladm_parse_link_props(propstr, &proplist, B_TRUE) 5761 != DLADM_STATUS_OK) 5762 die("invalid link properties specified"); 5763 state.ls_proplist = proplist; 5764 state.ls_status = DLADM_STATUS_OK; 5765 5766 if (state.ls_parsable) 5767 ofmtflags |= OFMT_PARSABLE; 5768 oferr = ofmt_open(fields_str, linkprop_fields, ofmtflags, 0, &ofmt); 5769 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 5770 state.ls_ofmt = ofmt; 5771 5772 if (linkid == DATALINK_ALL_LINKID) { 5773 (void) dladm_walk_datalink_id(show_linkprop_onelink, handle, 5774 &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 5775 } else { 5776 (void) show_linkprop_onelink(handle, linkid, &state); 5777 } 5778 ofmt_close(ofmt); 5779 dladm_free_props(proplist); 5780 5781 if (state.ls_retstatus != DLADM_STATUS_OK) { 5782 dladm_close(handle); 5783 exit(EXIT_FAILURE); 5784 } 5785 } 5786 5787 static int 5788 show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg) 5789 { 5790 int i; 5791 char *buf; 5792 uint32_t flags; 5793 dladm_arg_list_t *proplist = NULL; 5794 show_linkprop_state_t *statep = arg; 5795 dlpi_handle_t dh = NULL; 5796 5797 statep->ls_status = DLADM_STATUS_OK; 5798 5799 if (dladm_datalink_id2info(hdl, linkid, &flags, NULL, NULL, 5800 statep->ls_link, MAXLINKNAMELEN) != DLADM_STATUS_OK) { 5801 statep->ls_status = DLADM_STATUS_NOTFOUND; 5802 return (DLADM_WALK_CONTINUE); 5803 } 5804 5805 if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) || 5806 (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) { 5807 statep->ls_status = DLADM_STATUS_BADARG; 5808 return (DLADM_WALK_CONTINUE); 5809 } 5810 5811 proplist = statep->ls_proplist; 5812 5813 /* 5814 * When some WiFi links are opened for the first time, their hardware 5815 * automatically scans for APs and does other slow operations. Thus, 5816 * if there are no open links, the retrieval of link properties 5817 * (below) will proceed slowly unless we hold the link open. 5818 * 5819 * Note that failure of dlpi_open() does not necessarily mean invalid 5820 * link properties, because dlpi_open() may fail because of incorrect 5821 * autopush configuration. Therefore, we ingore the return value of 5822 * dlpi_open(). 5823 */ 5824 if (!statep->ls_persist) 5825 (void) dlpi_open(statep->ls_link, &dh, 0); 5826 5827 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 5828 DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 5829 if (buf == NULL) 5830 die("insufficient memory"); 5831 5832 statep->ls_propvals = (char **)(void *)buf; 5833 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 5834 statep->ls_propvals[i] = buf + 5835 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 5836 i * DLADM_PROP_VAL_MAX; 5837 } 5838 statep->ls_line = buf + 5839 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 5840 5841 if (proplist != NULL) { 5842 for (i = 0; i < proplist->al_count; i++) { 5843 (void) show_linkprop(hdl, linkid, 5844 proplist->al_info[i].ai_name, statep); 5845 } 5846 } else { 5847 (void) dladm_walk_linkprop(hdl, linkid, statep, 5848 show_linkprop); 5849 } 5850 if (dh != NULL) 5851 dlpi_close(dh); 5852 free(buf); 5853 return (DLADM_WALK_CONTINUE); 5854 } 5855 5856 static dladm_status_t 5857 set_linkprop_persist(datalink_id_t linkid, const char *prop_name, 5858 char **prop_val, uint_t val_cnt, boolean_t reset) 5859 { 5860 dladm_status_t status; 5861 5862 status = dladm_set_linkprop(handle, linkid, prop_name, prop_val, 5863 val_cnt, DLADM_OPT_PERSIST); 5864 5865 if (status != DLADM_STATUS_OK) { 5866 warn_dlerr(status, "cannot persistently %s link property '%s'", 5867 reset ? "reset" : "set", prop_name); 5868 } 5869 return (status); 5870 } 5871 5872 static int 5873 reset_one_linkprop(dladm_handle_t dh, datalink_id_t linkid, 5874 const char *propname, void *arg) 5875 { 5876 set_linkprop_state_t *statep = arg; 5877 dladm_status_t status; 5878 5879 status = dladm_set_linkprop(dh, linkid, propname, NULL, 0, 5880 DLADM_OPT_ACTIVE); 5881 if (status != DLADM_STATUS_OK) { 5882 warn_dlerr(status, "cannot reset link property '%s' on '%s'", 5883 propname, statep->ls_name); 5884 } 5885 if (!statep->ls_temp) { 5886 dladm_status_t s; 5887 5888 s = set_linkprop_persist(linkid, propname, NULL, 0, 5889 statep->ls_reset); 5890 if (s != DLADM_STATUS_OK) 5891 status = s; 5892 } 5893 if (status != DLADM_STATUS_OK) 5894 statep->ls_status = status; 5895 5896 return (DLADM_WALK_CONTINUE); 5897 } 5898 5899 static void 5900 set_linkprop(int argc, char **argv, boolean_t reset, const char *use) 5901 { 5902 int i, option; 5903 char errmsg[DLADM_STRSIZE]; 5904 char *altroot = NULL; 5905 datalink_id_t linkid; 5906 boolean_t temp = B_FALSE; 5907 dladm_status_t status = DLADM_STATUS_OK; 5908 char propstr[DLADM_STRSIZE]; 5909 dladm_arg_list_t *proplist = NULL; 5910 5911 opterr = 0; 5912 bzero(propstr, DLADM_STRSIZE); 5913 5914 while ((option = getopt_long(argc, argv, ":p:R:t", 5915 prop_longopts, NULL)) != -1) { 5916 switch (option) { 5917 case 'p': 5918 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 5919 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 5920 DLADM_STRSIZE) 5921 die("property list too long '%s'", propstr); 5922 break; 5923 case 't': 5924 temp = B_TRUE; 5925 break; 5926 case 'R': 5927 altroot = optarg; 5928 break; 5929 default: 5930 die_opterr(optopt, option, use); 5931 5932 } 5933 } 5934 5935 /* get link name (required last argument) */ 5936 if (optind != (argc - 1)) 5937 usage(); 5938 5939 if (dladm_parse_link_props(propstr, &proplist, reset) != 5940 DLADM_STATUS_OK) 5941 die("invalid link properties specified"); 5942 5943 if (proplist == NULL && !reset) 5944 die("link property must be specified"); 5945 5946 if (altroot != NULL) { 5947 dladm_free_props(proplist); 5948 altroot_cmd(altroot, argc, argv); 5949 } 5950 5951 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 5952 NULL); 5953 if (status != DLADM_STATUS_OK) 5954 die_dlerr(status, "link %s is not valid", argv[optind]); 5955 5956 if (proplist == NULL) { 5957 set_linkprop_state_t state; 5958 5959 state.ls_name = argv[optind]; 5960 state.ls_reset = reset; 5961 state.ls_temp = temp; 5962 state.ls_status = DLADM_STATUS_OK; 5963 5964 (void) dladm_walk_linkprop(handle, linkid, &state, 5965 reset_one_linkprop); 5966 5967 status = state.ls_status; 5968 goto done; 5969 } 5970 5971 for (i = 0; i < proplist->al_count; i++) { 5972 dladm_arg_info_t *aip = &proplist->al_info[i]; 5973 char **val; 5974 uint_t count; 5975 dladm_status_t s; 5976 5977 if (reset) { 5978 val = NULL; 5979 count = 0; 5980 } else { 5981 val = aip->ai_val; 5982 count = aip->ai_count; 5983 if (count == 0) { 5984 warn("no value specified for '%s'", 5985 aip->ai_name); 5986 status = DLADM_STATUS_BADARG; 5987 continue; 5988 } 5989 } 5990 s = dladm_set_linkprop(handle, linkid, aip->ai_name, val, count, 5991 DLADM_OPT_ACTIVE); 5992 if (s == DLADM_STATUS_OK) { 5993 if (!temp) { 5994 s = set_linkprop_persist(linkid, 5995 aip->ai_name, val, count, reset); 5996 if (s != DLADM_STATUS_OK) 5997 status = s; 5998 } 5999 continue; 6000 } 6001 status = s; 6002 switch (s) { 6003 case DLADM_STATUS_NOTFOUND: 6004 warn("invalid link property '%s'", aip->ai_name); 6005 break; 6006 case DLADM_STATUS_BADVAL: { 6007 int j; 6008 char *ptr, *lim; 6009 char **propvals = NULL; 6010 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 6011 6012 ptr = malloc((sizeof (char *) + 6013 DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 6014 MAX_PROP_LINE); 6015 6016 propvals = (char **)(void *)ptr; 6017 if (propvals == NULL) 6018 die("insufficient memory"); 6019 6020 for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 6021 propvals[j] = ptr + sizeof (char *) * 6022 DLADM_MAX_PROP_VALCNT + 6023 j * DLADM_PROP_VAL_MAX; 6024 } 6025 s = dladm_get_linkprop(handle, linkid, 6026 DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals, 6027 &valcnt); 6028 6029 if (s != DLADM_STATUS_OK) { 6030 warn_dlerr(status, "cannot set link property " 6031 "'%s' on '%s'", aip->ai_name, argv[optind]); 6032 free(propvals); 6033 break; 6034 } 6035 6036 ptr = errmsg; 6037 lim = ptr + DLADM_STRSIZE; 6038 *ptr = '\0'; 6039 for (j = 0; j < valcnt; j++) { 6040 ptr += snprintf(ptr, lim - ptr, "%s,", 6041 propvals[j]); 6042 if (ptr >= lim) 6043 break; 6044 } 6045 if (ptr > errmsg) { 6046 *(ptr - 1) = '\0'; 6047 warn("link property '%s' must be one of: %s", 6048 aip->ai_name, errmsg); 6049 } else 6050 warn("invalid link property '%s'", *val); 6051 free(propvals); 6052 break; 6053 } 6054 default: 6055 if (reset) { 6056 warn_dlerr(status, "cannot reset link property " 6057 "'%s' on '%s'", aip->ai_name, argv[optind]); 6058 } else { 6059 warn_dlerr(status, "cannot set link property " 6060 "'%s' on '%s'", aip->ai_name, argv[optind]); 6061 } 6062 break; 6063 } 6064 } 6065 done: 6066 dladm_free_props(proplist); 6067 if (status != DLADM_STATUS_OK) { 6068 dladm_close(handle); 6069 exit(1); 6070 } 6071 } 6072 6073 static void 6074 do_set_linkprop(int argc, char **argv, const char *use) 6075 { 6076 set_linkprop(argc, argv, B_FALSE, use); 6077 } 6078 6079 static void 6080 do_reset_linkprop(int argc, char **argv, const char *use) 6081 { 6082 set_linkprop(argc, argv, B_TRUE, use); 6083 } 6084 6085 static int 6086 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 6087 dladm_secobj_class_t class) 6088 { 6089 int error = 0; 6090 6091 if (class == DLADM_SECOBJ_CLASS_WPA) { 6092 if (len < 8 || len > 63) 6093 return (EINVAL); 6094 (void) memcpy(obj_val, buf, len); 6095 *obj_lenp = len; 6096 return (error); 6097 } 6098 6099 if (class == DLADM_SECOBJ_CLASS_WEP) { 6100 switch (len) { 6101 case 5: /* ASCII key sizes */ 6102 case 13: 6103 (void) memcpy(obj_val, buf, len); 6104 *obj_lenp = len; 6105 break; 6106 case 10: /* Hex key sizes, not preceded by 0x */ 6107 case 26: 6108 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 6109 break; 6110 case 12: /* Hex key sizes, preceded by 0x */ 6111 case 28: 6112 if (strncmp(buf, "0x", 2) != 0) 6113 return (EINVAL); 6114 error = hexascii_to_octet(buf + 2, len - 2, 6115 obj_val, obj_lenp); 6116 break; 6117 default: 6118 return (EINVAL); 6119 } 6120 return (error); 6121 } 6122 6123 return (ENOENT); 6124 } 6125 6126 static void 6127 defersig(int sig) 6128 { 6129 signalled = sig; 6130 } 6131 6132 static int 6133 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 6134 { 6135 uint_t len = 0; 6136 int c; 6137 struct termios stored, current; 6138 void (*sigfunc)(int); 6139 6140 /* 6141 * Turn off echo -- but before we do so, defer SIGINT handling 6142 * so that a ^C doesn't leave the terminal corrupted. 6143 */ 6144 sigfunc = signal(SIGINT, defersig); 6145 (void) fflush(stdin); 6146 (void) tcgetattr(0, &stored); 6147 current = stored; 6148 current.c_lflag &= ~(ICANON|ECHO); 6149 current.c_cc[VTIME] = 0; 6150 current.c_cc[VMIN] = 1; 6151 (void) tcsetattr(0, TCSANOW, ¤t); 6152 again: 6153 if (try == 1) 6154 (void) printf(gettext("provide value for '%s': "), objname); 6155 else 6156 (void) printf(gettext("confirm value for '%s': "), objname); 6157 6158 (void) fflush(stdout); 6159 while (signalled == 0) { 6160 c = getchar(); 6161 if (c == '\n' || c == '\r') { 6162 if (len != 0) 6163 break; 6164 (void) putchar('\n'); 6165 goto again; 6166 } 6167 6168 buf[len++] = c; 6169 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 6170 break; 6171 (void) putchar('*'); 6172 } 6173 6174 (void) putchar('\n'); 6175 (void) fflush(stdin); 6176 6177 /* 6178 * Restore terminal setting and handle deferred signals. 6179 */ 6180 (void) tcsetattr(0, TCSANOW, &stored); 6181 6182 (void) signal(SIGINT, sigfunc); 6183 if (signalled != 0) 6184 (void) kill(getpid(), signalled); 6185 6186 return (len); 6187 } 6188 6189 static int 6190 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 6191 dladm_secobj_class_t class, FILE *filep) 6192 { 6193 int rval; 6194 uint_t len, len2; 6195 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 6196 6197 if (filep == NULL) { 6198 len = get_secobj_from_tty(1, obj_name, buf); 6199 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 6200 if (rval == 0) { 6201 len2 = get_secobj_from_tty(2, obj_name, buf2); 6202 if (len != len2 || memcmp(buf, buf2, len) != 0) 6203 rval = ENOTSUP; 6204 } 6205 return (rval); 6206 } else { 6207 for (;;) { 6208 if (fgets(buf, sizeof (buf), filep) == NULL) 6209 break; 6210 if (isspace(buf[0])) 6211 continue; 6212 6213 len = strlen(buf); 6214 if (buf[len - 1] == '\n') { 6215 buf[len - 1] = '\0'; 6216 len--; 6217 } 6218 break; 6219 } 6220 (void) fclose(filep); 6221 } 6222 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 6223 } 6224 6225 static boolean_t 6226 check_auth(const char *auth) 6227 { 6228 struct passwd *pw; 6229 6230 if ((pw = getpwuid(getuid())) == NULL) 6231 return (B_FALSE); 6232 6233 return (chkauthattr(auth, pw->pw_name) != 0); 6234 } 6235 6236 static void 6237 audit_secobj(char *auth, char *class, char *obj, 6238 boolean_t success, boolean_t create) 6239 { 6240 adt_session_data_t *ah; 6241 adt_event_data_t *event; 6242 au_event_t flag; 6243 char *errstr; 6244 6245 if (create) { 6246 flag = ADT_dladm_create_secobj; 6247 errstr = "ADT_dladm_create_secobj"; 6248 } else { 6249 flag = ADT_dladm_delete_secobj; 6250 errstr = "ADT_dladm_delete_secobj"; 6251 } 6252 6253 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 6254 die("adt_start_session: %s", strerror(errno)); 6255 6256 if ((event = adt_alloc_event(ah, flag)) == NULL) 6257 die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 6258 6259 /* fill in audit info */ 6260 if (create) { 6261 event->adt_dladm_create_secobj.auth_used = auth; 6262 event->adt_dladm_create_secobj.obj_class = class; 6263 event->adt_dladm_create_secobj.obj_name = obj; 6264 } else { 6265 event->adt_dladm_delete_secobj.auth_used = auth; 6266 event->adt_dladm_delete_secobj.obj_class = class; 6267 event->adt_dladm_delete_secobj.obj_name = obj; 6268 } 6269 6270 if (success) { 6271 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 6272 die("adt_put_event (%s, success): %s", errstr, 6273 strerror(errno)); 6274 } 6275 } else { 6276 if (adt_put_event(event, ADT_FAILURE, 6277 ADT_FAIL_VALUE_AUTH) != 0) { 6278 die("adt_put_event: (%s, failure): %s", errstr, 6279 strerror(errno)); 6280 } 6281 } 6282 6283 adt_free_event(event); 6284 (void) adt_end_session(ah); 6285 } 6286 6287 #define MAX_SECOBJS 32 6288 #define MAX_SECOBJ_NAMELEN 32 6289 static void 6290 do_create_secobj(int argc, char **argv, const char *use) 6291 { 6292 int option, rval; 6293 FILE *filep = NULL; 6294 char *obj_name = NULL; 6295 char *class_name = NULL; 6296 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 6297 uint_t obj_len; 6298 boolean_t success, temp = B_FALSE; 6299 dladm_status_t status; 6300 dladm_secobj_class_t class = -1; 6301 uid_t euid; 6302 6303 opterr = 0; 6304 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 6305 while ((option = getopt_long(argc, argv, ":f:c:R:t", 6306 wifi_longopts, NULL)) != -1) { 6307 switch (option) { 6308 case 'f': 6309 euid = geteuid(); 6310 (void) seteuid(getuid()); 6311 filep = fopen(optarg, "r"); 6312 if (filep == NULL) { 6313 die("cannot open %s: %s", optarg, 6314 strerror(errno)); 6315 } 6316 (void) seteuid(euid); 6317 break; 6318 case 'c': 6319 class_name = optarg; 6320 status = dladm_str2secobjclass(optarg, &class); 6321 if (status != DLADM_STATUS_OK) { 6322 die("invalid secure object class '%s', " 6323 "valid values are: wep, wpa", optarg); 6324 } 6325 break; 6326 case 't': 6327 temp = B_TRUE; 6328 break; 6329 case 'R': 6330 status = dladm_set_rootdir(optarg); 6331 if (status != DLADM_STATUS_OK) { 6332 die_dlerr(status, "invalid directory " 6333 "specified"); 6334 } 6335 break; 6336 default: 6337 die_opterr(optopt, option, use); 6338 break; 6339 } 6340 } 6341 6342 if (optind == (argc - 1)) 6343 obj_name = argv[optind]; 6344 else if (optind != argc) 6345 usage(); 6346 6347 if (class == -1) 6348 die("secure object class required"); 6349 6350 if (obj_name == NULL) 6351 die("secure object name required"); 6352 6353 if (!dladm_valid_secobj_name(obj_name)) 6354 die("invalid secure object name '%s'", obj_name); 6355 6356 success = check_auth(LINK_SEC_AUTH); 6357 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 6358 if (!success) 6359 die("authorization '%s' is required", LINK_SEC_AUTH); 6360 6361 rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 6362 if (rval != 0) { 6363 switch (rval) { 6364 case ENOENT: 6365 die("invalid secure object class"); 6366 break; 6367 case EINVAL: 6368 die("invalid secure object value"); 6369 break; 6370 case ENOTSUP: 6371 die("verification failed"); 6372 break; 6373 default: 6374 die("invalid secure object: %s", strerror(rval)); 6375 break; 6376 } 6377 } 6378 6379 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 6380 DLADM_OPT_CREATE | DLADM_OPT_ACTIVE); 6381 if (status != DLADM_STATUS_OK) { 6382 die_dlerr(status, "could not create secure object '%s'", 6383 obj_name); 6384 } 6385 if (temp) 6386 return; 6387 6388 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 6389 DLADM_OPT_PERSIST); 6390 if (status != DLADM_STATUS_OK) { 6391 warn_dlerr(status, "could not persistently create secure " 6392 "object '%s'", obj_name); 6393 } 6394 } 6395 6396 static void 6397 do_delete_secobj(int argc, char **argv, const char *use) 6398 { 6399 int i, option; 6400 boolean_t temp = B_FALSE; 6401 boolean_t success; 6402 dladm_status_t status, pstatus; 6403 int nfields = 1; 6404 char *field, *token, *lasts = NULL, c; 6405 6406 opterr = 0; 6407 status = pstatus = DLADM_STATUS_OK; 6408 while ((option = getopt_long(argc, argv, ":R:t", 6409 wifi_longopts, NULL)) != -1) { 6410 switch (option) { 6411 case 't': 6412 temp = B_TRUE; 6413 break; 6414 case 'R': 6415 status = dladm_set_rootdir(optarg); 6416 if (status != DLADM_STATUS_OK) { 6417 die_dlerr(status, "invalid directory " 6418 "specified"); 6419 } 6420 break; 6421 default: 6422 die_opterr(optopt, option, use); 6423 break; 6424 } 6425 } 6426 6427 if (optind == (argc - 1)) { 6428 token = argv[optind]; 6429 if (token == NULL) 6430 die("secure object name required"); 6431 while ((c = *token++) != NULL) { 6432 if (c == ',') 6433 nfields++; 6434 } 6435 token = strdup(argv[optind]); 6436 if (token == NULL) 6437 die("no memory"); 6438 } else if (optind != argc) 6439 usage(); 6440 6441 success = check_auth(LINK_SEC_AUTH); 6442 audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE); 6443 if (!success) 6444 die("authorization '%s' is required", LINK_SEC_AUTH); 6445 6446 for (i = 0; i < nfields; i++) { 6447 6448 field = strtok_r(token, ",", &lasts); 6449 token = NULL; 6450 status = dladm_unset_secobj(handle, field, DLADM_OPT_ACTIVE); 6451 if (!temp) { 6452 pstatus = dladm_unset_secobj(handle, field, 6453 DLADM_OPT_PERSIST); 6454 } else { 6455 pstatus = DLADM_STATUS_OK; 6456 } 6457 6458 if (status != DLADM_STATUS_OK) { 6459 warn_dlerr(status, "could not delete secure object " 6460 "'%s'", field); 6461 } 6462 if (pstatus != DLADM_STATUS_OK) { 6463 warn_dlerr(pstatus, "could not persistently delete " 6464 "secure object '%s'", field); 6465 } 6466 } 6467 free(token); 6468 6469 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) { 6470 dladm_close(handle); 6471 exit(1); 6472 } 6473 } 6474 6475 typedef struct show_secobj_state { 6476 boolean_t ss_persist; 6477 boolean_t ss_parsable; 6478 boolean_t ss_header; 6479 ofmt_handle_t ss_ofmt; 6480 } show_secobj_state_t; 6481 6482 6483 static boolean_t 6484 show_secobj(dladm_handle_t dh, void *arg, const char *obj_name) 6485 { 6486 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 6487 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 6488 char buf[DLADM_STRSIZE]; 6489 uint_t flags = 0; 6490 dladm_secobj_class_t class; 6491 show_secobj_state_t *statep = arg; 6492 dladm_status_t status; 6493 secobj_fields_buf_t sbuf; 6494 6495 bzero(&sbuf, sizeof (secobj_fields_buf_t)); 6496 if (statep->ss_persist) 6497 flags |= DLADM_OPT_PERSIST; 6498 6499 status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len, 6500 flags); 6501 if (status != DLADM_STATUS_OK) 6502 die_dlerr(status, "cannot get secure object '%s'", obj_name); 6503 6504 (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), 6505 obj_name); 6506 (void) dladm_secobjclass2str(class, buf); 6507 (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf); 6508 if (getuid() == 0) { 6509 char val[DLADM_SECOBJ_VAL_MAX * 2]; 6510 uint_t len = sizeof (val); 6511 6512 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) 6513 (void) snprintf(sbuf.ss_val, 6514 sizeof (sbuf.ss_val), "%s", val); 6515 } 6516 ofmt_print(statep->ss_ofmt, &sbuf); 6517 return (B_TRUE); 6518 } 6519 6520 static void 6521 do_show_secobj(int argc, char **argv, const char *use) 6522 { 6523 int option; 6524 show_secobj_state_t state; 6525 dladm_status_t status; 6526 boolean_t o_arg = B_FALSE; 6527 uint_t i; 6528 uint_t flags; 6529 char *fields_str = NULL; 6530 char *def_fields = "object,class"; 6531 char *all_fields = "object,class,value"; 6532 char *field, *token, *lasts = NULL, c; 6533 ofmt_handle_t ofmt; 6534 ofmt_status_t oferr; 6535 uint_t ofmtflags = 0; 6536 6537 opterr = 0; 6538 bzero(&state, sizeof (state)); 6539 state.ss_parsable = B_FALSE; 6540 fields_str = def_fields; 6541 state.ss_persist = B_FALSE; 6542 state.ss_parsable = B_FALSE; 6543 state.ss_header = B_TRUE; 6544 while ((option = getopt_long(argc, argv, ":pPo:", 6545 wifi_longopts, NULL)) != -1) { 6546 switch (option) { 6547 case 'p': 6548 state.ss_parsable = B_TRUE; 6549 break; 6550 case 'P': 6551 state.ss_persist = B_TRUE; 6552 break; 6553 case 'o': 6554 o_arg = B_TRUE; 6555 if (strcasecmp(optarg, "all") == 0) 6556 fields_str = all_fields; 6557 else 6558 fields_str = optarg; 6559 break; 6560 default: 6561 die_opterr(optopt, option, use); 6562 break; 6563 } 6564 } 6565 6566 if (state.ss_parsable && !o_arg) 6567 die("option -c requires -o"); 6568 6569 if (state.ss_parsable && fields_str == all_fields) 6570 die("\"-o all\" is invalid with -p"); 6571 6572 if (state.ss_parsable) 6573 ofmtflags |= OFMT_PARSABLE; 6574 oferr = ofmt_open(fields_str, secobj_fields, ofmtflags, 0, &ofmt); 6575 dladm_ofmt_check(oferr, state.ss_parsable, ofmt); 6576 state.ss_ofmt = ofmt; 6577 6578 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 6579 6580 if (optind == (argc - 1)) { 6581 uint_t obj_fields = 1; 6582 6583 token = argv[optind]; 6584 if (token == NULL) 6585 die("secure object name required"); 6586 while ((c = *token++) != NULL) { 6587 if (c == ',') 6588 obj_fields++; 6589 } 6590 token = strdup(argv[optind]); 6591 if (token == NULL) 6592 die("no memory"); 6593 for (i = 0; i < obj_fields; i++) { 6594 field = strtok_r(token, ",", &lasts); 6595 token = NULL; 6596 if (!show_secobj(handle, &state, field)) 6597 break; 6598 } 6599 free(token); 6600 ofmt_close(ofmt); 6601 return; 6602 } else if (optind != argc) 6603 usage(); 6604 6605 status = dladm_walk_secobj(handle, &state, show_secobj, flags); 6606 6607 if (status != DLADM_STATUS_OK) 6608 die_dlerr(status, "show-secobj"); 6609 ofmt_close(ofmt); 6610 } 6611 6612 /*ARGSUSED*/ 6613 static int 6614 i_dladm_init_linkprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6615 { 6616 (void) dladm_init_linkprop(dh, linkid, B_TRUE); 6617 return (DLADM_WALK_CONTINUE); 6618 } 6619 6620 /*ARGSUSED*/ 6621 void 6622 do_init_linkprop(int argc, char **argv, const char *use) 6623 { 6624 int option; 6625 dladm_status_t status; 6626 datalink_id_t linkid = DATALINK_ALL_LINKID; 6627 datalink_media_t media = DATALINK_ANY_MEDIATYPE; 6628 uint_t any_media = B_TRUE; 6629 6630 opterr = 0; 6631 while ((option = getopt(argc, argv, ":w")) != -1) { 6632 switch (option) { 6633 case 'w': 6634 media = DL_WIFI; 6635 any_media = B_FALSE; 6636 break; 6637 default: 6638 /* 6639 * Because init-linkprop is not a public command, 6640 * print the usage instead. 6641 */ 6642 usage(); 6643 break; 6644 } 6645 } 6646 6647 if (optind == (argc - 1)) { 6648 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6649 NULL, NULL, NULL)) != DLADM_STATUS_OK) 6650 die_dlerr(status, "link %s is not valid", argv[optind]); 6651 } else if (optind != argc) { 6652 usage(); 6653 } 6654 6655 if (linkid == DATALINK_ALL_LINKID) { 6656 /* 6657 * linkprops of links of other classes have been initialized as 6658 * part of the dladm up-xxx operation. 6659 */ 6660 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle, 6661 NULL, DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST); 6662 } else { 6663 (void) dladm_init_linkprop(handle, linkid, any_media); 6664 } 6665 } 6666 6667 static void 6668 do_show_ether(int argc, char **argv, const char *use) 6669 { 6670 int option; 6671 datalink_id_t linkid; 6672 print_ether_state_t state; 6673 char *fields_str = NULL; 6674 ofmt_handle_t ofmt; 6675 ofmt_status_t oferr; 6676 uint_t ofmtflags = 0; 6677 6678 bzero(&state, sizeof (state)); 6679 state.es_link = NULL; 6680 state.es_parsable = B_FALSE; 6681 6682 while ((option = getopt_long(argc, argv, "o:px", 6683 showeth_lopts, NULL)) != -1) { 6684 switch (option) { 6685 case 'x': 6686 state.es_extended = B_TRUE; 6687 break; 6688 case 'p': 6689 state.es_parsable = B_TRUE; 6690 break; 6691 case 'o': 6692 fields_str = optarg; 6693 break; 6694 default: 6695 die_opterr(optopt, option, use); 6696 break; 6697 } 6698 } 6699 6700 if (optind == (argc - 1)) 6701 state.es_link = argv[optind]; 6702 6703 if (state.es_parsable) 6704 ofmtflags |= OFMT_PARSABLE; 6705 oferr = ofmt_open(fields_str, ether_fields, ofmtflags, 6706 DLADM_DEFAULT_COL, &ofmt); 6707 dladm_ofmt_check(oferr, state.es_parsable, ofmt); 6708 state.es_ofmt = ofmt; 6709 6710 if (state.es_link == NULL) { 6711 (void) dladm_walk_datalink_id(show_etherprop, handle, &state, 6712 DATALINK_CLASS_PHYS, DL_ETHER, DLADM_OPT_ACTIVE); 6713 } else { 6714 if (!link_is_ether(state.es_link, &linkid)) 6715 die("invalid link specified"); 6716 (void) show_etherprop(handle, linkid, &state); 6717 } 6718 ofmt_close(ofmt); 6719 } 6720 6721 static int 6722 show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6723 { 6724 print_ether_state_t *statep = arg; 6725 ether_fields_buf_t ebuf; 6726 dladm_ether_info_t eattr; 6727 dladm_status_t status; 6728 6729 bzero(&ebuf, sizeof (ether_fields_buf_t)); 6730 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, 6731 ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) { 6732 return (DLADM_WALK_CONTINUE); 6733 } 6734 6735 status = dladm_ether_info(dh, linkid, &eattr); 6736 if (status != DLADM_STATUS_OK) 6737 goto cleanup; 6738 6739 (void) strlcpy(ebuf.eth_ptype, "current", sizeof (ebuf.eth_ptype)); 6740 6741 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 6742 sizeof (ebuf.eth_autoneg), &eattr, CURRENT); 6743 (void) dladm_ether_pause2str(ebuf.eth_pause, 6744 sizeof (ebuf.eth_pause), &eattr, CURRENT); 6745 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 6746 sizeof (ebuf.eth_spdx), &eattr, CURRENT); 6747 (void) strlcpy(ebuf.eth_state, 6748 dladm_linkstate2str(eattr.lei_state, ebuf.eth_state), 6749 sizeof (ebuf.eth_state)); 6750 (void) strlcpy(ebuf.eth_rem_fault, 6751 (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"), 6752 sizeof (ebuf.eth_rem_fault)); 6753 6754 ofmt_print(statep->es_ofmt, &ebuf); 6755 6756 if (statep->es_extended) 6757 show_ether_xprop(arg, &eattr); 6758 6759 cleanup: 6760 dladm_ether_info_done(&eattr); 6761 return (DLADM_WALK_CONTINUE); 6762 } 6763 6764 /* ARGSUSED */ 6765 static void 6766 do_init_secobj(int argc, char **argv, const char *use) 6767 { 6768 dladm_status_t status; 6769 6770 status = dladm_init_secobj(handle); 6771 if (status != DLADM_STATUS_OK) 6772 die_dlerr(status, "secure object initialization failed"); 6773 } 6774 6775 /* 6776 * "-R" option support. It is used for live upgrading. Append dladm commands 6777 * to a upgrade script which will be run when the alternative root boots up: 6778 * 6779 * - If the /etc/dladm/datalink.conf file exists on the alternative root, 6780 * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink 6781 * script. This script will be run as part of the network/physical service. 6782 * We cannot defer this to /var/svc/profile/upgrade because then the 6783 * configuration will not be able to take effect before network/physical 6784 * plumbs various interfaces. 6785 * 6786 * - If the /etc/dladm/datalink.conf file does not exist on the alternative 6787 * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script, 6788 * which will be run in the manifest-import service. 6789 * 6790 * Note that the SMF team is considering to move the manifest-import service 6791 * to be run at the very begining of boot. Once that is done, the need for 6792 * the /var/svc/profile/upgrade_datalink script will not exist any more. 6793 */ 6794 static void 6795 altroot_cmd(char *altroot, int argc, char *argv[]) 6796 { 6797 char path[MAXPATHLEN]; 6798 struct stat stbuf; 6799 FILE *fp; 6800 int i; 6801 6802 /* 6803 * Check for the existence of the /etc/dladm/datalink.conf 6804 * configuration file, and determine the name of script file. 6805 */ 6806 (void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf", 6807 altroot); 6808 if (stat(path, &stbuf) < 0) { 6809 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 6810 SMF_UPGRADE_FILE); 6811 } else { 6812 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 6813 SMF_UPGRADEDATALINK_FILE); 6814 } 6815 6816 if ((fp = fopen(path, "a+")) == NULL) 6817 die("operation not supported on %s", altroot); 6818 6819 (void) fprintf(fp, "/sbin/dladm "); 6820 for (i = 0; i < argc; i++) { 6821 /* 6822 * Directly write to the file if it is not the "-R <altroot>" 6823 * option. In which case, skip it. 6824 */ 6825 if (strcmp(argv[i], "-R") != 0) 6826 (void) fprintf(fp, "%s ", argv[i]); 6827 else 6828 i ++; 6829 } 6830 (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG); 6831 (void) fclose(fp); 6832 dladm_close(handle); 6833 exit(0); 6834 } 6835 6836 /* 6837 * Convert the string to an integer. Note that the string must not have any 6838 * trailing non-integer characters. 6839 */ 6840 static boolean_t 6841 str2int(const char *str, int *valp) 6842 { 6843 int val; 6844 char *endp = NULL; 6845 6846 errno = 0; 6847 val = strtol(str, &endp, 10); 6848 if (errno != 0 || *endp != '\0') 6849 return (B_FALSE); 6850 6851 *valp = val; 6852 return (B_TRUE); 6853 } 6854 6855 /* PRINTFLIKE1 */ 6856 static void 6857 warn(const char *format, ...) 6858 { 6859 va_list alist; 6860 6861 format = gettext(format); 6862 (void) fprintf(stderr, "%s: warning: ", progname); 6863 6864 va_start(alist, format); 6865 (void) vfprintf(stderr, format, alist); 6866 va_end(alist); 6867 6868 (void) putchar('\n'); 6869 } 6870 6871 /* PRINTFLIKE2 */ 6872 static void 6873 warn_dlerr(dladm_status_t err, const char *format, ...) 6874 { 6875 va_list alist; 6876 char errmsg[DLADM_STRSIZE]; 6877 6878 format = gettext(format); 6879 (void) fprintf(stderr, gettext("%s: warning: "), progname); 6880 6881 va_start(alist, format); 6882 (void) vfprintf(stderr, format, alist); 6883 va_end(alist); 6884 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 6885 } 6886 6887 /* 6888 * Also closes the dladm handle if it is not NULL. 6889 */ 6890 /* PRINTFLIKE2 */ 6891 static void 6892 die_dlerr(dladm_status_t err, const char *format, ...) 6893 { 6894 va_list alist; 6895 char errmsg[DLADM_STRSIZE]; 6896 6897 format = gettext(format); 6898 (void) fprintf(stderr, "%s: ", progname); 6899 6900 va_start(alist, format); 6901 (void) vfprintf(stderr, format, alist); 6902 va_end(alist); 6903 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 6904 6905 /* close dladm handle if it was opened */ 6906 if (handle != NULL) 6907 dladm_close(handle); 6908 6909 exit(EXIT_FAILURE); 6910 } 6911 6912 /* PRINTFLIKE1 */ 6913 static void 6914 die(const char *format, ...) 6915 { 6916 va_list alist; 6917 6918 format = gettext(format); 6919 (void) fprintf(stderr, "%s: ", progname); 6920 6921 va_start(alist, format); 6922 (void) vfprintf(stderr, format, alist); 6923 va_end(alist); 6924 6925 (void) putchar('\n'); 6926 6927 /* close dladm handle if it was opened */ 6928 if (handle != NULL) 6929 dladm_close(handle); 6930 6931 exit(EXIT_FAILURE); 6932 } 6933 6934 static void 6935 die_optdup(int opt) 6936 { 6937 die("the option -%c cannot be specified more than once", opt); 6938 } 6939 6940 static void 6941 die_opterr(int opt, int opterr, const char *usage) 6942 { 6943 switch (opterr) { 6944 case ':': 6945 die("option '-%c' requires a value\nusage: %s", opt, 6946 gettext(usage)); 6947 break; 6948 case '?': 6949 default: 6950 die("unrecognized option '-%c'\nusage: %s", opt, 6951 gettext(usage)); 6952 break; 6953 } 6954 } 6955 6956 static void 6957 show_ether_xprop(void *arg, dladm_ether_info_t *eattr) 6958 { 6959 print_ether_state_t *statep = arg; 6960 ether_fields_buf_t ebuf; 6961 int i; 6962 6963 for (i = CAPABLE; i <= PEERADV; i++) { 6964 bzero(&ebuf, sizeof (ebuf)); 6965 (void) strlcpy(ebuf.eth_ptype, ptype[i], 6966 sizeof (ebuf.eth_ptype)); 6967 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 6968 sizeof (ebuf.eth_autoneg), eattr, i); 6969 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 6970 sizeof (ebuf.eth_spdx), eattr, i); 6971 (void) dladm_ether_pause2str(ebuf.eth_pause, 6972 sizeof (ebuf.eth_pause), eattr, i); 6973 (void) strlcpy(ebuf.eth_rem_fault, 6974 (eattr->lei_attr[i].le_fault ? "fault" : "none"), 6975 sizeof (ebuf.eth_rem_fault)); 6976 ofmt_print(statep->es_ofmt, &ebuf); 6977 } 6978 6979 } 6980 6981 static boolean_t 6982 link_is_ether(const char *link, datalink_id_t *linkid) 6983 { 6984 uint32_t media; 6985 datalink_class_t class; 6986 6987 if (dladm_name2info(handle, link, linkid, NULL, &class, &media) == 6988 DLADM_STATUS_OK) { 6989 if (class == DATALINK_CLASS_PHYS && media == DL_ETHER) 6990 return (B_TRUE); 6991 } 6992 return (B_FALSE); 6993 } 6994 6995 /* 6996 * default output callback function that, when invoked, 6997 * prints string which is offset by ofmt_arg->ofmt_id within buf. 6998 */ 6999 static boolean_t 7000 print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 7001 { 7002 char *value; 7003 7004 value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id; 7005 (void) strlcpy(buf, value, bufsize); 7006 return (B_TRUE); 7007 } 7008 7009 static void 7010 dladm_ofmt_check(ofmt_status_t oferr, boolean_t parsable, 7011 ofmt_handle_t ofmt) 7012 { 7013 char buf[OFMT_BUFSIZE]; 7014 7015 if (oferr == OFMT_SUCCESS) 7016 return; 7017 (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf)); 7018 /* 7019 * All errors are considered fatal in parsable mode. 7020 * NOMEM errors are always fatal, regardless of mode. 7021 * For other errors, we print diagnostics in human-readable 7022 * mode and processs what we can. 7023 */ 7024 if (parsable || oferr == OFMT_ENOFIELDS) { 7025 ofmt_close(ofmt); 7026 die(buf); 7027 } else { 7028 warn(buf); 7029 } 7030 } 7031