1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25#include <stdio.h>
26#include <ctype.h>
27#include <dlfcn.h>
28#include <locale.h>
29#include <signal.h>
30#include <stdarg.h>
31#include <stdlib.h>
32#include <fcntl.h>
33#include <string.h>
34#include <stropts.h>
35#include <sys/stat.h>
36#include <errno.h>
37#include <kstat.h>
38#include <strings.h>
39#include <getopt.h>
40#include <unistd.h>
41#include <priv.h>
42#include <limits.h>
43#include <termios.h>
44#include <pwd.h>
45#include <auth_attr.h>
46#include <auth_list.h>
47#include <libintl.h>
48#include <libdevinfo.h>
49#include <libdlpi.h>
50#include <libdladm.h>
51#include <libdllink.h>
52#include <libdlstat.h>
53#include <libdlaggr.h>
54#include <libdlwlan.h>
55#include <libdlvlan.h>
56#include <libdlvnic.h>
57#include <libdlib.h>
58#include <libdlether.h>
59#include <libdliptun.h>
60#include <libdlsim.h>
61#include <libdlbridge.h>
62#include <libinetutil.h>
63#include <libvrrpadm.h>
64#include <bsm/adt.h>
65#include <bsm/adt_event.h>
66#include <libdlvnic.h>
67#include <sys/types.h>
68#include <sys/socket.h>
69#include <sys/ib/ib_types.h>
70#include <sys/processor.h>
71#include <netinet/in.h>
72#include <arpa/inet.h>
73#include <net/if_types.h>
74#include <stddef.h>
75#include <stp_in.h>
76#include <ofmt.h>
77
78#define	MAXPORT			256
79#define	MAXVNIC			256
80#define	BUFLEN(lim, ptr)	(((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
81#define	MAXLINELEN		1024
82#define	SMF_UPGRADE_FILE		"/var/svc/profile/upgrade"
83#define	SMF_UPGRADEDATALINK_FILE	"/var/svc/profile/upgrade_datalink"
84#define	SMF_DLADM_UPGRADE_MSG		" # added by dladm(1M)"
85#define	DLADM_DEFAULT_COL	80
86
87/*
88 * used by the wifi show-* commands to set up ofmt_field_t structures.
89 */
90#define	WIFI_CMD_SCAN		0x00000001
91#define	WIFI_CMD_SHOW		0x00000002
92#define	WIFI_CMD_ALL		(WIFI_CMD_SCAN | WIFI_CMD_SHOW)
93
94/* No larger than pktsum_t */
95typedef struct brsum_s {
96	uint64_t	drops;
97	uint64_t	forward_dir;
98	uint64_t	forward_mb;
99	uint64_t	forward_unk;
100	uint64_t	recv;
101	uint64_t	sent;
102} brsum_t;
103
104/* No larger than pktsum_t */
105typedef struct brlsum_s {
106	uint32_t	cfgbpdu;
107	uint32_t	tcnbpdu;
108	uint32_t	rstpbpdu;
109	uint32_t	txbpdu;
110	uint64_t	drops;
111	uint64_t	recv;
112	uint64_t	xmit;
113} brlsum_t;
114
115typedef struct show_state {
116	boolean_t	ls_firstonly;
117	boolean_t	ls_donefirst;
118	pktsum_t	ls_prevstats;
119	uint32_t	ls_flags;
120	dladm_status_t	ls_status;
121	ofmt_handle_t	ls_ofmt;
122	boolean_t	ls_parsable;
123	boolean_t	ls_mac;
124	boolean_t	ls_hwgrp;
125} show_state_t;
126
127typedef struct show_grp_state {
128	pktsum_t	gs_prevstats[MAXPORT];
129	uint32_t	gs_flags;
130	dladm_status_t	gs_status;
131	boolean_t	gs_parsable;
132	boolean_t	gs_lacp;
133	boolean_t	gs_extended;
134	boolean_t	gs_stats;
135	boolean_t	gs_firstonly;
136	boolean_t	gs_donefirst;
137	ofmt_handle_t	gs_ofmt;
138} show_grp_state_t;
139
140typedef struct show_vnic_state {
141	datalink_id_t	vs_vnic_id;
142	datalink_id_t	vs_link_id;
143	char		vs_vnic[MAXLINKNAMELEN];
144	char		vs_link[MAXLINKNAMELEN];
145	boolean_t	vs_parsable;
146	boolean_t	vs_found;
147	boolean_t	vs_firstonly;
148	boolean_t	vs_donefirst;
149	boolean_t	vs_stats;
150	boolean_t	vs_printstats;
151	pktsum_t	vs_totalstats;
152	pktsum_t	vs_prevstats[MAXVNIC];
153	boolean_t	vs_etherstub;
154	dladm_status_t	vs_status;
155	uint32_t	vs_flags;
156	ofmt_handle_t	vs_ofmt;
157} show_vnic_state_t;
158
159typedef struct show_part_state {
160	datalink_id_t	ps_over_id;
161	char		ps_part[MAXLINKNAMELEN];
162	boolean_t	ps_parsable;
163	boolean_t	ps_found;
164	dladm_status_t	ps_status;
165	uint32_t	ps_flags;
166	ofmt_handle_t	ps_ofmt;
167} show_part_state_t;
168
169typedef struct show_ib_state {
170	datalink_id_t	is_link_id;
171	char		is_link[MAXLINKNAMELEN];
172	boolean_t	is_parsable;
173	dladm_status_t	is_status;
174	uint32_t	is_flags;
175	ofmt_handle_t	is_ofmt;
176} show_ib_state_t;
177
178typedef struct show_usage_state_s {
179	boolean_t	us_plot;
180	boolean_t	us_parsable;
181	boolean_t	us_printheader;
182	boolean_t	us_first;
183	boolean_t	us_showall;
184	ofmt_handle_t	us_ofmt;
185} show_usage_state_t;
186
187/*
188 * callback functions for printing output and error diagnostics.
189 */
190static ofmt_cb_t print_default_cb, print_link_stats_cb, print_linkprop_cb;
191static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb;
192static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb;
193static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb;
194static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb;
195static void dladm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
196
197typedef void cmdfunc_t(int, char **, const char *);
198
199static cmdfunc_t do_show_link, do_show_wifi, do_show_phys;
200static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr;
201static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr;
202static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi;
203static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop;
204static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj;
205static cmdfunc_t do_init_linkprop, do_init_secobj;
206static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan;
207static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys;
208static cmdfunc_t do_show_linkmap;
209static cmdfunc_t do_show_ether;
210static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic;
211static cmdfunc_t do_up_vnic;
212static cmdfunc_t do_create_part, do_delete_part, do_show_part, do_show_ib;
213static cmdfunc_t do_up_part;
214static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub;
215static cmdfunc_t do_create_simnet, do_modify_simnet;
216static cmdfunc_t do_delete_simnet, do_show_simnet, do_up_simnet;
217static cmdfunc_t do_show_usage;
218static cmdfunc_t do_create_bridge, do_modify_bridge, do_delete_bridge;
219static cmdfunc_t do_add_bridge, do_remove_bridge, do_show_bridge;
220static cmdfunc_t do_create_iptun, do_modify_iptun, do_delete_iptun;
221static cmdfunc_t do_show_iptun, do_up_iptun, do_down_iptun;
222
223static void 	do_up_vnic_common(int, char **, const char *, boolean_t);
224
225static int show_part(dladm_handle_t, datalink_id_t, void *);
226
227static void	altroot_cmd(char *, int, char **);
228static int	show_linkprop_onelink(dladm_handle_t, datalink_id_t, void *);
229
230static void	link_stats(datalink_id_t, uint_t, char *, show_state_t *);
231static void	aggr_stats(datalink_id_t, show_grp_state_t *, uint_t);
232static void	vnic_stats(show_vnic_state_t *, uint32_t);
233
234static int	get_one_kstat(const char *, const char *, uint8_t,
235		    void *, boolean_t);
236static void	get_mac_stats(const char *, pktsum_t *);
237static void	get_link_stats(const char *, pktsum_t *);
238static uint64_t	get_ifspeed(const char *, boolean_t);
239static const char	*get_linkstate(const char *, boolean_t, char *);
240static const char	*get_linkduplex(const char *, boolean_t, char *);
241
242static iptun_type_t	iptun_gettypebyname(char *);
243static const char	*iptun_gettypebyvalue(iptun_type_t);
244static dladm_status_t	print_iptun(dladm_handle_t, datalink_id_t,
245			    show_state_t *);
246static int	print_iptun_walker(dladm_handle_t, datalink_id_t, void *);
247
248static int	show_etherprop(dladm_handle_t, datalink_id_t, void *);
249static void	show_ether_xprop(void *, dladm_ether_info_t *);
250static boolean_t	link_is_ether(const char *, datalink_id_t *);
251
252static boolean_t str2int(const char *, int *);
253static void	die(const char *, ...);
254static void	die_optdup(int);
255static void	die_opterr(int, int, const char *);
256static void	die_dlerr(dladm_status_t, const char *, ...);
257static void	warn(const char *, ...);
258static void	warn_dlerr(dladm_status_t, const char *, ...);
259
260typedef struct	cmd {
261	char		*c_name;
262	cmdfunc_t	*c_fn;
263	const char	*c_usage;
264} cmd_t;
265
266static cmd_t	cmds[] = {
267	{ "rename-link",	do_rename_link,
268	    "    rename-link      <oldlink> <newlink>"			},
269	{ "show-link",		do_show_link,
270	    "    show-link        [-pP] [-o <field>,..] [-s [-i <interval>]] "
271	    "[<link>]\n"						},
272	{ "create-aggr",	do_create_aggr,
273	    "    create-aggr      [-t] [-P <policy>] [-L <mode>] [-T <time>] "
274	    "[-u <address>]\n"
275	    "\t\t     -l <link> [-l <link>...] <link>"			},
276	{ "delete-aggr",	do_delete_aggr,
277	    "    delete-aggr      [-t] <link>"				},
278	{ "add-aggr",		do_add_aggr,
279	    "    add-aggr         [-t] -l <link> [-l <link>...] <link>" },
280	{ "remove-aggr",	do_remove_aggr,
281	    "    remove-aggr      [-t] -l <link> [-l <link>...] <link>" },
282	{ "modify-aggr",	do_modify_aggr,
283	    "    modify-aggr      [-t] [-P <policy>] [-L <mode>] [-T <time>] "
284	    "[-u <address>]\n"
285	    "\t\t     <link>"						},
286	{ "show-aggr",		do_show_aggr,
287	    "    show-aggr        [-pPLx] [-o <field>,..] [-s [-i <interval>]] "
288	    "[<link>]\n"						},
289	{ "up-aggr",		do_up_aggr,	NULL			},
290	{ "scan-wifi",		do_scan_wifi,
291	    "    scan-wifi        [-p] [-o <field>,...] [<link>]"	},
292	{ "connect-wifi",	do_connect_wifi,
293	    "    connect-wifi     [-e <essid>] [-i <bssid>] [-k <key>,...] "
294	    "[-s wep|wpa]\n"
295	    "\t\t     [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g] "
296	    "[-T <time>]\n"
297	    "\t\t     [<link>]"						},
298	{ "disconnect-wifi",	do_disconnect_wifi,
299	    "    disconnect-wifi  [-a] [<link>]"			},
300	{ "show-wifi",		do_show_wifi,
301	    "    show-wifi        [-p] [-o <field>,...] [<link>]\n"	},
302	{ "set-linkprop",	do_set_linkprop,
303	    "    set-linkprop     [-t] -p <prop>=<value>[,...] <name>"	},
304	{ "reset-linkprop",	do_reset_linkprop,
305	    "    reset-linkprop   [-t] [-p <prop>,...] <name>"		},
306	{ "show-linkprop",	do_show_linkprop,
307	    "    show-linkprop    [-cP] [-o <field>,...] [-p <prop>,...] "
308	    "<name>\n"							},
309	{ "show-ether",		do_show_ether,
310	    "    show-ether       [-px][-o <field>,...] <link>\n"	},
311	{ "create-secobj",	do_create_secobj,
312	    "    create-secobj    [-t] [-f <file>] -c <class> <secobj>"	},
313	{ "delete-secobj",	do_delete_secobj,
314	    "    delete-secobj    [-t] <secobj>[,...]"			},
315	{ "show-secobj",	do_show_secobj,
316	    "    show-secobj      [-pP] [-o <field>,...] [<secobj>,...]\n" },
317	{ "init-linkprop",	do_init_linkprop,	NULL		},
318	{ "init-secobj",	do_init_secobj,		NULL		},
319	{ "create-vlan", 	do_create_vlan,
320	    "    create-vlan      [-ft] -l <link> -v <vid> [link]"	},
321	{ "delete-vlan", 	do_delete_vlan,
322	    "    delete-vlan      [-t] <link>"				},
323	{ "show-vlan",		do_show_vlan,
324	    "    show-vlan        [-pP] [-o <field>,..] [<link>]\n"	},
325	{ "up-vlan",		do_up_vlan,		NULL		},
326	{ "create-iptun",	do_create_iptun,
327	    "    create-iptun     [-t] -T <type> "
328	    "[-a {local|remote}=<addr>,...] <link>]" },
329	{ "delete-iptun",	do_delete_iptun,
330	    "    delete-iptun     [-t] <link>"				},
331	{ "modify-iptun",	do_modify_iptun,
332	    "    modify-iptun     [-t] -a {local|remote}=<addr>,... <link>" },
333	{ "show-iptun",		do_show_iptun,
334	    "    show-iptun       [-pP] [-o <field>,..] [<link>]\n"	},
335	{ "up-iptun",		do_up_iptun,		NULL		},
336	{ "down-iptun",		do_down_iptun,		NULL		},
337	{ "delete-phys",	do_delete_phys,
338	    "    delete-phys      <link>"				},
339	{ "show-phys",		do_show_phys,
340	    "    show-phys        [-pP] [-o <field>,..] [-H] [<link>]\n"},
341	{ "init-phys",		do_init_phys,		NULL		},
342	{ "show-linkmap",	do_show_linkmap,	NULL		},
343	{ "create-vnic",	do_create_vnic,
344	    "    create-vnic      [-t] -l <link> [-m <value> | auto |\n"
345	    "\t\t     {factory [-n <slot-id>]} | {random [-r <prefix>]} |\n"
346	    "\t\t     {vrrp -V <vrid> -A {inet | inet6}} [-v <vid> [-f]]\n"
347	    "\t\t     [-p <prop>=<value>[,...]] <vnic-link>"	},
348	{ "delete-vnic",	do_delete_vnic,
349	    "    delete-vnic      [-t] <vnic-link>"			},
350	{ "show-vnic",		do_show_vnic,
351	    "    show-vnic        [-pP] [-l <link>] [-s [-i <interval>]] "
352	    "[<link>]\n"						},
353	{ "up-vnic",		do_up_vnic,		NULL		},
354	{ "create-part",	do_create_part,
355	    "    create-part      [-t] [-f] -l <link> [-P <pkey>]\n"
356	    "\t\t     [-R <root-dir>] <part-link>"			},
357	{ "delete-part",	do_delete_part,
358	    "    delete-part      [-t] [-R <root-dir>] <part-link>"},
359	{ "show-part",		do_show_part,
360	    "    show-part        [-pP] [-o <field>,...][-l <linkover>]\n"
361	    "\t\t     [<part-link>]"		},
362	{ "show-ib",		do_show_ib,
363	    "    show-ib          [-p] [-o <field>,...] [<link>]\n"	},
364	{ "up-part",		do_up_part,		NULL		},
365	{ "create-etherstub",	do_create_etherstub,
366	    "    create-etherstub [-t] <link>"				},
367	{ "delete-etherstub",	do_delete_etherstub,
368	    "    delete-etherstub [-t] <link>"				},
369	{ "show-etherstub",	do_show_etherstub,
370	    "    show-etherstub   [-t] [<link>]\n"			},
371	{ "create-simnet",	do_create_simnet,	NULL		},
372	{ "modify-simnet",	do_modify_simnet,	NULL		},
373	{ "delete-simnet",	do_delete_simnet,	NULL		},
374	{ "show-simnet",	do_show_simnet,		NULL		},
375	{ "up-simnet",		do_up_simnet,		NULL		},
376	{ "create-bridge",	do_create_bridge,
377	    "    create-bridge    [-R <root-dir>] [-P <protect>] "
378	    "[-p <priority>]\n"
379	    "\t\t     [-m <max-age>] [-h <hello-time>] [-d <forward-delay>]\n"
380	    "\t\t     [-f <force-protocol>] [-l <link>]... <bridge>"	},
381	{ "modify-bridge",	do_modify_bridge,
382	    "    modify-bridge    [-R <root-dir>] [-P <protect>] "
383	    "[-p <priority>]\n"
384	    "\t\t     [-m <max-age>] [-h <hello-time>] [-d <forward-delay>]\n"
385	    "\t\t     [-f <force-protocol>] <bridge>"			},
386	{ "delete-bridge",	do_delete_bridge,
387	    "    delete-bridge    [-R <root-dir>] <bridge>"		},
388	{ "add-bridge",		do_add_bridge,
389	    "    add-bridge       [-R <root-dir>] -l <link> [-l <link>]... "
390	    "<bridge>"							},
391	{ "remove-bridge",	do_remove_bridge,
392	    "    remove-bridge    [-R <root-dir>] -l <link> [-l <link>]... "
393	    "<bridge>"							},
394	{ "show-bridge",	do_show_bridge,
395	    "    show-bridge      [-p] [-o <field>,...] [-s [-i <interval>]] "
396	    "[<bridge>]\n"
397	    "    show-bridge      -l [-p] [-o <field>,...] [-s [-i <interval>]]"
398	    " <bridge>\n"
399	    "    show-bridge      -f [-p] [-o <field>,...] [-s [-i <interval>]]"
400	    " <bridge>\n"
401	    "    show-bridge      -t [-p] [-o <field>,...] [-s [-i <interval>]]"
402	    " <bridge>\n"						},
403	{ "show-usage",		do_show_usage,
404	    "    show-usage       [-a] [-d | -F <format>] "
405	    "[-s <DD/MM/YYYY,HH:MM:SS>]\n"
406	    "\t\t     [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<link>]"	}
407};
408
409static const struct option lopts[] = {
410	{"vlan-id",	required_argument,	0, 'v'},
411	{"output",	required_argument,	0, 'o'},
412	{"dev",		required_argument,	0, 'd'},
413	{"policy",	required_argument,	0, 'P'},
414	{"lacp-mode",	required_argument,	0, 'L'},
415	{"lacp-timer",	required_argument,	0, 'T'},
416	{"unicast",	required_argument,	0, 'u'},
417	{"temporary",	no_argument,		0, 't'},
418	{"root-dir",	required_argument,	0, 'R'},
419	{"link",	required_argument,	0, 'l'},
420	{"forcible",	no_argument,		0, 'f'},
421	{"bw-limit",	required_argument,	0, 'b'},
422	{"mac-address",	required_argument,	0, 'm'},
423	{"slot",	required_argument,	0, 'n'},
424	{ 0, 0, 0, 0 }
425};
426
427static const struct option show_lopts[] = {
428	{"statistics",	no_argument,		0, 's'},
429	{"continuous",	no_argument,		0, 'S'},
430	{"interval",	required_argument,	0, 'i'},
431	{"parsable",	no_argument,		0, 'p'},
432	{"parseable",	no_argument,		0, 'p'},
433	{"extended",	no_argument,		0, 'x'},
434	{"output",	required_argument,	0, 'o'},
435	{"persistent",	no_argument,		0, 'P'},
436	{"lacp",	no_argument,		0, 'L'},
437	{ 0, 0, 0, 0 }
438};
439
440static const struct option iptun_lopts[] = {
441	{"output",	required_argument,	0, 'o'},
442	{"tunnel-type",	required_argument,	0, 'T'},
443	{"address",	required_argument,	0, 'a'},
444	{"root-dir",	required_argument,	0, 'R'},
445	{"parsable",	no_argument,		0, 'p'},
446	{"parseable",	no_argument,		0, 'p'},
447	{"persistent",	no_argument,		0, 'P'},
448	{ 0, 0, 0, 0 }
449};
450
451static char * const iptun_addropts[] = {
452#define	IPTUN_LOCAL	0
453	"local",
454#define	IPTUN_REMOTE	1
455	"remote",
456	NULL};
457
458static const struct {
459	const char	*type_name;
460	iptun_type_t	type_value;
461} iptun_types[] = {
462	{"ipv4",	IPTUN_TYPE_IPV4},
463	{"ipv6",	IPTUN_TYPE_IPV6},
464	{"6to4",	IPTUN_TYPE_6TO4},
465	{NULL,		0}
466};
467
468static const struct option prop_longopts[] = {
469	{"temporary",	no_argument,		0, 't'  },
470	{"output",	required_argument,	0, 'o'  },
471	{"root-dir",	required_argument,	0, 'R'  },
472	{"prop",	required_argument,	0, 'p'  },
473	{"parsable",	no_argument,		0, 'c'  },
474	{"parseable",	no_argument,		0, 'c'  },
475	{"persistent",	no_argument,		0, 'P'  },
476	{ 0, 0, 0, 0 }
477};
478
479static const struct option wifi_longopts[] = {
480	{"parsable",	no_argument,		0, 'p'  },
481	{"parseable",	no_argument,		0, 'p'  },
482	{"output",	required_argument,	0, 'o'  },
483	{"essid",	required_argument,	0, 'e'  },
484	{"bsstype",	required_argument,	0, 'b'  },
485	{"mode",	required_argument,	0, 'm'  },
486	{"key",		required_argument,	0, 'k'  },
487	{"sec",		required_argument,	0, 's'  },
488	{"auth",	required_argument,	0, 'a'  },
489	{"create-ibss",	required_argument,	0, 'c'  },
490	{"timeout",	required_argument,	0, 'T'  },
491	{"all-links",	no_argument,		0, 'a'  },
492	{"temporary",	no_argument,		0, 't'  },
493	{"root-dir",	required_argument,	0, 'R'  },
494	{"persistent",	no_argument,		0, 'P'  },
495	{"file",	required_argument,	0, 'f'  },
496	{ 0, 0, 0, 0 }
497};
498
499static const struct option showeth_lopts[] = {
500	{"parsable",	no_argument,		0, 'p'	},
501	{"parseable",	no_argument,		0, 'p'	},
502	{"extended",	no_argument,		0, 'x'	},
503	{"output",	required_argument,	0, 'o'	},
504	{ 0, 0, 0, 0 }
505};
506
507static const struct option vnic_lopts[] = {
508	{"temporary",	no_argument,		0, 't'	},
509	{"root-dir",	required_argument,	0, 'R'	},
510	{"dev",		required_argument,	0, 'd'	},
511	{"mac-address",	required_argument,	0, 'm'	},
512	{"cpus",	required_argument,	0, 'c'	},
513	{"bw-limit",	required_argument,	0, 'b'	},
514	{"slot",	required_argument,	0, 'n'	},
515	{"mac-prefix",	required_argument,	0, 'r'	},
516	{"vrid",	required_argument,	0, 'V'	},
517	{"address-family",	required_argument,	0, 'A'	},
518	{ 0, 0, 0, 0 }
519};
520
521static const struct option part_lopts[] = {
522	{"temporary",	no_argument,		0, 't'  },
523	{"pkey",	required_argument,	0, 'P'  },
524	{"link",	required_argument,	0, 'l'  },
525	{"force",	no_argument,		0, 'f'  },
526	{"root-dir",	required_argument,	0, 'R'  },
527	{"prop",	required_argument,	0, 'p'  },
528	{ 0, 0, 0, 0 }
529};
530
531static const struct option show_part_lopts[] = {
532	{"parsable",	no_argument,		0, 'p'  },
533	{"parseable",	no_argument,		0, 'p'  },
534	{"link",	required_argument,	0, 'l'  },
535	{"persistent",	no_argument,		0, 'P'  },
536	{"output",	required_argument,	0, 'o'  },
537	{ 0, 0, 0, 0 }
538};
539
540static const struct option etherstub_lopts[] = {
541	{"temporary",	no_argument,		0, 't'	},
542	{"root-dir",	required_argument,	0, 'R'	},
543	{ 0, 0, 0, 0 }
544};
545
546static const struct option usage_opts[] = {
547	{"file",	required_argument,	0, 'f'	},
548	{"format",	required_argument,	0, 'F'	},
549	{"start",	required_argument,	0, 's'	},
550	{"stop",	required_argument,	0, 'e'	},
551	{ 0, 0, 0, 0 }
552};
553
554static const struct option simnet_lopts[] = {
555	{"temporary",	no_argument,		0, 't'	},
556	{"root-dir",	required_argument,	0, 'R'	},
557	{"media",	required_argument,	0, 'm'	},
558	{"peer",	required_argument,	0, 'p'	},
559	{ 0, 0, 0, 0 }
560};
561
562static const struct option bridge_lopts[] = {
563	{ "protect",		required_argument,	0, 'P' },
564	{ "root-dir",		required_argument,	0, 'R'	},
565	{ "forward-delay",	required_argument,	0, 'd'	},
566	{ "force-protocol",	required_argument,	0, 'f'	},
567	{ "hello-time",		required_argument,	0, 'h'	},
568	{ "link",		required_argument,	0, 'l'	},
569	{ "max-age",		required_argument,	0, 'm'	},
570	{ "priority",		required_argument,	0, 'p'	},
571	{ NULL, NULL, 0, 0 }
572};
573
574static const struct option bridge_show_lopts[] = {
575	{ "forwarding", no_argument,		0, 'f' },
576	{ "interval",	required_argument,	0, 'i' },
577	{ "link",	no_argument,		0, 'l' },
578	{ "output",	required_argument,	0, 'o' },
579	{ "parsable",	no_argument,		0, 'p' },
580	{ "parseable",	no_argument,		0, 'p' },
581	{ "statistics",	no_argument,		0, 's' },
582	{ "trill",	no_argument,		0, 't' },
583	{ 0, 0, 0, 0 }
584};
585
586/*
587 * structures for 'dladm show-ether'
588 */
589static const char *ptype[] = {LEI_ATTR_NAMES};
590
591typedef struct ether_fields_buf_s
592{
593	char	eth_link[15];
594	char	eth_ptype[8];
595	char	eth_state[8];
596	char	eth_autoneg[5];
597	char	eth_spdx[31];
598	char	eth_pause[6];
599	char	eth_rem_fault[16];
600} ether_fields_buf_t;
601
602static const ofmt_field_t ether_fields[] = {
603/* name,	field width,	offset	    callback */
604{ "LINK",	16,
605	offsetof(ether_fields_buf_t, eth_link), print_default_cb},
606{ "PTYPE",	9,
607	offsetof(ether_fields_buf_t, eth_ptype), print_default_cb},
608{ "STATE",	9,
609	offsetof(ether_fields_buf_t, eth_state),
610	print_default_cb},
611{ "AUTO",	6,
612	offsetof(ether_fields_buf_t, eth_autoneg), print_default_cb},
613{ "SPEED-DUPLEX", 32,
614	offsetof(ether_fields_buf_t, eth_spdx), print_default_cb},
615{ "PAUSE",	7,
616	offsetof(ether_fields_buf_t, eth_pause), print_default_cb},
617{ "REM_FAULT",	17,
618	offsetof(ether_fields_buf_t, eth_rem_fault), print_default_cb},
619{NULL,		0,
620	0, 	NULL}}
621;
622
623typedef struct print_ether_state {
624	const char	*es_link;
625	boolean_t	es_parsable;
626	boolean_t	es_header;
627	boolean_t	es_extended;
628	ofmt_handle_t	es_ofmt;
629} print_ether_state_t;
630
631/*
632 * structures for 'dladm show-link -s' (print statistics)
633 */
634typedef enum {
635	LINK_S_LINK,
636	LINK_S_IPKTS,
637	LINK_S_RBYTES,
638	LINK_S_IERRORS,
639	LINK_S_OPKTS,
640	LINK_S_OBYTES,
641	LINK_S_OERRORS
642} link_s_field_index_t;
643
644static const ofmt_field_t link_s_fields[] = {
645/* name,	field width,	index,		callback	*/
646{ "LINK",	15,		LINK_S_LINK,	print_link_stats_cb},
647{ "IPACKETS",	10,		LINK_S_IPKTS,	print_link_stats_cb},
648{ "RBYTES",	8,		LINK_S_RBYTES,	print_link_stats_cb},
649{ "IERRORS",	10,		LINK_S_IERRORS,	print_link_stats_cb},
650{ "OPACKETS",	12,		LINK_S_OPKTS,	print_link_stats_cb},
651{ "OBYTES",	12,		LINK_S_OBYTES,	print_link_stats_cb},
652{ "OERRORS",	8,		LINK_S_OERRORS,	print_link_stats_cb}}
653;
654
655typedef struct link_args_s {
656	char		*link_s_link;
657	pktsum_t	*link_s_psum;
658} link_args_t;
659
660/*
661 * buffer used by print functions for show-{link,phys,vlan} commands.
662 */
663typedef struct link_fields_buf_s {
664	char link_name[MAXLINKNAMELEN];
665	char link_class[DLADM_STRSIZE];
666	char link_mtu[11];
667	char link_state[DLADM_STRSIZE];
668	char link_bridge[MAXLINKNAMELEN];
669	char link_over[MAXLINKNAMELEN];
670	char link_phys_state[DLADM_STRSIZE];
671	char link_phys_media[DLADM_STRSIZE];
672	char link_phys_speed[DLADM_STRSIZE];
673	char link_phys_duplex[DLPI_LINKNAME_MAX];
674	char link_phys_device[DLPI_LINKNAME_MAX];
675	char link_flags[6];
676	char link_vlan_vid[6];
677} link_fields_buf_t;
678
679/*
680 * structures for 'dladm show-link'
681 */
682static const ofmt_field_t link_fields[] = {
683/* name,	field width,	index,	callback */
684{ "LINK",	12,
685	offsetof(link_fields_buf_t, link_name), print_default_cb},
686{ "CLASS",	10,
687	offsetof(link_fields_buf_t, link_class), print_default_cb},
688{ "MTU",	7,
689	offsetof(link_fields_buf_t, link_mtu), print_default_cb},
690{ "STATE",	9,
691	offsetof(link_fields_buf_t, link_state), print_default_cb},
692{ "BRIDGE",	11,
693    offsetof(link_fields_buf_t, link_bridge), print_default_cb},
694{ "OVER",	DLPI_LINKNAME_MAX,
695	offsetof(link_fields_buf_t, link_over), print_default_cb},
696{ NULL,		0, 0, NULL}}
697;
698
699/*
700 * structures for 'dladm show-aggr'
701 */
702typedef struct laggr_fields_buf_s {
703	char laggr_name[DLPI_LINKNAME_MAX];
704	char laggr_policy[9];
705	char laggr_addrpolicy[ETHERADDRL * 3 + 3];
706	char laggr_lacpactivity[14];
707	char laggr_lacptimer[DLADM_STRSIZE];
708	char laggr_flags[7];
709} laggr_fields_buf_t;
710
711typedef struct laggr_args_s {
712	int			laggr_lport; /* -1 indicates the aggr itself */
713	const char 		*laggr_link;
714	dladm_aggr_grp_attr_t	*laggr_ginfop;
715	dladm_status_t		*laggr_status;
716	pktsum_t		*laggr_pktsumtot; /* -s only */
717	pktsum_t		*laggr_diffstats; /* -s only */
718	boolean_t		laggr_parsable;
719} laggr_args_t;
720
721static const ofmt_field_t laggr_fields[] = {
722/* name,	field width,	offset,	callback */
723{ "LINK",	16,
724	offsetof(laggr_fields_buf_t, laggr_name), print_default_cb},
725{ "POLICY",	9,
726	offsetof(laggr_fields_buf_t, laggr_policy), print_default_cb},
727{ "ADDRPOLICY",	ETHERADDRL * 3 + 3,
728	offsetof(laggr_fields_buf_t, laggr_addrpolicy), print_default_cb},
729{ "LACPACTIVITY", 14,
730	offsetof(laggr_fields_buf_t, laggr_lacpactivity), print_default_cb},
731{ "LACPTIMER",	12,
732	offsetof(laggr_fields_buf_t, laggr_lacptimer), print_default_cb},
733{ "FLAGS",	8,
734	offsetof(laggr_fields_buf_t, laggr_flags), print_default_cb},
735{ NULL,		0, 0, NULL}}
736;
737
738/*
739 * structures for 'dladm show-aggr -x'.
740 */
741typedef enum {
742	AGGR_X_LINK,
743	AGGR_X_PORT,
744	AGGR_X_SPEED,
745	AGGR_X_DUPLEX,
746	AGGR_X_STATE,
747	AGGR_X_ADDRESS,
748	AGGR_X_PORTSTATE
749} aggr_x_field_index_t;
750
751static const ofmt_field_t aggr_x_fields[] = {
752/* name,	field width,	index		callback */
753{ "LINK",	12,	AGGR_X_LINK,		print_xaggr_cb},
754{ "PORT",	15,	AGGR_X_PORT,		print_xaggr_cb},
755{ "SPEED",	5,	AGGR_X_SPEED,		print_xaggr_cb},
756{ "DUPLEX",	10,	AGGR_X_DUPLEX,		print_xaggr_cb},
757{ "STATE",	10,	AGGR_X_STATE,		print_xaggr_cb},
758{ "ADDRESS",	19,	AGGR_X_ADDRESS,		print_xaggr_cb},
759{ "PORTSTATE",	16,	AGGR_X_PORTSTATE,	print_xaggr_cb},
760{ NULL,		0,	0,			NULL}}
761;
762
763/*
764 * structures for 'dladm show-aggr -s'.
765 */
766typedef enum {
767	AGGR_S_LINK,
768	AGGR_S_PORT,
769	AGGR_S_IPKTS,
770	AGGR_S_RBYTES,
771	AGGR_S_OPKTS,
772	AGGR_S_OBYTES,
773	AGGR_S_IPKTDIST,
774	AGGR_S_OPKTDIST
775} aggr_s_field_index_t;
776
777static const ofmt_field_t aggr_s_fields[] = {
778{ "LINK",		12,	AGGR_S_LINK, print_aggr_stats_cb},
779{ "PORT",		10,	AGGR_S_PORT, print_aggr_stats_cb},
780{ "IPACKETS",		8,	AGGR_S_IPKTS, print_aggr_stats_cb},
781{ "RBYTES",		8,	AGGR_S_RBYTES, print_aggr_stats_cb},
782{ "OPACKETS",		8,	AGGR_S_OPKTS, print_aggr_stats_cb},
783{ "OBYTES",		8,	AGGR_S_OBYTES, print_aggr_stats_cb},
784{ "IPKTDIST",		9,	AGGR_S_IPKTDIST, print_aggr_stats_cb},
785{ "OPKTDIST",		15,	AGGR_S_OPKTDIST, print_aggr_stats_cb},
786{ NULL,			0,	0,		NULL}}
787;
788
789/*
790 * structures for 'dladm show-aggr -L'.
791 */
792typedef enum {
793	AGGR_L_LINK,
794	AGGR_L_PORT,
795	AGGR_L_AGGREGATABLE,
796	AGGR_L_SYNC,
797	AGGR_L_COLL,
798	AGGR_L_DIST,
799	AGGR_L_DEFAULTED,
800	AGGR_L_EXPIRED
801} aggr_l_field_index_t;
802
803static const ofmt_field_t aggr_l_fields[] = {
804/* name,		field width,	index */
805{ "LINK",		12,	AGGR_L_LINK,		print_lacp_cb},
806{ "PORT",		13,	AGGR_L_PORT,		print_lacp_cb},
807{ "AGGREGATABLE",	13,	AGGR_L_AGGREGATABLE,	print_lacp_cb},
808{ "SYNC",		5,	AGGR_L_SYNC,		print_lacp_cb},
809{ "COLL",		5,	AGGR_L_COLL,		print_lacp_cb},
810{ "DIST",		5,	AGGR_L_DIST,		print_lacp_cb},
811{ "DEFAULTED",		10,	AGGR_L_DEFAULTED,	print_lacp_cb},
812{ "EXPIRED",		15,	AGGR_L_EXPIRED,		print_lacp_cb},
813{ NULL,			0,	0,			NULL}}
814;
815
816/*
817 * structures for 'dladm show-phys'
818 */
819
820static const ofmt_field_t phys_fields[] = {
821/* name,	field width,	offset */
822{ "LINK",	13,
823	offsetof(link_fields_buf_t, link_name), print_default_cb},
824{ "MEDIA",	21,
825	offsetof(link_fields_buf_t, link_phys_media), print_default_cb},
826{ "STATE",	11,
827	offsetof(link_fields_buf_t, link_phys_state), print_default_cb},
828{ "SPEED",	7,
829	offsetof(link_fields_buf_t, link_phys_speed), print_default_cb},
830{ "DUPLEX",	10,
831	offsetof(link_fields_buf_t, link_phys_duplex), print_default_cb},
832{ "DEVICE",	13,
833	offsetof(link_fields_buf_t, link_phys_device), print_default_cb},
834{ "FLAGS",	7,
835	offsetof(link_fields_buf_t, link_flags), print_default_cb},
836{ NULL,		0, NULL, 0}}
837;
838
839/*
840 * structures for 'dladm show-phys -m'
841 */
842
843typedef enum {
844	PHYS_M_LINK,
845	PHYS_M_SLOT,
846	PHYS_M_ADDRESS,
847	PHYS_M_INUSE,
848	PHYS_M_CLIENT
849} phys_m_field_index_t;
850
851static const ofmt_field_t phys_m_fields[] = {
852/* name,	field width,	offset */
853{ "LINK",	13,	PHYS_M_LINK,	print_phys_one_mac_cb},
854{ "SLOT",	9,	PHYS_M_SLOT,	print_phys_one_mac_cb},
855{ "ADDRESS",	19,	PHYS_M_ADDRESS,	print_phys_one_mac_cb},
856{ "INUSE",	5,	PHYS_M_INUSE,	print_phys_one_mac_cb},
857{ "CLIENT",	13,	PHYS_M_CLIENT,	print_phys_one_mac_cb},
858{ NULL,		0,	0,		NULL}}
859;
860
861/*
862 * structures for 'dladm show-phys -H'
863 */
864
865typedef enum {
866	PHYS_H_LINK,
867	PHYS_H_RINGTYPE,
868	PHYS_H_RINGS,
869	PHYS_H_CLIENTS
870} phys_h_field_index_t;
871
872#define	RINGSTRLEN	21
873
874static const ofmt_field_t phys_h_fields[] = {
875{ "LINK",	13,	PHYS_H_LINK,	print_phys_one_hwgrp_cb},
876{ "RINGTYPE",	9,	PHYS_H_RINGTYPE,	print_phys_one_hwgrp_cb},
877{ "RINGS",	RINGSTRLEN,	PHYS_H_RINGS,	print_phys_one_hwgrp_cb},
878{ "CLIENTS",	24,	PHYS_H_CLIENTS,	print_phys_one_hwgrp_cb},
879{ NULL,		0,	0,		NULL}}
880;
881
882/*
883 * structures for 'dladm show-vlan'
884 */
885static const ofmt_field_t vlan_fields[] = {
886{ "LINK",	16,
887	offsetof(link_fields_buf_t, link_name), print_default_cb},
888{ "VID",	9,
889	offsetof(link_fields_buf_t, link_vlan_vid), print_default_cb},
890{ "OVER",	13,
891	offsetof(link_fields_buf_t, link_over), print_default_cb},
892{ "FLAGS",	7,
893	offsetof(link_fields_buf_t, link_flags), print_default_cb},
894{ NULL,		0, 0, NULL}}
895;
896
897/*
898 * structures common to 'dladm scan-wifi' and 'dladm show-wifi'
899 * callback will be determined in parse_wifi_fields.
900 */
901static ofmt_field_t wifi_common_fields[] = {
902{ "LINK",	11, 0,				NULL},
903{ "ESSID",	20, DLADM_WLAN_ATTR_ESSID,	NULL},
904{ "BSSID",	18, DLADM_WLAN_ATTR_BSSID,	NULL},
905{ "IBSSID",	18, DLADM_WLAN_ATTR_BSSID,	NULL},
906{ "MODE",	7,  DLADM_WLAN_ATTR_MODE,	NULL},
907{ "SPEED",	7,  DLADM_WLAN_ATTR_SPEED,	NULL},
908{ "BSSTYPE",	9,  DLADM_WLAN_ATTR_BSSTYPE,	NULL},
909{ "SEC",	7,  DLADM_WLAN_ATTR_SECMODE,	NULL},
910{ "STRENGTH",	11, DLADM_WLAN_ATTR_STRENGTH,	NULL},
911{ NULL,		0,  0,				NULL}};
912
913/*
914 * the 'show-wifi' command supports all the fields in wifi_common_fields
915 * plus the AUTH and STATUS fields.
916 */
917static ofmt_field_t wifi_show_fields[A_CNT(wifi_common_fields) + 2] = {
918{ "AUTH",	9,  DLADM_WLAN_ATTR_AUTH,	NULL},
919{ "STATUS",	18, DLADM_WLAN_LINKATTR_STATUS,	print_wifi_status_cb},
920/* copy wifi_common_fields here */
921};
922
923static char *all_scan_wifi_fields =
924	"link,essid,bssid,sec,strength,mode,speed,bsstype";
925static char *all_show_wifi_fields =
926	"link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype";
927static char *def_scan_wifi_fields =
928	"link,essid,bssid,sec,strength,mode,speed";
929static char *def_show_wifi_fields =
930	"link,status,essid,sec,strength,mode,speed";
931
932/*
933 * structures for 'dladm show-linkprop'
934 */
935typedef enum {
936	LINKPROP_LINK,
937	LINKPROP_PROPERTY,
938	LINKPROP_PERM,
939	LINKPROP_VALUE,
940	LINKPROP_DEFAULT,
941	LINKPROP_POSSIBLE
942} linkprop_field_index_t;
943
944static const ofmt_field_t linkprop_fields[] = {
945/* name,	field width,  index */
946{ "LINK",	13,	LINKPROP_LINK,		print_linkprop_cb},
947{ "PROPERTY",	16,	LINKPROP_PROPERTY,	print_linkprop_cb},
948{ "PERM",	5,	LINKPROP_PERM,		print_linkprop_cb},
949{ "VALUE",	15,	LINKPROP_VALUE,		print_linkprop_cb},
950{ "DEFAULT",	15,	LINKPROP_DEFAULT,	print_linkprop_cb},
951{ "POSSIBLE",	20,	LINKPROP_POSSIBLE,	print_linkprop_cb},
952{ NULL,		0,	0,			NULL}}
953;
954
955#define	MAX_PROP_LINE		512
956
957typedef struct show_linkprop_state {
958	char			ls_link[MAXLINKNAMELEN];
959	char			*ls_line;
960	char			**ls_propvals;
961	dladm_arg_list_t	*ls_proplist;
962	boolean_t		ls_parsable;
963	boolean_t		ls_persist;
964	boolean_t		ls_header;
965	dladm_status_t		ls_status;
966	dladm_status_t		ls_retstatus;
967	ofmt_handle_t		ls_ofmt;
968} show_linkprop_state_t;
969
970typedef struct set_linkprop_state {
971	const char		*ls_name;
972	boolean_t		ls_reset;
973	boolean_t		ls_temp;
974	dladm_status_t		ls_status;
975} set_linkprop_state_t;
976
977typedef struct linkprop_args_s {
978	show_linkprop_state_t	*ls_state;
979	char			*ls_propname;
980	datalink_id_t		ls_linkid;
981} linkprop_args_t;
982
983/*
984 * structures for 'dladm show-secobj'
985 */
986typedef struct secobj_fields_buf_s {
987	char			ss_obj_name[DLADM_SECOBJ_VAL_MAX];
988	char			ss_class[20];
989	char			ss_val[30];
990} secobj_fields_buf_t;
991
992static const ofmt_field_t secobj_fields[] = {
993{ "OBJECT",	21,
994	offsetof(secobj_fields_buf_t, ss_obj_name), print_default_cb},
995{ "CLASS",	21,
996	offsetof(secobj_fields_buf_t, ss_class), print_default_cb},
997{ "VALUE",	31,
998	offsetof(secobj_fields_buf_t, ss_val), print_default_cb},
999{ NULL,		0, 0, NULL}}
1000;
1001
1002/*
1003 * structures for 'dladm show-vnic'
1004 */
1005typedef struct vnic_fields_buf_s
1006{
1007	char vnic_link[DLPI_LINKNAME_MAX];
1008	char vnic_over[DLPI_LINKNAME_MAX];
1009	char vnic_speed[6];
1010	char vnic_macaddr[18];
1011	char vnic_macaddrtype[19];
1012	char vnic_vid[6];
1013} vnic_fields_buf_t;
1014
1015static const ofmt_field_t vnic_fields[] = {
1016{ "LINK",		13,
1017	offsetof(vnic_fields_buf_t, vnic_link),	print_default_cb},
1018{ "OVER",		13,
1019	offsetof(vnic_fields_buf_t, vnic_over),	print_default_cb},
1020{ "SPEED",		7,
1021	offsetof(vnic_fields_buf_t, vnic_speed), print_default_cb},
1022{ "MACADDRESS",		18,
1023	offsetof(vnic_fields_buf_t, vnic_macaddr), print_default_cb},
1024{ "MACADDRTYPE",	20,
1025	offsetof(vnic_fields_buf_t, vnic_macaddrtype), print_default_cb},
1026{ "VID",		7,
1027	offsetof(vnic_fields_buf_t, vnic_vid), print_default_cb},
1028{ NULL,			0, 0, NULL}}
1029;
1030
1031/*
1032 * structures for 'dladm show-ib'
1033 */
1034typedef struct ib_fields_buf_s
1035{
1036	char ib_link[DLPI_LINKNAME_MAX];
1037	char ib_hcaguid[17];
1038	char ib_portguid[17];
1039	char ib_portnum[4];
1040	char ib_state[6];
1041	char ib_pkeys[MAXPKEYSTRSZ];
1042} ib_fields_buf_t;
1043
1044static const ofmt_field_t ib_fields[] = {
1045{ "LINK",		13,
1046	offsetof(ib_fields_buf_t, ib_link),	print_default_cb},
1047{ "HCAGUID",		IBGUIDSTRLEN,
1048	offsetof(ib_fields_buf_t, ib_hcaguid),	print_default_cb},
1049{ "PORTGUID",		IBGUIDSTRLEN,
1050	offsetof(ib_fields_buf_t, ib_portguid),	print_default_cb},
1051{ "PORT",		IBPORTSTRLEN,
1052	offsetof(ib_fields_buf_t, ib_portnum), print_default_cb},
1053{ "STATE",		7,
1054	offsetof(ib_fields_buf_t, ib_state), print_default_cb},
1055{ "PKEYS",	18,
1056	offsetof(ib_fields_buf_t, ib_pkeys), print_default_cb},
1057{ NULL,			0, 0, NULL}};
1058
1059/*
1060 * structures for 'dladm show-part'
1061 */
1062typedef struct part_fields_buf_s
1063{
1064	char part_link[DLPI_LINKNAME_MAX];
1065	char part_pkey[5];
1066	char part_over[DLPI_LINKNAME_MAX];
1067	char part_state[8];
1068	char part_flags[5];
1069} part_fields_buf_t;
1070
1071static const ofmt_field_t part_fields[] = {
1072{ "LINK",		13,
1073	offsetof(part_fields_buf_t, part_link),	print_default_cb},
1074{ "PKEY",		MAXPKEYLEN,
1075	offsetof(part_fields_buf_t, part_pkey),	print_default_cb},
1076{ "OVER",		13,
1077	offsetof(part_fields_buf_t, part_over), print_default_cb},
1078{ "STATE",		9,
1079	offsetof(part_fields_buf_t, part_state), print_default_cb},
1080{ "FLAGS",	5,
1081	offsetof(part_fields_buf_t, part_flags), print_default_cb},
1082{ NULL,			0, 0, NULL}};
1083
1084/*
1085 * structures for 'dladm show-simnet'
1086 */
1087typedef struct simnet_fields_buf_s
1088{
1089	char simnet_name[DLPI_LINKNAME_MAX];
1090	char simnet_media[DLADM_STRSIZE];
1091	char simnet_macaddr[18];
1092	char simnet_otherlink[DLPI_LINKNAME_MAX];
1093} simnet_fields_buf_t;
1094
1095static const ofmt_field_t simnet_fields[] = {
1096{ "LINK",		12,
1097	offsetof(simnet_fields_buf_t, simnet_name), print_default_cb},
1098{ "MEDIA",		20,
1099	offsetof(simnet_fields_buf_t, simnet_media), print_default_cb},
1100{ "MACADDRESS",		18,
1101	offsetof(simnet_fields_buf_t, simnet_macaddr), print_default_cb},
1102{ "OTHERLINK",		12,
1103	offsetof(simnet_fields_buf_t, simnet_otherlink), print_default_cb},
1104{ NULL,			0, 0, NULL}}
1105;
1106
1107/*
1108 * structures for 'dladm show-usage'
1109 */
1110
1111typedef struct  usage_fields_buf_s {
1112	char	usage_link[12];
1113	char	usage_duration[10];
1114	char	usage_ipackets[9];
1115	char	usage_rbytes[10];
1116	char	usage_opackets[9];
1117	char	usage_obytes[10];
1118	char	usage_bandwidth[14];
1119} usage_fields_buf_t;
1120
1121static const ofmt_field_t usage_fields[] = {
1122{ "LINK",	13,
1123	offsetof(usage_fields_buf_t, usage_link), print_default_cb},
1124{ "DURATION",	11,
1125	offsetof(usage_fields_buf_t, usage_duration), print_default_cb},
1126{ "IPACKETS",	10,
1127	offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb},
1128{ "RBYTES",	11,
1129	offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb},
1130{ "OPACKETS",	10,
1131	offsetof(usage_fields_buf_t, usage_opackets), print_default_cb},
1132{ "OBYTES",	11,
1133	offsetof(usage_fields_buf_t, usage_obytes), print_default_cb},
1134{ "BANDWIDTH",	15,
1135	offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb},
1136{ NULL,		0, 0, NULL}}
1137;
1138
1139
1140/*
1141 * structures for 'dladm show-usage link'
1142 */
1143
1144typedef struct  usage_l_fields_buf_s {
1145	char	usage_l_link[12];
1146	char	usage_l_stime[13];
1147	char	usage_l_etime[13];
1148	char	usage_l_rbytes[8];
1149	char	usage_l_obytes[8];
1150	char	usage_l_bandwidth[14];
1151} usage_l_fields_buf_t;
1152
1153static const ofmt_field_t usage_l_fields[] = {
1154/* name,	field width,	offset */
1155{ "LINK",	13,
1156	offsetof(usage_l_fields_buf_t, usage_l_link), print_default_cb},
1157{ "START",	14,
1158	offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb},
1159{ "END",	14,
1160	offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb},
1161{ "RBYTES",	9,
1162	offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb},
1163{ "OBYTES",	9,
1164	offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb},
1165{ "BANDWIDTH",	15,
1166	offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb},
1167{ NULL,		0, 0, NULL}}
1168;
1169
1170/* IPTUN_*FLAG_INDEX values are indices into iptun_flags below. */
1171enum { IPTUN_SFLAG_INDEX, IPTUN_IFLAG_INDEX, IPTUN_NUM_FLAGS };
1172
1173/*
1174 * structures for 'dladm show-iptun'
1175 */
1176typedef struct iptun_fields_buf_s {
1177	char	iptun_name[MAXLINKNAMELEN];
1178	char	iptun_type[5];
1179	char	iptun_laddr[NI_MAXHOST];
1180	char	iptun_raddr[NI_MAXHOST];
1181	char	iptun_flags[IPTUN_NUM_FLAGS + 1];
1182} iptun_fields_buf_t;
1183
1184static const ofmt_field_t iptun_fields[] = {
1185{ "LINK",	16,
1186	offsetof(iptun_fields_buf_t, iptun_name), print_default_cb },
1187{ "TYPE",	6,
1188	offsetof(iptun_fields_buf_t, iptun_type), print_default_cb },
1189{ "FLAGS",	7,
1190	offsetof(iptun_fields_buf_t, iptun_flags), print_default_cb },
1191{ "LOCAL",	20,
1192	offsetof(iptun_fields_buf_t, iptun_laddr), print_default_cb },
1193{ "REMOTE",	20,
1194	offsetof(iptun_fields_buf_t, iptun_raddr), print_default_cb },
1195{ NULL, 0, 0, NULL}
1196};
1197
1198/*
1199 * structures for 'dladm show-bridge'.  These are based on sections 14.8.1.1.3
1200 * and 14.8.1.2.2 of IEEE 802.1D-2004.
1201 */
1202typedef struct bridge_fields_buf_s {
1203	char bridge_name[MAXLINKNAMELEN]; /* 14.4.1.2.3(b) */
1204	char bridge_protect[7];		/* stp or trill */
1205	char bridge_address[24];	/* 17.18.3, 7.12.5, 14.4.1.2.3(a) */
1206	char bridge_priority[7];	/* 17.18.3 9.2.5 - only upper 4 bits */
1207	char bridge_bmaxage[7];		/* 17.18.4 configured */
1208	char bridge_bhellotime[7];	/* 17.18.4 configured */
1209	char bridge_bfwddelay[7];	/* 17.18.4 configured */
1210	char bridge_forceproto[3];	/* 17.13.4 configured */
1211	char bridge_tctime[12];		/* 14.8.1.1.3(b) */
1212	char bridge_tccount[12];	/* 17.17.8 */
1213	char bridge_tchange[12];	/* 17.17.8 */
1214	char bridge_desroot[24];	/* 17.18.6 priority "/" MAC */
1215	char bridge_rootcost[12];	/* 17.18.6 */
1216	char bridge_rootport[12];	/* 17.18.6 */
1217	char bridge_maxage[7];		/* 17.18.7 for root */
1218	char bridge_hellotime[7];	/* 17.13.6 for root */
1219	char bridge_fwddelay[7];	/* 17.13.5 for root */
1220	char bridge_holdtime[12];	/* 17.13.12 for root */
1221} bridge_fields_buf_t;
1222
1223static ofmt_field_t bridge_fields[] = {
1224/* name,	field width,	offset,	callback	*/
1225{ "BRIDGE",	12,
1226    offsetof(bridge_fields_buf_t, bridge_name), print_default_cb },
1227{ "PROTECT",	8,
1228    offsetof(bridge_fields_buf_t, bridge_protect), print_default_cb },
1229{ "ADDRESS",	19,
1230    offsetof(bridge_fields_buf_t, bridge_address), print_default_cb },
1231{ "PRIORITY",	9,
1232    offsetof(bridge_fields_buf_t, bridge_priority), print_default_cb },
1233{ "BMAXAGE",	8,
1234    offsetof(bridge_fields_buf_t, bridge_bmaxage), print_default_cb },
1235{ "BHELLOTIME",	11,
1236    offsetof(bridge_fields_buf_t, bridge_bhellotime), print_default_cb },
1237{ "BFWDDELAY",	10,
1238    offsetof(bridge_fields_buf_t, bridge_bfwddelay), print_default_cb },
1239{ "FORCEPROTO",	11,
1240    offsetof(bridge_fields_buf_t, bridge_forceproto), print_default_cb },
1241{ "TCTIME",	10,
1242    offsetof(bridge_fields_buf_t, bridge_tctime), print_default_cb },
1243{ "TCCOUNT",	10,
1244    offsetof(bridge_fields_buf_t, bridge_tccount), print_default_cb },
1245{ "TCHANGE",	10,
1246    offsetof(bridge_fields_buf_t, bridge_tchange), print_default_cb },
1247{ "DESROOT",	23,
1248    offsetof(bridge_fields_buf_t, bridge_desroot), print_default_cb },
1249{ "ROOTCOST",	11,
1250    offsetof(bridge_fields_buf_t, bridge_rootcost), print_default_cb },
1251{ "ROOTPORT",	11,
1252    offsetof(bridge_fields_buf_t, bridge_rootport), print_default_cb },
1253{ "MAXAGE",	8,
1254    offsetof(bridge_fields_buf_t, bridge_maxage), print_default_cb },
1255{ "HELLOTIME",	10,
1256    offsetof(bridge_fields_buf_t, bridge_hellotime), print_default_cb },
1257{ "FWDDELAY",	9,
1258    offsetof(bridge_fields_buf_t, bridge_fwddelay), print_default_cb },
1259{ "HOLDTIME",	9,
1260    offsetof(bridge_fields_buf_t, bridge_holdtime), print_default_cb },
1261{ NULL,		0, 0, NULL}};
1262
1263/*
1264 * structures for 'dladm show-bridge -l'.  These are based on 14.4.1.2.3 and
1265 * 14.8.2.1.3 of IEEE 802.1D-2004.
1266 */
1267typedef struct bridge_link_fields_buf_s {
1268	char bridgel_link[MAXLINKNAMELEN];
1269	char bridgel_index[7];			/* 14.4.1.2.3(d1) */
1270	char bridgel_state[11];			/* 14.8.2.1.3(b) */
1271	char bridgel_uptime[7];			/* 14.8.2.1.3(a) */
1272	char bridgel_opercost[7]		/* 14.8.2.1.3(d) */;
1273	char bridgel_operp2p[4];		/* 14.8.2.1.3(p) */
1274	char bridgel_operedge[4];		/* 14.8.2.1.3(k) */
1275	char bridgel_desroot[23];		/* 14.8.2.1.3(e) */
1276	char bridgel_descost[12];		/* 14.8.2.1.3(f) */
1277	char bridgel_desbridge[23];		/* 14.8.2.1.3(g) */
1278	char bridgel_desport[7];		/* 14.8.2.1.3(h) */
1279	char bridgel_tcack[4];			/* 14.8.2.1.3(i) */
1280} bridge_link_fields_buf_t;
1281
1282static ofmt_field_t bridge_link_fields[] = {
1283/* name,	field width,	offset,	callback	*/
1284{ "LINK",		12,
1285    offsetof(bridge_link_fields_buf_t, bridgel_link), print_default_cb },
1286{ "INDEX",	8,
1287    offsetof(bridge_link_fields_buf_t, bridgel_index), print_default_cb },
1288{ "STATE",	12,
1289    offsetof(bridge_link_fields_buf_t, bridgel_state), print_default_cb },
1290{ "UPTIME",	8,
1291    offsetof(bridge_link_fields_buf_t, bridgel_uptime), print_default_cb },
1292{ "OPERCOST",	9,
1293    offsetof(bridge_link_fields_buf_t, bridgel_opercost), print_default_cb },
1294{ "OPERP2P",	8,
1295    offsetof(bridge_link_fields_buf_t, bridgel_operp2p), print_default_cb },
1296{ "OPEREDGE",	9,
1297    offsetof(bridge_link_fields_buf_t, bridgel_operedge), print_default_cb },
1298{ "DESROOT",	22,
1299    offsetof(bridge_link_fields_buf_t, bridgel_desroot), print_default_cb },
1300{ "DESCOST",	11,
1301    offsetof(bridge_link_fields_buf_t, bridgel_descost), print_default_cb },
1302{ "DESBRIDGE",	22,
1303    offsetof(bridge_link_fields_buf_t, bridgel_desbridge), print_default_cb },
1304{ "DESPORT",	8,
1305    offsetof(bridge_link_fields_buf_t, bridgel_desport), print_default_cb },
1306{ "TCACK",	6,
1307    offsetof(bridge_link_fields_buf_t, bridgel_tcack), print_default_cb },
1308{ NULL,		0, 0, NULL}};
1309
1310/*
1311 * structures for 'dladm show-bridge -s'.  These are not based on IEEE
1312 * 802.1D-2004.
1313 */
1314#define	ULONG_DIG	(((sizeof (ulong_t) * NBBY) * 3 / 10) + 1)
1315#define	UINT64_DIG	(((sizeof (uint64_t) * NBBY) * 3 / 10) + 1)
1316typedef struct bridge_statfields_buf_s {
1317	char bridges_name[MAXLINKNAMELEN];
1318	char bridges_drops[UINT64_DIG];
1319	char bridges_forwards[UINT64_DIG];
1320	char bridges_mbcast[UINT64_DIG];
1321	char bridges_unknown[UINT64_DIG];
1322	char bridges_recv[UINT64_DIG];
1323	char bridges_sent[UINT64_DIG];
1324} bridge_statfields_buf_t;
1325
1326static ofmt_field_t bridge_statfields[] = {
1327/* name,	field width,	offset,	callback	*/
1328{ "BRIDGE",	12,
1329    offsetof(bridge_statfields_buf_t, bridges_name), print_default_cb },
1330{ "DROPS",	12,
1331    offsetof(bridge_statfields_buf_t, bridges_drops), print_default_cb },
1332{ "FORWARDS",	12,
1333    offsetof(bridge_statfields_buf_t, bridges_forwards), print_default_cb },
1334{ "MBCAST",	12,
1335    offsetof(bridge_statfields_buf_t, bridges_mbcast), print_default_cb },
1336{ "UNKNOWN",	12,
1337    offsetof(bridge_statfields_buf_t, bridges_unknown), print_default_cb },
1338{ "RECV",	12,
1339    offsetof(bridge_statfields_buf_t, bridges_recv), print_default_cb },
1340{ "SENT",	12,
1341    offsetof(bridge_statfields_buf_t, bridges_sent), print_default_cb },
1342{ NULL,		0, 0, NULL}};
1343
1344/*
1345 * structures for 'dladm show-bridge -s -l'.  These are based in part on
1346 * section 14.6.1.1.3 of IEEE 802.1D-2004.
1347 */
1348typedef struct bridge_link_statfields_buf_s {
1349	char bridgels_link[MAXLINKNAMELEN];
1350	char bridgels_cfgbpdu[ULONG_DIG];
1351	char bridgels_tcnbpdu[ULONG_DIG];
1352	char bridgels_rstpbpdu[ULONG_DIG];
1353	char bridgels_txbpdu[ULONG_DIG];
1354	char bridgels_drops[UINT64_DIG];	/* 14.6.1.1.3(d) */
1355	char bridgels_recv[UINT64_DIG];		/* 14.6.1.1.3(a) */
1356	char bridgels_xmit[UINT64_DIG];		/* 14.6.1.1.3(c) */
1357} bridge_link_statfields_buf_t;
1358
1359static ofmt_field_t bridge_link_statfields[] = {
1360/* name,	field width,	offset,	callback	*/
1361{ "LINK",	12,
1362    offsetof(bridge_link_statfields_buf_t, bridgels_link), print_default_cb },
1363{ "CFGBPDU",	9,
1364    offsetof(bridge_link_statfields_buf_t, bridgels_cfgbpdu),
1365    print_default_cb },
1366{ "TCNBPDU",	9,
1367    offsetof(bridge_link_statfields_buf_t, bridgels_tcnbpdu),
1368    print_default_cb },
1369{ "RSTPBPDU",	9,
1370    offsetof(bridge_link_statfields_buf_t, bridgels_rstpbpdu),
1371    print_default_cb },
1372{ "TXBPDU",	9,
1373    offsetof(bridge_link_statfields_buf_t, bridgels_txbpdu), print_default_cb },
1374{ "DROPS",	9,
1375    offsetof(bridge_link_statfields_buf_t, bridgels_drops), print_default_cb },
1376{ "RECV",	9,
1377    offsetof(bridge_link_statfields_buf_t, bridgels_recv), print_default_cb },
1378{ "XMIT",	9,
1379    offsetof(bridge_link_statfields_buf_t, bridgels_xmit), print_default_cb },
1380{ NULL,		0, 0, NULL}};
1381
1382/*
1383 * structures for 'dladm show-bridge -f'.  These are based in part on
1384 * section  14.7.6.3.3 of IEEE 802.1D-2004.
1385 */
1386typedef struct bridge_fwd_fields_buf_s {
1387	char bridgef_dest[18];			/* 14.7.6.3.3(a) */
1388	char bridgef_age[8];
1389	char bridgef_flags[6];
1390	char bridgef_output[MAXLINKNAMELEN];	/* 14.7.6.3.3(c) */
1391} bridge_fwd_fields_buf_t;
1392
1393static ofmt_field_t bridge_fwd_fields[] = {
1394/* name,	field width,	offset,	callback	*/
1395{ "DEST",	17,
1396    offsetof(bridge_fwd_fields_buf_t, bridgef_dest), print_default_cb },
1397{ "AGE",	7,
1398    offsetof(bridge_fwd_fields_buf_t, bridgef_age), print_default_cb },
1399{ "FLAGS",	6,
1400    offsetof(bridge_fwd_fields_buf_t, bridgef_flags), print_default_cb },
1401{ "OUTPUT",	12,
1402    offsetof(bridge_fwd_fields_buf_t, bridgef_output), print_default_cb },
1403{ NULL,		0, 0, NULL}};
1404
1405/*
1406 * structures for 'dladm show-bridge -t'.
1407 */
1408typedef struct bridge_trill_fields_buf_s {
1409	char bridget_nick[6];
1410	char bridget_flags[6];
1411	char bridget_link[MAXLINKNAMELEN];
1412	char bridget_nexthop[18];
1413} bridge_trill_fields_buf_t;
1414
1415static ofmt_field_t bridge_trill_fields[] = {
1416/* name,	field width,	offset,	callback	*/
1417{ "NICK",	5,
1418    offsetof(bridge_trill_fields_buf_t, bridget_nick), print_default_cb },
1419{ "FLAGS",	6,
1420    offsetof(bridge_trill_fields_buf_t, bridget_flags), print_default_cb },
1421{ "LINK",	12,
1422    offsetof(bridge_trill_fields_buf_t, bridget_link), print_default_cb },
1423{ "NEXTHOP",	17,
1424    offsetof(bridge_trill_fields_buf_t, bridget_nexthop), print_default_cb },
1425{ NULL,		0, 0, NULL}};
1426
1427static char *progname;
1428static sig_atomic_t signalled;
1429
1430/*
1431 * Handle to libdladm.  Opened in main() before the sub-command
1432 * specific function is called.
1433 */
1434static dladm_handle_t handle = NULL;
1435
1436#define	DLADM_ETHERSTUB_NAME	"etherstub"
1437#define	DLADM_IS_ETHERSTUB(id)	(id == DATALINK_INVALID_LINKID)
1438
1439static void
1440usage(void)
1441{
1442	int	i;
1443	cmd_t	*cmdp;
1444	(void) fprintf(stderr, gettext("usage:  dladm <subcommand> <args> ..."
1445	    "\n"));
1446	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
1447		cmdp = &cmds[i];
1448		if (cmdp->c_usage != NULL)
1449			(void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
1450	}
1451
1452	/* close dladm handle if it was opened */
1453	if (handle != NULL)
1454		dladm_close(handle);
1455
1456	exit(EXIT_FAILURE);
1457}
1458
1459int
1460main(int argc, char *argv[])
1461{
1462	int	i;
1463	cmd_t	*cmdp;
1464	dladm_status_t status;
1465
1466	(void) setlocale(LC_ALL, "");
1467#if !defined(TEXT_DOMAIN)
1468#define	TEXT_DOMAIN "SYS_TEST"
1469#endif
1470	(void) textdomain(TEXT_DOMAIN);
1471
1472	progname = argv[0];
1473
1474	if (argc < 2)
1475		usage();
1476
1477	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
1478		cmdp = &cmds[i];
1479		if (strcmp(argv[1], cmdp->c_name) == 0) {
1480			/* Open the libdladm handle */
1481			if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) {
1482				die_dlerr(status,
1483				    "could not open /dev/dld");
1484			}
1485
1486			cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage);
1487
1488			dladm_close(handle);
1489			return (EXIT_SUCCESS);
1490		}
1491	}
1492
1493	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
1494	    progname, argv[1]);
1495	usage();
1496	return (EXIT_FAILURE);
1497}
1498
1499/*ARGSUSED*/
1500static int
1501show_usage_date(dladm_usage_t *usage, void *arg)
1502{
1503	show_usage_state_t	*state = (show_usage_state_t *)arg;
1504	time_t			stime;
1505	char			timebuf[20];
1506	dladm_status_t		status;
1507	uint32_t		flags;
1508
1509	/*
1510	 * Only show usage information for existing links unless '-a'
1511	 * is specified.
1512	 */
1513	if (!state->us_showall) {
1514		if ((status = dladm_name2info(handle, usage->du_name,
1515		    NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1516			return (status);
1517		}
1518		if ((flags & DLADM_OPT_ACTIVE) == 0)
1519			return (DLADM_STATUS_LINKINVAL);
1520	}
1521
1522	stime = usage->du_stime;
1523	(void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y",
1524	    localtime(&stime));
1525	(void) printf("%s\n", timebuf);
1526
1527	return (DLADM_STATUS_OK);
1528}
1529
1530static int
1531show_usage_time(dladm_usage_t *usage, void *arg)
1532{
1533	show_usage_state_t	*state = (show_usage_state_t *)arg;
1534	char			buf[DLADM_STRSIZE];
1535	usage_l_fields_buf_t 	ubuf;
1536	time_t			time;
1537	double			bw;
1538	dladm_status_t		status;
1539	uint32_t		flags;
1540
1541	/*
1542	 * Only show usage information for existing links unless '-a'
1543	 * is specified.
1544	 */
1545	if (!state->us_showall) {
1546		if ((status = dladm_name2info(handle, usage->du_name,
1547		    NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1548			return (status);
1549		}
1550		if ((flags & DLADM_OPT_ACTIVE) == 0)
1551			return (DLADM_STATUS_LINKINVAL);
1552	}
1553
1554	if (state->us_plot) {
1555		if (!state->us_printheader) {
1556			if (state->us_first) {
1557				(void) printf("# Time");
1558				state->us_first = B_FALSE;
1559			}
1560			(void) printf(" %s", usage->du_name);
1561			if (usage->du_last) {
1562				(void) printf("\n");
1563				state->us_first = B_TRUE;
1564				state->us_printheader = B_TRUE;
1565			}
1566		} else {
1567			if (state->us_first) {
1568				time = usage->du_etime;
1569				(void) strftime(buf, sizeof (buf), "%T",
1570				    localtime(&time));
1571				state->us_first = B_FALSE;
1572				(void) printf("%s", buf);
1573			}
1574			bw = (double)usage->du_bandwidth/1000;
1575			(void) printf(" %.2f", bw);
1576			if (usage->du_last) {
1577				(void) printf("\n");
1578				state->us_first = B_TRUE;
1579			}
1580		}
1581		return (DLADM_STATUS_OK);
1582	}
1583
1584	bzero(&ubuf, sizeof (ubuf));
1585
1586	(void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s",
1587	    usage->du_name);
1588	time = usage->du_stime;
1589	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
1590	(void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s",
1591	    buf);
1592	time = usage->du_etime;
1593	(void) strftime(buf, sizeof (buf), "%T", localtime(&time));
1594	(void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s",
1595	    buf);
1596	(void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes),
1597	    "%llu", usage->du_rbytes);
1598	(void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes),
1599	    "%llu", usage->du_obytes);
1600	(void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth),
1601	    "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
1602
1603	ofmt_print(state->us_ofmt, &ubuf);
1604	return (DLADM_STATUS_OK);
1605}
1606
1607static int
1608show_usage_res(dladm_usage_t *usage, void *arg)
1609{
1610	show_usage_state_t	*state = (show_usage_state_t *)arg;
1611	char			buf[DLADM_STRSIZE];
1612	usage_fields_buf_t	ubuf;
1613	dladm_status_t		status;
1614	uint32_t		flags;
1615
1616	/*
1617	 * Only show usage information for existing links unless '-a'
1618	 * is specified.
1619	 */
1620	if (!state->us_showall) {
1621		if ((status = dladm_name2info(handle, usage->du_name,
1622		    NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
1623			return (status);
1624		}
1625		if ((flags & DLADM_OPT_ACTIVE) == 0)
1626			return (DLADM_STATUS_LINKINVAL);
1627	}
1628
1629	bzero(&ubuf, sizeof (ubuf));
1630
1631	(void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s",
1632	    usage->du_name);
1633	(void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration),
1634	    "%llu", usage->du_duration);
1635	(void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets),
1636	    "%llu", usage->du_ipackets);
1637	(void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes),
1638	    "%llu", usage->du_rbytes);
1639	(void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets),
1640	    "%llu", usage->du_opackets);
1641	(void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes),
1642	    "%llu", usage->du_obytes);
1643	(void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth),
1644	    "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf));
1645
1646	ofmt_print(state->us_ofmt, &ubuf);
1647
1648	return (DLADM_STATUS_OK);
1649}
1650
1651static boolean_t
1652valid_formatspec(char *formatspec_str)
1653{
1654	if (strcmp(formatspec_str, "gnuplot") == 0)
1655		return (B_TRUE);
1656	return (B_FALSE);
1657
1658}
1659
1660/*ARGSUSED*/
1661static void
1662do_show_usage(int argc, char *argv[], const char *use)
1663{
1664	char			*file = NULL;
1665	int			opt;
1666	dladm_status_t		status;
1667	boolean_t		d_arg = B_FALSE;
1668	char			*stime = NULL;
1669	char			*etime = NULL;
1670	char			*resource = NULL;
1671	show_usage_state_t	state;
1672	boolean_t		o_arg = B_FALSE;
1673	boolean_t		F_arg = B_FALSE;
1674	char			*fields_str = NULL;
1675	char			*formatspec_str = NULL;
1676	char			*all_l_fields =
1677	    "link,start,end,rbytes,obytes,bandwidth";
1678	ofmt_handle_t		ofmt;
1679	ofmt_status_t		oferr;
1680	uint_t			ofmtflags = 0;
1681
1682	bzero(&state, sizeof (show_usage_state_t));
1683	state.us_parsable = B_FALSE;
1684	state.us_printheader = B_FALSE;
1685	state.us_plot = B_FALSE;
1686	state.us_first = B_TRUE;
1687
1688	while ((opt = getopt_long(argc, argv, "das:e:o:f:F:",
1689	    usage_opts, NULL)) != -1) {
1690		switch (opt) {
1691		case 'd':
1692			d_arg = B_TRUE;
1693			break;
1694		case 'a':
1695			state.us_showall = B_TRUE;
1696			break;
1697		case 'f':
1698			file = optarg;
1699			break;
1700		case 's':
1701			stime = optarg;
1702			break;
1703		case 'e':
1704			etime = optarg;
1705			break;
1706		case 'o':
1707			o_arg = B_TRUE;
1708			fields_str = optarg;
1709			break;
1710		case 'F':
1711			state.us_plot = F_arg = B_TRUE;
1712			formatspec_str = optarg;
1713			break;
1714		default:
1715			die_opterr(optopt, opt, use);
1716			break;
1717		}
1718	}
1719
1720	if (file == NULL)
1721		die("show-usage requires a file");
1722
1723	if (optind == (argc-1)) {
1724		uint32_t 	flags;
1725
1726		resource = argv[optind];
1727		if (!state.us_showall &&
1728		    (((status = dladm_name2info(handle, resource, NULL, &flags,
1729		    NULL, NULL)) != DLADM_STATUS_OK) ||
1730		    ((flags & DLADM_OPT_ACTIVE) == 0))) {
1731			die("invalid link: '%s'", resource);
1732		}
1733	}
1734
1735	if (F_arg && d_arg)
1736		die("incompatible -d and -F options");
1737
1738	if (F_arg && valid_formatspec(formatspec_str) == B_FALSE)
1739		die("Format specifier %s not supported", formatspec_str);
1740
1741	if (state.us_parsable)
1742		ofmtflags |= OFMT_PARSABLE;
1743
1744	if (resource == NULL && stime == NULL && etime == NULL) {
1745		oferr = ofmt_open(fields_str, usage_fields, ofmtflags, 0,
1746		    &ofmt);
1747	} else {
1748		if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
1749			fields_str = all_l_fields;
1750		oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags, 0,
1751		    &ofmt);
1752
1753	}
1754	dladm_ofmt_check(oferr, state.us_parsable, ofmt);
1755	state.us_ofmt = ofmt;
1756
1757	if (d_arg) {
1758		/* Print log dates */
1759		status = dladm_usage_dates(show_usage_date,
1760		    DLADM_LOGTYPE_LINK, file, resource, &state);
1761	} else if (resource == NULL && stime == NULL && etime == NULL &&
1762	    !F_arg) {
1763		/* Print summary */
1764		status = dladm_usage_summary(show_usage_res,
1765		    DLADM_LOGTYPE_LINK, file, &state);
1766	} else if (resource != NULL) {
1767		/* Print log entries for named resource */
1768		status = dladm_walk_usage_res(show_usage_time,
1769		    DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state);
1770	} else {
1771		/* Print time and information for each link */
1772		status = dladm_walk_usage_time(show_usage_time,
1773		    DLADM_LOGTYPE_LINK, file, stime, etime, &state);
1774	}
1775
1776	if (status != DLADM_STATUS_OK)
1777		die_dlerr(status, "show-usage");
1778	ofmt_close(ofmt);
1779}
1780
1781static void
1782do_create_aggr(int argc, char *argv[], const char *use)
1783{
1784	int			option;
1785	int			key = 0;
1786	uint32_t		policy = AGGR_POLICY_L4;
1787	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
1788	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
1789	dladm_aggr_port_attr_db_t	port[MAXPORT];
1790	uint_t			n, ndev, nlink;
1791	uint8_t			mac_addr[ETHERADDRL];
1792	boolean_t		mac_addr_fixed = B_FALSE;
1793	boolean_t		P_arg = B_FALSE;
1794	boolean_t		l_arg = B_FALSE;
1795	boolean_t		u_arg = B_FALSE;
1796	boolean_t		T_arg = B_FALSE;
1797	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
1798	char			*altroot = NULL;
1799	char			name[MAXLINKNAMELEN];
1800	char			*devs[MAXPORT];
1801	char			*links[MAXPORT];
1802	dladm_status_t		status;
1803	dladm_status_t		pstatus;
1804	char			propstr[DLADM_STRSIZE];
1805	dladm_arg_list_t	*proplist = NULL;
1806	int			i;
1807	datalink_id_t		linkid;
1808
1809	ndev = nlink = opterr = 0;
1810	bzero(propstr, DLADM_STRSIZE);
1811
1812	while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:",
1813	    lopts, NULL)) != -1) {
1814		switch (option) {
1815		case 'd':
1816			if (ndev + nlink >= MAXPORT)
1817				die("too many ports specified");
1818
1819			devs[ndev++] = optarg;
1820			break;
1821		case 'P':
1822			if (P_arg)
1823				die_optdup(option);
1824
1825			P_arg = B_TRUE;
1826			if (!dladm_aggr_str2policy(optarg, &policy))
1827				die("invalid policy '%s'", optarg);
1828			break;
1829		case 'u':
1830			if (u_arg)
1831				die_optdup(option);
1832
1833			u_arg = B_TRUE;
1834			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
1835			    mac_addr))
1836				die("invalid MAC address '%s'", optarg);
1837			break;
1838		case 'l':
1839			if (isdigit(optarg[strlen(optarg) - 1])) {
1840
1841				/*
1842				 * Ended with digit, possibly a link name.
1843				 */
1844				if (ndev + nlink >= MAXPORT)
1845					die("too many ports specified");
1846
1847				links[nlink++] = optarg;
1848				break;
1849			}
1850			/* FALLTHROUGH */
1851		case 'L':
1852			if (l_arg)
1853				die_optdup(option);
1854
1855			l_arg = B_TRUE;
1856			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
1857				die("invalid LACP mode '%s'", optarg);
1858			break;
1859		case 'T':
1860			if (T_arg)
1861				die_optdup(option);
1862
1863			T_arg = B_TRUE;
1864			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
1865				die("invalid LACP timer value '%s'", optarg);
1866			break;
1867		case 't':
1868			flags &= ~DLADM_OPT_PERSIST;
1869			break;
1870		case 'f':
1871			flags |= DLADM_OPT_FORCE;
1872			break;
1873		case 'R':
1874			altroot = optarg;
1875			break;
1876		case 'p':
1877			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
1878			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
1879			    DLADM_STRSIZE)
1880				die("property list too long '%s'", propstr);
1881			break;
1882
1883		default:
1884			die_opterr(optopt, option, use);
1885			break;
1886		}
1887	}
1888
1889	if (ndev + nlink == 0)
1890		usage();
1891
1892	/* get key value or the aggregation name (required last argument) */
1893	if (optind != (argc-1))
1894		usage();
1895
1896	if (!str2int(argv[optind], &key)) {
1897		if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >=
1898		    MAXLINKNAMELEN) {
1899			die("link name too long '%s'", argv[optind]);
1900		}
1901
1902		if (!dladm_valid_linkname(name))
1903			die("invalid link name '%s'", argv[optind]);
1904	} else {
1905		(void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key);
1906	}
1907
1908	if (altroot != NULL)
1909		altroot_cmd(altroot, argc, argv);
1910
1911	for (n = 0; n < ndev; n++) {
1912		if ((status = dladm_dev2linkid(handle, devs[n],
1913		    &port[n].lp_linkid)) != DLADM_STATUS_OK) {
1914			die_dlerr(status, "invalid dev name '%s'", devs[n]);
1915		}
1916	}
1917
1918	for (n = 0; n < nlink; n++) {
1919		if ((status = dladm_name2info(handle, links[n],
1920		    &port[ndev + n].lp_linkid, NULL, NULL, NULL)) !=
1921		    DLADM_STATUS_OK) {
1922			die_dlerr(status, "invalid link name '%s'", links[n]);
1923		}
1924	}
1925
1926	status = dladm_aggr_create(handle, name, key, ndev + nlink, port,
1927	    policy, mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode,
1928	    lacp_timer, flags);
1929	if (status != DLADM_STATUS_OK)
1930		goto done;
1931
1932	if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
1933	    != DLADM_STATUS_OK)
1934		die("invalid aggregation property");
1935
1936	if (proplist == NULL)
1937		return;
1938
1939	status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL);
1940	if (status != DLADM_STATUS_OK)
1941		goto done;
1942
1943	for (i = 0; i < proplist->al_count; i++) {
1944		dladm_arg_info_t	*aip = &proplist->al_info[i];
1945
1946		pstatus = dladm_set_linkprop(handle, linkid, aip->ai_name,
1947		    aip->ai_val, aip->ai_count, flags);
1948
1949		if (pstatus != DLADM_STATUS_OK) {
1950			die_dlerr(pstatus,
1951			    "aggr creation succeeded but "
1952			    "could not set property '%s'", aip->ai_name);
1953		}
1954	}
1955done:
1956	dladm_free_props(proplist);
1957	if (status != DLADM_STATUS_OK) {
1958		if (status == DLADM_STATUS_NONOTIF) {
1959			die("not all links have link up/down detection; must "
1960			    "use -f (see dladm(1M))");
1961		} else {
1962			die_dlerr(status, "create operation failed");
1963		}
1964	}
1965}
1966
1967/*
1968 * arg is either the key or the aggr name. Validate it and convert it to
1969 * the linkid if altroot is NULL.
1970 */
1971static dladm_status_t
1972i_dladm_aggr_get_linkid(const char *altroot, const char *arg,
1973    datalink_id_t *linkidp, uint32_t flags)
1974{
1975	int		key = 0;
1976	char		*aggr = NULL;
1977	dladm_status_t	status;
1978
1979	if (!str2int(arg, &key))
1980		aggr = (char *)arg;
1981
1982	if (aggr == NULL && key == 0)
1983		return (DLADM_STATUS_LINKINVAL);
1984
1985	if (altroot != NULL)
1986		return (DLADM_STATUS_OK);
1987
1988	if (aggr != NULL) {
1989		status = dladm_name2info(handle, aggr, linkidp, NULL, NULL,
1990		    NULL);
1991	} else {
1992		status = dladm_key2linkid(handle, key, linkidp, flags);
1993	}
1994
1995	return (status);
1996}
1997
1998static void
1999do_delete_aggr(int argc, char *argv[], const char *use)
2000{
2001	int			option;
2002	char			*altroot = NULL;
2003	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
2004	dladm_status_t		status;
2005	datalink_id_t		linkid;
2006
2007	opterr = 0;
2008	while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
2009		switch (option) {
2010		case 't':
2011			flags &= ~DLADM_OPT_PERSIST;
2012			break;
2013		case 'R':
2014			altroot = optarg;
2015			break;
2016		default:
2017			die_opterr(optopt, option, use);
2018			break;
2019		}
2020	}
2021
2022	/* get key value or the aggregation name (required last argument) */
2023	if (optind != (argc-1))
2024		usage();
2025
2026	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
2027	if (status != DLADM_STATUS_OK)
2028		goto done;
2029
2030	if (altroot != NULL)
2031		altroot_cmd(altroot, argc, argv);
2032
2033	status = dladm_aggr_delete(handle, linkid, flags);
2034done:
2035	if (status != DLADM_STATUS_OK)
2036		die_dlerr(status, "delete operation failed");
2037}
2038
2039static void
2040do_add_aggr(int argc, char *argv[], const char *use)
2041{
2042	int			option;
2043	uint_t			n, ndev, nlink;
2044	char			*altroot = NULL;
2045	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
2046	datalink_id_t		linkid;
2047	dladm_status_t		status;
2048	dladm_aggr_port_attr_db_t	port[MAXPORT];
2049	char			*devs[MAXPORT];
2050	char			*links[MAXPORT];
2051
2052	ndev = nlink = opterr = 0;
2053	while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts,
2054	    NULL)) != -1) {
2055		switch (option) {
2056		case 'd':
2057			if (ndev + nlink >= MAXPORT)
2058				die("too many ports specified");
2059
2060			devs[ndev++] = optarg;
2061			break;
2062		case 'l':
2063			if (ndev + nlink >= MAXPORT)
2064				die("too many ports specified");
2065
2066			links[nlink++] = optarg;
2067			break;
2068		case 't':
2069			flags &= ~DLADM_OPT_PERSIST;
2070			break;
2071		case 'f':
2072			flags |= DLADM_OPT_FORCE;
2073			break;
2074		case 'R':
2075			altroot = optarg;
2076			break;
2077		default:
2078			die_opterr(optopt, option, use);
2079			break;
2080		}
2081	}
2082
2083	if (ndev + nlink == 0)
2084		usage();
2085
2086	/* get key value or the aggregation name (required last argument) */
2087	if (optind != (argc-1))
2088		usage();
2089
2090	if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid,
2091	    flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) !=
2092	    DLADM_STATUS_OK) {
2093		goto done;
2094	}
2095
2096	if (altroot != NULL)
2097		altroot_cmd(altroot, argc, argv);
2098
2099	for (n = 0; n < ndev; n++) {
2100		if ((status = dladm_dev2linkid(handle, devs[n],
2101		    &(port[n].lp_linkid))) != DLADM_STATUS_OK) {
2102			die_dlerr(status, "invalid <dev> '%s'", devs[n]);
2103		}
2104	}
2105
2106	for (n = 0; n < nlink; n++) {
2107		if ((status = dladm_name2info(handle, links[n],
2108		    &port[n + ndev].lp_linkid, NULL, NULL, NULL)) !=
2109		    DLADM_STATUS_OK) {
2110			die_dlerr(status, "invalid <link> '%s'", links[n]);
2111		}
2112	}
2113
2114	status = dladm_aggr_add(handle, linkid, ndev + nlink, port, flags);
2115done:
2116	if (status != DLADM_STATUS_OK) {
2117		/*
2118		 * checking DLADM_STATUS_NOTSUP is a temporary workaround
2119		 * and should be removed once 6399681 is fixed.
2120		 */
2121		if (status == DLADM_STATUS_NOTSUP) {
2122			die("add operation failed: link capabilities don't "
2123			    "match");
2124		} else if (status == DLADM_STATUS_NONOTIF) {
2125			die("not all links have link up/down detection; must "
2126			    "use -f (see dladm(1M))");
2127		} else {
2128			die_dlerr(status, "add operation failed");
2129		}
2130	}
2131}
2132
2133static void
2134do_remove_aggr(int argc, char *argv[], const char *use)
2135{
2136	int				option;
2137	dladm_aggr_port_attr_db_t	port[MAXPORT];
2138	uint_t				n, ndev, nlink;
2139	char				*devs[MAXPORT];
2140	char				*links[MAXPORT];
2141	char				*altroot = NULL;
2142	uint32_t			flags;
2143	datalink_id_t			linkid;
2144	dladm_status_t			status;
2145
2146	flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
2147	ndev = nlink = opterr = 0;
2148	while ((option = getopt_long(argc, argv, ":d:l:R:t",
2149	    lopts, NULL)) != -1) {
2150		switch (option) {
2151		case 'd':
2152			if (ndev + nlink >= MAXPORT)
2153				die("too many ports specified");
2154
2155			devs[ndev++] = optarg;
2156			break;
2157		case 'l':
2158			if (ndev + nlink >= MAXPORT)
2159				die("too many ports specified");
2160
2161			links[nlink++] = optarg;
2162			break;
2163		case 't':
2164			flags &= ~DLADM_OPT_PERSIST;
2165			break;
2166		case 'R':
2167			altroot = optarg;
2168			break;
2169		default:
2170			die_opterr(optopt, option, use);
2171			break;
2172		}
2173	}
2174
2175	if (ndev + nlink == 0)
2176		usage();
2177
2178	/* get key value or the aggregation name (required last argument) */
2179	if (optind != (argc-1))
2180		usage();
2181
2182	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
2183	if (status != DLADM_STATUS_OK)
2184		goto done;
2185
2186	if (altroot != NULL)
2187		altroot_cmd(altroot, argc, argv);
2188
2189	for (n = 0; n < ndev; n++) {
2190		if ((status = dladm_dev2linkid(handle, devs[n],
2191		    &(port[n].lp_linkid))) != DLADM_STATUS_OK) {
2192			die_dlerr(status, "invalid <dev> '%s'", devs[n]);
2193		}
2194	}
2195
2196	for (n = 0; n < nlink; n++) {
2197		if ((status = dladm_name2info(handle, links[n],
2198		    &port[n + ndev].lp_linkid, NULL, NULL, NULL)) !=
2199		    DLADM_STATUS_OK) {
2200			die_dlerr(status, "invalid <link> '%s'", links[n]);
2201		}
2202	}
2203
2204	status = dladm_aggr_remove(handle, linkid, ndev + nlink, port, flags);
2205done:
2206	if (status != DLADM_STATUS_OK)
2207		die_dlerr(status, "remove operation failed");
2208}
2209
2210static void
2211do_modify_aggr(int argc, char *argv[], const char *use)
2212{
2213	int			option;
2214	uint32_t		policy = AGGR_POLICY_L4;
2215	aggr_lacp_mode_t	lacp_mode = AGGR_LACP_OFF;
2216	aggr_lacp_timer_t	lacp_timer = AGGR_LACP_TIMER_SHORT;
2217	uint8_t			mac_addr[ETHERADDRL];
2218	boolean_t		mac_addr_fixed = B_FALSE;
2219	uint8_t			modify_mask = 0;
2220	char			*altroot = NULL;
2221	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
2222	datalink_id_t		linkid;
2223	dladm_status_t		status;
2224
2225	opterr = 0;
2226	while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts,
2227	    NULL)) != -1) {
2228		switch (option) {
2229		case 'P':
2230			if (modify_mask & DLADM_AGGR_MODIFY_POLICY)
2231				die_optdup(option);
2232
2233			modify_mask |= DLADM_AGGR_MODIFY_POLICY;
2234
2235			if (!dladm_aggr_str2policy(optarg, &policy))
2236				die("invalid policy '%s'", optarg);
2237			break;
2238		case 'u':
2239			if (modify_mask & DLADM_AGGR_MODIFY_MAC)
2240				die_optdup(option);
2241
2242			modify_mask |= DLADM_AGGR_MODIFY_MAC;
2243
2244			if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed,
2245			    mac_addr))
2246				die("invalid MAC address '%s'", optarg);
2247			break;
2248		case 'l':
2249		case 'L':
2250			if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE)
2251				die_optdup(option);
2252
2253			modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE;
2254
2255			if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode))
2256				die("invalid LACP mode '%s'", optarg);
2257			break;
2258		case 'T':
2259			if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER)
2260				die_optdup(option);
2261
2262			modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER;
2263
2264			if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer))
2265				die("invalid LACP timer value '%s'", optarg);
2266			break;
2267		case 't':
2268			flags &= ~DLADM_OPT_PERSIST;
2269			break;
2270		case 'R':
2271			altroot = optarg;
2272			break;
2273		default:
2274			die_opterr(optopt, option, use);
2275			break;
2276		}
2277	}
2278
2279	if (modify_mask == 0)
2280		die("at least one of the -PulT options must be specified");
2281
2282	/* get key value or the aggregation name (required last argument) */
2283	if (optind != (argc-1))
2284		usage();
2285
2286	status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags);
2287	if (status != DLADM_STATUS_OK)
2288		goto done;
2289
2290	if (altroot != NULL)
2291		altroot_cmd(altroot, argc, argv);
2292
2293	status = dladm_aggr_modify(handle, linkid, modify_mask, policy,
2294	    mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, lacp_timer,
2295	    flags);
2296
2297done:
2298	if (status != DLADM_STATUS_OK)
2299		die_dlerr(status, "modify operation failed");
2300}
2301
2302/*ARGSUSED*/
2303static void
2304do_up_aggr(int argc, char *argv[], const char *use)
2305{
2306	datalink_id_t	linkid = DATALINK_ALL_LINKID;
2307	dladm_status_t	status;
2308
2309	/*
2310	 * get the key or the name of the aggregation (optional last argument)
2311	 */
2312	if (argc == 2) {
2313		if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid,
2314		    DLADM_OPT_PERSIST)) != DLADM_STATUS_OK)
2315			goto done;
2316	} else if (argc > 2) {
2317		usage();
2318	}
2319
2320	status = dladm_aggr_up(handle, linkid);
2321done:
2322	if (status != DLADM_STATUS_OK) {
2323		if (argc == 2) {
2324			die_dlerr(status,
2325			    "could not bring up aggregation '%s'", argv[1]);
2326		} else {
2327			die_dlerr(status, "could not bring aggregations up");
2328		}
2329	}
2330}
2331
2332static void
2333do_create_vlan(int argc, char *argv[], const char *use)
2334{
2335	char			*link = NULL;
2336	char			drv[DLPI_LINKNAME_MAX];
2337	uint_t			ppa;
2338	datalink_id_t		linkid;
2339	datalink_id_t		dev_linkid;
2340	int			vid = 0;
2341	int			option;
2342	uint32_t		flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
2343	char			*altroot = NULL;
2344	char			vlan[MAXLINKNAMELEN];
2345	char			propstr[DLADM_STRSIZE];
2346	dladm_arg_list_t	*proplist = NULL;
2347	dladm_status_t		status;
2348
2349	opterr = 0;
2350	bzero(propstr, DLADM_STRSIZE);
2351
2352	while ((option = getopt_long(argc, argv, ":tfR:l:v:p:",
2353	    lopts, NULL)) != -1) {
2354		switch (option) {
2355		case 'v':
2356			if (vid != 0)
2357				die_optdup(option);
2358
2359			if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
2360				die("invalid VLAN identifier '%s'", optarg);
2361
2362			break;
2363		case 'l':
2364			if (link != NULL)
2365				die_optdup(option);
2366
2367			link = optarg;
2368			break;
2369		case 't':
2370			flags &= ~DLADM_OPT_PERSIST;
2371			break;
2372		case 'R':
2373			altroot = optarg;
2374			break;
2375		case 'p':
2376			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
2377			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
2378			    DLADM_STRSIZE)
2379				die("property list too long '%s'", propstr);
2380			break;
2381		case 'f':
2382			flags |= DLADM_OPT_FORCE;
2383			break;
2384		default:
2385			die_opterr(optopt, option, use);
2386			break;
2387		}
2388	}
2389
2390	/* get vlan name if there is any */
2391	if ((vid == 0) || (link == NULL) || (argc - optind > 1))
2392		usage();
2393
2394	if (optind == (argc - 1)) {
2395		if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >=
2396		    MAXLINKNAMELEN) {
2397			die("vlan name too long '%s'", argv[optind]);
2398		}
2399	} else {
2400		if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) ||
2401		    (ppa >= 1000) ||
2402		    (dlpi_makelink(vlan, drv, vid * 1000 + ppa) !=
2403		    DLPI_SUCCESS)) {
2404			die("invalid link name '%s'", link);
2405		}
2406	}
2407
2408	if (altroot != NULL)
2409		altroot_cmd(altroot, argc, argv);
2410
2411	if (dladm_name2info(handle, link, &dev_linkid, NULL, NULL, NULL) !=
2412	    DLADM_STATUS_OK) {
2413		die("invalid link name '%s'", link);
2414	}
2415
2416	if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
2417	    != DLADM_STATUS_OK)
2418		die("invalid vlan property");
2419
2420	status = dladm_vlan_create(handle, vlan, dev_linkid, vid, proplist,
2421	    flags, &linkid);
2422	switch (status) {
2423	case DLADM_STATUS_OK:
2424		break;
2425
2426	case DLADM_STATUS_NOTSUP:
2427		die("VLAN over '%s' may require lowered MTU; must use -f (see "
2428		    "dladm(1M))", link);
2429		break;
2430
2431	case DLADM_STATUS_LINKBUSY:
2432		die("VLAN over '%s' may not use default_tag ID "
2433		    "(see dladm(1M))", link);
2434		break;
2435
2436	default:
2437		die_dlerr(status, "create operation failed");
2438	}
2439}
2440
2441static void
2442do_delete_vlan(int argc, char *argv[], const char *use)
2443{
2444	int		option;
2445	uint32_t	flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
2446	char		*altroot = NULL;
2447	datalink_id_t	linkid;
2448	dladm_status_t	status;
2449
2450	opterr = 0;
2451	while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) {
2452		switch (option) {
2453		case 't':
2454			flags &= ~DLADM_OPT_PERSIST;
2455			break;
2456		case 'R':
2457			altroot = optarg;
2458			break;
2459		default:
2460			die_opterr(optopt, option, use);
2461			break;
2462		}
2463	}
2464
2465	/* get VLAN link name (required last argument) */
2466	if (optind != (argc - 1))
2467		usage();
2468
2469	if (altroot != NULL)
2470		altroot_cmd(altroot, argc, argv);
2471
2472	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
2473	    NULL);
2474	if (status != DLADM_STATUS_OK)
2475		goto done;
2476
2477	status = dladm_vlan_delete(handle, linkid, flags);
2478done:
2479	if (status != DLADM_STATUS_OK)
2480		die_dlerr(status, "delete operation failed");
2481}
2482
2483/*ARGSUSED*/
2484static void
2485do_up_vlan(int argc, char *argv[], const char *use)
2486{
2487	do_up_vnic_common(argc, argv, use, B_TRUE);
2488}
2489
2490static void
2491do_rename_link(int argc, char *argv[], const char *use)
2492{
2493	int		option;
2494	char		*link1, *link2;
2495	char		*altroot = NULL;
2496	dladm_status_t	status;
2497
2498	opterr = 0;
2499	while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) {
2500		switch (option) {
2501		case 'R':
2502			altroot = optarg;
2503			break;
2504		default:
2505			die_opterr(optopt, option, use);
2506			break;
2507		}
2508	}
2509
2510	/* get link1 and link2 name (required the last 2 arguments) */
2511	if (optind != (argc - 2))
2512		usage();
2513
2514	if (altroot != NULL)
2515		altroot_cmd(altroot, argc, argv);
2516
2517	link1 = argv[optind++];
2518	link2 = argv[optind];
2519	if ((status = dladm_rename_link(handle, link1, link2)) !=
2520	    DLADM_STATUS_OK)
2521		die_dlerr(status, "rename operation failed");
2522}
2523
2524/*ARGSUSED*/
2525static void
2526do_delete_phys(int argc, char *argv[], const char *use)
2527{
2528	datalink_id_t	linkid = DATALINK_ALL_LINKID;
2529	dladm_status_t	status;
2530
2531	/* get link name (required the last argument) */
2532	if (argc > 2)
2533		usage();
2534
2535	if (argc == 2) {
2536		if ((status = dladm_name2info(handle, argv[1], &linkid, NULL,
2537		    NULL, NULL)) != DLADM_STATUS_OK)
2538			die_dlerr(status, "cannot delete '%s'", argv[1]);
2539	}
2540
2541	if ((status = dladm_phys_delete(handle, linkid)) != DLADM_STATUS_OK) {
2542		if (argc == 2)
2543			die_dlerr(status, "cannot delete '%s'", argv[1]);
2544		else
2545			die_dlerr(status, "delete operation failed");
2546	}
2547}
2548
2549/*ARGSUSED*/
2550static int
2551i_dladm_walk_linkmap(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2552{
2553	char			name[MAXLINKNAMELEN];
2554	char			mediabuf[DLADM_STRSIZE];
2555	char			classbuf[DLADM_STRSIZE];
2556	datalink_class_t	class;
2557	uint32_t		media;
2558	uint32_t		flags;
2559
2560	if (dladm_datalink_id2info(dh, linkid, &flags, &class, &media, name,
2561	    MAXLINKNAMELEN) == DLADM_STATUS_OK) {
2562		(void) dladm_class2str(class, classbuf);
2563		(void) dladm_media2str(media, mediabuf);
2564		(void) printf("%-12s%8d  %-12s%-20s %6d\n", name,
2565		    linkid, classbuf, mediabuf, flags);
2566	}
2567	return (DLADM_WALK_CONTINUE);
2568}
2569
2570/*ARGSUSED*/
2571static void
2572do_show_linkmap(int argc, char *argv[], const char *use)
2573{
2574	if (argc != 1)
2575		die("invalid arguments");
2576
2577	(void) printf("%-12s%8s  %-12s%-20s %6s\n", "NAME", "LINKID",
2578	    "CLASS", "MEDIA", "FLAGS");
2579
2580	(void) dladm_walk_datalink_id(i_dladm_walk_linkmap, handle, NULL,
2581	    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
2582	    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
2583}
2584
2585/*
2586 * Delete inactive physical links.
2587 */
2588/*ARGSUSED*/
2589static int
2590purge_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2591{
2592	datalink_class_t	class;
2593	uint32_t		flags;
2594
2595	if (dladm_datalink_id2info(dh, linkid, &flags, &class, NULL, NULL, 0)
2596	    != DLADM_STATUS_OK) {
2597		return (DLADM_WALK_CONTINUE);
2598	}
2599
2600	if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE))
2601		(void) dladm_phys_delete(dh, linkid);
2602
2603	return (DLADM_WALK_CONTINUE);
2604}
2605
2606/*ARGSUSED*/
2607static void
2608do_init_phys(int argc, char *argv[], const char *use)
2609{
2610	di_node_t	devtree;
2611
2612	if (argc > 1)
2613		usage();
2614
2615	/*
2616	 * Force all the devices to attach, therefore all the network physical
2617	 * devices can be known to the dlmgmtd daemon.
2618	 */
2619	if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL)
2620		di_fini(devtree);
2621
2622	(void) dladm_walk_datalink_id(purge_phys, handle, NULL,
2623	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
2624}
2625
2626/*
2627 * Print the active topology information.
2628 */
2629void
2630print_link_topology(show_state_t *state, datalink_id_t linkid,
2631    datalink_class_t class, link_fields_buf_t *lbuf)
2632{
2633	uint32_t	flags = state->ls_flags;
2634	dladm_status_t	status;
2635	char		tmpbuf[MAXLINKNAMELEN];
2636
2637	lbuf->link_over[0] = '\0';
2638	lbuf->link_bridge[0] = '\0';
2639
2640	switch (class) {
2641	case DATALINK_CLASS_AGGR:
2642	case DATALINK_CLASS_PHYS:
2643	case DATALINK_CLASS_ETHERSTUB:
2644		status = dladm_bridge_getlink(handle, linkid, lbuf->link_bridge,
2645		    sizeof (lbuf->link_bridge));
2646		if (status != DLADM_STATUS_OK &&
2647		    status != DLADM_STATUS_NOTFOUND)
2648			(void) strcpy(lbuf->link_bridge, "?");
2649		break;
2650	}
2651
2652	switch (class) {
2653	case DATALINK_CLASS_VLAN: {
2654		dladm_vlan_attr_t	vinfo;
2655
2656		if (dladm_vlan_info(handle, linkid, &vinfo, flags) !=
2657		    DLADM_STATUS_OK) {
2658			(void) strcpy(lbuf->link_over, "?");
2659			break;
2660		}
2661		if (dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, NULL,
2662		    NULL, lbuf->link_over, sizeof (lbuf->link_over)) !=
2663		    DLADM_STATUS_OK)
2664			(void) strcpy(lbuf->link_over, "?");
2665		break;
2666	}
2667	case DATALINK_CLASS_AGGR: {
2668		dladm_aggr_grp_attr_t	ginfo;
2669		int			i;
2670
2671		if (dladm_aggr_info(handle, linkid, &ginfo, flags) !=
2672		    DLADM_STATUS_OK || ginfo.lg_nports == 0) {
2673			(void) strcpy(lbuf->link_over, "?");
2674			break;
2675		}
2676		for (i = 0; i < ginfo.lg_nports; i++) {
2677			if (dladm_datalink_id2info(handle,
2678			    ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL,
2679			    tmpbuf, sizeof (tmpbuf)) != DLADM_STATUS_OK) {
2680				(void) strcpy(lbuf->link_over, "?");
2681				break;
2682			}
2683			(void) strlcat(lbuf->link_over, tmpbuf,
2684			    sizeof (lbuf->link_over));
2685			if (i != (ginfo.lg_nports - 1)) {
2686				(void) strlcat(lbuf->link_over, " ",
2687				    sizeof (lbuf->link_over));
2688			}
2689		}
2690		free(ginfo.lg_ports);
2691		break;
2692	}
2693	case DATALINK_CLASS_VNIC: {
2694		dladm_vnic_attr_t	vinfo;
2695
2696		if (dladm_vnic_info(handle, linkid, &vinfo, flags) !=
2697		    DLADM_STATUS_OK) {
2698			(void) strcpy(lbuf->link_over, "?");
2699			break;
2700		}
2701		if (dladm_datalink_id2info(handle, vinfo.va_link_id, NULL, NULL,
2702		    NULL, lbuf->link_over, sizeof (lbuf->link_over)) !=
2703		    DLADM_STATUS_OK)
2704			(void) strcpy(lbuf->link_over, "?");
2705		break;
2706	}
2707
2708	case DATALINK_CLASS_PART: {
2709		dladm_part_attr_t	pinfo;
2710
2711		if (dladm_part_info(handle, linkid, &pinfo, flags) !=
2712		    DLADM_STATUS_OK) {
2713			(void) strcpy(lbuf->link_over, "?");
2714			break;
2715		}
2716		if (dladm_datalink_id2info(handle, pinfo.dia_physlinkid, NULL,
2717		    NULL, NULL, lbuf->link_over, sizeof (lbuf->link_over)) !=
2718		    DLADM_STATUS_OK)
2719			(void) strcpy(lbuf->link_over, "?");
2720		break;
2721	}
2722
2723	case DATALINK_CLASS_BRIDGE: {
2724		datalink_id_t *dlp;
2725		uint_t i, nports;
2726
2727		if (dladm_datalink_id2info(handle, linkid, NULL, NULL,
2728		    NULL, tmpbuf, sizeof (tmpbuf)) != DLADM_STATUS_OK) {
2729			(void) strcpy(lbuf->link_over, "?");
2730			break;
2731		}
2732		if (tmpbuf[0] != '\0')
2733			tmpbuf[strlen(tmpbuf) - 1] = '\0';
2734		dlp = dladm_bridge_get_portlist(tmpbuf, &nports);
2735		if (dlp == NULL) {
2736			(void) strcpy(lbuf->link_over, "?");
2737			break;
2738		}
2739		for (i = 0; i < nports; i++) {
2740			if (dladm_datalink_id2info(handle, dlp[i], NULL,
2741			    NULL, NULL, tmpbuf, sizeof (tmpbuf)) !=
2742			    DLADM_STATUS_OK) {
2743				(void) strcpy(lbuf->link_over, "?");
2744				break;
2745			}
2746			(void) strlcat(lbuf->link_over, tmpbuf,
2747			    sizeof (lbuf->link_over));
2748			if (i != nports - 1) {
2749				(void) strlcat(lbuf->link_over, " ",
2750				    sizeof (lbuf->link_over));
2751			}
2752		}
2753		dladm_bridge_free_portlist(dlp);
2754		break;
2755	}
2756
2757	case DATALINK_CLASS_SIMNET: {
2758		dladm_simnet_attr_t	slinfo;
2759
2760		if (dladm_simnet_info(handle, linkid, &slinfo, flags) !=
2761		    DLADM_STATUS_OK) {
2762			(void) strcpy(lbuf->link_over, "?");
2763			break;
2764		}
2765		if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID) {
2766			if (dladm_datalink_id2info(handle,
2767			    slinfo.sna_peer_link_id, NULL, NULL, NULL,
2768			    lbuf->link_over, sizeof (lbuf->link_over)) !=
2769			    DLADM_STATUS_OK)
2770				(void) strcpy(lbuf->link_over, "?");
2771		}
2772		break;
2773	}
2774	}
2775}
2776
2777static dladm_status_t
2778print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf)
2779{
2780	char			link[MAXLINKNAMELEN];
2781	datalink_class_t	class;
2782	uint_t			mtu;
2783	uint32_t		flags;
2784	dladm_status_t		status;
2785
2786	if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
2787	    NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
2788		goto done;
2789	}
2790
2791	if (!(state->ls_flags & flags)) {
2792		status = DLADM_STATUS_NOTFOUND;
2793		goto done;
2794	}
2795
2796	if (state->ls_flags == DLADM_OPT_ACTIVE) {
2797		dladm_attr_t	dlattr;
2798
2799		if (class == DATALINK_CLASS_PHYS) {
2800			dladm_phys_attr_t	dpa;
2801			dlpi_handle_t		dh;
2802			dlpi_info_t		dlinfo;
2803
2804			if ((status = dladm_phys_info(handle, linkid, &dpa,
2805			    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
2806				goto done;
2807			}
2808
2809			if (!dpa.dp_novanity)
2810				goto link_mtu;
2811
2812			/*
2813			 * This is a physical link that does not have
2814			 * vanity naming support.
2815			 */
2816			if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) !=
2817			    DLPI_SUCCESS) {
2818				status = DLADM_STATUS_NOTFOUND;
2819				goto done;
2820			}
2821
2822			if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) {
2823				dlpi_close(dh);
2824				status = DLADM_STATUS_BADARG;
2825				goto done;
2826			}
2827
2828			dlpi_close(dh);
2829			mtu = dlinfo.di_max_sdu;
2830		} else {
2831link_mtu:
2832			status = dladm_info(handle, linkid, &dlattr);
2833			if (status != DLADM_STATUS_OK)
2834				goto done;
2835			mtu = dlattr.da_max_sdu;
2836		}
2837	}
2838
2839	(void) snprintf(lbuf->link_name, sizeof (lbuf->link_name),
2840	    "%s", link);
2841	(void) dladm_class2str(class, lbuf->link_class);
2842	if (state->ls_flags == DLADM_OPT_ACTIVE) {
2843		(void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu),
2844		    "%u", mtu);
2845		(void) get_linkstate(link, B_TRUE, lbuf->link_state);
2846	}
2847
2848	print_link_topology(state, linkid, class, lbuf);
2849done:
2850	return (status);
2851}
2852
2853/* ARGSUSED */
2854static int
2855show_link(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2856{
2857	show_state_t		*state = (show_state_t *)arg;
2858	dladm_status_t		status;
2859	link_fields_buf_t	lbuf;
2860
2861	/*
2862	 * first get all the link attributes into lbuf;
2863	 */
2864	bzero(&lbuf, sizeof (link_fields_buf_t));
2865	if ((status = print_link(state, linkid, &lbuf)) == DLADM_STATUS_OK)
2866		ofmt_print(state->ls_ofmt, &lbuf);
2867	state->ls_status = status;
2868	return (DLADM_WALK_CONTINUE);
2869}
2870
2871static boolean_t
2872print_link_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2873{
2874	link_args_t *largs = ofarg->ofmt_cbarg;
2875	pktsum_t *diff_stats = largs->link_s_psum;
2876
2877	switch (ofarg->ofmt_id) {
2878	case LINK_S_LINK:
2879		(void) snprintf(buf, bufsize, "%s", largs->link_s_link);
2880		break;
2881	case LINK_S_IPKTS:
2882		(void) snprintf(buf, bufsize, "%llu", diff_stats->ipackets);
2883		break;
2884	case LINK_S_RBYTES:
2885		(void) snprintf(buf, bufsize, "%llu", diff_stats->rbytes);
2886		break;
2887	case LINK_S_IERRORS:
2888		(void) snprintf(buf, bufsize, "%u", diff_stats->ierrors);
2889		break;
2890	case LINK_S_OPKTS:
2891		(void) snprintf(buf, bufsize, "%llu", diff_stats->opackets);
2892		break;
2893	case LINK_S_OBYTES:
2894		(void) snprintf(buf, bufsize, "%llu", diff_stats->obytes);
2895		break;
2896	case LINK_S_OERRORS:
2897		(void) snprintf(buf, bufsize, "%u", diff_stats->oerrors);
2898		break;
2899	default:
2900		die("invalid input");
2901		break;
2902	}
2903	return (B_TRUE);
2904}
2905
2906static int
2907show_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg)
2908{
2909	char			link[DLPI_LINKNAME_MAX];
2910	datalink_class_t	class;
2911	show_state_t		*state = arg;
2912	pktsum_t		stats, diff_stats;
2913	dladm_phys_attr_t	dpa;
2914	link_args_t		largs;
2915
2916	if (state->ls_firstonly) {
2917		if (state->ls_donefirst)
2918			return (DLADM_WALK_CONTINUE);
2919		state->ls_donefirst = B_TRUE;
2920	} else {
2921		bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
2922	}
2923
2924	if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, link,
2925	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2926		return (DLADM_WALK_CONTINUE);
2927	}
2928
2929	if (class == DATALINK_CLASS_PHYS) {
2930		if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
2931		    DLADM_STATUS_OK) {
2932			return (DLADM_WALK_CONTINUE);
2933		}
2934		if (dpa.dp_novanity)
2935			get_mac_stats(dpa.dp_dev, &stats);
2936		else
2937			get_link_stats(link, &stats);
2938	} else {
2939		get_link_stats(link, &stats);
2940	}
2941	dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats);
2942
2943	largs.link_s_link = link;
2944	largs.link_s_psum = &diff_stats;
2945	ofmt_print(state->ls_ofmt, &largs);
2946
2947	state->ls_prevstats = stats;
2948	return (DLADM_WALK_CONTINUE);
2949}
2950
2951
2952static dladm_status_t
2953print_aggr_info(show_grp_state_t *state, const char *link,
2954    dladm_aggr_grp_attr_t *ginfop)
2955{
2956	char			addr_str[ETHERADDRL * 3];
2957	laggr_fields_buf_t	lbuf;
2958
2959	(void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name),
2960	    "%s", link);
2961
2962	(void) dladm_aggr_policy2str(ginfop->lg_policy,
2963	    lbuf.laggr_policy);
2964
2965	if (ginfop->lg_mac_fixed) {
2966		(void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str);
2967		(void) snprintf(lbuf.laggr_addrpolicy,
2968		    sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str);
2969	} else {
2970		(void) snprintf(lbuf.laggr_addrpolicy,
2971		    sizeof (lbuf.laggr_addrpolicy), "auto");
2972	}
2973
2974	(void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode,
2975	    lbuf.laggr_lacpactivity);
2976	(void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer,
2977	    lbuf.laggr_lacptimer);
2978	(void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----",
2979	    ginfop->lg_force ? 'f' : '-');
2980
2981	ofmt_print(state->gs_ofmt, &lbuf);
2982
2983	return (DLADM_STATUS_OK);
2984}
2985
2986static boolean_t
2987print_xaggr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2988{
2989	const laggr_args_t 	*l = ofarg->ofmt_cbarg;
2990	boolean_t		is_port = (l->laggr_lport >= 0);
2991	char			tmpbuf[DLADM_STRSIZE];
2992	const char		*objname;
2993	dladm_aggr_port_attr_t	*portp;
2994	dladm_phys_attr_t	dpa;
2995
2996	if (is_port) {
2997		portp = &(l->laggr_ginfop->lg_ports[l->laggr_lport]);
2998		if (dladm_phys_info(handle, portp->lp_linkid, &dpa,
2999		    DLADM_OPT_ACTIVE) != DLADM_STATUS_OK)
3000			objname = "?";
3001		else
3002			objname = dpa.dp_dev;
3003	} else {
3004		objname = l->laggr_link;
3005	}
3006
3007	switch (ofarg->ofmt_id) {
3008	case AGGR_X_LINK:
3009		(void) snprintf(buf, bufsize, "%s",
3010		    (is_port && !l->laggr_parsable ? " " : l->laggr_link));
3011		break;
3012	case AGGR_X_PORT:
3013		if (is_port) {
3014			if (dladm_datalink_id2info(handle, portp->lp_linkid,
3015			    NULL, NULL, NULL, buf, bufsize) != DLADM_STATUS_OK)
3016				(void) sprintf(buf, "?");
3017		}
3018		break;
3019
3020	case AGGR_X_SPEED:
3021		(void) snprintf(buf, bufsize, "%uMb",
3022		    (uint_t)((get_ifspeed(objname, !is_port)) / 1000000ull));
3023		break;
3024
3025	case AGGR_X_DUPLEX:
3026		(void) get_linkduplex(objname, !is_port, tmpbuf);
3027		(void) strlcpy(buf, tmpbuf, bufsize);
3028		break;
3029
3030	case AGGR_X_STATE:
3031		(void) get_linkstate(objname, !is_port, tmpbuf);
3032		(void) strlcpy(buf, tmpbuf, bufsize);
3033		break;
3034	case AGGR_X_ADDRESS:
3035		(void) dladm_aggr_macaddr2str(
3036		    (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac),
3037		    tmpbuf);
3038		(void) strlcpy(buf, tmpbuf, bufsize);
3039		break;
3040	case AGGR_X_PORTSTATE:
3041		if (is_port) {
3042			(void) dladm_aggr_portstate2str(portp->lp_state,
3043			    tmpbuf);
3044			(void) strlcpy(buf, tmpbuf, bufsize);
3045		}
3046		break;
3047	}
3048err:
3049	*(l->laggr_status) = DLADM_STATUS_OK;
3050	return (B_TRUE);
3051}
3052
3053static dladm_status_t
3054print_aggr_extended(show_grp_state_t *state, const char *link,
3055    dladm_aggr_grp_attr_t *ginfop)
3056{
3057	int			i;
3058	dladm_status_t		status;
3059	laggr_args_t		largs;
3060
3061	largs.laggr_lport = -1;
3062	largs.laggr_link = link;
3063	largs.laggr_ginfop = ginfop;
3064	largs.laggr_status = &status;
3065	largs.laggr_parsable = state->gs_parsable;
3066
3067	ofmt_print(state->gs_ofmt, &largs);
3068
3069	if (status != DLADM_STATUS_OK)
3070		goto done;
3071
3072	for (i = 0; i < ginfop->lg_nports; i++) {
3073		largs.laggr_lport = i;
3074		ofmt_print(state->gs_ofmt, &largs);
3075		if (status != DLADM_STATUS_OK)
3076			goto done;
3077	}
3078
3079	status = DLADM_STATUS_OK;
3080done:
3081	return (status);
3082}
3083
3084static boolean_t
3085print_lacp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3086{
3087	const laggr_args_t	*l = ofarg->ofmt_cbarg;
3088	int			portnum;
3089	boolean_t		is_port = (l->laggr_lport >= 0);
3090	dladm_aggr_port_attr_t	*portp;
3091	aggr_lacp_state_t	*lstate;
3092
3093	if (!is_port)
3094		return (B_FALSE); /* cannot happen! */
3095
3096	portnum = l->laggr_lport;
3097	portp = &(l->laggr_ginfop->lg_ports[portnum]);
3098	lstate = &(portp->lp_lacp_state);
3099
3100	switch (ofarg->ofmt_id) {
3101	case AGGR_L_LINK:
3102		(void) snprintf(buf, bufsize, "%s",
3103		    (portnum > 0 ? "" : l->laggr_link));
3104		break;
3105
3106	case AGGR_L_PORT:
3107		if (dladm_datalink_id2info(handle, portp->lp_linkid, NULL, NULL,
3108		    NULL, buf, bufsize) != DLADM_STATUS_OK)
3109			(void) sprintf(buf, "?");
3110		break;
3111
3112	case AGGR_L_AGGREGATABLE:
3113		(void) snprintf(buf, bufsize, "%s",
3114		    (lstate->bit.aggregation ? "yes" : "no"));
3115		break;
3116
3117	case AGGR_L_SYNC:
3118		(void) snprintf(buf, bufsize, "%s",
3119		    (lstate->bit.sync ? "yes" : "no"));
3120		break;
3121
3122	case AGGR_L_COLL:
3123		(void) snprintf(buf, bufsize, "%s",
3124		    (lstate->bit.collecting ? "yes" : "no"));
3125		break;
3126
3127	case AGGR_L_DIST:
3128		(void) snprintf(buf, bufsize, "%s",
3129		    (lstate->bit.distributing ? "yes" : "no"));
3130		break;
3131
3132	case AGGR_L_DEFAULTED:
3133		(void) snprintf(buf, bufsize, "%s",
3134		    (lstate->bit.defaulted ? "yes" : "no"));
3135		break;
3136
3137	case AGGR_L_EXPIRED:
3138		(void) snprintf(buf, bufsize, "%s",
3139		    (lstate->bit.expired ? "yes" : "no"));
3140		break;
3141	}
3142
3143	*(l->laggr_status) = DLADM_STATUS_OK;
3144	return (B_TRUE);
3145}
3146
3147static dladm_status_t
3148print_aggr_lacp(show_grp_state_t *state, const char *link,
3149    dladm_aggr_grp_attr_t *ginfop)
3150{
3151	int		i;
3152	dladm_status_t	status;
3153	laggr_args_t	largs;
3154
3155	largs.laggr_link = link;
3156	largs.laggr_ginfop = ginfop;
3157	largs.laggr_status = &status;
3158
3159	for (i = 0; i < ginfop->lg_nports; i++) {
3160		largs.laggr_lport = i;
3161		ofmt_print(state->gs_ofmt, &largs);
3162		if (status != DLADM_STATUS_OK)
3163			goto done;
3164	}
3165
3166	status = DLADM_STATUS_OK;
3167done:
3168	return (status);
3169}
3170
3171static boolean_t
3172print_aggr_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3173{
3174	const laggr_args_t	*l = ofarg->ofmt_cbarg;
3175	int 			portnum;
3176	boolean_t		is_port = (l->laggr_lport >= 0);
3177	dladm_aggr_port_attr_t	*portp;
3178	dladm_status_t		*stat, status;
3179	pktsum_t		*diff_stats;
3180
3181	stat = l->laggr_status;
3182	*stat = DLADM_STATUS_OK;
3183
3184	if (is_port) {
3185		portnum = l->laggr_lport;
3186		portp = &(l->laggr_ginfop->lg_ports[portnum]);
3187
3188		if ((status = dladm_datalink_id2info(handle,
3189		    portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) !=
3190		    DLADM_STATUS_OK) {
3191			goto err;
3192		}
3193		diff_stats = l->laggr_diffstats;
3194	}
3195
3196	switch (ofarg->ofmt_id) {
3197	case AGGR_S_LINK:
3198		(void) snprintf(buf, bufsize, "%s",
3199		    (is_port ? "" : l->laggr_link));
3200		break;
3201	case AGGR_S_PORT:
3202		/*
3203		 * if (is_port), buf has port name. Otherwise we print
3204		 * STR_UNDEF_VAL
3205		 */
3206		break;
3207
3208	case AGGR_S_IPKTS:
3209		if (is_port) {
3210			(void) snprintf(buf, bufsize, "%llu",
3211			    diff_stats->ipackets);
3212		} else {
3213			(void) snprintf(buf, bufsize, "%llu",
3214			    l->laggr_pktsumtot->ipackets);
3215		}
3216		break;
3217
3218	case AGGR_S_RBYTES:
3219		if (is_port) {
3220			(void) snprintf(buf, bufsize, "%llu",
3221			    diff_stats->rbytes);
3222		} else {
3223			(void) snprintf(buf, bufsize, "%llu",
3224			    l->laggr_pktsumtot->rbytes);
3225		}
3226		break;
3227
3228	case AGGR_S_OPKTS:
3229		if (is_port) {
3230			(void) snprintf(buf, bufsize, "%llu",
3231			    diff_stats->opackets);
3232		} else {
3233			(void) snprintf(buf, bufsize, "%llu",
3234			    l->laggr_pktsumtot->opackets);
3235		}
3236		break;
3237	case AGGR_S_OBYTES:
3238		if (is_port) {
3239			(void) snprintf(buf, bufsize, "%llu",
3240			    diff_stats->obytes);
3241		} else {
3242			(void) snprintf(buf, bufsize, "%llu",
3243			    l->laggr_pktsumtot->obytes);
3244		}
3245		break;
3246
3247	case AGGR_S_IPKTDIST:
3248		if (is_port) {
3249			(void) snprintf(buf, bufsize, "%-6.1f",
3250			    (double)diff_stats->ipackets/
3251			    (double)l->laggr_pktsumtot->ipackets * 100);
3252		}
3253		break;
3254	case AGGR_S_OPKTDIST:
3255		if (is_port) {
3256			(void) snprintf(buf, bufsize, "%-6.1f",
3257			    (double)diff_stats->opackets/
3258			    (double)l->laggr_pktsumtot->opackets * 100);
3259		}
3260		break;
3261	}
3262	return (B_TRUE);
3263
3264err:
3265	*stat = status;
3266	return (B_TRUE);
3267}
3268
3269static dladm_status_t
3270print_aggr_stats(show_grp_state_t *state, const char *link,
3271    dladm_aggr_grp_attr_t *ginfop)
3272{
3273	dladm_phys_attr_t	dpa;
3274	dladm_aggr_port_attr_t	*portp;
3275	pktsum_t		pktsumtot, *port_stat;
3276	dladm_status_t		status;
3277	int			i;
3278	laggr_args_t		largs;
3279
3280	/* sum the ports statistics */
3281	bzero(&pktsumtot, sizeof (pktsumtot));
3282
3283	/* Allocate memory to keep stats of each port */
3284	port_stat = malloc(ginfop->lg_nports * sizeof (pktsum_t));
3285	if (port_stat == NULL) {
3286		/* Bail out; no memory */
3287		return (DLADM_STATUS_NOMEM);
3288	}
3289
3290
3291	for (i = 0; i < ginfop->lg_nports; i++) {
3292
3293		portp = &(ginfop->lg_ports[i]);
3294		if ((status = dladm_phys_info(handle, portp->lp_linkid, &dpa,
3295		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
3296			goto done;
3297		}
3298
3299		get_mac_stats(dpa.dp_dev, &port_stat[i]);
3300
3301		/*
3302		 * Let's re-use gs_prevstats[] to store the difference of the
3303		 * counters since last use. We will store the new stats from
3304		 * port_stat[] once we have the stats displayed.
3305		 */
3306
3307		dladm_stats_diff(&state->gs_prevstats[i], &port_stat[i],
3308		    &state->gs_prevstats[i]);
3309		dladm_stats_total(&pktsumtot, &pktsumtot,
3310		    &state->gs_prevstats[i]);
3311	}
3312
3313	largs.laggr_lport = -1;
3314	largs.laggr_link = link;
3315	largs.laggr_ginfop = ginfop;
3316	largs.laggr_status = &status;
3317	largs.laggr_pktsumtot = &pktsumtot;
3318
3319	ofmt_print(state->gs_ofmt, &largs);
3320
3321	if (status != DLADM_STATUS_OK)
3322		goto done;
3323
3324	for (i = 0; i < ginfop->lg_nports; i++) {
3325		largs.laggr_lport = i;
3326		largs.laggr_diffstats = &state->gs_prevstats[i];
3327		ofmt_print(state->gs_ofmt, &largs);
3328		if (status != DLADM_STATUS_OK)
3329			goto done;
3330	}
3331
3332	status = DLADM_STATUS_OK;
3333	for (i = 0; i < ginfop->lg_nports; i++)
3334		state->gs_prevstats[i] = port_stat[i];
3335
3336done:
3337	free(port_stat);
3338	return (status);
3339}
3340
3341static dladm_status_t
3342print_aggr(show_grp_state_t *state, datalink_id_t linkid)
3343{
3344	char			link[MAXLINKNAMELEN];
3345	dladm_aggr_grp_attr_t	ginfo;
3346	uint32_t		flags;
3347	dladm_status_t		status;
3348
3349	bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
3350	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
3351	    NULL, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
3352		return (status);
3353	}
3354
3355	if (!(state->gs_flags & flags))
3356		return (DLADM_STATUS_NOTFOUND);
3357
3358	status = dladm_aggr_info(handle, linkid, &ginfo, state->gs_flags);
3359	if (status != DLADM_STATUS_OK)
3360		return (status);
3361
3362	if (state->gs_lacp)
3363		status = print_aggr_lacp(state, link, &ginfo);
3364	else if (state->gs_extended)
3365		status = print_aggr_extended(state, link, &ginfo);
3366	else if (state->gs_stats)
3367		status = print_aggr_stats(state, link, &ginfo);
3368	else
3369		status = print_aggr_info(state, link, &ginfo);
3370
3371done:
3372	free(ginfo.lg_ports);
3373	return (status);
3374}
3375
3376/* ARGSUSED */
3377static int
3378show_aggr(dladm_handle_t dh, datalink_id_t linkid, void *arg)
3379{
3380	show_grp_state_t	*state = arg;
3381
3382	state->gs_status = print_aggr(state, linkid);
3383	return (DLADM_WALK_CONTINUE);
3384}
3385
3386static void
3387do_show_link(int argc, char *argv[], const char *use)
3388{
3389	int		option;
3390	boolean_t	s_arg = B_FALSE;
3391	boolean_t	S_arg = B_FALSE;
3392	boolean_t	i_arg = B_FALSE;
3393	uint32_t	flags = DLADM_OPT_ACTIVE;
3394	boolean_t	p_arg = B_FALSE;
3395	datalink_id_t	linkid = DATALINK_ALL_LINKID;
3396	char		linkname[MAXLINKNAMELEN];
3397	uint32_t	interval = 0;
3398	show_state_t	state;
3399	dladm_status_t	status;
3400	boolean_t	o_arg = B_FALSE;
3401	char		*fields_str = NULL;
3402	char		*all_active_fields = "link,class,mtu,state,bridge,over";
3403	char		*all_inactive_fields = "link,class,bridge,over";
3404	char		*allstat_fields =
3405	    "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors";
3406	ofmt_handle_t	ofmt;
3407	ofmt_status_t	oferr;
3408	uint_t		ofmtflags = 0;
3409
3410	bzero(&state, sizeof (state));
3411
3412	opterr = 0;
3413	while ((option = getopt_long(argc, argv, ":pPsSi:o:",
3414	    show_lopts, NULL)) != -1) {
3415		switch (option) {
3416		case 'p':
3417			if (p_arg)
3418				die_optdup(option);
3419
3420			p_arg = B_TRUE;
3421			break;
3422		case 's':
3423			if (s_arg)
3424				die_optdup(option);
3425
3426			s_arg = B_TRUE;
3427			break;
3428		case 'P':
3429			if (flags != DLADM_OPT_ACTIVE)
3430				die_optdup(option);
3431
3432			flags = DLADM_OPT_PERSIST;
3433			break;
3434		case 'S':
3435			if (S_arg)
3436				die_optdup(option);
3437
3438			S_arg = B_TRUE;
3439			break;
3440		case 'o':
3441			o_arg = B_TRUE;
3442			fields_str = optarg;
3443			break;
3444		case 'i':
3445			if (i_arg)
3446				die_optdup(option);
3447
3448			i_arg = B_TRUE;
3449			if (!dladm_str2interval(optarg, &interval))
3450				die("invalid interval value '%s'", optarg);
3451			break;
3452		default:
3453			die_opterr(optopt, option, use);
3454			break;
3455		}
3456	}
3457
3458	if (i_arg && !(s_arg || S_arg))
3459		die("the option -i can be used only with -s or -S");
3460
3461	if (s_arg && S_arg)
3462		die("the -s option cannot be used with -S");
3463
3464	if (s_arg && flags != DLADM_OPT_ACTIVE)
3465		die("the option -P cannot be used with -s");
3466
3467	if (S_arg && (p_arg || flags != DLADM_OPT_ACTIVE))
3468		die("the option -%c cannot be used with -S", p_arg ? 'p' : 'P');
3469
3470	/* get link name (optional last argument) */
3471	if (optind == (argc-1)) {
3472		uint32_t	f;
3473
3474		if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN) >=
3475		    MAXLINKNAMELEN)
3476			die("link name too long");
3477		if ((status = dladm_name2info(handle, linkname, &linkid, &f,
3478		    NULL, NULL)) != DLADM_STATUS_OK) {
3479			die_dlerr(status, "link %s is not valid", linkname);
3480		}
3481
3482		if (!(f & flags)) {
3483			die_dlerr(DLADM_STATUS_BADARG, "link %s is %s",
3484			    argv[optind], flags == DLADM_OPT_PERSIST ?
3485			    "a temporary link" : "temporarily removed");
3486		}
3487	} else if (optind != argc) {
3488		usage();
3489	}
3490
3491	if (p_arg && !o_arg)
3492		die("-p requires -o");
3493
3494	if (S_arg) {
3495		dladm_continuous(handle, linkid, NULL, interval, LINK_REPORT);
3496		return;
3497	}
3498
3499	if (p_arg && strcasecmp(fields_str, "all") == 0)
3500		die("\"-o all\" is invalid with -p");
3501
3502	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3503		if (s_arg)
3504			fields_str = allstat_fields;
3505		else if (flags & DLADM_OPT_ACTIVE)
3506			fields_str = all_active_fields;
3507		else
3508			fields_str = all_inactive_fields;
3509	}
3510
3511	state.ls_parsable = p_arg;
3512	state.ls_flags = flags;
3513	state.ls_donefirst = B_FALSE;
3514
3515	if (s_arg) {
3516		link_stats(linkid, interval, fields_str, &state);
3517		return;
3518	}
3519	if (state.ls_parsable)
3520		ofmtflags |= OFMT_PARSABLE;
3521	oferr = ofmt_open(fields_str, link_fields, ofmtflags, 0, &ofmt);
3522	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
3523	state.ls_ofmt = ofmt;
3524
3525	if (linkid == DATALINK_ALL_LINKID) {
3526		(void) dladm_walk_datalink_id(show_link, handle, &state,
3527		    DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags);
3528	} else {
3529		(void) show_link(handle, linkid, &state);
3530		if (state.ls_status != DLADM_STATUS_OK) {
3531			die_dlerr(state.ls_status, "failed to show link %s",
3532			    argv[optind]);
3533		}
3534	}
3535	ofmt_close(ofmt);
3536}
3537
3538static void
3539do_show_aggr(int argc, char *argv[], const char *use)
3540{
3541	boolean_t		L_arg = B_FALSE;
3542	boolean_t		s_arg = B_FALSE;
3543	boolean_t		i_arg = B_FALSE;
3544	boolean_t		p_arg = B_FALSE;
3545	boolean_t		x_arg = B_FALSE;
3546	show_grp_state_t	state;
3547	uint32_t		flags = DLADM_OPT_ACTIVE;
3548	datalink_id_t		linkid = DATALINK_ALL_LINKID;
3549	int			option;
3550	uint32_t		interval = 0;
3551	int			key;
3552	dladm_status_t		status;
3553	boolean_t		o_arg = B_FALSE;
3554	char			*fields_str = NULL;
3555	char			*all_fields =
3556	    "link,policy,addrpolicy,lacpactivity,lacptimer,flags";
3557	char			*all_lacp_fields =
3558	    "link,port,aggregatable,sync,coll,dist,defaulted,expired";
3559	char			*all_stats_fields =
3560	    "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist";
3561	char			*all_extended_fields =
3562	    "link,port,speed,duplex,state,address,portstate";
3563	const ofmt_field_t	*pf;
3564	ofmt_handle_t		ofmt;
3565	ofmt_status_t		oferr;
3566	uint_t			ofmtflags = 0;
3567
3568	opterr = 0;
3569	while ((option = getopt_long(argc, argv, ":LpPxsi:o:",
3570	    show_lopts, NULL)) != -1) {
3571		switch (option) {
3572		case 'L':
3573			if (L_arg)
3574				die_optdup(option);
3575
3576			L_arg = B_TRUE;
3577			break;
3578		case 'p':
3579			if (p_arg)
3580				die_optdup(option);
3581
3582			p_arg = B_TRUE;
3583			break;
3584		case 'x':
3585			if (x_arg)
3586				die_optdup(option);
3587
3588			x_arg = B_TRUE;
3589			break;
3590		case 'P':
3591			if (flags != DLADM_OPT_ACTIVE)
3592				die_optdup(option);
3593
3594			flags = DLADM_OPT_PERSIST;
3595			break;
3596		case 's':
3597			if (s_arg)
3598				die_optdup(option);
3599
3600			s_arg = B_TRUE;
3601			break;
3602		case 'o':
3603			o_arg = B_TRUE;
3604			fields_str = optarg;
3605			break;
3606		case 'i':
3607			if (i_arg)
3608				die_optdup(option);
3609
3610			i_arg = B_TRUE;
3611			if (!dladm_str2interval(optarg, &interval))
3612				die("invalid interval value '%s'", optarg);
3613			break;
3614		default:
3615			die_opterr(optopt, option, use);
3616			break;
3617		}
3618	}
3619
3620	if (p_arg && !o_arg)
3621		die("-p requires -o");
3622
3623	if (p_arg && strcasecmp(fields_str, "all") == 0)
3624		die("\"-o all\" is invalid with -p");
3625
3626	if (i_arg && !s_arg)
3627		die("the option -i can be used only with -s");
3628
3629	if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) {
3630		die("the option -%c cannot be used with -s",
3631		    L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P')));
3632	}
3633
3634	if (L_arg && flags != DLADM_OPT_ACTIVE)
3635		die("the option -P cannot be used with -L");
3636
3637	if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE))
3638		die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P');
3639
3640	/* get aggregation key or aggrname (optional last argument) */
3641	if (optind == (argc-1)) {
3642		if (!str2int(argv[optind], &key)) {
3643			status = dladm_name2info(handle, argv[optind],
3644			    &linkid, NULL, NULL, NULL);
3645		} else {
3646			status = dladm_key2linkid(handle, (uint16_t)key,
3647			    &linkid, DLADM_OPT_ACTIVE);
3648		}
3649
3650		if (status != DLADM_STATUS_OK)
3651			die("non-existent aggregation '%s'", argv[optind]);
3652
3653	} else if (optind != argc) {
3654		usage();
3655	}
3656
3657	bzero(&state, sizeof (state));
3658	state.gs_lacp = L_arg;
3659	state.gs_stats = s_arg;
3660	state.gs_flags = flags;
3661	state.gs_parsable = p_arg;
3662	state.gs_extended = x_arg;
3663
3664	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
3665		if (state.gs_lacp)
3666			fields_str = all_lacp_fields;
3667		else if (state.gs_stats)
3668			fields_str = all_stats_fields;
3669		else if (state.gs_extended)
3670			fields_str = all_extended_fields;
3671		else
3672			fields_str = all_fields;
3673	}
3674
3675	if (state.gs_lacp) {
3676		pf = aggr_l_fields;
3677	} else if (state.gs_stats) {
3678		pf = aggr_s_fields;
3679	} else if (state.gs_extended) {
3680		pf = aggr_x_fields;
3681	} else {
3682		pf = laggr_fields;
3683	}
3684
3685	if (state.gs_parsable)
3686		ofmtflags |= OFMT_PARSABLE;
3687	oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
3688	dladm_ofmt_check(oferr, state.gs_parsable, ofmt);
3689	state.gs_ofmt = ofmt;
3690
3691	if (s_arg) {
3692		aggr_stats(linkid, &state, interval);
3693		ofmt_close(ofmt);
3694		return;
3695	}
3696
3697	if (linkid == DATALINK_ALL_LINKID) {
3698		(void) dladm_walk_datalink_id(show_aggr, handle, &state,
3699		    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags);
3700	} else {
3701		(void) show_aggr(handle, linkid, &state);
3702		if (state.gs_status != DLADM_STATUS_OK) {
3703			die_dlerr(state.gs_status, "failed to show aggr %s",
3704			    argv[optind]);
3705		}
3706	}
3707	ofmt_close(ofmt);
3708}
3709
3710static dladm_status_t
3711print_phys_default(show_state_t *state, datalink_id_t linkid,
3712    const char *link, uint32_t flags, uint32_t media)
3713{
3714	dladm_phys_attr_t dpa;
3715	dladm_status_t status;
3716	link_fields_buf_t pattr;
3717
3718	status = dladm_phys_info(handle, linkid, &dpa, state->ls_flags);
3719	if (status != DLADM_STATUS_OK)
3720		goto done;
3721
3722	(void) snprintf(pattr.link_phys_device,
3723	    sizeof (pattr.link_phys_device), "%s", dpa.dp_dev);
3724	(void) dladm_media2str(media, pattr.link_phys_media);
3725	if (state->ls_flags == DLADM_OPT_ACTIVE) {
3726		boolean_t	islink;
3727
3728		if (!dpa.dp_novanity) {
3729			(void) strlcpy(pattr.link_name, link,
3730			    sizeof (pattr.link_name));
3731			islink = B_TRUE;
3732		} else {
3733			/*
3734			 * This is a physical link that does not have
3735			 * vanity naming support.
3736			 */
3737			(void) strlcpy(pattr.link_name, dpa.dp_dev,
3738			    sizeof (pattr.link_name));
3739			islink = B_FALSE;
3740		}
3741
3742		(void) get_linkstate(pattr.link_name, islink,
3743		    pattr.link_phys_state);
3744		(void) snprintf(pattr.link_phys_speed,
3745		    sizeof (pattr.link_phys_speed), "%u",
3746		    (uint_t)((get_ifspeed(pattr.link_name,
3747		    islink)) / 1000000ull));
3748		(void) get_linkduplex(pattr.link_name, islink,
3749		    pattr.link_phys_duplex);
3750	} else {
3751		(void) snprintf(pattr.link_name, sizeof (pattr.link_name),
3752		    "%s", link);
3753		(void) snprintf(pattr.link_flags, sizeof (pattr.link_flags),
3754		    "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r');
3755	}
3756
3757	ofmt_print(state->ls_ofmt, &pattr);
3758
3759done:
3760	return (status);
3761}
3762
3763typedef struct {
3764	show_state_t	*ms_state;
3765	char		*ms_link;
3766	dladm_macaddr_attr_t *ms_mac_attr;
3767} print_phys_mac_state_t;
3768
3769/*
3770 *  callback for ofmt_print()
3771 */
3772static boolean_t
3773print_phys_one_mac_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3774{
3775	print_phys_mac_state_t *mac_state = ofarg->ofmt_cbarg;
3776	dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr;
3777	boolean_t is_primary = (attr->ma_slot == 0);
3778	boolean_t is_parsable = mac_state->ms_state->ls_parsable;
3779
3780	switch (ofarg->ofmt_id) {
3781	case PHYS_M_LINK:
3782		(void) snprintf(buf, bufsize, "%s",
3783		    (is_primary || is_parsable) ? mac_state->ms_link : " ");
3784		break;
3785	case PHYS_M_SLOT:
3786		if (is_primary)
3787			(void) snprintf(buf, bufsize, gettext("primary"));
3788		else
3789			(void) snprintf(buf, bufsize, "%d", attr->ma_slot);
3790		break;
3791	case PHYS_M_ADDRESS:
3792		(void) dladm_aggr_macaddr2str(attr->ma_addr, buf);
3793		break;
3794	case PHYS_M_INUSE:
3795		(void) snprintf(buf, bufsize, "%s",
3796		    attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") :
3797		    gettext("no"));
3798		break;
3799	case PHYS_M_CLIENT:
3800		/*
3801		 * CR 6678526: resolve link id to actual link name if
3802		 * it is valid.
3803		 */
3804		(void) snprintf(buf, bufsize, "%s", attr->ma_client_name);
3805		break;
3806	}
3807
3808	return (B_TRUE);
3809}
3810
3811typedef struct {
3812	show_state_t	*hs_state;
3813	char		*hs_link;
3814	dladm_hwgrp_attr_t *hs_grp_attr;
3815} print_phys_hwgrp_state_t;
3816
3817static boolean_t
3818print_phys_one_hwgrp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
3819{
3820	int		i;
3821	boolean_t	first = B_TRUE;
3822	int		start = -1;
3823	int		end = -1;
3824	char		ringstr[RINGSTRLEN];
3825	char		ringsubstr[RINGSTRLEN];
3826
3827	print_phys_hwgrp_state_t *hg_state = ofarg->ofmt_cbarg;
3828	dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr;
3829
3830	switch (ofarg->ofmt_id) {
3831	case PHYS_H_LINK:
3832		(void) snprintf(buf, bufsize, "%s", attr->hg_link_name);
3833		break;
3834	case PHYS_H_RINGTYPE:
3835		(void) snprintf(buf, bufsize, "%s",
3836		    attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX");
3837		break;
3838	case PHYS_H_RINGS:
3839		ringstr[0] = '\0';
3840		for (i = 0; i < attr->hg_n_rings; i++) {
3841			uint_t 	index = attr->hg_rings[i];
3842
3843			if (start == -1) {
3844				start = index;
3845				end = index;
3846			} else if (index == end + 1) {
3847				end = index;
3848			} else {
3849				if (start == end) {
3850					if (first) {
3851						(void) snprintf(
3852						    ringsubstr,
3853						    RINGSTRLEN, "%d",
3854						    start);
3855						first = B_FALSE;
3856					} else {
3857						(void) snprintf(
3858						    ringsubstr,
3859						    RINGSTRLEN, ",%d",
3860						    start);
3861					}
3862				} else {
3863					if (first) {
3864						(void) snprintf(
3865						    ringsubstr,
3866						    RINGSTRLEN,
3867						    "%d-%d",
3868						    start, end);
3869						first = B_FALSE;
3870					} else {
3871						(void) snprintf(
3872						    ringsubstr,
3873						    RINGSTRLEN,
3874						    ",%d-%d",
3875						    start, end);
3876					}
3877				}
3878				(void) strlcat(ringstr, ringsubstr,
3879				    RINGSTRLEN);
3880				start = index;
3881				end = index;
3882			}
3883		}
3884		/* The last one */
3885		if (start != -1) {
3886			if (first) {
3887				if (start == end) {
3888					(void) snprintf(buf, bufsize, "%d",
3889					    start);
3890				} else {
3891					(void) snprintf(buf, bufsize, "%d-%d",
3892					    start, end);
3893				}
3894			} else {
3895				if (start == end) {
3896					(void) snprintf(ringsubstr, RINGSTRLEN,
3897					    ",%d", start);
3898				} else {
3899					(void) snprintf(ringsubstr, RINGSTRLEN,
3900					    ",%d-%d", start, end);
3901				}
3902				(void) strlcat(ringstr, ringsubstr, RINGSTRLEN);
3903				(void) snprintf(buf, bufsize, "%s", ringstr);
3904			}
3905		}
3906		break;
3907	case PHYS_H_CLIENTS:
3908		if (attr->hg_client_names[0] == '\0') {
3909			(void) snprintf(buf, bufsize, "--");
3910		} else {
3911			(void) snprintf(buf, bufsize, "%s ",
3912			    attr->hg_client_names);
3913		}
3914		break;
3915	}
3916
3917	return (B_TRUE);
3918}
3919
3920/*
3921 * callback for dladm_walk_macaddr, invoked for each MAC address slot
3922 */
3923static boolean_t
3924print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr)
3925{
3926	print_phys_mac_state_t *mac_state = arg;
3927	show_state_t *state = mac_state->ms_state;
3928
3929	mac_state->ms_mac_attr = attr;
3930	ofmt_print(state->ls_ofmt, mac_state);
3931
3932	return (B_TRUE);
3933}
3934
3935/*
3936 * invoked by show-phys -m for each physical data-link
3937 */
3938static dladm_status_t
3939print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link)
3940{
3941	print_phys_mac_state_t mac_state;
3942
3943	mac_state.ms_state = state;
3944	mac_state.ms_link = link;
3945
3946	return (dladm_walk_macaddr(handle, linkid, &mac_state,
3947	    print_phys_mac_callback));
3948}
3949
3950/*
3951 * callback for dladm_walk_hwgrp, invoked for each MAC hwgrp
3952 */
3953static boolean_t
3954print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr)
3955{
3956	print_phys_hwgrp_state_t *hwgrp_state = arg;
3957	show_state_t *state = hwgrp_state->hs_state;
3958
3959	hwgrp_state->hs_grp_attr = attr;
3960	ofmt_print(state->ls_ofmt, hwgrp_state);
3961
3962	return (B_TRUE);
3963}
3964
3965/* invoked by show-phys -H for each physical data-link */
3966static dladm_status_t
3967print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link)
3968{
3969	print_phys_hwgrp_state_t hwgrp_state;
3970
3971	hwgrp_state.hs_state = state;
3972	hwgrp_state.hs_link = link;
3973	return (dladm_walk_hwgrp(handle, linkid, &hwgrp_state,
3974	    print_phys_hwgrp_callback));
3975}
3976
3977/*
3978 * Parse the "local=<laddr>,remote=<raddr>" sub-options for the -a option of
3979 * *-iptun subcommands.
3980 */
3981static void
3982iptun_process_addrarg(char *addrarg, iptun_params_t *params)
3983{
3984	char *addrval;
3985
3986	while (*addrarg != '\0') {
3987		switch (getsubopt(&addrarg, iptun_addropts, &addrval)) {
3988		case IPTUN_LOCAL:
3989			params->iptun_param_flags |= IPTUN_PARAM_LADDR;
3990			if (strlcpy(params->iptun_param_laddr, addrval,
3991			    sizeof (params->iptun_param_laddr)) >=
3992			    sizeof (params->iptun_param_laddr))
3993				die("tunnel source address is too long");
3994			break;
3995		case IPTUN_REMOTE:
3996			params->iptun_param_flags |= IPTUN_PARAM_RADDR;
3997			if (strlcpy(params->iptun_param_raddr, addrval,
3998			    sizeof (params->iptun_param_raddr)) >=
3999			    sizeof (params->iptun_param_raddr))
4000				die("tunnel destination address is too long");
4001			break;
4002		default:
4003			die("invalid address type: %s", addrval);
4004			break;
4005		}
4006	}
4007}
4008
4009/*
4010 * Convenience routine to process iptun-create/modify/delete subcommand
4011 * arguments.
4012 */
4013static void
4014iptun_process_args(int argc, char *argv[], const char *opts,
4015    iptun_params_t *params, uint32_t *flags, char *name, const char *use)
4016{
4017	int	option;
4018	char	*altroot = NULL;
4019
4020	if (params != NULL)
4021		bzero(params, sizeof (*params));
4022	*flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4023
4024	opterr = 0;
4025	while ((option = getopt_long(argc, argv, opts, iptun_lopts, NULL)) !=
4026	    -1) {
4027		switch (option) {
4028		case 'a':
4029			iptun_process_addrarg(optarg, params);
4030			break;
4031		case 'R':
4032			altroot = optarg;
4033			break;
4034		case 't':
4035			*flags &= ~DLADM_OPT_PERSIST;
4036			break;
4037		case 'T':
4038			params->iptun_param_type = iptun_gettypebyname(optarg);
4039			if (params->iptun_param_type == IPTUN_TYPE_UNKNOWN)
4040				die("unknown tunnel type: %s", optarg);
4041			params->iptun_param_flags |= IPTUN_PARAM_TYPE;
4042			break;
4043		default:
4044			die_opterr(optopt, option, use);
4045			break;
4046		}
4047	}
4048
4049	/* Get the required tunnel name argument. */
4050	if (argc - optind != 1)
4051		usage();
4052
4053	if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
4054		die("tunnel name is too long");
4055
4056	if (altroot != NULL)
4057		altroot_cmd(altroot, argc, argv);
4058}
4059
4060static void
4061do_create_iptun(int argc, char *argv[], const char *use)
4062{
4063	iptun_params_t	params;
4064	dladm_status_t	status;
4065	uint32_t	flags;
4066	char		name[MAXLINKNAMELEN];
4067
4068	iptun_process_args(argc, argv, ":a:R:tT:", &params, &flags, name,
4069	    use);
4070
4071	status = dladm_iptun_create(handle, name, &params, flags);
4072	if (status != DLADM_STATUS_OK)
4073		die_dlerr(status, "could not create tunnel");
4074}
4075
4076static void
4077do_delete_iptun(int argc, char *argv[], const char *use)
4078{
4079	uint32_t	flags;
4080	datalink_id_t	linkid;
4081	dladm_status_t	status;
4082	char		name[MAXLINKNAMELEN];
4083
4084	iptun_process_args(argc, argv, ":R:t", NULL, &flags, name, use);
4085
4086	status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL);
4087	if (status != DLADM_STATUS_OK)
4088		die_dlerr(status, "could not delete tunnel");
4089	status = dladm_iptun_delete(handle, linkid, flags);
4090	if (status != DLADM_STATUS_OK)
4091		die_dlerr(status, "could not delete tunnel");
4092}
4093
4094static void
4095do_modify_iptun(int argc, char *argv[], const char *use)
4096{
4097	iptun_params_t	params;
4098	uint32_t	flags;
4099	dladm_status_t	status;
4100	char		name[MAXLINKNAMELEN];
4101
4102	iptun_process_args(argc, argv, ":a:R:t", &params, &flags, name, use);
4103
4104	if ((status = dladm_name2info(handle, name, &params.iptun_param_linkid,
4105	    NULL, NULL, NULL)) != DLADM_STATUS_OK)
4106		die_dlerr(status, "could not modify tunnel");
4107	status = dladm_iptun_modify(handle, &params, flags);
4108	if (status != DLADM_STATUS_OK)
4109		die_dlerr(status, "could not modify tunnel");
4110}
4111
4112static void
4113do_show_iptun(int argc, char *argv[], const char *use)
4114{
4115	char		option;
4116	datalink_id_t	linkid;
4117	uint32_t	flags = DLADM_OPT_ACTIVE;
4118	char		*name = NULL;
4119	dladm_status_t	status;
4120	const char	*fields_str = NULL;
4121	show_state_t	state;
4122	ofmt_handle_t	ofmt;
4123	ofmt_status_t	oferr;
4124	uint_t		ofmtflags = 0;
4125
4126	bzero(&state, sizeof (state));
4127	opterr = 0;
4128	while ((option = getopt_long(argc, argv, ":pPo:",
4129	    iptun_lopts, NULL)) != -1) {
4130		switch (option) {
4131		case 'o':
4132			fields_str = optarg;
4133			break;
4134		case 'p':
4135			state.ls_parsable = B_TRUE;
4136			ofmtflags = OFMT_PARSABLE;
4137			break;
4138		case 'P':
4139			flags = DLADM_OPT_PERSIST;
4140			break;
4141		default:
4142			die_opterr(optopt, option, use);
4143			break;
4144		}
4145	}
4146
4147	/*
4148	 * Get the optional tunnel name argument.  If there is one, it must
4149	 * be the last thing remaining on the command-line.
4150	 */
4151	if (argc - optind > 1)
4152		die(gettext(use));
4153	if (argc - optind == 1)
4154		name = argv[optind];
4155
4156	oferr = ofmt_open(fields_str, iptun_fields, ofmtflags,
4157	    DLADM_DEFAULT_COL, &ofmt);
4158	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
4159
4160	state.ls_ofmt = ofmt;
4161	state.ls_flags = flags;
4162
4163	if (name == NULL) {
4164		(void) dladm_walk_datalink_id(print_iptun_walker, handle,
4165		    &state, DATALINK_CLASS_IPTUN, DATALINK_ANY_MEDIATYPE,
4166		    flags);
4167		status = state.ls_status;
4168	} else {
4169		if ((status = dladm_name2info(handle, name, &linkid, NULL, NULL,
4170		    NULL)) == DLADM_STATUS_OK)
4171			status = print_iptun(handle, linkid, &state);
4172	}
4173
4174	if (status != DLADM_STATUS_OK)
4175		die_dlerr(status, "unable to obtain tunnel status");
4176}
4177
4178/* ARGSUSED */
4179static void
4180do_up_iptun(int argc, char *argv[], const char *use)
4181{
4182	datalink_id_t	linkid = DATALINK_ALL_LINKID;
4183	dladm_status_t	status = DLADM_STATUS_OK;
4184
4185	/*
4186	 * Get the optional tunnel name argument.  If there is one, it must
4187	 * be the last thing remaining on the command-line.
4188	 */
4189	if (argc - optind > 1)
4190		usage();
4191	if (argc - optind == 1) {
4192		status = dladm_name2info(handle, argv[optind], &linkid, NULL,
4193		    NULL, NULL);
4194	}
4195	if (status == DLADM_STATUS_OK)
4196		status = dladm_iptun_up(handle, linkid);
4197	if (status != DLADM_STATUS_OK)
4198		die_dlerr(status, "unable to configure IP tunnel links");
4199}
4200
4201/* ARGSUSED */
4202static void
4203do_down_iptun(int argc, char *argv[], const char *use)
4204{
4205	datalink_id_t	linkid = DATALINK_ALL_LINKID;
4206	dladm_status_t	status = DLADM_STATUS_OK;
4207
4208	/*
4209	 * Get the optional tunnel name argument.  If there is one, it must
4210	 * be the last thing remaining on the command-line.
4211	 */
4212	if (argc - optind > 1)
4213		usage();
4214	if (argc - optind == 1) {
4215		status = dladm_name2info(handle, argv[optind], &linkid, NULL,
4216		    NULL, NULL);
4217	}
4218	if (status == DLADM_STATUS_OK)
4219		status = dladm_iptun_down(handle, linkid);
4220	if (status != DLADM_STATUS_OK)
4221		die_dlerr(status, "unable to bring down IP tunnel links");
4222}
4223
4224static iptun_type_t
4225iptun_gettypebyname(char *typestr)
4226{
4227	int i;
4228
4229	for (i = 0; iptun_types[i].type_name != NULL; i++) {
4230		if (strncmp(iptun_types[i].type_name, typestr,
4231		    strlen(iptun_types[i].type_name)) == 0) {
4232			return (iptun_types[i].type_value);
4233		}
4234	}
4235	return (IPTUN_TYPE_UNKNOWN);
4236}
4237
4238static const char *
4239iptun_gettypebyvalue(iptun_type_t type)
4240{
4241	int i;
4242
4243	for (i = 0; iptun_types[i].type_name != NULL; i++) {
4244		if (iptun_types[i].type_value == type)
4245			return (iptun_types[i].type_name);
4246	}
4247	return (NULL);
4248}
4249
4250static dladm_status_t
4251print_iptun(dladm_handle_t dh, datalink_id_t linkid, show_state_t *state)
4252{
4253	dladm_status_t		status;
4254	iptun_params_t		params;
4255	iptun_fields_buf_t	lbuf;
4256	const char		*laddr;
4257	const char		*raddr;
4258
4259	params.iptun_param_linkid = linkid;
4260	status = dladm_iptun_getparams(dh, &params, state->ls_flags);
4261	if (status != DLADM_STATUS_OK)
4262		return (status);
4263
4264	/* LINK */
4265	status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL,
4266	    lbuf.iptun_name, sizeof (lbuf.iptun_name));
4267	if (status != DLADM_STATUS_OK)
4268		return (status);
4269
4270	/* TYPE */
4271	(void) strlcpy(lbuf.iptun_type,
4272	    iptun_gettypebyvalue(params.iptun_param_type),
4273	    sizeof (lbuf.iptun_type));
4274
4275	/* FLAGS */
4276	(void) memset(lbuf.iptun_flags, '-', IPTUN_NUM_FLAGS);
4277	lbuf.iptun_flags[IPTUN_NUM_FLAGS] = '\0';
4278	if (params.iptun_param_flags & IPTUN_PARAM_IPSECPOL)
4279		lbuf.iptun_flags[IPTUN_SFLAG_INDEX] = 's';
4280	if (params.iptun_param_flags & IPTUN_PARAM_IMPLICIT)
4281		lbuf.iptun_flags[IPTUN_IFLAG_INDEX] = 'i';
4282
4283	/* LOCAL */
4284	if (params.iptun_param_flags & IPTUN_PARAM_LADDR)
4285		laddr = params.iptun_param_laddr;
4286	else
4287		laddr = (state->ls_parsable) ? "" : "--";
4288	(void) strlcpy(lbuf.iptun_laddr, laddr, sizeof (lbuf.iptun_laddr));
4289
4290	/* REMOTE */
4291	if (params.iptun_param_flags & IPTUN_PARAM_RADDR)
4292		raddr = params.iptun_param_raddr;
4293	else
4294		raddr = (state->ls_parsable) ? "" : "--";
4295	(void) strlcpy(lbuf.iptun_raddr, raddr, sizeof (lbuf.iptun_raddr));
4296
4297	ofmt_print(state->ls_ofmt, &lbuf);
4298
4299	return (DLADM_STATUS_OK);
4300}
4301
4302static int
4303print_iptun_walker(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4304{
4305	((show_state_t *)arg)->ls_status = print_iptun(dh, linkid, arg);
4306	return (DLADM_WALK_CONTINUE);
4307}
4308
4309static dladm_status_t
4310print_phys(show_state_t *state, datalink_id_t linkid)
4311{
4312	char			link[MAXLINKNAMELEN];
4313	uint32_t		flags;
4314	dladm_status_t		status;
4315	datalink_class_t	class;
4316	uint32_t		media;
4317
4318	if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
4319	    &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
4320		goto done;
4321	}
4322
4323	if (class != DATALINK_CLASS_PHYS) {
4324		status = DLADM_STATUS_BADARG;
4325		goto done;
4326	}
4327
4328	if (!(state->ls_flags & flags)) {
4329		status = DLADM_STATUS_NOTFOUND;
4330		goto done;
4331	}
4332
4333	if (state->ls_mac)
4334		status = print_phys_mac(state, linkid, link);
4335	else if (state->ls_hwgrp)
4336		status = print_phys_hwgrp(state, linkid, link);
4337	else
4338		status = print_phys_default(state, linkid, link, flags, media);
4339
4340done:
4341	return (status);
4342}
4343
4344/* ARGSUSED */
4345static int
4346show_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4347{
4348	show_state_t	*state = arg;
4349
4350	state->ls_status = print_phys(state, linkid);
4351	return (DLADM_WALK_CONTINUE);
4352}
4353
4354/*
4355 * Print the active topology information.
4356 */
4357static dladm_status_t
4358print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l)
4359{
4360	dladm_vlan_attr_t	vinfo;
4361	uint32_t		flags;
4362	dladm_status_t		status;
4363
4364	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL,
4365	    l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) {
4366		goto done;
4367	}
4368
4369	if (!(state->ls_flags & flags)) {
4370		status = DLADM_STATUS_NOTFOUND;
4371		goto done;
4372	}
4373
4374	if ((status = dladm_vlan_info(handle, linkid, &vinfo,
4375	    state->ls_flags)) != DLADM_STATUS_OK ||
4376	    (status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL,
4377	    NULL, NULL, l->link_over, sizeof (l->link_over))) !=
4378	    DLADM_STATUS_OK) {
4379		goto done;
4380	}
4381
4382	(void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d",
4383	    vinfo.dv_vid);
4384	(void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----",
4385	    vinfo.dv_force ? 'f' : '-');
4386
4387done:
4388	return (status);
4389}
4390
4391/* ARGSUSED */
4392static int
4393show_vlan(dladm_handle_t dh, datalink_id_t linkid, void *arg)
4394{
4395	show_state_t		*state = arg;
4396	dladm_status_t		status;
4397	link_fields_buf_t	lbuf;
4398
4399	bzero(&lbuf, sizeof (link_fields_buf_t));
4400	status = print_vlan(state, linkid, &lbuf);
4401	if (status != DLADM_STATUS_OK)
4402		goto done;
4403
4404	ofmt_print(state->ls_ofmt, &lbuf);
4405
4406done:
4407	state->ls_status = status;
4408	return (DLADM_WALK_CONTINUE);
4409}
4410
4411static void
4412do_show_phys(int argc, char *argv[], const char *use)
4413{
4414	int		option;
4415	uint32_t	flags = DLADM_OPT_ACTIVE;
4416	boolean_t	p_arg = B_FALSE;
4417	boolean_t	o_arg = B_FALSE;
4418	boolean_t	m_arg = B_FALSE;
4419	boolean_t	H_arg = B_FALSE;
4420	datalink_id_t	linkid = DATALINK_ALL_LINKID;
4421	show_state_t	state;
4422	dladm_status_t	status;
4423	char		*fields_str = NULL;
4424	char		*all_active_fields =
4425	    "link,media,state,speed,duplex,device";
4426	char		*all_inactive_fields = "link,device,media,flags";
4427	char		*all_mac_fields = "link,slot,address,inuse,client";
4428	char		*all_hwgrp_fields = "link,ringtype,rings,clients";
4429	const ofmt_field_t *pf;
4430	ofmt_handle_t	ofmt;
4431	ofmt_status_t	oferr;
4432	uint_t		ofmtflags = 0;
4433
4434	bzero(&state, sizeof (state));
4435	opterr = 0;
4436	while ((option = getopt_long(argc, argv, ":pPo:mH",
4437	    show_lopts, NULL)) != -1) {
4438		switch (option) {
4439		case 'p':
4440			if (p_arg)
4441				die_optdup(option);
4442
4443			p_arg = B_TRUE;
4444			break;
4445		case 'P':
4446			if (flags != DLADM_OPT_ACTIVE)
4447				die_optdup(option);
4448
4449			flags = DLADM_OPT_PERSIST;
4450			break;
4451		case 'o':
4452			o_arg = B_TRUE;
4453			fields_str = optarg;
4454			break;
4455		case 'm':
4456			m_arg = B_TRUE;
4457			break;
4458		case 'H':
4459			H_arg = B_TRUE;
4460			break;
4461		default:
4462			die_opterr(optopt, option, use);
4463			break;
4464		}
4465	}
4466
4467	if (p_arg && !o_arg)
4468		die("-p requires -o");
4469
4470	if (m_arg && H_arg)
4471		die("-m cannot combine with -H");
4472
4473	if (p_arg && strcasecmp(fields_str, "all") == 0)
4474		die("\"-o all\" is invalid with -p");
4475
4476	/* get link name (optional last argument) */
4477	if (optind == (argc-1)) {
4478		if ((status = dladm_name2info(handle, argv[optind], &linkid,
4479		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
4480			die_dlerr(status, "link %s is not valid", argv[optind]);
4481		}
4482	} else if (optind != argc) {
4483		usage();
4484	}
4485
4486	state.ls_parsable = p_arg;
4487	state.ls_flags = flags;
4488	state.ls_donefirst = B_FALSE;
4489	state.ls_mac = m_arg;
4490	state.ls_hwgrp = H_arg;
4491
4492	if (m_arg && !(flags & DLADM_OPT_ACTIVE)) {
4493		/*
4494		 * We can only display the factory MAC addresses of
4495		 * active data-links.
4496		 */
4497		die("-m not compatible with -P");
4498	}
4499
4500	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
4501		if (state.ls_mac)
4502			fields_str = all_mac_fields;
4503		else if (state.ls_hwgrp)
4504			fields_str = all_hwgrp_fields;
4505		else if (state.ls_flags & DLADM_OPT_ACTIVE) {
4506			fields_str = all_active_fields;
4507		} else {
4508			fields_str = all_inactive_fields;
4509		}
4510	}
4511
4512	if (state.ls_mac) {
4513		pf = phys_m_fields;
4514	} else if (state.ls_hwgrp) {
4515		pf = phys_h_fields;
4516	} else {
4517		pf = phys_fields;
4518	}
4519
4520	if (state.ls_parsable)
4521		ofmtflags |= OFMT_PARSABLE;
4522	oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
4523	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
4524	state.ls_ofmt = ofmt;
4525
4526	if (linkid == DATALINK_ALL_LINKID) {
4527		(void) dladm_walk_datalink_id(show_phys, handle, &state,
4528		    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags);
4529	} else {
4530		(void) show_phys(handle, linkid, &state);
4531		if (state.ls_status != DLADM_STATUS_OK) {
4532			die_dlerr(state.ls_status,
4533			    "failed to show physical link %s", argv[optind]);
4534		}
4535	}
4536	ofmt_close(ofmt);
4537}
4538
4539static void
4540do_show_vlan(int argc, char *argv[], const char *use)
4541{
4542	int		option;
4543	uint32_t	flags = DLADM_OPT_ACTIVE;
4544	boolean_t	p_arg = B_FALSE;
4545	datalink_id_t	linkid = DATALINK_ALL_LINKID;
4546	show_state_t	state;
4547	dladm_status_t	status;
4548	boolean_t	o_arg = B_FALSE;
4549	char		*fields_str = NULL;
4550	ofmt_handle_t	ofmt;
4551	ofmt_status_t	oferr;
4552	uint_t		ofmtflags = 0;
4553
4554	bzero(&state, sizeof (state));
4555
4556	opterr = 0;
4557	while ((option = getopt_long(argc, argv, ":pPo:",
4558	    show_lopts, NULL)) != -1) {
4559		switch (option) {
4560		case 'p':
4561			if (p_arg)
4562				die_optdup(option);
4563
4564			p_arg = B_TRUE;
4565			break;
4566		case 'P':
4567			if (flags != DLADM_OPT_ACTIVE)
4568				die_optdup(option);
4569
4570			flags = DLADM_OPT_PERSIST;
4571			break;
4572		case 'o':
4573			o_arg = B_TRUE;
4574			fields_str = optarg;
4575			break;
4576		default:
4577			die_opterr(optopt, option, use);
4578			break;
4579		}
4580	}
4581
4582	/* get link name (optional last argument) */
4583	if (optind == (argc-1)) {
4584		if ((status = dladm_name2info(handle, argv[optind], &linkid,
4585		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
4586			die_dlerr(status, "link %s is not valid", argv[optind]);
4587		}
4588	} else if (optind != argc) {
4589		usage();
4590	}
4591
4592	state.ls_parsable = p_arg;
4593	state.ls_flags = flags;
4594	state.ls_donefirst = B_FALSE;
4595
4596	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
4597		fields_str = NULL;
4598
4599	if (state.ls_parsable)
4600		ofmtflags |= OFMT_PARSABLE;
4601	oferr = ofmt_open(fields_str, vlan_fields, ofmtflags, 0, &ofmt);
4602	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
4603	state.ls_ofmt = ofmt;
4604
4605	if (linkid == DATALINK_ALL_LINKID) {
4606		(void) dladm_walk_datalink_id(show_vlan, handle, &state,
4607		    DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags);
4608	} else {
4609		(void) show_vlan(handle, linkid, &state);
4610		if (state.ls_status != DLADM_STATUS_OK) {
4611			die_dlerr(state.ls_status, "failed to show vlan %s",
4612			    argv[optind]);
4613		}
4614	}
4615	ofmt_close(ofmt);
4616}
4617
4618static void
4619do_create_vnic(int argc, char *argv[], const char *use)
4620{
4621	datalink_id_t		linkid, dev_linkid;
4622	char			devname[MAXLINKNAMELEN];
4623	char			name[MAXLINKNAMELEN];
4624	boolean_t		l_arg = B_FALSE;
4625	uint32_t		flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4626	char			*altroot = NULL;
4627	int			option;
4628	char			*endp = NULL;
4629	dladm_status_t		status;
4630	vnic_mac_addr_type_t	mac_addr_type = VNIC_MAC_ADDR_TYPE_UNKNOWN;
4631	uchar_t			*mac_addr = NULL;
4632	int			mac_slot = -1;
4633	uint_t			maclen = 0, mac_prefix_len = 0;
4634	char			propstr[DLADM_STRSIZE];
4635	dladm_arg_list_t	*proplist = NULL;
4636	int			vid = 0;
4637	int			af = AF_UNSPEC;
4638	vrid_t			vrid = VRRP_VRID_NONE;
4639
4640	opterr = 0;
4641	bzero(propstr, DLADM_STRSIZE);
4642
4643	while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:V:A:H",
4644	    vnic_lopts, NULL)) != -1) {
4645		switch (option) {
4646		case 't':
4647			flags &= ~DLADM_OPT_PERSIST;
4648			break;
4649		case 'R':
4650			altroot = optarg;
4651			break;
4652		case 'l':
4653			if (strlcpy(devname, optarg, MAXLINKNAMELEN) >=
4654			    MAXLINKNAMELEN)
4655				die("link name too long");
4656			l_arg = B_TRUE;
4657			break;
4658		case 'm':
4659			if (mac_addr_type != VNIC_MAC_ADDR_TYPE_UNKNOWN)
4660				die("cannot specify -m option twice");
4661
4662			if (strcmp(optarg, "fixed") == 0) {
4663				/*
4664				 * A fixed MAC address must be specified
4665				 * by its value, not by the keyword 'fixed'.
4666				 */
4667				die("'fixed' is not a valid MAC address");
4668			}
4669			if (dladm_vnic_str2macaddrtype(optarg,
4670			    &mac_addr_type) != DLADM_STATUS_OK) {
4671				mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED;
4672				/* MAC address specified by value */
4673				mac_addr = _link_aton(optarg, (int *)&maclen);
4674				if (mac_addr == NULL) {
4675					if (maclen == (uint_t)-1)
4676						die("invalid MAC address");
4677					else
4678						die("out of memory");
4679				}
4680			}
4681			break;
4682		case 'n':
4683			errno = 0;
4684			mac_slot = (int)strtol(optarg, &endp, 10);
4685			if (errno != 0 || *endp != '\0')
4686				die("invalid slot number");
4687			break;
4688		case 'p':
4689			(void) strlcat(propstr, optarg, DLADM_STRSIZE);
4690			if (strlcat(propstr, ",", DLADM_STRSIZE) >=
4691			    DLADM_STRSIZE)
4692				die("property list too long '%s'", propstr);
4693			break;
4694		case 'r':
4695			mac_addr = _link_aton(optarg, (int *)&mac_prefix_len);
4696			if (mac_addr == NULL) {
4697				if (mac_prefix_len == (uint_t)-1)
4698					die("invalid MAC address");
4699				else
4700					die("out of memory");
4701			}
4702			break;
4703		case 'V':
4704			if (!str2int(optarg, (int *)&vrid) ||
4705			    vrid < VRRP_VRID_MIN || vrid > VRRP_VRID_MAX) {
4706				die("invalid VRRP identifier '%s'", optarg);
4707			}
4708
4709			break;
4710		case 'A':
4711			if (strcmp(optarg, "inet") == 0)
4712				af = AF_INET;
4713			else if (strcmp(optarg, "inet6") == 0)
4714				af = AF_INET6;
4715			else
4716				die("invalid address family '%s'", optarg);
4717			break;
4718		case 'v':
4719			if (vid != 0)
4720				die_optdup(option);
4721
4722			if (!str2int(optarg, &vid) || vid < 1 || vid > 4094)
4723				die("invalid VLAN identifier '%s'", optarg);
4724
4725			break;
4726		case 'f':
4727			flags |= DLADM_OPT_FORCE;
4728			break;
4729		default:
4730			die_opterr(optopt, option, use);
4731		}
4732	}
4733
4734	if (mac_addr_type == VNIC_MAC_ADDR_TYPE_UNKNOWN)
4735		mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO;
4736
4737	/*
4738	 * 'f' - force, flag can be specified only with 'v' - vlan.
4739	 */
4740	if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0)
4741		die("-f option can only be used with -v");
4742
4743	if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM &&
4744	    mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED)
4745		usage();
4746
4747	if (mac_addr_type == VNIC_MAC_ADDR_TYPE_VRID) {
4748		if (vrid == VRRP_VRID_NONE || af == AF_UNSPEC ||
4749		    mac_addr != NULL || maclen != 0 || mac_slot != -1 ||
4750		    mac_prefix_len != 0) {
4751			usage();
4752		}
4753	} else if ((af != AF_UNSPEC || vrid != VRRP_VRID_NONE)) {
4754		usage();
4755	}
4756
4757	/* check required options */
4758	if (!l_arg)
4759		usage();
4760
4761	if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY)
4762		usage();
4763
4764	/* the VNIC id is the required operand */
4765	if (optind != (argc - 1))
4766		usage();
4767
4768	if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
4769		die("link name too long '%s'", argv[optind]);
4770
4771	if (!dladm_valid_linkname(name))
4772		die("invalid link name '%s'", argv[optind]);
4773
4774	if (altroot != NULL)
4775		altroot_cmd(altroot, argc, argv);
4776
4777	if (dladm_name2info(handle, devname, &dev_linkid, NULL, NULL, NULL) !=
4778	    DLADM_STATUS_OK)
4779		die("invalid link name '%s'", devname);
4780
4781	if (dladm_parse_link_props(propstr, &proplist, B_FALSE)
4782	    != DLADM_STATUS_OK)
4783		die("invalid vnic property");
4784
4785	status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type,
4786	    mac_addr, maclen, &mac_slot, mac_prefix_len, vid, vrid, af,
4787	    &linkid, proplist, flags);
4788	switch (status) {
4789	case DLADM_STATUS_OK:
4790		break;
4791
4792	case DLADM_STATUS_LINKBUSY:
4793		die("VLAN over '%s' may not use default_tag ID "
4794		    "(see dladm(1M))", devname);
4795		break;
4796
4797	default:
4798		die_dlerr(status, "vnic creation over %s failed", devname);
4799	}
4800
4801	dladm_free_props(proplist);
4802	free(mac_addr);
4803}
4804
4805static void
4806do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub,
4807    uint32_t flags)
4808{
4809	boolean_t is_etherstub;
4810	dladm_vnic_attr_t attr;
4811
4812	if (dladm_vnic_info(handle, linkid, &attr, flags) != DLADM_STATUS_OK) {
4813		/*
4814		 * Let the delete continue anyway.
4815		 */
4816		return;
4817	}
4818	is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID);
4819	if (is_etherstub != etherstub) {
4820		die("'%s' is not %s", name,
4821		    (is_etherstub ? "a vnic" : "an etherstub"));
4822	}
4823}
4824
4825static void
4826do_delete_vnic_common(int argc, char *argv[], const char *use,
4827    boolean_t etherstub)
4828{
4829	int option;
4830	uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
4831	datalink_id_t linkid;
4832	char *altroot = NULL;
4833	dladm_status_t status;
4834
4835	opterr = 0;
4836	while ((option = getopt_long(argc, argv, ":R:t", lopts,
4837	    NULL)) != -1) {
4838		switch (option) {
4839		case 't':
4840			flags &= ~DLADM_OPT_PERSIST;
4841			break;
4842		case 'R':
4843			altroot = optarg;
4844			break;
4845		default:
4846			die_opterr(optopt, option, use);
4847		}
4848	}
4849
4850	/* get vnic name (required last argument) */
4851	if (optind != (argc - 1))
4852		usage();
4853
4854	if (altroot != NULL)
4855		altroot_cmd(altroot, argc, argv);
4856
4857	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
4858	    NULL);
4859	if (status != DLADM_STATUS_OK)
4860		die("invalid link name '%s'", argv[optind]);
4861
4862	if ((flags & DLADM_OPT_ACTIVE) != 0) {
4863		do_etherstub_check(argv[optind], linkid, etherstub,
4864		    DLADM_OPT_ACTIVE);
4865	}
4866	if ((flags & DLADM_OPT_PERSIST) != 0) {
4867		do_etherstub_check(argv[optind], linkid, etherstub,
4868		    DLADM_OPT_PERSIST);
4869	}
4870
4871	status = dladm_vnic_delete(handle, linkid, flags);
4872	if (status != DLADM_STATUS_OK)
4873		die_dlerr(status, "vnic deletion failed");
4874}
4875
4876static void
4877do_delete_vnic(int argc, char *argv[], const char *use)
4878{
4879	do_delete_vnic_common(argc, argv, use, B_FALSE);
4880}
4881
4882/* ARGSUSED */
4883static void
4884do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan)
4885{
4886	datalink_id_t	linkid = DATALINK_ALL_LINKID;
4887	dladm_status_t	status;
4888	char 		*type;
4889
4890	type = vlan ? "vlan" : "vnic";
4891
4892	/*
4893	 * get the id or the name of the vnic/vlan (optional last argument)
4894	 */
4895	if (argc == 2) {
4896		status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL,
4897		    NULL);
4898		if (status != DLADM_STATUS_OK)
4899			goto done;
4900
4901	} else if (argc > 2) {
4902		usage();
4903	}
4904
4905	if (vlan)
4906		status = dladm_vlan_up(handle, linkid);
4907	else
4908		status = dladm_vnic_up(handle, linkid, 0);
4909
4910done:
4911	if (status != DLADM_STATUS_OK) {
4912		if (argc == 2) {
4913			die_dlerr(status,
4914			    "could not bring up %s '%s'", type, argv[1]);
4915		} else {
4916			die_dlerr(status, "could not bring %ss up", type);
4917		}
4918	}
4919}
4920
4921static void
4922do_up_vnic(int argc, char *argv[], const char *use)
4923{
4924	do_up_vnic_common(argc, argv, use, B_FALSE);
4925}
4926
4927static void
4928dump_vnics_head(const char *dev)
4929{
4930	if (strlen(dev))
4931		(void) printf("%s", dev);
4932
4933	(void) printf("\tipackets  rbytes      opackets  obytes          ");
4934
4935	if (strlen(dev))
4936		(void) printf("%%ipkts  %%opkts\n");
4937	else
4938		(void) printf("\n");
4939}
4940
4941static void
4942dump_vnic_stat(const char *name, datalink_id_t vnic_id,
4943    show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats)
4944{
4945	pktsum_t	diff_stats;
4946	pktsum_t	*old_stats = &state->vs_prevstats[vnic_id];
4947
4948	dladm_stats_diff(&diff_stats, vnic_stats, old_stats);
4949
4950	(void) printf("%s", name);
4951
4952	(void) printf("\t%-10llu", diff_stats.ipackets);
4953	(void) printf("%-12llu", diff_stats.rbytes);
4954	(void) printf("%-10llu", diff_stats.opackets);
4955	(void) printf("%-12llu", diff_stats.obytes);
4956
4957	if (tot_stats) {
4958		if (tot_stats->ipackets == 0) {
4959			(void) printf("\t-");
4960		} else {
4961			(void) printf("\t%-6.1f", (double)diff_stats.ipackets/
4962			    (double)tot_stats->ipackets * 100);
4963		}
4964		if (tot_stats->opackets == 0) {
4965			(void) printf("\t-");
4966		} else {
4967			(void) printf("\t%-6.1f", (double)diff_stats.opackets/
4968			    (double)tot_stats->opackets * 100);
4969		}
4970	}
4971	(void) printf("\n");
4972
4973	*old_stats = *vnic_stats;
4974}
4975
4976/*
4977 * Called from the walker dladm_vnic_walk_sys() for each vnic to display
4978 * vnic information or statistics.
4979 */
4980static dladm_status_t
4981print_vnic(show_vnic_state_t *state, datalink_id_t linkid)
4982{
4983	dladm_vnic_attr_t	attr, *vnic = &attr;
4984	dladm_status_t		status;
4985	boolean_t		is_etherstub;
4986	char			devname[MAXLINKNAMELEN];
4987	char			vnic_name[MAXLINKNAMELEN];
4988	char			mstr[MAXMACADDRLEN * 3];
4989	vnic_fields_buf_t	vbuf;
4990
4991	if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) !=
4992	    DLADM_STATUS_OK)
4993		return (status);
4994
4995	is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID);
4996	if (state->vs_etherstub != is_etherstub) {
4997		/*
4998		 * Want all etherstub but it's not one, or want
4999		 * non-etherstub and it's one.
5000		 */
5001		return (DLADM_STATUS_OK);
5002	}
5003
5004	if (state->vs_link_id != DATALINK_ALL_LINKID) {
5005		if (state->vs_link_id != vnic->va_link_id)
5006			return (DLADM_STATUS_OK);
5007	}
5008
5009	if (dladm_datalink_id2info(handle, linkid, NULL, NULL,
5010	    NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK)
5011		return (DLADM_STATUS_BADARG);
5012
5013	bzero(devname, sizeof (devname));
5014	if (!is_etherstub &&
5015	    dladm_datalink_id2info(handle, vnic->va_link_id, NULL, NULL,
5016	    NULL, devname, sizeof (devname)) != DLADM_STATUS_OK)
5017		(void) sprintf(devname, "?");
5018
5019	state->vs_found = B_TRUE;
5020	if (state->vs_stats) {
5021		/* print vnic statistics */
5022		pktsum_t vnic_stats;
5023
5024		if (state->vs_firstonly) {
5025			if (state->vs_donefirst)
5026				return (0);
5027			state->vs_donefirst = B_TRUE;
5028		}
5029
5030		if (!state->vs_printstats) {
5031			/*
5032			 * get vnic statistics and add to the sum for the
5033			 * named device.
5034			 */
5035			get_link_stats(vnic_name, &vnic_stats);
5036			dladm_stats_total(&state->vs_totalstats, &vnic_stats,
5037			    &state->vs_prevstats[vnic->va_vnic_id]);
5038		} else {
5039			/* get and print vnic statistics */
5040			get_link_stats(vnic_name, &vnic_stats);
5041			dump_vnic_stat(vnic_name, linkid, state, &vnic_stats,
5042			    &state->vs_totalstats);
5043		}
5044		return (DLADM_STATUS_OK);
5045	} else {
5046		(void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link),
5047		    "%s", vnic_name);
5048
5049		if (!is_etherstub) {
5050
5051			(void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over),
5052			    "%s", devname);
5053			(void) snprintf(vbuf.vnic_speed,
5054			    sizeof (vbuf.vnic_speed), "%u",
5055			    (uint_t)((get_ifspeed(vnic_name, B_TRUE))
5056			    / 1000000ull));
5057
5058			switch (vnic->va_mac_addr_type) {
5059			case VNIC_MAC_ADDR_TYPE_FIXED:
5060			case VNIC_MAC_ADDR_TYPE_PRIMARY:
5061				(void) snprintf(vbuf.vnic_macaddrtype,
5062				    sizeof (vbuf.vnic_macaddrtype),
5063				    gettext("fixed"));
5064				break;
5065			case VNIC_MAC_ADDR_TYPE_RANDOM:
5066				(void) snprintf(vbuf.vnic_macaddrtype,
5067				    sizeof (vbuf.vnic_macaddrtype),
5068				    gettext("random"));
5069				break;
5070			case VNIC_MAC_ADDR_TYPE_FACTORY:
5071				(void) snprintf(vbuf.vnic_macaddrtype,
5072				    sizeof (vbuf.vnic_macaddrtype),
5073				    gettext("factory, slot %d"),
5074				    vnic->va_mac_slot);
5075				break;
5076			case VNIC_MAC_ADDR_TYPE_VRID:
5077				(void) snprintf(vbuf.vnic_macaddrtype,
5078				    sizeof (vbuf.vnic_macaddrtype),
5079				    gettext("vrrp, %d/%s"),
5080				    vnic->va_vrid, vnic->va_af == AF_INET ?
5081				    "inet" : "inet6");
5082				break;
5083			}
5084
5085			if (strlen(vbuf.vnic_macaddrtype) > 0) {
5086				(void) snprintf(vbuf.vnic_macaddr,
5087				    sizeof (vbuf.vnic_macaddr), "%s",
5088				    dladm_aggr_macaddr2str(vnic->va_mac_addr,
5089				    mstr));
5090			}
5091
5092			(void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid),
5093			    "%d", vnic->va_vid);
5094		}
5095
5096		ofmt_print(state->vs_ofmt, &vbuf);
5097
5098		return (DLADM_STATUS_OK);
5099	}
5100}
5101
5102/* ARGSUSED */
5103static int
5104show_vnic(dladm_handle_t dh, datalink_id_t linkid, void *arg)
5105{
5106	show_vnic_state_t	*state = arg;
5107
5108	state->vs_status = print_vnic(state, linkid);
5109	return (DLADM_WALK_CONTINUE);
5110}
5111
5112static void
5113do_show_vnic_common(int argc, char *argv[], const char *use,
5114    boolean_t etherstub)
5115{
5116	int			option;
5117	boolean_t		s_arg = B_FALSE;
5118	boolean_t		i_arg = B_FALSE;
5119	boolean_t		l_arg = B_FALSE;
5120	uint32_t		interval = 0, flags = DLADM_OPT_ACTIVE;
5121	datalink_id_t		linkid = DATALINK_ALL_LINKID;
5122	datalink_id_t		dev_linkid = DATALINK_ALL_LINKID;
5123	show_vnic_state_t	state;
5124	dladm_status_t		status;
5125	boolean_t		o_arg = B_FALSE;
5126	char			*fields_str = NULL;
5127	const ofmt_field_t	*pf;
5128	char			*all_e_fields = "link";
5129	ofmt_handle_t		ofmt;
5130	ofmt_status_t		oferr;
5131	uint_t			ofmtflags = 0;
5132
5133	bzero(&state, sizeof (state));
5134	opterr = 0;
5135	while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts,
5136	    NULL)) != -1) {
5137		switch (option) {
5138		case 'p':
5139			state.vs_parsable = B_TRUE;
5140			break;
5141		case 'P':
5142			flags = DLADM_OPT_PERSIST;
5143			break;
5144		case 'l':
5145			if (etherstub)
5146				die("option not supported for this command");
5147
5148			if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >=
5149			    MAXLINKNAMELEN)
5150				die("link name too long");
5151
5152			l_arg = B_TRUE;
5153			break;
5154		case 's':
5155			if (s_arg) {
5156				die("the option -s cannot be specified "
5157				    "more than once");
5158			}
5159			s_arg = B_TRUE;
5160			break;
5161		case 'i':
5162			if (i_arg) {
5163				die("the option -i cannot be specified "
5164				    "more than once");
5165			}
5166			i_arg = B_TRUE;
5167			if (!dladm_str2interval(optarg, &interval))
5168				die("invalid interval value '%s'", optarg);
5169			break;
5170		case 'o':
5171			o_arg = B_TRUE;
5172			fields_str = optarg;
5173			break;
5174		default:
5175			die_opterr(optopt, option, use);
5176		}
5177	}
5178
5179	if (i_arg && !s_arg)
5180		die("the option -i can be used only with -s");
5181
5182	/* get vnic ID (optional last argument) */
5183	if (optind == (argc - 1)) {
5184		status = dladm_name2info(handle, argv[optind], &linkid, NULL,
5185		    NULL, NULL);
5186		if (status != DLADM_STATUS_OK) {
5187			die_dlerr(status, "invalid vnic name '%s'",
5188			    argv[optind]);
5189		}
5190		(void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN);
5191	} else if (optind != argc) {
5192		usage();
5193	}
5194
5195	if (l_arg) {
5196		status = dladm_name2info(handle, state.vs_link, &dev_linkid,
5197		    NULL, NULL, NULL);
5198		if (status != DLADM_STATUS_OK) {
5199			die_dlerr(status, "invalid link name '%s'",
5200			    state.vs_link);
5201		}
5202	}
5203
5204	state.vs_vnic_id = linkid;
5205	state.vs_link_id = dev_linkid;
5206	state.vs_etherstub = etherstub;
5207	state.vs_found = B_FALSE;
5208	state.vs_flags = flags;
5209
5210	if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) {
5211		if (etherstub)
5212			fields_str = all_e_fields;
5213	}
5214	pf = vnic_fields;
5215
5216	if (state.vs_parsable)
5217		ofmtflags |= OFMT_PARSABLE;
5218	oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt);
5219	dladm_ofmt_check(oferr, state.vs_parsable, ofmt);
5220	state.vs_ofmt = ofmt;
5221
5222	if (s_arg) {
5223		/* Display vnic statistics */
5224		vnic_stats(&state, interval);
5225		ofmt_close(ofmt);
5226		return;
5227	}
5228
5229	/* Display vnic information */
5230	state.vs_donefirst = B_FALSE;
5231
5232	if (linkid == DATALINK_ALL_LINKID) {
5233		(void) dladm_walk_datalink_id(show_vnic, handle, &state,
5234		    DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB,
5235		    DATALINK_ANY_MEDIATYPE, flags);
5236	} else {
5237		(void) show_vnic(handle, linkid, &state);
5238		if (state.vs_status != DLADM_STATUS_OK) {
5239			ofmt_close(ofmt);
5240			die_dlerr(state.vs_status, "failed to show vnic '%s'",
5241			    state.vs_vnic);
5242		}
5243	}
5244	ofmt_close(ofmt);
5245}
5246
5247static void
5248do_show_vnic(int argc, char *argv[], const char *use)
5249{
5250	do_show_vnic_common(argc, argv, use, B_FALSE);
5251}
5252
5253static void
5254do_create_etherstub(int argc, char *argv[], const char *use)
5255{
5256	uint32_t flags;
5257	char *altroot = NULL;
5258	int option;
5259	dladm_status_t status;
5260	char name[MAXLINKNAMELEN];
5261	uchar_t mac_addr[ETHERADDRL];
5262
5263	name[0] = '\0';
5264	bzero(mac_addr, sizeof (mac_addr));
5265	flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
5266
5267	opterr = 0;
5268	while ((option = getopt_long(argc, argv, "tR:",
5269	    etherstub_lopts, NULL)) != -1) {
5270		switch (option) {
5271		case 't':
5272			flags &= ~DLADM_OPT_PERSIST;
5273			break;
5274		case 'R':
5275			altroot = optarg;
5276			break;
5277		default:
5278			die_opterr(optopt, option, use);
5279		}
5280	}
5281
5282	/* the etherstub id is the required operand */
5283	if (optind != (argc - 1))
5284		usage();
5285
5286	if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
5287		die("link name too long '%s'", argv[optind]);
5288
5289	if (!dladm_valid_linkname(name))
5290		die("invalid link name '%s'", argv[optind]);
5291
5292	if (altroot != NULL)
5293		altroot_cmd(altroot, argc, argv);
5294
5295	status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID,
5296	    VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0,
5297	    VRRP_VRID_NONE, AF_UNSPEC, NULL, NULL, flags);
5298	if (status != DLADM_STATUS_OK)
5299		die_dlerr(status, "etherstub creation failed");
5300}
5301
5302static void
5303do_delete_etherstub(int argc, char *argv[], const char *use)
5304{
5305	do_delete_vnic_common(argc, argv, use, B_TRUE);
5306}
5307
5308/* ARGSUSED */
5309static void
5310do_show_etherstub(int argc, char *argv[], const char *use)
5311{
5312	do_show_vnic_common(argc, argv, use, B_TRUE);
5313}
5314
5315/* ARGSUSED */
5316static void
5317do_up_simnet(int argc, char *argv[], const char *use)
5318{
5319	(void) dladm_simnet_up(handle, DATALINK_ALL_LINKID, 0);
5320}
5321
5322static void
5323do_create_simnet(int argc, char *argv[], const char *use)
5324{
5325	uint32_t flags;
5326	char *altroot = NULL;
5327	char *media = NULL;
5328	uint32_t mtype = DL_ETHER;
5329	int option;
5330	dladm_status_t status;
5331	char name[MAXLINKNAMELEN];
5332
5333	name[0] = '\0';
5334	flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
5335
5336	opterr = 0;
5337	while ((option = getopt_long(argc, argv, ":tR:m:",
5338	    simnet_lopts, NULL)) != -1) {
5339		switch (option) {
5340		case 't':
5341			flags &= ~DLADM_OPT_PERSIST;
5342			break;
5343		case 'R':
5344			altroot = optarg;
5345			break;
5346		case 'm':
5347			media = optarg;
5348			break;
5349		default:
5350			die_opterr(optopt, option, use);
5351		}
5352	}
5353
5354	/* the simnet id is the required operand */
5355	if (optind != (argc - 1))
5356		usage();
5357
5358	if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN)
5359		die("link name too long '%s'", argv[optind]);
5360
5361	if (!dladm_valid_linkname(name))
5362		die("invalid link name '%s'", name);
5363
5364	if (media != NULL) {
5365		mtype = dladm_str2media(media);
5366		if (mtype != DL_ETHER && mtype != DL_WIFI)
5367			die("media type '%s' is not supported", media);
5368	}
5369
5370	if (altroot != NULL)
5371		altroot_cmd(altroot, argc, argv);
5372
5373	status = dladm_simnet_create(handle, name, mtype, flags);
5374	if (status != DLADM_STATUS_OK)
5375		die_dlerr(status, "simnet creation failed");
5376}
5377
5378static void
5379do_delete_simnet(int argc, char *argv[], const char *use)
5380{
5381	int option;
5382	uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
5383	datalink_id_t linkid;
5384	char *altroot = NULL;
5385	dladm_status_t status;
5386	dladm_simnet_attr_t slinfo;
5387
5388	opterr = 0;
5389	while ((option = getopt_long(argc, argv, ":tR:", simnet_lopts,
5390	    NULL)) != -1) {
5391		switch (option) {
5392		case 't':
5393			flags &= ~DLADM_OPT_PERSIST;
5394			break;
5395		case 'R':
5396			altroot = optarg;
5397			break;
5398		default:
5399			die_opterr(optopt, option, use);
5400		}
5401	}
5402
5403	/* get simnet name (required last argument) */
5404	if (optind != (argc - 1))
5405		usage();
5406
5407	if (!dladm_valid_linkname(argv[optind]))
5408		die("invalid link name '%s'", argv[optind]);
5409
5410	if (altroot != NULL)
5411		altroot_cmd(altroot, argc, argv);
5412
5413	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
5414	    NULL);
5415	if (status != DLADM_STATUS_OK)
5416		die("simnet '%s' not found", argv[optind]);
5417
5418	if ((status = dladm_simnet_info(handle, linkid, &slinfo,
5419	    flags)) != DLADM_STATUS_OK)
5420		die_dlerr(status, "failed to retrieve simnet information");
5421
5422	status = dladm_simnet_delete(handle, linkid, flags);
5423	if (status != DLADM_STATUS_OK)
5424		die_dlerr(status, "simnet deletion failed");
5425}
5426
5427static void
5428do_modify_simnet(int argc, char *argv[], const char *use)
5429{
5430	int option;
5431	uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST;
5432	datalink_id_t linkid;
5433	datalink_id_t peer_linkid;
5434	char *altroot = NULL;
5435	dladm_status_t status;
5436	boolean_t p_arg = B_FALSE;
5437
5438	opterr = 0;
5439	while ((option = getopt_long(argc, argv, ":tR:p:", simnet_lopts,
5440	    NULL)) != -1) {
5441		switch (option) {
5442		case 't':
5443			flags &= ~DLADM_OPT_PERSIST;
5444			break;
5445		case 'R':
5446			altroot = optarg;
5447			break;
5448		case 'p':
5449			if (p_arg)
5450				die_optdup(option);
5451			p_arg = B_TRUE;
5452			if (strcasecmp(optarg, "none") == 0)
5453				peer_linkid = DATALINK_INVALID_LINKID;
5454			else if (dladm_name2info(handle, optarg, &peer_linkid,
5455			    NULL, NULL, NULL) != DLADM_STATUS_OK)
5456				die("invalid peer link name '%s'", optarg);
5457			break;
5458		default:
5459			die_opterr(optopt, option, use);
5460		}
5461	}
5462
5463	/* get simnet name (required last argument) */
5464	if (optind != (argc - 1))
5465		usage();
5466
5467	/* Nothing to do if no peer link argument */
5468	if (!p_arg)
5469		return;
5470
5471	if (altroot != NULL)
5472		altroot_cmd(altroot, argc, argv);
5473
5474	status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL,
5475	    NULL);
5476	if (status != DLADM_STATUS_OK)
5477		die("invalid link name '%s'", argv[optind]);
5478
5479	status = dladm_simnet_modify(handle, linkid, peer_linkid, flags);
5480	if (status != DLADM_STATUS_OK)
5481		die_dlerr(status, "simnet modification failed");
5482}
5483
5484static dladm_status_t
5485print_simnet(show_state_t *state, datalink_id_t linkid)
5486{
5487	dladm_simnet_attr_t	slinfo;
5488	uint32_t		flags;
5489	dladm_status_t		status;
5490	simnet_fields_buf_t	slbuf;
5491	char			mstr[ETHERADDRL * 3];
5492
5493	bzero(&slbuf, sizeof (slbuf));
5494	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL,
5495	    slbuf.simnet_name, sizeof (slbuf.simnet_name)))
5496	    != DLADM_STATUS_OK)
5497		return (status);
5498
5499	if (!(state->ls_flags & flags))
5500		return (DLADM_STATUS_NOTFOUND);
5501
5502	if ((status = dladm_simnet_info(handle, linkid, &slinfo,
5503	    state->ls_flags)) != DLADM_STATUS_OK)
5504		return (status);
5505
5506	if (slinfo.sna_peer_link_id != DATALINK_INVALID_LINKID &&
5507	    (status = dladm_datalink_id2info(handle, slinfo.sna_peer_link_id,
5508	    NULL, NULL, NULL, slbuf.simnet_otherlink,
5509	    sizeof (slbuf.simnet_otherlink))) !=
5510	    DLADM_STATUS_OK)
5511		return (status);
5512
5513	if (slinfo.sna_mac_len > sizeof (slbuf.simnet_macaddr))
5514		return (DLADM_STATUS_BADVAL);
5515
5516	(void) strlcpy(slbuf.simnet_macaddr,
5517	    dladm_aggr_macaddr2str(slinfo.sna_mac_addr, mstr),
5518	    sizeof (slbuf.simnet_macaddr));
5519	(void) dladm_media2str(slinfo.sna_type, slbuf.simnet_media);
5520
5521	ofmt_print(state->ls_ofmt, &slbuf);
5522	return (status);
5523}
5524
5525/* ARGSUSED */
5526static int
5527show_simnet(dladm_handle_t dh, datalink_id_t linkid, void *arg)
5528{
5529	show_state_t		*state = arg;
5530
5531	state->ls_status = print_simnet(state, linkid);
5532	return (DLADM_WALK_CONTINUE);
5533}
5534
5535static void
5536do_show_simnet(int argc, char *argv[], const char *use)
5537{
5538	int		option;
5539	uint32_t	flags = DLADM_OPT_ACTIVE;
5540	boolean_t	p_arg = B_FALSE;
5541	datalink_id_t	linkid = DATALINK_ALL_LINKID;
5542	show_state_t	state;
5543	dladm_status_t	status;
5544	boolean_t	o_arg = B_FALSE;
5545	ofmt_handle_t	ofmt;
5546	ofmt_status_t	oferr;
5547	char		*all_fields = "link,media,macaddress,otherlink";
5548	char		*fields_str = all_fields;
5549	uint_t		ofmtflags = 0;
5550
5551	bzero(&state, sizeof (state));
5552
5553	opterr = 0;
5554	while ((option = getopt_long(argc, argv, ":pPo:",
5555	    show_lopts, NULL)) != -1) {
5556		switch (option) {
5557		case 'p':
5558			if (p_arg)
5559				die_optdup(option);
5560
5561			p_arg = B_TRUE;
5562			state.ls_parsable = p_arg;
5563			break;
5564		case 'P':
5565			if (flags != DLADM_OPT_ACTIVE)
5566				die_optdup(option);
5567
5568			flags = DLADM_OPT_PERSIST;
5569			break;
5570		case 'o':
5571			o_arg = B_TRUE;
5572			fields_str = optarg;
5573			break;
5574		default:
5575			die_opterr(optopt, option, use);
5576			break;
5577		}
5578	}
5579
5580	if (p_arg && !o_arg)
5581		die("-p requires -o");
5582
5583	if (strcasecmp(fields_str, "all") == 0) {
5584		if (p_arg)
5585			die("\"-o all\" is invalid with -p");
5586		fields_str = all_fields;
5587	}
5588
5589	/* get link name (optional last argument) */
5590	if (optind == (argc-1)) {
5591		if ((status = dladm_name2info(handle, argv[optind], &linkid,
5592		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
5593			die_dlerr(status, "link %s is not valid", argv[optind]);
5594		}
5595	} else if (optind != argc) {
5596		usage();
5597	}
5598
5599	state.ls_flags = flags;
5600	state.ls_donefirst = B_FALSE;
5601	if (state.ls_parsable)
5602		ofmtflags |= OFMT_PARSABLE;
5603	oferr = ofmt_open(fields_str, simnet_fields, ofmtflags, 0, &ofmt);
5604	dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
5605	state.ls_ofmt = ofmt;
5606
5607	if (linkid == DATALINK_ALL_LINKID) {
5608		(void) dladm_walk_datalink_id(show_simnet, handle, &state,
5609		    DATALINK_CLASS_SIMNET, DATALINK_ANY_MEDIATYPE, flags);
5610	} else {
5611		(void) show_simnet(handle, linkid, &state);
5612		if (state.ls_status != DLADM_STATUS_OK) {
5613			ofmt_close(ofmt);
5614			die_dlerr(state.ls_status, "failed to show simnet %s",
5615			    argv[optind]);
5616		}
5617	}
5618	ofmt_close(ofmt);
5619}
5620
5621static void
5622link_stats(datalink_id_t linkid, uint_t interval, char *fields_str,
5623    show_state_t *state)
5624{
5625	ofmt_handle_t	ofmt;
5626	ofmt_status_t	oferr;
5627	uint_t		ofmtflags = 0;
5628
5629	if (state->ls_parsable)
5630		ofmtflags |= OFMT_PARSABLE;
5631	oferr = ofmt_open(fields_str, link_s_fields, ofmtflags, 0, &ofmt);
5632	dladm_ofmt_check(oferr, state->ls_parsable, ofmt);
5633	state->ls_ofmt = ofmt;
5634
5635	/*
5636	 * If an interval is specified, continuously show the stats
5637	 * only for the first MAC port.
5638	 */
5639	state->ls_firstonly = (interval != 0);
5640
5641	for (;;) {
5642		state->ls_donefirst = B_FALSE;
5643		if (linkid == DATALINK_ALL_LINKID) {
5644			(void) dladm_walk_datalink_id(show_link_stats, handle,
5645			    state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
5646			    DLADM_OPT_ACTIVE);
5647		} else {
5648			(void) show_link_stats(handle, linkid, state);
5649		}
5650
5651		if (interval == 0)
5652			break;
5653
5654		(void) fflush(stdout);
5655		(void) sleep(interval);
5656	}
5657	ofmt_close(ofmt);
5658}
5659
5660static void
5661aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval)
5662{
5663	/*
5664	 * If an interval is specified, continuously show the stats
5665	 * only for the first group.
5666	 */
5667	state->gs_firstonly = (interval != 0);
5668
5669	for (;;) {
5670		state->gs_donefirst = B_FALSE;
5671		if (linkid == DATALINK_ALL_LINKID)
5672			(void) dladm_walk_datalink_id(show_aggr, handle, state,
5673			    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
5674			    DLADM_OPT_ACTIVE);
5675		else
5676			(void) show_aggr(handle, linkid, state);
5677
5678		if (interval == 0)
5679			break;
5680
5681		(void) fflush(stdout);
5682		(void) sleep(interval);
5683	}
5684}
5685
5686/* ARGSUSED */
5687static void
5688vnic_stats(show_vnic_state_t *sp, uint32_t interval)
5689{
5690	show_vnic_state_t	state;
5691	boolean_t		specific_link, specific_dev;
5692
5693	/* Display vnic statistics */
5694	dump_vnics_head(sp->vs_link);
5695
5696	bzero(&state, sizeof (state));
5697	state.vs_stats = B_TRUE;
5698	state.vs_vnic_id = sp->vs_vnic_id;
5699	state.vs_link_id = sp->vs_link_id;
5700
5701	/*
5702	 * If an interval is specified, and a vnic ID is not specified,
5703	 * continuously show the stats only for the first vnic.
5704	 */
5705	specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID);
5706	specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID);
5707
5708	for (;;) {
5709		/* Get stats for each vnic */
5710		state.vs_found = B_FALSE;
5711		state.vs_donefirst = B_FALSE;
5712		state.vs_printstats = B_FALSE;
5713		state.vs_flags = DLADM_OPT_ACTIVE;
5714
5715		if (!specific_link) {
5716			(void) dladm_walk_datalink_id(show_vnic, handle, &state,
5717			    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
5718			    DLADM_OPT_ACTIVE);
5719		} else {
5720			(void) show_vnic(handle, sp->vs_vnic_id, &state);
5721			if (state.vs_status != DLADM_STATUS_OK) {
5722				die_dlerr(state.vs_status,
5723				    "failed to show vnic '%s'", sp->vs_vnic);
5724			}
5725		}
5726
5727		if (specific_link && !state.vs_found)
5728			die("non-existent vnic '%s'", sp->vs_vnic);
5729		if (specific_dev && !state.vs_found)
5730			die("device %s has no vnics", sp->vs_link);
5731
5732		/* Show totals */
5733		if ((specific_link | specific_dev) && !interval) {
5734			(void) printf("Total");
5735			(void) printf("\t%-10llu",
5736			    state.vs_totalstats.ipackets);
5737			(void) printf("%-12llu",
5738			    state.vs_totalstats.rbytes);
5739			(void) printf("%-10llu",
5740			    state.vs_totalstats.opackets);
5741			(void) printf("%-12llu\n",
5742			    state.vs_totalstats.obytes);
5743		}
5744
5745		/* Show stats for each vnic */
5746		state.vs_donefirst = B_FALSE;
5747		state.vs_printstats = B_TRUE;
5748
5749		if (!specific_link) {
5750			(void) dladm_walk_datalink_id(show_vnic, handle, &state,
5751			    DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE,
5752			    DLADM_OPT_ACTIVE);
5753		} else {
5754			(void) show_vnic(handle, sp->vs_vnic_id, &state);
5755			if (state.vs_status != DLADM_STATUS_OK) {
5756				die_dlerr(state.vs_status,
5757				    "failed to show vnic '%s'", sp->vs_vnic);
5758			}
5759		}
5760
5761		if (interval == 0)
5762			break;
5763
5764		(void) fflush(stdout);
5765		(void) sleep(interval);
5766	}
5767}
5768
5769static void
5770get_mac_stats(const char *dev, pktsum_t *stats)
5771{
5772	kstat_ctl_t	*kcp;
5773	kstat_t		*ksp;
5774	char module[DLPI_LINKNAME_MAX];
5775	uint_t instance;
5776
5777
5778	bzero(stats, sizeof (*stats));
5779
5780	if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS)
5781		return;
5782
5783	if ((kcp = kstat_open()) == NULL) {
5784		warn("kstat open operation failed");
5785		return;
5786	}
5787
5788	ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL);
5789	if (ksp != NULL)
5790		dladm_get_stats(kcp, ksp, stats);
5791
5792	(void) kstat_close(kcp);
5793
5794}
5795
5796static void
5797get_link_stats(const char *link, pktsum_t *stats)
5798{
5799	kstat_ctl_t	*kcp;
5800	kstat_t		*ksp;
5801
5802	bzero(stats, sizeof (*stats));
5803
5804	if ((kcp = kstat_open()) == NULL) {
5805		warn("kstat_open operation failed");
5806		return;
5807	}
5808
5809	ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL);
5810
5811	if (ksp != NULL)
5812		dladm_get_stats(kcp, ksp, stats);
5813
5814	(void) kstat_close(kcp);
5815}
5816
5817static int
5818query_kstat(char *module, int instance, const char *name, const char *stat,
5819    uint8_t type, void *val)
5820{
5821	kstat_ctl_t	*kcp;
5822	kstat_t		*ksp;
5823
5824	if ((kcp = kstat_open()) == NULL) {
5825		warn("kstat open operation failed");
5826		return (-1);
5827	}
5828
5829	if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) {
5830		/*
5831		 * The kstat query could fail if the underlying MAC
5832		 * driver was already detached.
5833		 */
5834		goto bail;
5835	}
5836
5837	if (kstat_read(kcp, ksp, NULL) == -1) {
5838		warn("kstat read failed");
5839		goto bail;
5840	}
5841
5842	if (dladm_kstat_value(ksp, stat, type, val) < 0)
5843		goto bail;
5844
5845	(void) kstat_close(kcp);
5846	return (0);
5847
5848bail:
5849	(void) kstat_close(kcp);
5850	return (-1);
5851}
5852
5853static int
5854get_one_kstat(const char *name, const char *stat, uint8_t type,
5855    void *val, boolean_t islink)
5856{
5857	char		module[DLPI_LINKNAME_MAX];
5858	uint_t		instance;
5859
5860	if (islink) {
5861		return (query_kstat("link", 0, name, stat, type, val));
5862	} else {
5863		if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS)
5864			return (-1);
5865
5866		return (query_kstat(module, instance, "mac", stat, type, val));
5867	}
5868}
5869
5870static uint64_t
5871get_ifspeed(const char *name, boolean_t islink)
5872{
5873	uint64_t ifspeed = 0;
5874
5875	(void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64,
5876	    &ifspeed, islink</