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.
27 * Copyright 2017 Joyent, Inc.
44 #include <libdlflow.h>
45 #include <libdllink.h>
46 #include <libdlstat.h>
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51 #include <sys/ethernet.h>
57 typedef struct show_flow_state
{
58 dladm_status_t fs_status
;
59 ofmt_handle_t fs_ofmt
;
61 boolean_t fs_parsable
;
65 typedef void cmdfunc_t(int, char **);
67 static cmdfunc_t do_add_flow
, do_remove_flow
, do_init_flow
, do_show_flow
;
68 static cmdfunc_t do_show_flowprop
, do_set_flowprop
, do_reset_flowprop
;
70 static int show_flow(dladm_handle_t
, dladm_flow_attr_t
*, void *);
71 static int show_flows_onelink(dladm_handle_t
, datalink_id_t
, void *);
73 static int remove_flow(dladm_handle_t
, dladm_flow_attr_t
*, void *);
75 static int show_flowprop(dladm_handle_t
, dladm_flow_attr_t
*, void *);
76 static void show_flowprop_one_flow(void *, const char *);
77 static int show_flowprop_onelink(dladm_handle_t
, datalink_id_t
, void *);
79 static void die(const char *, ...);
80 static void die_optdup(int);
81 static void die_opterr(int, int);
82 static void die_dlerr(dladm_status_t
, const char *, ...);
83 static void warn(const char *, ...);
84 static void warn_dlerr(dladm_status_t
, const char *, ...);
86 /* callback functions for printing output */
87 static ofmt_cb_t print_flowprop_cb
, print_default_cb
;
91 void (*c_fn
)(int, char **);
94 static cmd_t cmds
[] = {
95 { "add-flow", do_add_flow
},
96 { "remove-flow", do_remove_flow
},
97 { "show-flowprop", do_show_flowprop
},
98 { "set-flowprop", do_set_flowprop
},
99 { "reset-flowprop", do_reset_flowprop
},
100 { "show-flow", do_show_flow
},
101 { "init-flow", do_init_flow
},
104 static const struct option longopts
[] = {
105 {"link", required_argument
, 0, 'l'},
106 {"parsable", no_argument
, 0, 'p'},
107 {"parseable", no_argument
, 0, 'p'},
108 {"temporary", no_argument
, 0, 't'},
109 {"root-dir", required_argument
, 0, 'R'},
113 static const struct option prop_longopts
[] = {
114 {"link", required_argument
, 0, 'l'},
115 {"temporary", no_argument
, 0, 't'},
116 {"root-dir", required_argument
, 0, 'R'},
117 {"prop", required_argument
, 0, 'p'},
118 {"attr", required_argument
, 0, 'a'},
123 * structures for 'flowadm remove-flow'
125 typedef struct remove_flow_state
{
127 const char *fs_altroot
;
128 dladm_status_t fs_status
;
129 } remove_flow_state_t
;
131 #define PROTO_MAXSTR_LEN 7
132 #define PORT_MAXSTR_LEN 6
133 #define DSFIELD_MAXSTR_LEN 10
134 #define NULL_OFMT {NULL, 0, 0, NULL}
136 typedef struct flow_fields_buf_s
138 char flow_name
[MAXFLOWNAMELEN
];
139 char flow_link
[MAXLINKNAMELEN
];
140 char flow_ipaddr
[INET6_ADDRSTRLEN
+4];
141 char flow_proto
[PROTO_MAXSTR_LEN
];
142 char flow_lport
[PORT_MAXSTR_LEN
];
143 char flow_rport
[PORT_MAXSTR_LEN
];
144 char flow_dsfield
[DSFIELD_MAXSTR_LEN
];
147 static ofmt_field_t flow_fields
[] = {
148 /* name, field width, index */
150 offsetof(flow_fields_buf_t
, flow_name
), print_default_cb
},
152 offsetof(flow_fields_buf_t
, flow_link
), print_default_cb
},
154 offsetof(flow_fields_buf_t
, flow_ipaddr
), print_default_cb
},
156 offsetof(flow_fields_buf_t
, flow_proto
), print_default_cb
},
158 offsetof(flow_fields_buf_t
, flow_lport
), print_default_cb
},
160 offsetof(flow_fields_buf_t
, flow_rport
), print_default_cb
},
162 offsetof(flow_fields_buf_t
, flow_dsfield
), print_default_cb
},
167 * structures for 'flowadm show-flowprop'
175 } flowprop_field_index_t
;
177 static ofmt_field_t flowprop_fields
[] = {
178 /* name, fieldwidth, index, callback */
179 { "FLOW", 13, FLOWPROP_FLOW
, print_flowprop_cb
},
180 { "PROPERTY", 16, FLOWPROP_PROPERTY
, print_flowprop_cb
},
181 { "VALUE", 15, FLOWPROP_VALUE
, print_flowprop_cb
},
182 { "DEFAULT", 15, FLOWPROP_DEFAULT
, print_flowprop_cb
},
183 { "POSSIBLE", 21, FLOWPROP_POSSIBLE
, print_flowprop_cb
},
187 #define MAX_PROP_LINE 512
189 typedef struct show_flowprop_state
{
191 datalink_id_t fs_linkid
;
194 dladm_arg_list_t
*fs_proplist
;
195 boolean_t fs_parsable
;
196 boolean_t fs_persist
;
198 dladm_status_t fs_status
;
199 dladm_status_t fs_retstatus
;
200 ofmt_handle_t fs_ofmt
;
201 } show_flowprop_state_t
;
203 typedef struct set_flowprop_state
{
207 dladm_status_t fs_status
;
208 } set_flowprop_state_t
;
210 typedef struct flowprop_args_s
{
211 show_flowprop_state_t
*fs_state
;
216 static char *progname
;
218 boolean_t t_arg
= B_FALSE
; /* changes are persistent */
219 char *altroot
= NULL
;
222 * Handle to libdladm. Opened in main() before the sub-command
223 * specific function is called.
225 static dladm_handle_t handle
= NULL
;
227 static const char *attr_table
[] =
228 {"local_ip", "remote_ip", "transport", "local_port", "remote_port",
231 #define NATTR (sizeof (attr_table)/sizeof (char *))
236 (void) fprintf(stderr
, gettext("usage: flowadm <subcommand>"
238 " add-flow [-t] -l <link> -a <attr>=<value>[,...]\n"
239 "\t\t [-p <prop>=<value>,...] <flow>\n"
240 " remove-flow [-t] {-l <link> | <flow>}\n"
241 " show-flow [-p] [-l <link>] "
243 " set-flowprop [-t] -p <prop>=<value>[,...] <flow>\n"
244 " reset-flowprop [-t] [-p <prop>,...] <flow>\n"
245 " show-flowprop [-cP] [-l <link>] [-p <prop>,...] "
248 /* close dladm handle if it was opened */
256 main(int argc
, char *argv
[])
258 int i
, arglen
, cmdlen
;
260 dladm_status_t status
;
262 (void) setlocale(LC_ALL
, "");
263 #if !defined(TEXT_DOMAIN)
264 #define TEXT_DOMAIN "SYS_TEST"
266 (void) textdomain(TEXT_DOMAIN
);
273 for (i
= 0; i
< sizeof (cmds
) / sizeof (cmds
[0]); i
++) {
275 arglen
= strlen(argv
[1]);
276 cmdlen
= strlen(cmdp
->c_name
);
277 if ((arglen
== cmdlen
) && (strncmp(argv
[1], cmdp
->c_name
,
279 /* Open the libdladm handle */
280 if ((status
= dladm_open(&handle
)) != DLADM_STATUS_OK
) {
282 "could not open /dev/dld");
285 cmdp
->c_fn(argc
- 1, &argv
[1]);
292 (void) fprintf(stderr
, gettext("%s: unknown subcommand '%s'\n"),
300 match_attr(char *attr
)
304 for (i
= 0; i
< NATTR
; i
++) {
305 if (strlen(attr
) == strlen(attr_table
[i
]) &&
306 strncmp(attr
, attr_table
[i
], strlen(attr_table
[i
])) == 0) {
315 do_init_flow(int argc
, char *argv
[])
317 dladm_status_t status
;
319 status
= dladm_flow_init(handle
);
320 if (status
!= DLADM_STATUS_OK
)
321 die_dlerr(status
, "flows initialization failed");
325 do_add_flow(int argc
, char *argv
[])
327 char devname
[MAXLINKNAMELEN
];
330 datalink_id_t linkid
;
333 boolean_t l_arg
= B_FALSE
;
334 char propstr
[DLADM_STRSIZE
];
335 char attrstr
[DLADM_STRSIZE
];
336 dladm_arg_list_t
*proplist
= NULL
;
337 dladm_arg_list_t
*attrlist
= NULL
;
338 dladm_status_t status
;
340 bzero(propstr
, DLADM_STRSIZE
);
341 bzero(attrstr
, DLADM_STRSIZE
);
343 while ((option
= getopt_long(argc
, argv
, "tR:l:a:p:",
344 prop_longopts
, NULL
)) != -1) {
353 if (strlcpy(devname
, optarg
,
354 MAXLINKNAMELEN
) >= MAXLINKNAMELEN
) {
355 die("link name too long");
357 if (dladm_name2info(handle
, devname
, &linkid
, NULL
,
358 NULL
, NULL
) != DLADM_STATUS_OK
)
359 die("invalid link '%s'", devname
);
363 (void) strlcat(attrstr
, optarg
, DLADM_STRSIZE
);
364 if (strlcat(attrstr
, ",", DLADM_STRSIZE
) >=
366 die("attribute list too long '%s'", attrstr
);
369 (void) strlcat(propstr
, optarg
, DLADM_STRSIZE
);
370 if (strlcat(propstr
, ",", DLADM_STRSIZE
) >=
372 die("property list too long '%s'", propstr
);
375 die_opterr(optopt
, option
);
379 die("link is required");
385 if ((index
!= (argc
- 1)) || match_attr(argv
[index
]) != NULL
) {
386 die("flow name is required");
388 /* get flow name; required last argument */
389 if (strlen(argv
[index
]) >= MAXFLOWNAMELEN
)
390 die("flow name too long");
394 if (dladm_parse_flow_attrs(attrstr
, &attrlist
, B_FALSE
)
396 die("invalid flow attribute specified");
397 if (dladm_parse_flow_props(propstr
, &proplist
, B_FALSE
)
399 die("invalid flow property specified");
401 status
= dladm_flow_add(handle
, linkid
, attrlist
, proplist
, name
,
403 if (status
!= DLADM_STATUS_OK
)
404 die_dlerr(status
, "add flow failed");
406 dladm_free_attrs(attrlist
);
407 dladm_free_props(proplist
);
411 do_remove_flow(int argc
, char *argv
[])
414 char *flowname
= NULL
;
415 char linkname
[MAXLINKNAMELEN
];
416 datalink_id_t linkid
= DATALINK_ALL_LINKID
;
417 boolean_t l_arg
= B_FALSE
;
418 remove_flow_state_t state
;
419 dladm_status_t status
;
421 bzero(&state
, sizeof (state
));
424 while ((option
= getopt_long(argc
, argv
, ":tR:l:",
425 longopts
, NULL
)) != -1) {
434 if (strlcpy(linkname
, optarg
,
435 MAXLINKNAMELEN
) >= MAXLINKNAMELEN
) {
436 die("link name too long");
438 if (dladm_name2info(handle
, linkname
, &linkid
, NULL
,
439 NULL
, NULL
) != DLADM_STATUS_OK
) {
440 die("invalid link '%s'", linkname
);
445 die_opterr(optopt
, option
);
450 /* when link not specified get flow name */
452 if (optind
!= (argc
-1)) {
455 if (strlen(argv
[optind
]) >= MAXFLOWNAMELEN
)
456 die("flow name too long");
457 flowname
= argv
[optind
];
459 status
= dladm_flow_remove(handle
, flowname
, t_arg
, altroot
);
461 /* if link is specified then flow name should not be there */
462 if (optind
== argc
-1)
464 /* walk the link to find flows and remove them */
465 state
.fs_tempop
= t_arg
;
466 state
.fs_altroot
= altroot
;
467 state
.fs_status
= DLADM_STATUS_OK
;
468 status
= dladm_walk_flow(remove_flow
, handle
, linkid
, &state
,
471 * check if dladm_walk_flow terminated early and see if the
472 * walker function as any status for us
474 if (status
== DLADM_STATUS_OK
)
475 status
= state
.fs_status
;
478 if (status
!= DLADM_STATUS_OK
)
479 die_dlerr(status
, "remove flow failed");
483 * Walker function for removing a flow through dladm_walk_flow();
487 remove_flow(dladm_handle_t handle
, dladm_flow_attr_t
*attr
, void *arg
)
489 remove_flow_state_t
*state
= (remove_flow_state_t
*)arg
;
491 state
->fs_status
= dladm_flow_remove(handle
, attr
->fa_flowname
,
492 state
->fs_tempop
, state
->fs_altroot
);
494 if (state
->fs_status
== DLADM_STATUS_OK
)
495 return (DLADM_WALK_CONTINUE
);
497 return (DLADM_WALK_TERMINATE
);
501 static dladm_status_t
502 print_flow(show_flow_state_t
*state
, dladm_flow_attr_t
*attr
,
503 flow_fields_buf_t
*fbuf
)
505 char link
[MAXLINKNAMELEN
];
506 dladm_status_t status
;
508 if ((status
= dladm_datalink_id2info(handle
, attr
->fa_linkid
, NULL
,
509 NULL
, NULL
, link
, sizeof (link
))) != DLADM_STATUS_OK
) {
513 (void) snprintf(fbuf
->flow_name
, sizeof (fbuf
->flow_name
),
514 "%s", attr
->fa_flowname
);
515 (void) snprintf(fbuf
->flow_link
, sizeof (fbuf
->flow_link
),
518 (void) dladm_flow_attr_ip2str(attr
, fbuf
->flow_ipaddr
,
519 sizeof (fbuf
->flow_ipaddr
));
520 (void) dladm_flow_attr_proto2str(attr
, fbuf
->flow_proto
,
521 sizeof (fbuf
->flow_proto
));
522 if ((attr
->fa_flow_desc
.fd_mask
& FLOW_ULP_PORT_LOCAL
) != 0) {
523 (void) dladm_flow_attr_port2str(attr
, fbuf
->flow_lport
,
524 sizeof (fbuf
->flow_lport
));
526 if ((attr
->fa_flow_desc
.fd_mask
& FLOW_ULP_PORT_REMOTE
) != 0) {
527 (void) dladm_flow_attr_port2str(attr
, fbuf
->flow_rport
,
528 sizeof (fbuf
->flow_rport
));
530 (void) dladm_flow_attr_dsfield2str(attr
, fbuf
->flow_dsfield
,
531 sizeof (fbuf
->flow_dsfield
));
533 return (DLADM_STATUS_OK
);
537 * Walker function for showing flow attributes through dladm_walk_flow().
541 show_flow(dladm_handle_t handle
, dladm_flow_attr_t
*attr
, void *arg
)
543 show_flow_state_t
*statep
= arg
;
544 dladm_status_t status
;
545 flow_fields_buf_t fbuf
;
548 * first get all the flow attributes into fbuf;
550 bzero(&fbuf
, sizeof (fbuf
));
551 status
= print_flow(statep
, attr
, &fbuf
);
553 if (status
!= DLADM_STATUS_OK
)
556 ofmt_print(statep
->fs_ofmt
, (void *)&fbuf
);
559 statep
->fs_status
= status
;
560 return (DLADM_WALK_CONTINUE
);
564 show_one_flow(void *arg
, const char *name
)
566 dladm_flow_attr_t attr
;
568 if (dladm_flow_info(handle
, name
, &attr
) != DLADM_STATUS_OK
)
569 die("invalid flow: '%s'", name
);
571 (void) show_flow(handle
, &attr
, arg
);
575 * Wrapper of dladm_walk_flow(show_flow,...) to make it usable to
576 * dladm_walk_datalink_id(). Used for showing flow attributes for
577 * all flows on all links.
580 show_flows_onelink(dladm_handle_t dh
, datalink_id_t linkid
, void *arg
)
582 show_flow_state_t
*state
= arg
;
584 (void) dladm_walk_flow(show_flow
, dh
, linkid
, arg
, state
->fs_persist
);
586 return (DLADM_WALK_CONTINUE
);
590 do_show_flow(int argc
, char *argv
[])
592 char flowname
[MAXFLOWNAMELEN
];
593 char linkname
[MAXLINKNAMELEN
];
594 datalink_id_t linkid
= DATALINK_ALL_LINKID
;
596 boolean_t l_arg
= B_FALSE
;
597 boolean_t o_arg
= B_FALSE
;
598 show_flow_state_t state
;
599 char *fields_str
= NULL
;
602 uint_t ofmtflags
= 0;
604 bzero(&state
, sizeof (state
));
607 while ((option
= getopt_long(argc
, argv
, ":pPl:o:",
608 longopts
, NULL
)) != -1) {
611 state
.fs_parsable
= B_TRUE
;
612 ofmtflags
|= OFMT_PARSABLE
;
615 state
.fs_persist
= B_TRUE
;
625 if (strlcpy(linkname
, optarg
, MAXLINKNAMELEN
)
627 die("link name too long\n");
628 if (dladm_name2info(handle
, linkname
, &linkid
, NULL
,
629 NULL
, NULL
) != DLADM_STATUS_OK
)
630 die("invalid link '%s'", linkname
);
634 die_opterr(optopt
, option
);
639 /* get flow name (optional last argument */
640 if (optind
== (argc
-1)) {
641 if (strlcpy(flowname
, argv
[optind
], MAXFLOWNAMELEN
)
643 die("flow name too long");
644 state
.fs_flow
= flowname
;
647 oferr
= ofmt_open(fields_str
, flow_fields
, ofmtflags
, 0, &ofmt
);
648 ofmt_check(oferr
, state
.fs_parsable
, ofmt
, die
, warn
);
649 state
.fs_ofmt
= ofmt
;
651 /* Show attributes of one flow */
652 if (state
.fs_flow
!= NULL
) {
653 show_one_flow(&state
, state
.fs_flow
);
655 /* Show attributes of flows on one link */
657 (void) show_flows_onelink(handle
, linkid
, &state
);
659 /* Show attributes of all flows on all links */
661 (void) dladm_walk_datalink_id(show_flows_onelink
, handle
,
662 &state
, DATALINK_CLASS_ALL
, DATALINK_ANY_MEDIATYPE
,
668 static dladm_status_t
669 set_flowprop_persist(const char *flow
, const char *prop_name
, char **prop_val
,
670 uint_t val_cnt
, boolean_t reset
)
672 dladm_status_t status
;
675 status
= dladm_set_flowprop(handle
, flow
, prop_name
, prop_val
, val_cnt
,
676 DLADM_OPT_PERSIST
, &errprop
);
678 if (status
!= DLADM_STATUS_OK
) {
679 warn_dlerr(status
, "cannot persistently %s flow "
680 "property '%s' on '%s'", reset
? "reset": "set",
687 set_flowprop(int argc
, char **argv
, boolean_t reset
)
690 char errmsg
[DLADM_STRSIZE
];
691 const char *flow
= NULL
;
692 char propstr
[DLADM_STRSIZE
];
693 dladm_arg_list_t
*proplist
= NULL
;
694 boolean_t temp
= B_FALSE
;
695 dladm_status_t status
= DLADM_STATUS_OK
;
698 bzero(propstr
, DLADM_STRSIZE
);
700 while ((option
= getopt_long(argc
, argv
, ":p:R:t",
701 prop_longopts
, NULL
)) != -1) {
704 (void) strlcat(propstr
, optarg
, DLADM_STRSIZE
);
705 if (strlcat(propstr
, ",", DLADM_STRSIZE
) >=
707 die("property list too long '%s'", propstr
);
713 status
= dladm_set_rootdir(optarg
);
714 if (status
!= DLADM_STATUS_OK
) {
715 die_dlerr(status
, "invalid directory "
720 die_opterr(optopt
, option
);
725 if (optind
== (argc
- 1)) {
726 if (strlen(argv
[optind
]) >= MAXFLOWNAMELEN
)
727 die("flow name too long");
729 } else if (optind
!= argc
) {
733 die("flow name must be specified");
735 if (dladm_parse_flow_props(propstr
, &proplist
, reset
)
737 die("invalid flow property specified");
739 if (proplist
== NULL
) {
743 die("flow property must be specified");
745 status
= dladm_set_flowprop(handle
, flow
, NULL
, NULL
, 0,
746 DLADM_OPT_ACTIVE
, &errprop
);
747 if (status
!= DLADM_STATUS_OK
) {
748 warn_dlerr(status
, "cannot reset flow property '%s' "
749 "on '%s'", errprop
, flow
);
754 s
= set_flowprop_persist(flow
, NULL
, NULL
, 0, reset
);
755 if (s
!= DLADM_STATUS_OK
)
761 for (i
= 0; i
< proplist
->al_count
; i
++) {
762 dladm_arg_info_t
*aip
= &proplist
->al_info
[i
];
772 count
= aip
->ai_count
;
774 warn("no value specified for '%s'",
776 status
= DLADM_STATUS_BADARG
;
780 s
= dladm_set_flowprop(handle
, flow
, aip
->ai_name
, val
, count
,
781 DLADM_OPT_ACTIVE
, NULL
);
782 if (s
== DLADM_STATUS_OK
) {
784 s
= set_flowprop_persist(flow
,
785 aip
->ai_name
, val
, count
, reset
);
786 if (s
!= DLADM_STATUS_OK
)
793 case DLADM_STATUS_NOTFOUND
:
794 warn("invalid flow property '%s'", aip
->ai_name
);
796 case DLADM_STATUS_BADVAL
: {
799 char **propvals
= NULL
;
800 uint_t valcnt
= DLADM_MAX_PROP_VALCNT
;
802 ptr
= malloc((sizeof (char *) +
803 DLADM_PROP_VAL_MAX
) * DLADM_MAX_PROP_VALCNT
+
807 die("insufficient memory");
808 propvals
= (char **)(void *)ptr
;
810 for (j
= 0; j
< DLADM_MAX_PROP_VALCNT
; j
++) {
811 propvals
[j
] = ptr
+ sizeof (char *) *
812 DLADM_MAX_PROP_VALCNT
+
813 j
* DLADM_PROP_VAL_MAX
;
815 s
= dladm_get_flowprop(handle
, flow
,
816 DLADM_PROP_VAL_MODIFIABLE
, aip
->ai_name
, propvals
,
820 lim
= ptr
+ DLADM_STRSIZE
;
822 for (j
= 0; j
< valcnt
&& s
== DLADM_STATUS_OK
; j
++) {
823 ptr
+= snprintf(ptr
, lim
- ptr
, "%s,",
830 warn("flow property '%s' must be one of: %s",
831 aip
->ai_name
, errmsg
);
833 warn("%s is an invalid value for "
834 "flow property %s", *val
, aip
->ai_name
);
840 warn_dlerr(status
, "cannot reset flow property "
841 "'%s' on '%s'", aip
->ai_name
, flow
);
843 warn_dlerr(status
, "cannot set flow property "
844 "'%s' on '%s'", aip
->ai_name
, flow
);
850 dladm_free_props(proplist
);
851 if (status
!= DLADM_STATUS_OK
) {
858 do_set_flowprop(int argc
, char **argv
)
860 set_flowprop(argc
, argv
, B_FALSE
);
864 do_reset_flowprop(int argc
, char **argv
)
866 set_flowprop(argc
, argv
, B_TRUE
);
870 warn(const char *format
, ...)
874 format
= gettext(format
);
875 (void) fprintf(stderr
, "%s: warning: ", progname
);
877 va_start(alist
, format
);
878 (void) vfprintf(stderr
, format
, alist
);
881 (void) putc('\n', stderr
);
886 warn_dlerr(dladm_status_t err
, const char *format
, ...)
889 char errmsg
[DLADM_STRSIZE
];
891 format
= gettext(format
);
892 (void) fprintf(stderr
, gettext("%s: warning: "), progname
);
894 va_start(alist
, format
);
895 (void) vfprintf(stderr
, format
, alist
);
897 (void) fprintf(stderr
, ": %s\n", dladm_status2str(err
, errmsg
));
902 die(const char *format
, ...)
906 format
= gettext(format
);
907 (void) fprintf(stderr
, "%s: ", progname
);
909 va_start(alist
, format
);
910 (void) vfprintf(stderr
, format
, alist
);
913 (void) putc('\n', stderr
);
915 /* close dladm handle if it was opened */
925 die("the option -%c cannot be specified more than once", opt
);
929 die_opterr(int opt
, int opterr
)
933 die("option '-%c' requires a value", opt
);
937 die("unrecognized option '-%c'", opt
);
944 die_dlerr(dladm_status_t err
, const char *format
, ...)
947 char errmsg
[DLADM_STRSIZE
];
949 format
= gettext(format
);
950 (void) fprintf(stderr
, "%s: ", progname
);
952 va_start(alist
, format
);
953 (void) vfprintf(stderr
, format
, alist
);
955 (void) fprintf(stderr
, ": %s\n", dladm_status2str(err
, errmsg
));
957 /* close dladm handle if it was opened */
965 print_flowprop(const char *flowname
, show_flowprop_state_t
*statep
,
966 const char *propname
, dladm_prop_type_t type
,
967 const char *format
, char **pptr
)
971 char buf
[DLADM_STRSIZE
];
972 char *unknown
= "--", *notsup
= "";
973 char **propvals
= statep
->fs_propvals
;
974 uint_t valcnt
= DLADM_MAX_PROP_VALCNT
;
975 dladm_status_t status
;
977 status
= dladm_get_flowprop(handle
, flowname
, type
, propname
, propvals
,
979 if (status
!= DLADM_STATUS_OK
) {
980 if (status
== DLADM_STATUS_TEMPONLY
) {
981 if (type
== DLADM_PROP_VAL_MODIFIABLE
&&
982 statep
->fs_persist
) {
986 statep
->fs_status
= status
;
987 statep
->fs_retstatus
= status
;
990 } else if (status
== DLADM_STATUS_NOTSUP
||
991 statep
->fs_persist
) {
993 if (type
== DLADM_PROP_VAL_CURRENT
)
998 if ((statep
->fs_proplist
!= NULL
) &&
999 statep
->fs_status
== DLADM_STATUS_OK
) {
1000 warn("invalid flow property '%s'", propname
);
1002 statep
->fs_status
= status
;
1003 statep
->fs_retstatus
= status
;
1008 statep
->fs_status
= DLADM_STATUS_OK
;
1011 lim
= buf
+ DLADM_STRSIZE
;
1012 for (i
= 0; i
< valcnt
; i
++) {
1013 if (propvals
[i
][0] == '\0' && !statep
->fs_parsable
)
1014 ptr
+= snprintf(ptr
, lim
- ptr
, "--,");
1016 ptr
+= snprintf(ptr
, lim
- ptr
, "%s,", propvals
[i
]);
1021 buf
[strlen(buf
) - 1] = '\0';
1023 lim
= statep
->fs_line
+ MAX_PROP_LINE
;
1024 if (statep
->fs_parsable
) {
1025 *pptr
+= snprintf(*pptr
, lim
- *pptr
,
1028 *pptr
+= snprintf(*pptr
, lim
- *pptr
, format
, buf
);
1033 print_flowprop_cb(ofmt_arg_t
*of_arg
, char *buf
, uint_t bufsize
)
1035 flowprop_args_t
*arg
= of_arg
->ofmt_cbarg
;
1036 char *propname
= arg
->fs_propname
;
1037 show_flowprop_state_t
*statep
= arg
->fs_state
;
1038 char *ptr
= statep
->fs_line
;
1039 char *lim
= ptr
+ MAX_PROP_LINE
;
1040 char *flowname
= arg
->fs_flowname
;
1042 switch (of_arg
->ofmt_id
) {
1044 (void) snprintf(ptr
, lim
- ptr
, "%s", statep
->fs_flow
);
1046 case FLOWPROP_PROPERTY
:
1047 (void) snprintf(ptr
, lim
- ptr
, "%s", propname
);
1049 case FLOWPROP_VALUE
:
1050 print_flowprop(flowname
, statep
, propname
,
1051 statep
->fs_persist
? DLADM_PROP_VAL_PERSISTENT
:
1052 DLADM_PROP_VAL_CURRENT
, "%s", &ptr
);
1054 * If we failed to query the flow property, for example, query
1055 * the persistent value of a non-persistable flow property,
1056 * simply skip the output.
1058 if (statep
->fs_status
!= DLADM_STATUS_OK
)
1060 ptr
= statep
->fs_line
;
1062 case FLOWPROP_DEFAULT
:
1063 print_flowprop(flowname
, statep
, propname
,
1064 DLADM_PROP_VAL_DEFAULT
, "%s", &ptr
);
1065 if (statep
->fs_status
!= DLADM_STATUS_OK
)
1067 ptr
= statep
->fs_line
;
1069 case FLOWPROP_POSSIBLE
:
1070 print_flowprop(flowname
, statep
, propname
,
1071 DLADM_PROP_VAL_MODIFIABLE
, "%s ", &ptr
);
1072 if (statep
->fs_status
!= DLADM_STATUS_OK
)
1074 ptr
= statep
->fs_line
;
1077 die("invalid input");
1080 (void) strlcpy(buf
, ptr
, bufsize
);
1084 return ((statep
->fs_status
== DLADM_STATUS_OK
) ?
1089 show_one_flowprop(void *arg
, const char *propname
)
1091 show_flowprop_state_t
*statep
= arg
;
1092 flowprop_args_t fs_arg
;
1094 bzero(&fs_arg
, sizeof (fs_arg
));
1095 fs_arg
.fs_state
= statep
;
1096 fs_arg
.fs_propname
= (char *)propname
;
1097 fs_arg
.fs_flowname
= (char *)statep
->fs_flow
;
1099 ofmt_print(statep
->fs_ofmt
, (void *)&fs_arg
);
1101 return (DLADM_WALK_CONTINUE
);
1105 /* Walker function called by dladm_walk_flow to display flow properties */
1107 show_flowprop(dladm_handle_t handle
, dladm_flow_attr_t
*attr
, void *arg
)
1109 show_flowprop_one_flow(arg
, attr
->fa_flowname
);
1110 return (DLADM_WALK_CONTINUE
);
1114 * Wrapper of dladm_walk_flow(show_walk_fn,...) to make it
1115 * usable to dladm_walk_datalink_id()
1118 show_flowprop_onelink(dladm_handle_t dh
, datalink_id_t linkid
, void *arg
)
1120 char name
[MAXLINKNAMELEN
];
1122 if (dladm_datalink_id2info(dh
, linkid
, NULL
, NULL
, NULL
, name
,
1123 sizeof (name
)) != DLADM_STATUS_OK
)
1124 return (DLADM_WALK_TERMINATE
);
1126 (void) dladm_walk_flow(show_flowprop
, dh
, linkid
, arg
, B_FALSE
);
1128 return (DLADM_WALK_CONTINUE
);
1132 do_show_flowprop(int argc
, char **argv
)
1135 dladm_arg_list_t
*proplist
= NULL
;
1136 show_flowprop_state_t state
;
1137 char *fields_str
= NULL
;
1139 ofmt_status_t oferr
;
1140 uint_t ofmtflags
= 0;
1143 state
.fs_propvals
= NULL
;
1144 state
.fs_line
= NULL
;
1145 state
.fs_parsable
= B_FALSE
;
1146 state
.fs_persist
= B_FALSE
;
1147 state
.fs_header
= B_TRUE
;
1148 state
.fs_retstatus
= DLADM_STATUS_OK
;
1149 state
.fs_linkid
= DATALINK_INVALID_LINKID
;
1150 state
.fs_flow
= NULL
;
1152 while ((option
= getopt_long(argc
, argv
, ":p:cPl:o:",
1153 prop_longopts
, NULL
)) != -1) {
1156 if (dladm_parse_flow_props(optarg
, &proplist
, B_TRUE
)
1158 die("invalid flow properties specified");
1161 state
.fs_parsable
= B_TRUE
;
1162 ofmtflags
|= OFMT_PARSABLE
;
1165 state
.fs_persist
= B_TRUE
;
1168 if (dladm_name2info(handle
, optarg
, &state
.fs_linkid
,
1169 NULL
, NULL
, NULL
) != DLADM_STATUS_OK
)
1170 die("invalid link '%s'", optarg
);
1173 fields_str
= optarg
;
1176 die_opterr(optopt
, option
);
1181 if (optind
== (argc
- 1)) {
1182 if (strlen(argv
[optind
]) >= MAXFLOWNAMELEN
)
1183 die("flow name too long");
1184 state
.fs_flow
= argv
[optind
];
1185 } else if (optind
!= argc
) {
1188 state
.fs_proplist
= proplist
;
1189 state
.fs_status
= DLADM_STATUS_OK
;
1191 oferr
= ofmt_open(fields_str
, flowprop_fields
, ofmtflags
, 0, &ofmt
);
1192 ofmt_check(oferr
, state
.fs_parsable
, ofmt
, die
, warn
);
1193 state
.fs_ofmt
= ofmt
;
1195 /* Show properties for one flow */
1196 if (state
.fs_flow
!= NULL
) {
1197 show_flowprop_one_flow(&state
, state
.fs_flow
);
1199 /* Show properties for all flows on one link */
1200 } else if (state
.fs_linkid
!= DATALINK_INVALID_LINKID
) {
1201 (void) show_flowprop_onelink(handle
, state
.fs_linkid
, &state
);
1203 /* Show properties for all flows on all links */
1205 (void) dladm_walk_datalink_id(show_flowprop_onelink
, handle
,
1206 &state
, DATALINK_CLASS_ALL
, DATALINK_ANY_MEDIATYPE
,
1210 dladm_free_props(proplist
);
1215 show_flowprop_one_flow(void *arg
, const char *flow
)
1219 dladm_status_t status
;
1220 dladm_arg_list_t
*proplist
= NULL
;
1221 show_flowprop_state_t
*statep
= arg
;
1222 dladm_flow_attr_t attr
;
1226 * Do not print flow props for invalid flows.
1228 if ((status
= dladm_flow_info(handle
, flow
, &attr
)) !=
1230 die("invalid flow: '%s'", flow
);
1233 savep
= statep
->fs_flow
;
1234 statep
->fs_flow
= flow
;
1236 proplist
= statep
->fs_proplist
;
1238 buf
= malloc((sizeof (char *) + DLADM_PROP_VAL_MAX
)
1239 * DLADM_MAX_PROP_VALCNT
+ MAX_PROP_LINE
);
1241 die("insufficient memory");
1243 statep
->fs_propvals
= (char **)(void *)buf
;
1244 for (i
= 0; i
< DLADM_MAX_PROP_VALCNT
; i
++) {
1245 statep
->fs_propvals
[i
] = buf
+
1246 sizeof (char *) * DLADM_MAX_PROP_VALCNT
+
1247 i
* DLADM_PROP_VAL_MAX
;
1249 statep
->fs_line
= buf
+
1250 (sizeof (char *) + DLADM_PROP_VAL_MAX
) * DLADM_MAX_PROP_VALCNT
;
1252 /* show only specified flow properties */
1253 if (proplist
!= NULL
) {
1254 for (i
= 0; i
< proplist
->al_count
; i
++) {
1255 if (show_one_flowprop(statep
,
1256 proplist
->al_info
[i
].ai_name
) != DLADM_STATUS_OK
)
1260 /* show all flow properties */
1262 status
= dladm_walk_flowprop(show_one_flowprop
, flow
, statep
);
1263 if (status
!= DLADM_STATUS_OK
)
1264 die_dlerr(status
, "show-flowprop");
1267 statep
->fs_flow
= savep
;
1271 * default output callback function that, when invoked from dladm_print_output,
1272 * prints string which is offset by of_arg->ofmt_id within buf.
1275 print_default_cb(ofmt_arg_t
*of_arg
, char *buf
, uint_t bufsize
)
1279 value
= (char *)of_arg
->ofmt_cbarg
+ of_arg
->ofmt_id
;
1280 (void) strlcpy(buf
, value
, bufsize
);