Merge commit '00f1a4f432b3d8aad1aa270e91c44c57f03ef407'
[unleashed.git] / usr / src / cmd / flowadm / flowadm.c
blob058c1e03d81f61029da05d28a5acce54e4333e28
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.
27 * Copyright 2017 Joyent, Inc.
30 #include <stdio.h>
31 #include <locale.h>
32 #include <stdarg.h>
33 #include <stdlib.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <stropts.h>
37 #include <errno.h>
38 #include <strings.h>
39 #include <getopt.h>
40 #include <unistd.h>
41 #include <priv.h>
42 #include <netdb.h>
43 #include <libintl.h>
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>
52 #include <inet/ip.h>
53 #include <inet/ip6.h>
54 #include <stddef.h>
55 #include <ofmt.h>
57 typedef struct show_flow_state {
58 dladm_status_t fs_status;
59 ofmt_handle_t fs_ofmt;
60 const char *fs_flow;
61 boolean_t fs_parsable;
62 boolean_t fs_persist;
63 } show_flow_state_t;
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;
89 typedef struct cmd {
90 char *c_name;
91 void (*c_fn)(int, char **);
92 } cmd_t;
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'},
110 { 0, 0, 0, 0 }
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'},
119 { 0, 0, 0, 0 }
123 * structures for 'flowadm remove-flow'
125 typedef struct remove_flow_state {
126 boolean_t fs_tempop;
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];
145 } flow_fields_buf_t;
147 static ofmt_field_t flow_fields[] = {
148 /* name, field width, index */
149 { "FLOW", 12,
150 offsetof(flow_fields_buf_t, flow_name), print_default_cb},
151 { "LINK", 12,
152 offsetof(flow_fields_buf_t, flow_link), print_default_cb},
153 { "IPADDR", 25,
154 offsetof(flow_fields_buf_t, flow_ipaddr), print_default_cb},
155 { "PROTO", 7,
156 offsetof(flow_fields_buf_t, flow_proto), print_default_cb},
157 { "LPORT", 8,
158 offsetof(flow_fields_buf_t, flow_lport), print_default_cb},
159 { "RPORT", 8,
160 offsetof(flow_fields_buf_t, flow_rport), print_default_cb},
161 { "DSFLD", 10,
162 offsetof(flow_fields_buf_t, flow_dsfield), print_default_cb},
163 NULL_OFMT}
167 * structures for 'flowadm show-flowprop'
169 typedef enum {
170 FLOWPROP_FLOW,
171 FLOWPROP_PROPERTY,
172 FLOWPROP_VALUE,
173 FLOWPROP_DEFAULT,
174 FLOWPROP_POSSIBLE
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},
184 NULL_OFMT}
187 #define MAX_PROP_LINE 512
189 typedef struct show_flowprop_state {
190 const char *fs_flow;
191 datalink_id_t fs_linkid;
192 char *fs_line;
193 char **fs_propvals;
194 dladm_arg_list_t *fs_proplist;
195 boolean_t fs_parsable;
196 boolean_t fs_persist;
197 boolean_t fs_header;
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 {
204 const char *fs_name;
205 boolean_t fs_reset;
206 boolean_t fs_temp;
207 dladm_status_t fs_status;
208 } set_flowprop_state_t;
210 typedef struct flowprop_args_s {
211 show_flowprop_state_t *fs_state;
212 char *fs_propname;
213 char *fs_flowname;
214 } flowprop_args_t;
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",
229 "dsfield"};
231 #define NATTR (sizeof (attr_table)/sizeof (char *))
233 static void
234 usage(void)
236 (void) fprintf(stderr, gettext("usage: flowadm <subcommand>"
237 " <args>...\n"
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>] "
242 "[<flow>]\n\n"
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>,...] "
246 "[<flow>]\n"));
248 /* close dladm handle if it was opened */
249 if (handle != NULL)
250 dladm_close(handle);
252 exit(1);
256 main(int argc, char *argv[])
258 int i, arglen, cmdlen;
259 cmd_t *cmdp;
260 dladm_status_t status;
262 (void) setlocale(LC_ALL, "");
263 #if !defined(TEXT_DOMAIN)
264 #define TEXT_DOMAIN "SYS_TEST"
265 #endif
266 (void) textdomain(TEXT_DOMAIN);
268 progname = argv[0];
270 if (argc < 2)
271 usage();
273 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
274 cmdp = &cmds[i];
275 arglen = strlen(argv[1]);
276 cmdlen = strlen(cmdp->c_name);
277 if ((arglen == cmdlen) && (strncmp(argv[1], cmdp->c_name,
278 cmdlen) == 0)) {
279 /* Open the libdladm handle */
280 if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) {
281 die_dlerr(status,
282 "could not open /dev/dld");
285 cmdp->c_fn(argc - 1, &argv[1]);
287 dladm_close(handle);
288 exit(EXIT_SUCCESS);
292 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
293 progname, argv[1]);
294 usage();
296 return (0);
299 static const char *
300 match_attr(char *attr)
302 int i;
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) {
307 return (attr);
310 return (NULL);
313 /* ARGSUSED */
314 static void
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");
324 static void
325 do_add_flow(int argc, char *argv[])
327 char devname[MAXLINKNAMELEN];
328 char *name = NULL;
329 uint_t index;
330 datalink_id_t linkid;
332 char option;
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) {
345 switch (option) {
346 case 't':
347 t_arg = B_TRUE;
348 break;
349 case 'R':
350 altroot = optarg;
351 break;
352 case 'l':
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);
360 l_arg = B_TRUE;
361 break;
362 case 'a':
363 (void) strlcat(attrstr, optarg, DLADM_STRSIZE);
364 if (strlcat(attrstr, ",", DLADM_STRSIZE) >=
365 DLADM_STRSIZE)
366 die("attribute list too long '%s'", attrstr);
367 break;
368 case 'p':
369 (void) strlcat(propstr, optarg, DLADM_STRSIZE);
370 if (strlcat(propstr, ",", DLADM_STRSIZE) >=
371 DLADM_STRSIZE)
372 die("property list too long '%s'", propstr);
373 break;
374 default:
375 die_opterr(optopt, option);
378 if (!l_arg) {
379 die("link is required");
382 opterr = 0;
383 index = optind;
385 if ((index != (argc - 1)) || match_attr(argv[index]) != NULL) {
386 die("flow name is required");
387 } else {
388 /* get flow name; required last argument */
389 if (strlen(argv[index]) >= MAXFLOWNAMELEN)
390 die("flow name too long");
391 name = argv[index];
394 if (dladm_parse_flow_attrs(attrstr, &attrlist, B_FALSE)
395 != DLADM_STATUS_OK)
396 die("invalid flow attribute specified");
397 if (dladm_parse_flow_props(propstr, &proplist, B_FALSE)
398 != DLADM_STATUS_OK)
399 die("invalid flow property specified");
401 status = dladm_flow_add(handle, linkid, attrlist, proplist, name,
402 t_arg, altroot);
403 if (status != DLADM_STATUS_OK)
404 die_dlerr(status, "add flow failed");
406 dladm_free_attrs(attrlist);
407 dladm_free_props(proplist);
410 static void
411 do_remove_flow(int argc, char *argv[])
413 char option;
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));
423 opterr = 0;
424 while ((option = getopt_long(argc, argv, ":tR:l:",
425 longopts, NULL)) != -1) {
426 switch (option) {
427 case 't':
428 t_arg = B_TRUE;
429 break;
430 case 'R':
431 altroot = optarg;
432 break;
433 case 'l':
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);
442 l_arg = B_TRUE;
443 break;
444 default:
445 die_opterr(optopt, option);
446 break;
450 /* when link not specified get flow name */
451 if (!l_arg) {
452 if (optind != (argc-1)) {
453 usage();
454 } else {
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);
460 } else {
461 /* if link is specified then flow name should not be there */
462 if (optind == argc-1)
463 usage();
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,
469 B_FALSE);
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();
485 /*ARGSUSED*/
486 static int
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);
496 else
497 return (DLADM_WALK_TERMINATE);
500 /*ARGSUSED*/
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) {
510 return (status);
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),
516 "%s", 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().
539 /*ARGSUSED*/
540 static int
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)
554 goto done;
556 ofmt_print(statep->fs_ofmt, (void *)&fbuf);
558 done:
559 statep->fs_status = status;
560 return (DLADM_WALK_CONTINUE);
563 static void
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);
570 else
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.
579 static int
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);
589 static void
590 do_show_flow(int argc, char *argv[])
592 char flowname[MAXFLOWNAMELEN];
593 char linkname[MAXLINKNAMELEN];
594 datalink_id_t linkid = DATALINK_ALL_LINKID;
595 int option;
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;
600 ofmt_handle_t ofmt;
601 ofmt_status_t oferr;
602 uint_t ofmtflags = 0;
604 bzero(&state, sizeof (state));
606 opterr = 0;
607 while ((option = getopt_long(argc, argv, ":pPl:o:",
608 longopts, NULL)) != -1) {
609 switch (option) {
610 case 'p':
611 state.fs_parsable = B_TRUE;
612 ofmtflags |= OFMT_PARSABLE;
613 break;
614 case 'P':
615 state.fs_persist = B_TRUE;
616 break;
617 case 'o':
618 if (o_arg)
619 die_optdup(option);
621 o_arg = B_TRUE;
622 fields_str = optarg;
623 break;
624 case 'l':
625 if (strlcpy(linkname, optarg, MAXLINKNAMELEN)
626 >= 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);
631 l_arg = B_TRUE;
632 break;
633 default:
634 die_opterr(optopt, option);
635 break;
639 /* get flow name (optional last argument */
640 if (optind == (argc-1)) {
641 if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN)
642 >= 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 */
656 } else if (l_arg) {
657 (void) show_flows_onelink(handle, linkid, &state);
659 /* Show attributes of all flows on all links */
660 } else {
661 (void) dladm_walk_datalink_id(show_flows_onelink, handle,
662 &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
663 DLADM_OPT_ACTIVE);
665 ofmt_close(ofmt);
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;
673 char *errprop;
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",
681 errprop, flow);
683 return (status);
686 static void
687 set_flowprop(int argc, char **argv, boolean_t reset)
689 int i, option;
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;
697 opterr = 0;
698 bzero(propstr, DLADM_STRSIZE);
700 while ((option = getopt_long(argc, argv, ":p:R:t",
701 prop_longopts, NULL)) != -1) {
702 switch (option) {
703 case 'p':
704 (void) strlcat(propstr, optarg, DLADM_STRSIZE);
705 if (strlcat(propstr, ",", DLADM_STRSIZE) >=
706 DLADM_STRSIZE)
707 die("property list too long '%s'", propstr);
708 break;
709 case 't':
710 temp = B_TRUE;
711 break;
712 case 'R':
713 status = dladm_set_rootdir(optarg);
714 if (status != DLADM_STATUS_OK) {
715 die_dlerr(status, "invalid directory "
716 "specified");
718 break;
719 default:
720 die_opterr(optopt, option);
721 break;
725 if (optind == (argc - 1)) {
726 if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
727 die("flow name too long");
728 flow = argv[optind];
729 } else if (optind != argc) {
730 usage();
732 if (flow == NULL)
733 die("flow name must be specified");
735 if (dladm_parse_flow_props(propstr, &proplist, reset)
736 != DLADM_STATUS_OK)
737 die("invalid flow property specified");
739 if (proplist == NULL) {
740 char *errprop;
742 if (!reset)
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);
751 if (!temp) {
752 dladm_status_t s;
754 s = set_flowprop_persist(flow, NULL, NULL, 0, reset);
755 if (s != DLADM_STATUS_OK)
756 status = s;
758 goto done;
761 for (i = 0; i < proplist->al_count; i++) {
762 dladm_arg_info_t *aip = &proplist->al_info[i];
763 char **val;
764 uint_t count;
765 dladm_status_t s;
767 if (reset) {
768 val = NULL;
769 count = 0;
770 } else {
771 val = aip->ai_val;
772 count = aip->ai_count;
773 if (count == 0) {
774 warn("no value specified for '%s'",
775 aip->ai_name);
776 status = DLADM_STATUS_BADARG;
777 continue;
780 s = dladm_set_flowprop(handle, flow, aip->ai_name, val, count,
781 DLADM_OPT_ACTIVE, NULL);
782 if (s == DLADM_STATUS_OK) {
783 if (!temp) {
784 s = set_flowprop_persist(flow,
785 aip->ai_name, val, count, reset);
786 if (s != DLADM_STATUS_OK)
787 status = s;
789 continue;
791 status = s;
792 switch (s) {
793 case DLADM_STATUS_NOTFOUND:
794 warn("invalid flow property '%s'", aip->ai_name);
795 break;
796 case DLADM_STATUS_BADVAL: {
797 int j;
798 char *ptr, *lim;
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 +
804 MAX_PROP_LINE);
806 if (ptr == NULL)
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,
817 &valcnt);
819 ptr = errmsg;
820 lim = ptr + DLADM_STRSIZE;
821 *ptr = '\0';
822 for (j = 0; j < valcnt && s == DLADM_STATUS_OK; j++) {
823 ptr += snprintf(ptr, lim - ptr, "%s,",
824 propvals[j]);
825 if (ptr >= lim)
826 break;
828 if (ptr > errmsg) {
829 *(ptr - 1) = '\0';
830 warn("flow property '%s' must be one of: %s",
831 aip->ai_name, errmsg);
832 } else
833 warn("%s is an invalid value for "
834 "flow property %s", *val, aip->ai_name);
835 free(propvals);
836 break;
838 default:
839 if (reset) {
840 warn_dlerr(status, "cannot reset flow property "
841 "'%s' on '%s'", aip->ai_name, flow);
842 } else {
843 warn_dlerr(status, "cannot set flow property "
844 "'%s' on '%s'", aip->ai_name, flow);
846 break;
849 done:
850 dladm_free_props(proplist);
851 if (status != DLADM_STATUS_OK) {
852 dladm_close(handle);
853 exit(EXIT_FAILURE);
857 static void
858 do_set_flowprop(int argc, char **argv)
860 set_flowprop(argc, argv, B_FALSE);
863 static void
864 do_reset_flowprop(int argc, char **argv)
866 set_flowprop(argc, argv, B_TRUE);
869 static void
870 warn(const char *format, ...)
872 va_list alist;
874 format = gettext(format);
875 (void) fprintf(stderr, "%s: warning: ", progname);
877 va_start(alist, format);
878 (void) vfprintf(stderr, format, alist);
879 va_end(alist);
881 (void) putc('\n', stderr);
884 /* PRINTFLIKE2 */
885 static void
886 warn_dlerr(dladm_status_t err, const char *format, ...)
888 va_list alist;
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);
896 va_end(alist);
897 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
900 /* PRINTFLIKE1 */
901 static void
902 die(const char *format, ...)
904 va_list alist;
906 format = gettext(format);
907 (void) fprintf(stderr, "%s: ", progname);
909 va_start(alist, format);
910 (void) vfprintf(stderr, format, alist);
911 va_end(alist);
913 (void) putc('\n', stderr);
915 /* close dladm handle if it was opened */
916 if (handle != NULL)
917 dladm_close(handle);
919 exit(EXIT_FAILURE);
922 static void
923 die_optdup(int opt)
925 die("the option -%c cannot be specified more than once", opt);
928 static void
929 die_opterr(int opt, int opterr)
931 switch (opterr) {
932 case ':':
933 die("option '-%c' requires a value", opt);
934 break;
935 case '?':
936 default:
937 die("unrecognized option '-%c'", opt);
938 break;
942 /* PRINTFLIKE2 */
943 static void
944 die_dlerr(dladm_status_t err, const char *format, ...)
946 va_list alist;
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);
954 va_end(alist);
955 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
957 /* close dladm handle if it was opened */
958 if (handle != NULL)
959 dladm_close(handle);
961 exit(EXIT_FAILURE);
964 static void
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)
969 int i;
970 char *ptr, *lim;
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,
978 &valcnt);
979 if (status != DLADM_STATUS_OK) {
980 if (status == DLADM_STATUS_TEMPONLY) {
981 if (type == DLADM_PROP_VAL_MODIFIABLE &&
982 statep->fs_persist) {
983 valcnt = 1;
984 propvals = &unknown;
985 } else {
986 statep->fs_status = status;
987 statep->fs_retstatus = status;
988 return;
990 } else if (status == DLADM_STATUS_NOTSUP ||
991 statep->fs_persist) {
992 valcnt = 1;
993 if (type == DLADM_PROP_VAL_CURRENT)
994 propvals = &unknown;
995 else
996 propvals = &notsup;
997 } else {
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;
1004 return;
1008 statep->fs_status = DLADM_STATUS_OK;
1010 ptr = buf;
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, "--,");
1015 else
1016 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]);
1017 if (ptr >= lim)
1018 break;
1020 if (valcnt > 0)
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,
1026 "%s", buf);
1027 } else {
1028 *pptr += snprintf(*pptr, lim - *pptr, format, buf);
1032 static boolean_t
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) {
1043 case FLOWPROP_FLOW:
1044 (void) snprintf(ptr, lim - ptr, "%s", statep->fs_flow);
1045 break;
1046 case FLOWPROP_PROPERTY:
1047 (void) snprintf(ptr, lim - ptr, "%s", propname);
1048 break;
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)
1059 goto skip;
1060 ptr = statep->fs_line;
1061 break;
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)
1066 goto skip;
1067 ptr = statep->fs_line;
1068 break;
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)
1073 goto skip;
1074 ptr = statep->fs_line;
1075 break;
1076 default:
1077 die("invalid input");
1078 break;
1080 (void) strlcpy(buf, ptr, bufsize);
1081 return (B_TRUE);
1082 skip:
1083 buf[0] = '\0';
1084 return ((statep->fs_status == DLADM_STATUS_OK) ?
1085 B_TRUE : B_FALSE);
1088 static int
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);
1104 /*ARGSUSED*/
1105 /* Walker function called by dladm_walk_flow to display flow properties */
1106 static int
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()
1117 static int
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);
1131 static void
1132 do_show_flowprop(int argc, char **argv)
1134 int option;
1135 dladm_arg_list_t *proplist = NULL;
1136 show_flowprop_state_t state;
1137 char *fields_str = NULL;
1138 ofmt_handle_t ofmt;
1139 ofmt_status_t oferr;
1140 uint_t ofmtflags = 0;
1142 opterr = 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) {
1154 switch (option) {
1155 case 'p':
1156 if (dladm_parse_flow_props(optarg, &proplist, B_TRUE)
1157 != DLADM_STATUS_OK)
1158 die("invalid flow properties specified");
1159 break;
1160 case 'c':
1161 state.fs_parsable = B_TRUE;
1162 ofmtflags |= OFMT_PARSABLE;
1163 break;
1164 case 'P':
1165 state.fs_persist = B_TRUE;
1166 break;
1167 case 'l':
1168 if (dladm_name2info(handle, optarg, &state.fs_linkid,
1169 NULL, NULL, NULL) != DLADM_STATUS_OK)
1170 die("invalid link '%s'", optarg);
1171 break;
1172 case 'o':
1173 fields_str = optarg;
1174 break;
1175 default:
1176 die_opterr(optopt, option);
1177 break;
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) {
1186 usage();
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 */
1204 } else {
1205 (void) dladm_walk_datalink_id(show_flowprop_onelink, handle,
1206 &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
1207 DLADM_OPT_ACTIVE);
1210 dladm_free_props(proplist);
1211 ofmt_close(ofmt);
1214 static void
1215 show_flowprop_one_flow(void *arg, const char *flow)
1217 int i;
1218 char *buf;
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;
1223 const char *savep;
1226 * Do not print flow props for invalid flows.
1228 if ((status = dladm_flow_info(handle, flow, &attr)) !=
1229 DLADM_STATUS_OK) {
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);
1240 if (buf == NULL)
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)
1257 break;
1260 /* show all flow properties */
1261 } else {
1262 status = dladm_walk_flowprop(show_one_flowprop, flow, statep);
1263 if (status != DLADM_STATUS_OK)
1264 die_dlerr(status, "show-flowprop");
1266 free(buf);
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.
1274 static boolean_t
1275 print_default_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize)
1277 char *value;
1279 value = (char *)of_arg->ofmt_cbarg + of_arg->ofmt_id;
1280 (void) strlcpy(buf, value, bufsize);
1281 return (B_TRUE);