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