5960 zfs recv should prefetch indirect blocks
[illumos-gate.git] / usr / src / cmd / flowadm / flowadm.c
blob374fa1675c94d449f5850fd83dbbd278364c5269
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <stdio.h>
27 #include <locale.h>
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <stropts.h>
33 #include <errno.h>
34 #include <strings.h>
35 #include <getopt.h>
36 #include <unistd.h>
37 #include <priv.h>
38 #include <netdb.h>
39 #include <libintl.h>
40 #include <libdlflow.h>
41 #include <libdllink.h>
42 #include <libdlstat.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <sys/ethernet.h>
48 #include <inet/ip.h>
49 #include <inet/ip6.h>
50 #include <stddef.h>
51 #include <ofmt.h>
53 typedef struct show_flow_state {
54 dladm_status_t fs_status;
55 ofmt_handle_t fs_ofmt;
56 const char *fs_flow;
57 boolean_t fs_parsable;
58 boolean_t fs_persist;
59 } show_flow_state_t;
61 typedef void cmdfunc_t(int, char **);
63 static cmdfunc_t do_add_flow, do_remove_flow, do_init_flow, do_show_flow;
64 static cmdfunc_t do_show_flowprop, do_set_flowprop, do_reset_flowprop;
66 static int show_flow(dladm_handle_t, dladm_flow_attr_t *, void *);
67 static int show_flows_onelink(dladm_handle_t, datalink_id_t, void *);
69 static int remove_flow(dladm_handle_t, dladm_flow_attr_t *, void *);
71 static int show_flowprop(dladm_handle_t, dladm_flow_attr_t *, void *);
72 static void show_flowprop_one_flow(void *, const char *);
73 static int show_flowprop_onelink(dladm_handle_t, datalink_id_t, void *);
75 static void die(const char *, ...);
76 static void die_optdup(int);
77 static void die_opterr(int, int);
78 static void die_dlerr(dladm_status_t, const char *, ...);
79 static void warn(const char *, ...);
80 static void warn_dlerr(dladm_status_t, const char *, ...);
82 /* callback functions for printing output */
83 static ofmt_cb_t print_flowprop_cb, print_default_cb;
84 static void flowadm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
86 typedef struct cmd {
87 char *c_name;
88 void (*c_fn)(int, char **);
89 } cmd_t;
91 static cmd_t cmds[] = {
92 { "add-flow", do_add_flow },
93 { "remove-flow", do_remove_flow },
94 { "show-flowprop", do_show_flowprop },
95 { "set-flowprop", do_set_flowprop },
96 { "reset-flowprop", do_reset_flowprop },
97 { "show-flow", do_show_flow },
98 { "init-flow", do_init_flow },
101 static const struct option longopts[] = {
102 {"link", required_argument, 0, 'l'},
103 {"parsable", no_argument, 0, 'p'},
104 {"parseable", no_argument, 0, 'p'},
105 {"temporary", no_argument, 0, 't'},
106 {"root-dir", required_argument, 0, 'R'},
107 { 0, 0, 0, 0 }
110 static const struct option prop_longopts[] = {
111 {"link", required_argument, 0, 'l'},
112 {"temporary", no_argument, 0, 't'},
113 {"root-dir", required_argument, 0, 'R'},
114 {"prop", required_argument, 0, 'p'},
115 {"attr", required_argument, 0, 'a'},
116 { 0, 0, 0, 0 }
120 * structures for 'flowadm remove-flow'
122 typedef struct remove_flow_state {
123 boolean_t fs_tempop;
124 const char *fs_altroot;
125 dladm_status_t fs_status;
126 } remove_flow_state_t;
128 #define PROTO_MAXSTR_LEN 7
129 #define PORT_MAXSTR_LEN 6
130 #define DSFIELD_MAXSTR_LEN 10
131 #define NULL_OFMT {NULL, 0, 0, NULL}
133 typedef struct flow_fields_buf_s
135 char flow_name[MAXFLOWNAMELEN];
136 char flow_link[MAXLINKNAMELEN];
137 char flow_ipaddr[INET6_ADDRSTRLEN+4];
138 char flow_proto[PROTO_MAXSTR_LEN];
139 char flow_lport[PORT_MAXSTR_LEN];
140 char flow_rport[PORT_MAXSTR_LEN];
141 char flow_dsfield[DSFIELD_MAXSTR_LEN];
142 } flow_fields_buf_t;
144 static ofmt_field_t flow_fields[] = {
145 /* name, field width, index */
146 { "FLOW", 12,
147 offsetof(flow_fields_buf_t, flow_name), print_default_cb},
148 { "LINK", 12,
149 offsetof(flow_fields_buf_t, flow_link), print_default_cb},
150 { "IPADDR", 25,
151 offsetof(flow_fields_buf_t, flow_ipaddr), print_default_cb},
152 { "PROTO", 7,
153 offsetof(flow_fields_buf_t, flow_proto), print_default_cb},
154 { "LPORT", 8,
155 offsetof(flow_fields_buf_t, flow_lport), print_default_cb},
156 { "RPORT", 8,
157 offsetof(flow_fields_buf_t, flow_rport), print_default_cb},
158 { "DSFLD", 10,
159 offsetof(flow_fields_buf_t, flow_dsfield), print_default_cb},
160 NULL_OFMT}
164 * structures for 'flowadm show-flowprop'
166 typedef enum {
167 FLOWPROP_FLOW,
168 FLOWPROP_PROPERTY,
169 FLOWPROP_VALUE,
170 FLOWPROP_DEFAULT,
171 FLOWPROP_POSSIBLE
172 } flowprop_field_index_t;
174 static ofmt_field_t flowprop_fields[] = {
175 /* name, fieldwidth, index, callback */
176 { "FLOW", 13, FLOWPROP_FLOW, print_flowprop_cb},
177 { "PROPERTY", 16, FLOWPROP_PROPERTY, print_flowprop_cb},
178 { "VALUE", 15, FLOWPROP_VALUE, print_flowprop_cb},
179 { "DEFAULT", 15, FLOWPROP_DEFAULT, print_flowprop_cb},
180 { "POSSIBLE", 21, FLOWPROP_POSSIBLE, print_flowprop_cb},
181 NULL_OFMT}
184 #define MAX_PROP_LINE 512
186 typedef struct show_flowprop_state {
187 const char *fs_flow;
188 datalink_id_t fs_linkid;
189 char *fs_line;
190 char **fs_propvals;
191 dladm_arg_list_t *fs_proplist;
192 boolean_t fs_parsable;
193 boolean_t fs_persist;
194 boolean_t fs_header;
195 dladm_status_t fs_status;
196 dladm_status_t fs_retstatus;
197 ofmt_handle_t fs_ofmt;
198 } show_flowprop_state_t;
200 typedef struct set_flowprop_state {
201 const char *fs_name;
202 boolean_t fs_reset;
203 boolean_t fs_temp;
204 dladm_status_t fs_status;
205 } set_flowprop_state_t;
207 typedef struct flowprop_args_s {
208 show_flowprop_state_t *fs_state;
209 char *fs_propname;
210 char *fs_flowname;
211 } flowprop_args_t;
213 static char *progname;
215 boolean_t t_arg = B_FALSE; /* changes are persistent */
216 char *altroot = NULL;
219 * Handle to libdladm. Opened in main() before the sub-command
220 * specific function is called.
222 static dladm_handle_t handle = NULL;
224 static const char *attr_table[] =
225 {"local_ip", "remote_ip", "transport", "local_port", "remote_port",
226 "dsfield"};
228 #define NATTR (sizeof (attr_table)/sizeof (char *))
230 static void
231 usage(void)
233 (void) fprintf(stderr, gettext("usage: flowadm <subcommand>"
234 " <args>...\n"
235 " add-flow [-t] -l <link> -a <attr>=<value>[,...]\n"
236 "\t\t [-p <prop>=<value>,...] <flow>\n"
237 " remove-flow [-t] {-l <link> | <flow>}\n"
238 " show-flow [-p] [-l <link>] "
239 "[<flow>]\n\n"
240 " set-flowprop [-t] -p <prop>=<value>[,...] <flow>\n"
241 " reset-flowprop [-t] [-p <prop>,...] <flow>\n"
242 " show-flowprop [-cP] [-l <link>] [-p <prop>,...] "
243 "[<flow>]\n"));
245 /* close dladm handle if it was opened */
246 if (handle != NULL)
247 dladm_close(handle);
249 exit(1);
253 main(int argc, char *argv[])
255 int i, arglen, cmdlen;
256 cmd_t *cmdp;
257 dladm_status_t status;
259 (void) setlocale(LC_ALL, "");
260 #if !defined(TEXT_DOMAIN)
261 #define TEXT_DOMAIN "SYS_TEST"
262 #endif
263 (void) textdomain(TEXT_DOMAIN);
265 progname = argv[0];
267 if (argc < 2)
268 usage();
270 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
271 cmdp = &cmds[i];
272 arglen = strlen(argv[1]);
273 cmdlen = strlen(cmdp->c_name);
274 if ((arglen == cmdlen) && (strncmp(argv[1], cmdp->c_name,
275 cmdlen) == 0)) {
276 /* Open the libdladm handle */
277 if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) {
278 die_dlerr(status,
279 "could not open /dev/dld");
282 cmdp->c_fn(argc - 1, &argv[1]);
284 dladm_close(handle);
285 exit(EXIT_SUCCESS);
289 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
290 progname, argv[1]);
291 usage();
293 return (0);
296 static const char *
297 match_attr(char *attr)
299 int i;
301 for (i = 0; i < NATTR; i++) {
302 if (strlen(attr) == strlen(attr_table[i]) &&
303 strncmp(attr, attr_table[i], strlen(attr_table[i])) == 0) {
304 return (attr);
307 return (NULL);
310 /* ARGSUSED */
311 static void
312 do_init_flow(int argc, char *argv[])
314 dladm_status_t status;
316 status = dladm_flow_init(handle);
317 if (status != DLADM_STATUS_OK)
318 die_dlerr(status, "flows initialization failed");
321 static void
322 do_add_flow(int argc, char *argv[])
324 char devname[MAXLINKNAMELEN];
325 char *name = NULL;
326 uint_t index;
327 datalink_id_t linkid;
329 char option;
330 boolean_t l_arg = B_FALSE;
331 char propstr[DLADM_STRSIZE];
332 char attrstr[DLADM_STRSIZE];
333 dladm_arg_list_t *proplist = NULL;
334 dladm_arg_list_t *attrlist = NULL;
335 dladm_status_t status;
337 bzero(propstr, DLADM_STRSIZE);
338 bzero(attrstr, DLADM_STRSIZE);
340 while ((option = getopt_long(argc, argv, "tR:l:a:p:",
341 prop_longopts, NULL)) != -1) {
342 switch (option) {
343 case 't':
344 t_arg = B_TRUE;
345 break;
346 case 'R':
347 altroot = optarg;
348 break;
349 case 'l':
350 if (strlcpy(devname, optarg,
351 MAXLINKNAMELEN) >= MAXLINKNAMELEN) {
352 die("link name too long");
354 if (dladm_name2info(handle, devname, &linkid, NULL,
355 NULL, NULL) != DLADM_STATUS_OK)
356 die("invalid link '%s'", devname);
357 l_arg = B_TRUE;
358 break;
359 case 'a':
360 (void) strlcat(attrstr, optarg, DLADM_STRSIZE);
361 if (strlcat(attrstr, ",", DLADM_STRSIZE) >=
362 DLADM_STRSIZE)
363 die("attribute list too long '%s'", attrstr);
364 break;
365 case 'p':
366 (void) strlcat(propstr, optarg, DLADM_STRSIZE);
367 if (strlcat(propstr, ",", DLADM_STRSIZE) >=
368 DLADM_STRSIZE)
369 die("property list too long '%s'", propstr);
370 break;
371 default:
372 die_opterr(optopt, option);
375 if (!l_arg) {
376 die("link is required");
379 opterr = 0;
380 index = optind;
382 if ((index != (argc - 1)) || match_attr(argv[index]) != NULL) {
383 die("flow name is required");
384 } else {
385 /* get flow name; required last argument */
386 if (strlen(argv[index]) >= MAXFLOWNAMELEN)
387 die("flow name too long");
388 name = argv[index];
391 if (dladm_parse_flow_attrs(attrstr, &attrlist, B_FALSE)
392 != DLADM_STATUS_OK)
393 die("invalid flow attribute specified");
394 if (dladm_parse_flow_props(propstr, &proplist, B_FALSE)
395 != DLADM_STATUS_OK)
396 die("invalid flow property specified");
398 status = dladm_flow_add(handle, linkid, attrlist, proplist, name,
399 t_arg, altroot);
400 if (status != DLADM_STATUS_OK)
401 die_dlerr(status, "add flow failed");
403 dladm_free_attrs(attrlist);
404 dladm_free_props(proplist);
407 static void
408 do_remove_flow(int argc, char *argv[])
410 char option;
411 char *flowname = NULL;
412 char linkname[MAXLINKNAMELEN];
413 datalink_id_t linkid = DATALINK_ALL_LINKID;
414 boolean_t l_arg = B_FALSE;
415 remove_flow_state_t state;
416 dladm_status_t status;
418 bzero(&state, sizeof (state));
420 opterr = 0;
421 while ((option = getopt_long(argc, argv, ":tR:l:",
422 longopts, NULL)) != -1) {
423 switch (option) {
424 case 't':
425 t_arg = B_TRUE;
426 break;
427 case 'R':
428 altroot = optarg;
429 break;
430 case 'l':
431 if (strlcpy(linkname, optarg,
432 MAXLINKNAMELEN) >= MAXLINKNAMELEN) {
433 die("link name too long");
435 if (dladm_name2info(handle, linkname, &linkid, NULL,
436 NULL, NULL) != DLADM_STATUS_OK) {
437 die("invalid link '%s'", linkname);
439 l_arg = B_TRUE;
440 break;
441 default:
442 die_opterr(optopt, option);
443 break;
447 /* when link not specified get flow name */
448 if (!l_arg) {
449 if (optind != (argc-1)) {
450 usage();
451 } else {
452 if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
453 die("flow name too long");
454 flowname = argv[optind];
456 status = dladm_flow_remove(handle, flowname, t_arg, altroot);
457 } else {
458 /* if link is specified then flow name should not be there */
459 if (optind == argc-1)
460 usage();
461 /* walk the link to find flows and remove them */
462 state.fs_tempop = t_arg;
463 state.fs_altroot = altroot;
464 state.fs_status = DLADM_STATUS_OK;
465 status = dladm_walk_flow(remove_flow, handle, linkid, &state,
466 B_FALSE);
468 * check if dladm_walk_flow terminated early and see if the
469 * walker function as any status for us
471 if (status == DLADM_STATUS_OK)
472 status = state.fs_status;
475 if (status != DLADM_STATUS_OK)
476 die_dlerr(status, "remove flow failed");
480 * Walker function for removing a flow through dladm_walk_flow();
482 /*ARGSUSED*/
483 static int
484 remove_flow(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
486 remove_flow_state_t *state = (remove_flow_state_t *)arg;
488 state->fs_status = dladm_flow_remove(handle, attr->fa_flowname,
489 state->fs_tempop, state->fs_altroot);
491 if (state->fs_status == DLADM_STATUS_OK)
492 return (DLADM_WALK_CONTINUE);
493 else
494 return (DLADM_WALK_TERMINATE);
497 /*ARGSUSED*/
498 static dladm_status_t
499 print_flow(show_flow_state_t *state, dladm_flow_attr_t *attr,
500 flow_fields_buf_t *fbuf)
502 char link[MAXLINKNAMELEN];
503 dladm_status_t status;
505 if ((status = dladm_datalink_id2info(handle, attr->fa_linkid, NULL,
506 NULL, NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
507 return (status);
510 (void) snprintf(fbuf->flow_name, sizeof (fbuf->flow_name),
511 "%s", attr->fa_flowname);
512 (void) snprintf(fbuf->flow_link, sizeof (fbuf->flow_link),
513 "%s", link);
515 (void) dladm_flow_attr_ip2str(attr, fbuf->flow_ipaddr,
516 sizeof (fbuf->flow_ipaddr));
517 (void) dladm_flow_attr_proto2str(attr, fbuf->flow_proto,
518 sizeof (fbuf->flow_proto));
519 if ((attr->fa_flow_desc.fd_mask & FLOW_ULP_PORT_LOCAL) != 0) {
520 (void) dladm_flow_attr_port2str(attr, fbuf->flow_lport,
521 sizeof (fbuf->flow_lport));
523 if ((attr->fa_flow_desc.fd_mask & FLOW_ULP_PORT_REMOTE) != 0) {
524 (void) dladm_flow_attr_port2str(attr, fbuf->flow_rport,
525 sizeof (fbuf->flow_rport));
527 (void) dladm_flow_attr_dsfield2str(attr, fbuf->flow_dsfield,
528 sizeof (fbuf->flow_dsfield));
530 return (DLADM_STATUS_OK);
534 * Walker function for showing flow attributes through dladm_walk_flow().
536 /*ARGSUSED*/
537 static int
538 show_flow(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
540 show_flow_state_t *statep = arg;
541 dladm_status_t status;
542 flow_fields_buf_t fbuf;
545 * first get all the flow attributes into fbuf;
547 bzero(&fbuf, sizeof (fbuf));
548 status = print_flow(statep, attr, &fbuf);
550 if (status != DLADM_STATUS_OK)
551 goto done;
553 ofmt_print(statep->fs_ofmt, (void *)&fbuf);
555 done:
556 statep->fs_status = status;
557 return (DLADM_WALK_CONTINUE);
560 static void
561 show_one_flow(void *arg, const char *name)
563 dladm_flow_attr_t attr;
565 if (dladm_flow_info(handle, name, &attr) != DLADM_STATUS_OK)
566 die("invalid flow: '%s'", name);
567 else
568 (void) show_flow(handle, &attr, arg);
572 * Wrapper of dladm_walk_flow(show_flow,...) to make it usable to
573 * dladm_walk_datalink_id(). Used for showing flow attributes for
574 * all flows on all links.
576 static int
577 show_flows_onelink(dladm_handle_t dh, datalink_id_t linkid, void *arg)
579 show_flow_state_t *state = arg;
581 (void) dladm_walk_flow(show_flow, dh, linkid, arg, state->fs_persist);
583 return (DLADM_WALK_CONTINUE);
586 static void
587 do_show_flow(int argc, char *argv[])
589 char flowname[MAXFLOWNAMELEN];
590 char linkname[MAXLINKNAMELEN];
591 datalink_id_t linkid = DATALINK_ALL_LINKID;
592 int option;
593 boolean_t l_arg = B_FALSE;
594 boolean_t o_arg = B_FALSE;
595 show_flow_state_t state;
596 char *fields_str = NULL;
597 ofmt_handle_t ofmt;
598 ofmt_status_t oferr;
599 uint_t ofmtflags = 0;
601 bzero(&state, sizeof (state));
603 opterr = 0;
604 while ((option = getopt_long(argc, argv, ":pPl:o:",
605 longopts, NULL)) != -1) {
606 switch (option) {
607 case 'p':
608 state.fs_parsable = B_TRUE;
609 ofmtflags |= OFMT_PARSABLE;
610 break;
611 case 'P':
612 state.fs_persist = B_TRUE;
613 break;
614 case 'o':
615 if (o_arg)
616 die_optdup(option);
618 o_arg = B_TRUE;
619 fields_str = optarg;
620 break;
621 case 'l':
622 if (strlcpy(linkname, optarg, MAXLINKNAMELEN)
623 >= MAXLINKNAMELEN)
624 die("link name too long\n");
625 if (dladm_name2info(handle, linkname, &linkid, NULL,
626 NULL, NULL) != DLADM_STATUS_OK)
627 die("invalid link '%s'", linkname);
628 l_arg = B_TRUE;
629 break;
630 default:
631 die_opterr(optopt, option);
632 break;
636 /* get flow name (optional last argument */
637 if (optind == (argc-1)) {
638 if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN)
639 >= MAXFLOWNAMELEN)
640 die("flow name too long");
641 state.fs_flow = flowname;
644 oferr = ofmt_open(fields_str, flow_fields, ofmtflags, 0, &ofmt);
645 flowadm_ofmt_check(oferr, state.fs_parsable, ofmt);
646 state.fs_ofmt = ofmt;
648 /* Show attributes of one flow */
649 if (state.fs_flow != NULL) {
650 show_one_flow(&state, state.fs_flow);
652 /* Show attributes of flows on one link */
653 } else if (l_arg) {
654 (void) show_flows_onelink(handle, linkid, &state);
656 /* Show attributes of all flows on all links */
657 } else {
658 (void) dladm_walk_datalink_id(show_flows_onelink, handle,
659 &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
660 DLADM_OPT_ACTIVE);
662 ofmt_close(ofmt);
665 static dladm_status_t
666 set_flowprop_persist(const char *flow, const char *prop_name, char **prop_val,
667 uint_t val_cnt, boolean_t reset)
669 dladm_status_t status;
670 char *errprop;
672 status = dladm_set_flowprop(handle, flow, prop_name, prop_val, val_cnt,
673 DLADM_OPT_PERSIST, &errprop);
675 if (status != DLADM_STATUS_OK) {
676 warn_dlerr(status, "cannot persistently %s flow "
677 "property '%s' on '%s'", reset? "reset": "set",
678 errprop, flow);
680 return (status);
683 static void
684 set_flowprop(int argc, char **argv, boolean_t reset)
686 int i, option;
687 char errmsg[DLADM_STRSIZE];
688 const char *flow = NULL;
689 char propstr[DLADM_STRSIZE];
690 dladm_arg_list_t *proplist = NULL;
691 boolean_t temp = B_FALSE;
692 dladm_status_t status = DLADM_STATUS_OK;
694 opterr = 0;
695 bzero(propstr, DLADM_STRSIZE);
697 while ((option = getopt_long(argc, argv, ":p:R:t",
698 prop_longopts, NULL)) != -1) {
699 switch (option) {
700 case 'p':
701 (void) strlcat(propstr, optarg, DLADM_STRSIZE);
702 if (strlcat(propstr, ",", DLADM_STRSIZE) >=
703 DLADM_STRSIZE)
704 die("property list too long '%s'", propstr);
705 break;
706 case 't':
707 temp = B_TRUE;
708 break;
709 case 'R':
710 status = dladm_set_rootdir(optarg);
711 if (status != DLADM_STATUS_OK) {
712 die_dlerr(status, "invalid directory "
713 "specified");
715 break;
716 default:
717 die_opterr(optopt, option);
718 break;
722 if (optind == (argc - 1)) {
723 if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
724 die("flow name too long");
725 flow = argv[optind];
726 } else if (optind != argc) {
727 usage();
729 if (flow == NULL)
730 die("flow name must be specified");
732 if (dladm_parse_flow_props(propstr, &proplist, reset)
733 != DLADM_STATUS_OK)
734 die("invalid flow property specified");
736 if (proplist == NULL) {
737 char *errprop;
739 if (!reset)
740 die("flow property must be specified");
742 status = dladm_set_flowprop(handle, flow, NULL, NULL, 0,
743 DLADM_OPT_ACTIVE, &errprop);
744 if (status != DLADM_STATUS_OK) {
745 warn_dlerr(status, "cannot reset flow property '%s' "
746 "on '%s'", errprop, flow);
748 if (!temp) {
749 dladm_status_t s;
751 s = set_flowprop_persist(flow, NULL, NULL, 0, reset);
752 if (s != DLADM_STATUS_OK)
753 status = s;
755 goto done;
758 for (i = 0; i < proplist->al_count; i++) {
759 dladm_arg_info_t *aip = &proplist->al_info[i];
760 char **val;
761 uint_t count;
762 dladm_status_t s;
764 if (reset) {
765 val = NULL;
766 count = 0;
767 } else {
768 val = aip->ai_val;
769 count = aip->ai_count;
770 if (count == 0) {
771 warn("no value specified for '%s'",
772 aip->ai_name);
773 status = DLADM_STATUS_BADARG;
774 continue;
777 s = dladm_set_flowprop(handle, flow, aip->ai_name, val, count,
778 DLADM_OPT_ACTIVE, NULL);
779 if (s == DLADM_STATUS_OK) {
780 if (!temp) {
781 s = set_flowprop_persist(flow,
782 aip->ai_name, val, count, reset);
783 if (s != DLADM_STATUS_OK)
784 status = s;
786 continue;
788 status = s;
789 switch (s) {
790 case DLADM_STATUS_NOTFOUND:
791 warn("invalid flow property '%s'", aip->ai_name);
792 break;
793 case DLADM_STATUS_BADVAL: {
794 int j;
795 char *ptr, *lim;
796 char **propvals = NULL;
797 uint_t valcnt = DLADM_MAX_PROP_VALCNT;
799 ptr = malloc((sizeof (char *) +
800 DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT +
801 MAX_PROP_LINE);
803 if (ptr == NULL)
804 die("insufficient memory");
805 propvals = (char **)(void *)ptr;
807 for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) {
808 propvals[j] = ptr + sizeof (char *) *
809 DLADM_MAX_PROP_VALCNT +
810 j * DLADM_PROP_VAL_MAX;
812 s = dladm_get_flowprop(handle, flow,
813 DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals,
814 &valcnt);
816 ptr = errmsg;
817 lim = ptr + DLADM_STRSIZE;
818 *ptr = '\0';
819 for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) {
820 ptr += snprintf(ptr, lim - ptr, "%s,",
821 propvals[j]);
822 if (ptr >= lim)
823 break;
825 if (ptr > errmsg) {
826 *(ptr - 1) = '\0';
827 warn("flow property '%s' must be one of: %s",
828 aip->ai_name, errmsg);
829 } else
830 warn("%s is an invalid value for "
831 "flow property %s", *val, aip->ai_name);
832 free(propvals);
833 break;
835 default:
836 if (reset) {
837 warn_dlerr(status, "cannot reset flow property "
838 "'%s' on '%s'", aip->ai_name, flow);
839 } else {
840 warn_dlerr(status, "cannot set flow property "
841 "'%s' on '%s'", aip->ai_name, flow);
843 break;
846 done:
847 dladm_free_props(proplist);
848 if (status != DLADM_STATUS_OK) {
849 dladm_close(handle);
850 exit(EXIT_FAILURE);
854 static void
855 do_set_flowprop(int argc, char **argv)
857 set_flowprop(argc, argv, B_FALSE);
860 static void
861 do_reset_flowprop(int argc, char **argv)
863 set_flowprop(argc, argv, B_TRUE);
866 static void
867 warn(const char *format, ...)
869 va_list alist;
871 format = gettext(format);
872 (void) fprintf(stderr, "%s: warning: ", progname);
874 va_start(alist, format);
875 (void) vfprintf(stderr, format, alist);
876 va_end(alist);
878 (void) putc('\n', stderr);
881 /* PRINTFLIKE2 */
882 static void
883 warn_dlerr(dladm_status_t err, const char *format, ...)
885 va_list alist;
886 char errmsg[DLADM_STRSIZE];
888 format = gettext(format);
889 (void) fprintf(stderr, gettext("%s: warning: "), progname);
891 va_start(alist, format);
892 (void) vfprintf(stderr, format, alist);
893 va_end(alist);
894 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
897 /* PRINTFLIKE1 */
898 static void
899 die(const char *format, ...)
901 va_list alist;
903 format = gettext(format);
904 (void) fprintf(stderr, "%s: ", progname);
906 va_start(alist, format);
907 (void) vfprintf(stderr, format, alist);
908 va_end(alist);
910 (void) putc('\n', stderr);
912 /* close dladm handle if it was opened */
913 if (handle != NULL)
914 dladm_close(handle);
916 exit(EXIT_FAILURE);
919 static void
920 die_optdup(int opt)
922 die("the option -%c cannot be specified more than once", opt);
925 static void
926 die_opterr(int opt, int opterr)
928 switch (opterr) {
929 case ':':
930 die("option '-%c' requires a value", opt);
931 break;
932 case '?':
933 default:
934 die("unrecognized option '-%c'", opt);
935 break;
939 /* PRINTFLIKE2 */
940 static void
941 die_dlerr(dladm_status_t err, const char *format, ...)
943 va_list alist;
944 char errmsg[DLADM_STRSIZE];
946 format = gettext(format);
947 (void) fprintf(stderr, "%s: ", progname);
949 va_start(alist, format);
950 (void) vfprintf(stderr, format, alist);
951 va_end(alist);
952 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
954 /* close dladm handle if it was opened */
955 if (handle != NULL)
956 dladm_close(handle);
958 exit(EXIT_FAILURE);
961 static void
962 print_flowprop(const char *flowname, show_flowprop_state_t *statep,
963 const char *propname, dladm_prop_type_t type,
964 const char *format, char **pptr)
966 int i;
967 char *ptr, *lim;
968 char buf[DLADM_STRSIZE];
969 char *unknown = "--", *notsup = "";
970 char **propvals = statep->fs_propvals;
971 uint_t valcnt = DLADM_MAX_PROP_VALCNT;
972 dladm_status_t status;
974 status = dladm_get_flowprop(handle, flowname, type, propname, propvals,
975 &valcnt);
976 if (status != DLADM_STATUS_OK) {
977 if (status == DLADM_STATUS_TEMPONLY) {
978 if (type == DLADM_PROP_VAL_MODIFIABLE &&
979 statep->fs_persist) {
980 valcnt = 1;
981 propvals = &unknown;
982 } else {
983 statep->fs_status = status;
984 statep->fs_retstatus = status;
985 return;
987 } else if (status == DLADM_STATUS_NOTSUP ||
988 statep->fs_persist) {
989 valcnt = 1;
990 if (type == DLADM_PROP_VAL_CURRENT)
991 propvals = &unknown;
992 else
993 propvals = &notsup;
994 } else {
995 if ((statep->fs_proplist != NULL) &&
996 statep->fs_status == DLADM_STATUS_OK) {
997 warn("invalid flow property '%s'", propname);
999 statep->fs_status = status;
1000 statep->fs_retstatus = status;
1001 return;
1005 statep->fs_status = DLADM_STATUS_OK;
1007 ptr = buf;
1008 lim = buf + DLADM_STRSIZE;
1009 for (i = 0; i < valcnt; i++) {
1010 if (propvals[i][0] == '\0' && !statep->fs_parsable)
1011 ptr += snprintf(ptr, lim - ptr, "--,");
1012 else
1013 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
1014 if (ptr >= lim)
1015 break;
1017 if (valcnt > 0)
1018 buf[strlen(buf) - 1] = '\0';
1020 lim = statep->fs_line + MAX_PROP_LINE;
1021 if (statep->fs_parsable) {
1022 *pptr += snprintf(*pptr, lim - *pptr,
1023 "%s", buf);
1024 } else {
1025 *pptr += snprintf(*pptr, lim - *pptr, format, buf);
1029 static boolean_t
1030 print_flowprop_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
1032 flowprop_args_t *arg = of_arg->ofmt_cbarg;
1033 char *propname = arg->fs_propname;
1034 show_flowprop_state_t *statep = arg->fs_state;
1035 char *ptr = statep->fs_line;
1036 char *lim = ptr + MAX_PROP_LINE;
1037 char *flowname = arg->fs_flowname;
1039 switch (of_arg->ofmt_id) {
1040 case FLOWPROP_FLOW:
1041 (void) snprintf(ptr, lim - ptr, "%s", statep->fs_flow);
1042 break;
1043 case FLOWPROP_PROPERTY:
1044 (void) snprintf(ptr, lim - ptr, "%s", propname);
1045 break;
1046 case FLOWPROP_VALUE:
1047 print_flowprop(flowname, statep, propname,
1048 statep->fs_persist ? DLADM_PROP_VAL_PERSISTENT :
1049 DLADM_PROP_VAL_CURRENT, "%s", &ptr);
1051 * If we failed to query the flow property, for example, query
1052 * the persistent value of a non-persistable flow property,
1053 * simply skip the output.
1055 if (statep->fs_status != DLADM_STATUS_OK)
1056 goto skip;
1057 ptr = statep->fs_line;
1058 break;
1059 case FLOWPROP_DEFAULT:
1060 print_flowprop(flowname, statep, propname,
1061 DLADM_PROP_VAL_DEFAULT, "%s", &ptr);
1062 if (statep->fs_status != DLADM_STATUS_OK)
1063 goto skip;
1064 ptr = statep->fs_line;
1065 break;
1066 case FLOWPROP_POSSIBLE:
1067 print_flowprop(flowname, statep, propname,
1068 DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr);
1069 if (statep->fs_status != DLADM_STATUS_OK)
1070 goto skip;
1071 ptr = statep->fs_line;
1072 break;
1073 default:
1074 die("invalid input");
1075 break;
1077 (void) strlcpy(buf, ptr, bufsize);
1078 return (B_TRUE);
1079 skip:
1080 buf[0] = '\0';
1081 return ((statep->fs_status == DLADM_STATUS_OK) ?
1082 B_TRUE : B_FALSE);
1085 static int
1086 show_one_flowprop(void *arg, const char *propname)
1088 show_flowprop_state_t *statep = arg;
1089 flowprop_args_t fs_arg;
1091 bzero(&fs_arg, sizeof (fs_arg));
1092 fs_arg.fs_state = statep;
1093 fs_arg.fs_propname = (char *)propname;
1094 fs_arg.fs_flowname = (char *)statep->fs_flow;
1096 ofmt_print(statep->fs_ofmt, (void *)&fs_arg);
1098 return (DLADM_WALK_CONTINUE);
1101 /*ARGSUSED*/
1102 /* Walker function called by dladm_walk_flow to display flow properties */
1103 static int
1104 show_flowprop(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
1106 show_flowprop_one_flow(arg, attr->fa_flowname);
1107 return (DLADM_WALK_CONTINUE);
1111 * Wrapper of dladm_walk_flow(show_walk_fn,...) to make it
1112 * usable to dladm_walk_datalink_id()
1114 static int
1115 show_flowprop_onelink(dladm_handle_t dh, datalink_id_t linkid, void *arg)
1117 char name[MAXLINKNAMELEN];
1119 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, name,
1120 sizeof (name)) != DLADM_STATUS_OK)
1121 return (DLADM_WALK_TERMINATE);
1123 (void) dladm_walk_flow(show_flowprop, dh, linkid, arg, B_FALSE);
1125 return (DLADM_WALK_CONTINUE);
1128 static void
1129 do_show_flowprop(int argc, char **argv)
1131 int option;
1132 dladm_arg_list_t *proplist = NULL;
1133 show_flowprop_state_t state;
1134 char *fields_str = NULL;
1135 ofmt_handle_t ofmt;
1136 ofmt_status_t oferr;
1137 uint_t ofmtflags = 0;
1139 opterr = 0;
1140 state.fs_propvals = NULL;
1141 state.fs_line = NULL;
1142 state.fs_parsable = B_FALSE;
1143 state.fs_persist = B_FALSE;
1144 state.fs_header = B_TRUE;
1145 state.fs_retstatus = DLADM_STATUS_OK;
1146 state.fs_linkid = DATALINK_INVALID_LINKID;
1147 state.fs_flow = NULL;
1149 while ((option = getopt_long(argc, argv, ":p:cPl:o:",
1150 prop_longopts, NULL)) != -1) {
1151 switch (option) {
1152 case 'p':
1153 if (dladm_parse_flow_props(optarg, &proplist, B_TRUE)
1154 != DLADM_STATUS_OK)
1155 die("invalid flow properties specified");
1156 break;
1157 case 'c':
1158 state.fs_parsable = B_TRUE;
1159 ofmtflags |= OFMT_PARSABLE;
1160 break;
1161 case 'P':
1162 state.fs_persist = B_TRUE;
1163 break;
1164 case 'l':
1165 if (dladm_name2info(handle, optarg, &state.fs_linkid,
1166 NULL, NULL, NULL) != DLADM_STATUS_OK)
1167 die("invalid link '%s'", optarg);
1168 break;
1169 case 'o':
1170 fields_str = optarg;
1171 break;
1172 default:
1173 die_opterr(optopt, option);
1174 break;
1178 if (optind == (argc - 1)) {
1179 if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
1180 die("flow name too long");
1181 state.fs_flow = argv[optind];
1182 } else if (optind != argc) {
1183 usage();
1185 state.fs_proplist = proplist;
1186 state.fs_status = DLADM_STATUS_OK;
1188 oferr = ofmt_open(fields_str, flowprop_fields, ofmtflags, 0, &ofmt);
1189 flowadm_ofmt_check(oferr, state.fs_parsable, ofmt);
1190 state.fs_ofmt = ofmt;
1192 /* Show properties for one flow */
1193 if (state.fs_flow != NULL) {
1194 show_flowprop_one_flow(&state, state.fs_flow);
1196 /* Show properties for all flows on one link */
1197 } else if (state.fs_linkid != DATALINK_INVALID_LINKID) {
1198 (void) show_flowprop_onelink(handle, state.fs_linkid, &state);
1200 /* Show properties for all flows on all links */
1201 } else {
1202 (void) dladm_walk_datalink_id(show_flowprop_onelink, handle,
1203 &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
1204 DLADM_OPT_ACTIVE);
1207 dladm_free_props(proplist);
1208 ofmt_close(ofmt);
1211 static void
1212 show_flowprop_one_flow(void *arg, const char *flow)
1214 int i;
1215 char *buf;
1216 dladm_status_t status;
1217 dladm_arg_list_t *proplist = NULL;
1218 show_flowprop_state_t *statep = arg;
1219 dladm_flow_attr_t attr;
1220 const char *savep;
1223 * Do not print flow props for invalid flows.
1225 if ((status = dladm_flow_info(handle, flow, &attr)) !=
1226 DLADM_STATUS_OK) {
1227 die("invalid flow: '%s'", flow);
1230 savep = statep->fs_flow;
1231 statep->fs_flow = flow;
1233 proplist = statep->fs_proplist;
1235 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX)
1236 * DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE);
1237 if (buf == NULL)
1238 die("insufficient memory");
1240 statep->fs_propvals = (char **)(void *)buf;
1241 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) {
1242 statep->fs_propvals[i] = buf +
1243 sizeof (char *) * DLADM_MAX_PROP_VALCNT +
1244 i * DLADM_PROP_VAL_MAX;
1246 statep->fs_line = buf +
1247 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT;
1249 /* show only specified flow properties */
1250 if (proplist != NULL) {
1251 for (i = 0; i < proplist->al_count; i++) {
1252 if (show_one_flowprop(statep,
1253 proplist->al_info[i].ai_name) != DLADM_STATUS_OK)
1254 break;
1257 /* show all flow properties */
1258 } else {
1259 status = dladm_walk_flowprop(show_one_flowprop, flow, statep);
1260 if (status != DLADM_STATUS_OK)
1261 die_dlerr(status, "show-flowprop");
1263 free(buf);
1264 statep->fs_flow = savep;
1268 * default output callback function that, when invoked from dladm_print_output,
1269 * prints string which is offset by of_arg->ofmt_id within buf.
1271 static boolean_t
1272 print_default_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
1274 char *value;
1276 value = (char *)of_arg->ofmt_cbarg + of_arg->ofmt_id;
1277 (void) strlcpy(buf, value, bufsize);
1278 return (B_TRUE);
1281 static void
1282 flowadm_ofmt_check(ofmt_status_t oferr, boolean_t parsable,
1283 ofmt_handle_t ofmt)
1285 char buf[OFMT_BUFSIZE];
1287 if (oferr == OFMT_SUCCESS)
1288 return;
1289 (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
1291 * All errors are considered fatal in parsable mode.
1292 * NOMEM errors are always fatal, regardless of mode.
1293 * For other errors, we print diagnostics in human-readable
1294 * mode and processs what we can.
1296 if (parsable || oferr == OFMT_ENOFIELDS) {
1297 ofmt_close(ofmt);
1298 die(buf);
1299 } else {
1300 warn(buf);