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