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