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