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