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