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]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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>
53 typedef struct show_flow_state
{
54 dladm_status_t fs_status
;
55 ofmt_handle_t fs_ofmt
;
57 boolean_t fs_parsable
;
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
);
88 void (*c_fn
)(int, char **);
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'},
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'},
120 * structures for 'flowadm remove-flow'
122 typedef struct remove_flow_state
{
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
];
144 static ofmt_field_t flow_fields
[] = {
145 /* name, field width, index */
147 offsetof(flow_fields_buf_t
, flow_name
), print_default_cb
},
149 offsetof(flow_fields_buf_t
, flow_link
), print_default_cb
},
151 offsetof(flow_fields_buf_t
, flow_ipaddr
), print_default_cb
},
153 offsetof(flow_fields_buf_t
, flow_proto
), print_default_cb
},
155 offsetof(flow_fields_buf_t
, flow_lport
), print_default_cb
},
157 offsetof(flow_fields_buf_t
, flow_rport
), print_default_cb
},
159 offsetof(flow_fields_buf_t
, flow_dsfield
), print_default_cb
},
164 * structures for 'flowadm show-flowprop'
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
},
184 #define MAX_PROP_LINE 512
186 typedef struct show_flowprop_state
{
188 datalink_id_t fs_linkid
;
191 dladm_arg_list_t
*fs_proplist
;
192 boolean_t fs_parsable
;
193 boolean_t fs_persist
;
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
{
204 dladm_status_t fs_status
;
205 } set_flowprop_state_t
;
207 typedef struct flowprop_args_s
{
208 show_flowprop_state_t
*fs_state
;
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",
228 #define NATTR (sizeof (attr_table)/sizeof (char *))
233 (void) fprintf(stderr
, gettext("usage: flowadm <subcommand>"
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>] "
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>,...] "
245 /* close dladm handle if it was opened */
253 main(int argc
, char *argv
[])
255 int i
, arglen
, cmdlen
;
257 dladm_status_t status
;
259 (void) setlocale(LC_ALL
, "");
260 #if !defined(TEXT_DOMAIN)
261 #define TEXT_DOMAIN "SYS_TEST"
263 (void) textdomain(TEXT_DOMAIN
);
270 for (i
= 0; i
< sizeof (cmds
) / sizeof (cmds
[0]); i
++) {
272 arglen
= strlen(argv
[1]);
273 cmdlen
= strlen(cmdp
->c_name
);
274 if ((arglen
== cmdlen
) && (strncmp(argv
[1], cmdp
->c_name
,
276 /* Open the libdladm handle */
277 if ((status
= dladm_open(&handle
)) != DLADM_STATUS_OK
) {
279 "could not open /dev/dld");
282 cmdp
->c_fn(argc
- 1, &argv
[1]);
289 (void) fprintf(stderr
, gettext("%s: unknown subcommand '%s'\n"),
297 match_attr(char *attr
)
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) {
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");
322 do_add_flow(int argc
, char *argv
[])
324 char devname
[MAXLINKNAMELEN
];
327 datalink_id_t linkid
;
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) {
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
);
360 (void) strlcat(attrstr
, optarg
, DLADM_STRSIZE
);
361 if (strlcat(attrstr
, ",", DLADM_STRSIZE
) >=
363 die("attribute list too long '%s'", attrstr
);
366 (void) strlcat(propstr
, optarg
, DLADM_STRSIZE
);
367 if (strlcat(propstr
, ",", DLADM_STRSIZE
) >=
369 die("property list too long '%s'", propstr
);
372 die_opterr(optopt
, option
);
376 die("link is required");
382 if ((index
!= (argc
- 1)) || match_attr(argv
[index
]) != NULL
) {
383 die("flow name is required");
385 /* get flow name; required last argument */
386 if (strlen(argv
[index
]) >= MAXFLOWNAMELEN
)
387 die("flow name too long");
391 if (dladm_parse_flow_attrs(attrstr
, &attrlist
, B_FALSE
)
393 die("invalid flow attribute specified");
394 if (dladm_parse_flow_props(propstr
, &proplist
, B_FALSE
)
396 die("invalid flow property specified");
398 status
= dladm_flow_add(handle
, linkid
, attrlist
, proplist
, name
,
400 if (status
!= DLADM_STATUS_OK
)
401 die_dlerr(status
, "add flow failed");
403 dladm_free_attrs(attrlist
);
404 dladm_free_props(proplist
);
408 do_remove_flow(int argc
, char *argv
[])
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
));
421 while ((option
= getopt_long(argc
, argv
, ":tR:l:",
422 longopts
, NULL
)) != -1) {
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
);
442 die_opterr(optopt
, option
);
447 /* when link not specified get flow name */
449 if (optind
!= (argc
-1)) {
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
);
458 /* if link is specified then flow name should not be there */
459 if (optind
== argc
-1)
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
,
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();
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
);
494 return (DLADM_WALK_TERMINATE
);
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
) {
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
),
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().
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
)
553 ofmt_print(statep
->fs_ofmt
, (void *)&fbuf
);
556 statep
->fs_status
= status
;
557 return (DLADM_WALK_CONTINUE
);
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
);
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.
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
);
587 do_show_flow(int argc
, char *argv
[])
589 char flowname
[MAXFLOWNAMELEN
];
590 char linkname
[MAXLINKNAMELEN
];
591 datalink_id_t linkid
= DATALINK_ALL_LINKID
;
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
;
599 uint_t ofmtflags
= 0;
601 bzero(&state
, sizeof (state
));
604 while ((option
= getopt_long(argc
, argv
, ":pPl:o:",
605 longopts
, NULL
)) != -1) {
608 state
.fs_parsable
= B_TRUE
;
609 ofmtflags
|= OFMT_PARSABLE
;
612 state
.fs_persist
= B_TRUE
;
622 if (strlcpy(linkname
, optarg
, 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
);
631 die_opterr(optopt
, option
);
636 /* get flow name (optional last argument */
637 if (optind
== (argc
-1)) {
638 if (strlcpy(flowname
, argv
[optind
], 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 */
654 (void) show_flows_onelink(handle
, linkid
, &state
);
656 /* Show attributes of all flows on all links */
658 (void) dladm_walk_datalink_id(show_flows_onelink
, handle
,
659 &state
, DATALINK_CLASS_ALL
, DATALINK_ANY_MEDIATYPE
,
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
;
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",
684 set_flowprop(int argc
, char **argv
, boolean_t reset
)
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
;
695 bzero(propstr
, DLADM_STRSIZE
);
697 while ((option
= getopt_long(argc
, argv
, ":p:R:t",
698 prop_longopts
, NULL
)) != -1) {
701 (void) strlcat(propstr
, optarg
, DLADM_STRSIZE
);
702 if (strlcat(propstr
, ",", DLADM_STRSIZE
) >=
704 die("property list too long '%s'", propstr
);
710 status
= dladm_set_rootdir(optarg
);
711 if (status
!= DLADM_STATUS_OK
) {
712 die_dlerr(status
, "invalid directory "
717 die_opterr(optopt
, option
);
722 if (optind
== (argc
- 1)) {
723 if (strlen(argv
[optind
]) >= MAXFLOWNAMELEN
)
724 die("flow name too long");
726 } else if (optind
!= argc
) {
730 die("flow name must be specified");
732 if (dladm_parse_flow_props(propstr
, &proplist
, reset
)
734 die("invalid flow property specified");
736 if (proplist
== NULL
) {
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
);
751 s
= set_flowprop_persist(flow
, NULL
, NULL
, 0, reset
);
752 if (s
!= DLADM_STATUS_OK
)
758 for (i
= 0; i
< proplist
->al_count
; i
++) {
759 dladm_arg_info_t
*aip
= &proplist
->al_info
[i
];
769 count
= aip
->ai_count
;
771 warn("no value specified for '%s'",
773 status
= DLADM_STATUS_BADARG
;
777 s
= dladm_set_flowprop(handle
, flow
, aip
->ai_name
, val
, count
,
778 DLADM_OPT_ACTIVE
, NULL
);
779 if (s
== DLADM_STATUS_OK
) {
781 s
= set_flowprop_persist(flow
,
782 aip
->ai_name
, val
, count
, reset
);
783 if (s
!= DLADM_STATUS_OK
)
790 case DLADM_STATUS_NOTFOUND
:
791 warn("invalid flow property '%s'", aip
->ai_name
);
793 case DLADM_STATUS_BADVAL
: {
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
+
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
,
817 lim
= ptr
+ DLADM_STRSIZE
;
819 for (j
= 0; j
< valcnt
&& s
== DLADM_STATUS_OK
; j
++) {
820 ptr
+= snprintf(ptr
, lim
- ptr
, "%s,",
827 warn("flow property '%s' must be one of: %s",
828 aip
->ai_name
, errmsg
);
830 warn("%s is an invalid value for "
831 "flow property %s", *val
, aip
->ai_name
);
837 warn_dlerr(status
, "cannot reset flow property "
838 "'%s' on '%s'", aip
->ai_name
, flow
);
840 warn_dlerr(status
, "cannot set flow property "
841 "'%s' on '%s'", aip
->ai_name
, flow
);
847 dladm_free_props(proplist
);
848 if (status
!= DLADM_STATUS_OK
) {
855 do_set_flowprop(int argc
, char **argv
)
857 set_flowprop(argc
, argv
, B_FALSE
);
861 do_reset_flowprop(int argc
, char **argv
)
863 set_flowprop(argc
, argv
, B_TRUE
);
867 warn(const char *format
, ...)
871 format
= gettext(format
);
872 (void) fprintf(stderr
, "%s: warning: ", progname
);
874 va_start(alist
, format
);
875 (void) vfprintf(stderr
, format
, alist
);
878 (void) putc('\n', stderr
);
883 warn_dlerr(dladm_status_t err
, const char *format
, ...)
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
);
894 (void) fprintf(stderr
, ": %s\n", dladm_status2str(err
, errmsg
));
899 die(const char *format
, ...)
903 format
= gettext(format
);
904 (void) fprintf(stderr
, "%s: ", progname
);
906 va_start(alist
, format
);
907 (void) vfprintf(stderr
, format
, alist
);
910 (void) putc('\n', stderr
);
912 /* close dladm handle if it was opened */
922 die("the option -%c cannot be specified more than once", opt
);
926 die_opterr(int opt
, int opterr
)
930 die("option '-%c' requires a value", opt
);
934 die("unrecognized option '-%c'", opt
);
941 die_dlerr(dladm_status_t err
, const char *format
, ...)
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
);
952 (void) fprintf(stderr
, ": %s\n", dladm_status2str(err
, errmsg
));
954 /* close dladm handle if it was opened */
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
)
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
,
976 if (status
!= DLADM_STATUS_OK
) {
977 if (status
== DLADM_STATUS_TEMPONLY
) {
978 if (type
== DLADM_PROP_VAL_MODIFIABLE
&&
979 statep
->fs_persist
) {
983 statep
->fs_status
= status
;
984 statep
->fs_retstatus
= status
;
987 } else if (status
== DLADM_STATUS_NOTSUP
||
988 statep
->fs_persist
) {
990 if (type
== DLADM_PROP_VAL_CURRENT
)
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
;
1005 statep
->fs_status
= DLADM_STATUS_OK
;
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
, "--,");
1013 ptr
+= snprintf(ptr
, lim
- ptr
, "%s,", propvals
[i
]);
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
,
1025 *pptr
+= snprintf(*pptr
, lim
- *pptr
, format
, buf
);
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
) {
1041 (void) snprintf(ptr
, lim
- ptr
, "%s", statep
->fs_flow
);
1043 case FLOWPROP_PROPERTY
:
1044 (void) snprintf(ptr
, lim
- ptr
, "%s", propname
);
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
)
1057 ptr
= statep
->fs_line
;
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
)
1064 ptr
= statep
->fs_line
;
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
)
1071 ptr
= statep
->fs_line
;
1074 die("invalid input");
1077 (void) strlcpy(buf
, ptr
, bufsize
);
1081 return ((statep
->fs_status
== DLADM_STATUS_OK
) ?
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
);
1102 /* Walker function called by dladm_walk_flow to display flow properties */
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()
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
);
1129 do_show_flowprop(int argc
, char **argv
)
1132 dladm_arg_list_t
*proplist
= NULL
;
1133 show_flowprop_state_t state
;
1134 char *fields_str
= NULL
;
1136 ofmt_status_t oferr
;
1137 uint_t ofmtflags
= 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) {
1153 if (dladm_parse_flow_props(optarg
, &proplist
, B_TRUE
)
1155 die("invalid flow properties specified");
1158 state
.fs_parsable
= B_TRUE
;
1159 ofmtflags
|= OFMT_PARSABLE
;
1162 state
.fs_persist
= B_TRUE
;
1165 if (dladm_name2info(handle
, optarg
, &state
.fs_linkid
,
1166 NULL
, NULL
, NULL
) != DLADM_STATUS_OK
)
1167 die("invalid link '%s'", optarg
);
1170 fields_str
= optarg
;
1173 die_opterr(optopt
, option
);
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
) {
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 */
1202 (void) dladm_walk_datalink_id(show_flowprop_onelink
, handle
,
1203 &state
, DATALINK_CLASS_ALL
, DATALINK_ANY_MEDIATYPE
,
1207 dladm_free_props(proplist
);
1212 show_flowprop_one_flow(void *arg
, const char *flow
)
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
;
1223 * Do not print flow props for invalid flows.
1225 if ((status
= dladm_flow_info(handle
, flow
, &attr
)) !=
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
);
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
)
1257 /* show all flow properties */
1259 status
= dladm_walk_flowprop(show_one_flowprop
, flow
, statep
);
1260 if (status
!= DLADM_STATUS_OK
)
1261 die_dlerr(status
, "show-flowprop");
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.
1272 print_default_cb(ofmt_arg_t
*of_arg
, char *buf
, uint_t bufsize
)
1276 value
= (char *)of_arg
->ofmt_cbarg
+ of_arg
->ofmt_id
;
1277 (void) strlcpy(buf
, value
, bufsize
);
1282 flowadm_ofmt_check(ofmt_status_t oferr
, boolean_t parsable
,
1285 char buf
[OFMT_BUFSIZE
];
1287 if (oferr
== OFMT_SUCCESS
)
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
) {