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 flow_chain_s
{
54 char fc_flowname
[MAXFLOWNAMELEN
];
57 struct flow_chain_s
*fc_next
;
60 typedef struct show_flow_state
{
61 flow_chain_t
*fs_flowchain
;
62 ofmt_handle_t fs_ofmt
;
64 boolean_t fs_parsable
;
67 typedef struct show_history_state_s
{
69 boolean_t us_parsable
;
70 boolean_t us_printheader
;
73 ofmt_handle_t us_ofmt
;
74 } show_history_state_t
;
76 static void do_show_history(int, char **);
78 static int query_flow_stats(dladm_handle_t
, dladm_flow_attr_t
*, void *);
79 static int query_link_flow_stats(dladm_handle_t
, datalink_id_t
, void *);
81 static void die(const char *, ...);
82 static void die_optdup(int);
83 static void die_opterr(int, int, const char *);
84 static void die_dlerr(dladm_status_t
, const char *, ...);
85 static void warn(const char *, ...);
87 /* callback functions for printing output */
88 static ofmt_cb_t print_default_cb
, print_flow_stats_cb
;
89 static void flowstat_ofmt_check(ofmt_status_t
, boolean_t
, ofmt_handle_t
);
91 #define NULL_OFMT {NULL, 0, 0, NULL}
94 * structures for flowstat (printing live statistics)
104 } flow_s_field_index_t
;
106 static ofmt_field_t flow_s_fields
[] = {
107 /* name, field width, index, callback */
108 { "FLOW", 15, FLOW_S_FLOW
, print_flow_stats_cb
},
109 { "IPKTS", 8, FLOW_S_IPKTS
, print_flow_stats_cb
},
110 { "RBYTES", 8, FLOW_S_RBYTES
, print_flow_stats_cb
},
111 { "IERRS", 8, FLOW_S_IERRORS
, print_flow_stats_cb
},
112 { "OPKTS", 8, FLOW_S_OPKTS
, print_flow_stats_cb
},
113 { "OBYTES", 8, FLOW_S_OBYTES
, print_flow_stats_cb
},
114 { "OERRS", 8, FLOW_S_OERRORS
, print_flow_stats_cb
},
118 typedef struct flow_args_s
{
120 flow_stat_t
*flow_s_stat
;
122 boolean_t flow_s_parsable
;
126 * structures for 'flowstat -h'
128 typedef struct history_fields_buf_s
{
129 char history_flow
[12];
130 char history_duration
[10];
131 char history_ipackets
[9];
132 char history_rbytes
[10];
133 char history_opackets
[9];
134 char history_obytes
[10];
135 char history_bandwidth
[14];
136 } history_fields_buf_t
;
138 static ofmt_field_t history_fields
[] = {
139 /* name, field width, offset */
141 offsetof(history_fields_buf_t
, history_flow
), print_default_cb
},
143 offsetof(history_fields_buf_t
, history_duration
), print_default_cb
},
145 offsetof(history_fields_buf_t
, history_ipackets
), print_default_cb
},
147 offsetof(history_fields_buf_t
, history_rbytes
), print_default_cb
},
149 offsetof(history_fields_buf_t
, history_opackets
), print_default_cb
},
151 offsetof(history_fields_buf_t
, history_obytes
), print_default_cb
},
153 offsetof(history_fields_buf_t
, history_bandwidth
), print_default_cb
},
157 typedef struct history_l_fields_buf_s
{
158 char history_l_flow
[12];
159 char history_l_stime
[13];
160 char history_l_etime
[13];
161 char history_l_rbytes
[8];
162 char history_l_obytes
[8];
163 char history_l_bandwidth
[14];
164 } history_l_fields_buf_t
;
166 static ofmt_field_t history_l_fields
[] = {
167 /* name, field width, offset */
169 offsetof(history_l_fields_buf_t
, history_l_flow
), print_default_cb
},
171 offsetof(history_l_fields_buf_t
, history_l_stime
), print_default_cb
},
173 offsetof(history_l_fields_buf_t
, history_l_etime
), print_default_cb
},
175 offsetof(history_l_fields_buf_t
, history_l_rbytes
), print_default_cb
},
177 offsetof(history_l_fields_buf_t
, history_l_obytes
), print_default_cb
},
179 offsetof(history_l_fields_buf_t
, history_l_bandwidth
),
184 static char *progname
;
187 * Handle to libdladm. Opened in main() before the sub-command
188 * specific function is called.
190 static dladm_handle_t handle
= NULL
;
192 const char *usage_ermsg
= "flowstat [-r | -t] [-i interval] "
194 " flowstat [-A] [-i interval] [-p] [ -o field[,...]]\n"
195 " [-u R|K|M|G|T|P] [-l link] [flow]\n"
196 " flowstat -h [-a] [-d] [-F format]"
197 " [-s <DD/MM/YYYY,HH:MM:SS>]\n"
198 " [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> "
204 (void) fprintf(stderr
, "%s\n", gettext(usage_ermsg
));
206 /* close dladm handle if it was opened */
214 flowstat_unit(char *oarg
, char *unit
)
216 if ((strcmp(oarg
, "R") == 0) || (strcmp(oarg
, "K") == 0) ||
217 (strcmp(oarg
, "M") == 0) || (strcmp(oarg
, "G") == 0) ||
218 (strcmp(oarg
, "T") == 0) || (strcmp(oarg
, "P") == 0)) {
227 map_to_units(char *buf
, uint_t bufsize
, double num
, char unit
,
231 (void) snprintf(buf
, bufsize
, "%.0lf", num
);
238 for (index
= 0; (int)(num
/1000) != 0; index
++, num
/= 1000)
258 /* Largest unit supported */
266 /* Already raw numbers */
276 num
/= (1000*1000*1000);
279 num
/= (1000.0*1000.0*1000.0*1000.0);
282 /* Largest unit supported */
284 num
/= (1000.0*1000.0*1000.0*1000.0*1000.0);
290 (void) snprintf(buf
, bufsize
, " %7.0lf%c", num
, unit
);
292 (void) snprintf(buf
, bufsize
, " %6.2lf%c", num
, unit
);
296 get_flow_prev_stat(const char *flowname
, void *arg
)
298 show_flow_state_t
*state
= arg
;
299 flow_chain_t
*flow_curr
= NULL
;
301 /* Scan prev flowname list and look for entry matching this entry */
302 for (flow_curr
= state
->fs_flowchain
; flow_curr
;
303 flow_curr
= flow_curr
->fc_next
) {
304 if (strcmp(flow_curr
->fc_flowname
, flowname
) == 0)
308 /* New flow, add it */
309 if (flow_curr
== NULL
) {
310 flow_curr
= (flow_chain_t
*)malloc(sizeof (flow_chain_t
));
311 if (flow_curr
== NULL
)
313 (void) strncpy(flow_curr
->fc_flowname
, flowname
,
315 flow_curr
->fc_stat
= NULL
;
316 flow_curr
->fc_next
= state
->fs_flowchain
;
317 state
->fs_flowchain
= flow_curr
;
324 * Number of flows may change while flowstat -i is executing.
325 * Free memory allocated for flows that are no longer there.
326 * Prepare for next iteration by marking visited = false for
327 * existing stat entries.
330 cleanup_removed_flows(show_flow_state_t
*state
)
334 flow_chain_t
*tofree
;
336 /* Delete all nodes from the list that have fc_visited marked false */
337 fcurr
= state
->fs_flowchain
;
338 while (fcurr
!= NULL
) {
339 if (fcurr
->fc_visited
) {
340 fcurr
->fc_visited
= B_FALSE
;
342 fcurr
= fcurr
->fc_next
;
346 /* Is it head of the list? */
347 if (fcurr
== state
->fs_flowchain
)
348 state
->fs_flowchain
= fcurr
->fc_next
;
350 fprev
->fc_next
= fcurr
->fc_next
;
352 /* fprev remains the same */
354 fcurr
= fcurr
->fc_next
;
356 /* Free stats memory for the removed flow */
357 dladm_flow_stat_free(tofree
->fc_stat
);
363 print_flow_stats_cb(ofmt_arg_t
*of_arg
, char *buf
, uint_t bufsize
)
365 flow_args_t
*fargs
= of_arg
->ofmt_cbarg
;
366 flow_stat_t
*diff_stats
= fargs
->flow_s_stat
;
367 char unit
= fargs
->flow_s_unit
;
368 boolean_t parsable
= fargs
->flow_s_parsable
;
370 switch (of_arg
->ofmt_id
) {
372 (void) snprintf(buf
, bufsize
, "%s", fargs
->flow_s_flow
);
375 map_to_units(buf
, bufsize
, diff_stats
->fl_ipackets
, unit
,
379 map_to_units(buf
, bufsize
, diff_stats
->fl_rbytes
, unit
,
383 map_to_units(buf
, bufsize
, diff_stats
->fl_ierrors
, unit
,
387 map_to_units(buf
, bufsize
, diff_stats
->fl_opackets
, unit
,
391 map_to_units(buf
, bufsize
, diff_stats
->fl_obytes
, unit
,
395 map_to_units(buf
, bufsize
, diff_stats
->fl_oerrors
, unit
,
399 die("invalid input");
407 query_flow_stats(dladm_handle_t handle
, dladm_flow_attr_t
*attr
, void *arg
)
409 show_flow_state_t
*state
= arg
;
410 flow_chain_t
*flow_node
;
411 flow_stat_t
*curr_stat
;
412 flow_stat_t
*prev_stat
;
413 flow_stat_t
*diff_stat
;
414 char *flowname
= attr
->fa_flowname
;
417 /* Get previous stats for the flow */
418 flow_node
= get_flow_prev_stat(flowname
, arg
);
419 if (flow_node
== NULL
)
422 flow_node
->fc_visited
= B_TRUE
;
423 prev_stat
= flow_node
->fc_stat
;
425 /* Query library for current stats */
426 curr_stat
= dladm_flow_stat_query(flowname
);
427 if (curr_stat
== NULL
)
430 /* current stats - prev iteration stats */
431 diff_stat
= dladm_flow_stat_diff(curr_stat
, prev_stat
);
433 /* Free prev stats */
434 dladm_flow_stat_free(prev_stat
);
436 /* Prev <- curr stats */
437 flow_node
->fc_stat
= curr_stat
;
439 if (diff_stat
== NULL
)
443 fargs
.flow_s_flow
= flowname
;
444 fargs
.flow_s_stat
= diff_stat
;
445 fargs
.flow_s_unit
= state
->fs_unit
;
446 fargs
.flow_s_parsable
= state
->fs_parsable
;
447 ofmt_print(state
->fs_ofmt
, &fargs
);
449 /* Free diff stats */
450 dladm_flow_stat_free(diff_stat
);
452 return (DLADM_WALK_CONTINUE
);
456 * Wrapper of dladm_walk_flow(query_flow_stats,...) to make it usable for
457 * dladm_walk_datalink_id(). Used for showing flow stats for
458 * all flows on all links.
461 query_link_flow_stats(dladm_handle_t dh
, datalink_id_t linkid
, void * arg
)
463 if (dladm_walk_flow(query_flow_stats
, dh
, linkid
, arg
, B_FALSE
)
465 return (DLADM_WALK_CONTINUE
);
467 return (DLADM_WALK_TERMINATE
);
471 print_all_stats(name_value_stat_entry_t
*stat_entry
)
473 name_value_stat_t
*curr_stat
;
475 printf("%s\n", stat_entry
->nve_header
);
477 for (curr_stat
= stat_entry
->nve_stats
; curr_stat
!= NULL
;
478 curr_stat
= curr_stat
->nv_nextstat
) {
479 printf("\t%15s", curr_stat
->nv_statname
);
480 printf("\t%15llu\n", curr_stat
->nv_statval
);
486 dump_one_flow_stats(dladm_handle_t handle
, dladm_flow_attr_t
*attr
, void *arg
)
488 char *flowname
= attr
->fa_flowname
;
491 stat
= dladm_flow_stat_query_all(flowname
);
494 print_all_stats(stat
);
495 dladm_flow_stat_query_all_free(stat
);
498 return (DLADM_WALK_CONTINUE
);
502 * Wrapper of dladm_walk_flow(query_flow_stats,...) to make it usable for
503 * dladm_walk_datalink_id(). Used for showing flow stats for
504 * all flows on all links.
507 dump_link_flow_stats(dladm_handle_t dh
, datalink_id_t linkid
, void * arg
)
509 if (dladm_walk_flow(dump_one_flow_stats
, dh
, linkid
, arg
, B_FALSE
)
511 return (DLADM_WALK_CONTINUE
);
513 return (DLADM_WALK_TERMINATE
);
517 dump_all_flow_stats(dladm_flow_attr_t
*attrp
, void *arg
, datalink_id_t linkid
,
520 /* Show stats for named flow */
522 (void) dump_one_flow_stats(handle
, attrp
, arg
);
524 /* Show stats for flows on one link */
525 } else if (linkid
!= DATALINK_INVALID_LINKID
) {
526 (void) dladm_walk_flow(dump_one_flow_stats
, handle
, linkid
,
529 /* Show stats for all flows on all links */
531 (void) dladm_walk_datalink_id(dump_link_flow_stats
,
532 handle
, arg
, DATALINK_CLASS_ALL
,
533 DATALINK_ANY_MEDIATYPE
, DLADM_OPT_ACTIVE
);
538 main(int argc
, char *argv
[])
540 dladm_status_t status
;
542 boolean_t r_arg
= B_FALSE
;
543 boolean_t t_arg
= B_FALSE
;
544 boolean_t p_arg
= B_FALSE
;
545 boolean_t i_arg
= B_FALSE
;
546 boolean_t o_arg
= B_FALSE
;
547 boolean_t u_arg
= B_FALSE
;
548 boolean_t A_arg
= B_FALSE
;
549 boolean_t flow_arg
= B_FALSE
;
550 datalink_id_t linkid
= DATALINK_ALL_LINKID
;
551 char linkname
[MAXLINKNAMELEN
];
552 char flowname
[MAXFLOWNAMELEN
];
553 uint32_t interval
= 0;
555 show_flow_state_t state
;
556 char *fields_str
= NULL
;
557 char *o_fields_str
= NULL
;
559 char *total_stat_fields
=
560 "flow,ipkts,rbytes,ierrs,opkts,obytes,oerrs";
561 char *rx_stat_fields
=
562 "flow,ipkts,rbytes,ierrs";
563 char *tx_stat_fields
=
564 "flow,opkts,obytes,oerrs";
568 uint_t ofmtflags
= OFMT_RIGHTJUST
;
570 dladm_flow_attr_t attr
;
572 (void) setlocale(LC_ALL
, "");
573 #if !defined(TEXT_DOMAIN)
574 #define TEXT_DOMAIN "SYS_TEST"
576 (void) textdomain(TEXT_DOMAIN
);
580 /* Open the libdladm handle */
581 if ((status
= dladm_open(&handle
)) != DLADM_STATUS_OK
)
582 die_dlerr(status
, "could not open /dev/dld");
584 bzero(&state
, sizeof (state
));
587 while ((option
= getopt_long(argc
, argv
, ":rtApi:o:u:l:h",
588 NULL
, NULL
)) != -1) {
619 if (!dladm_str2interval(optarg
, &interval
))
620 die("invalid interval value '%s'", optarg
);
624 o_fields_str
= optarg
;
631 if (!flowstat_unit(optarg
, &unit
))
632 die("invalid unit value '%s',"
633 "unit must be R|K|M|G|T|P", optarg
);
636 if (strlcpy(linkname
, optarg
, MAXLINKNAMELEN
)
638 die("link name too long\n");
639 if (dladm_name2info(handle
, linkname
, &linkid
, NULL
,
640 NULL
, NULL
) != DLADM_STATUS_OK
)
641 die("invalid link '%s'", linkname
);
644 if (r_arg
|| t_arg
|| p_arg
|| o_arg
|| u_arg
||
646 die("the option -h is not compatible with "
647 "-r, -t, -p, -o, -u, -i, -A");
649 do_show_history(argc
, argv
);
653 die_opterr(optopt
, option
, usage_ermsg
);
659 die("the option -t and -r are not compatible");
662 die("the option -u and -p are not compatible");
665 die("-p requires -o");
667 if (p_arg
&& strcasecmp(o_fields_str
, "all") == 0)
668 die("\"-o all\" is invalid with -p");
671 (r_arg
|| t_arg
|| p_arg
|| o_arg
|| u_arg
|| i_arg
))
672 die("the option -A is not compatible with "
673 "-r, -t, -p, -o, -u, -i");
675 /* get flow name (optional last argument) */
676 if (optind
== (argc
-1)) {
677 if (strlcpy(flowname
, argv
[optind
], MAXFLOWNAMELEN
)
679 die("flow name too long");
681 } else if (optind
!= argc
) {
686 dladm_flow_info(handle
, flowname
, &attr
) != DLADM_STATUS_OK
)
687 die("invalid flow %s", flowname
);
690 dump_all_flow_stats(&attr
, &state
, linkid
, flow_arg
);
694 state
.fs_unit
= unit
;
695 state
.fs_parsable
= p_arg
;
697 if (state
.fs_parsable
)
698 ofmtflags
|= OFMT_PARSABLE
;
701 fields_str
= rx_stat_fields
;
703 fields_str
= tx_stat_fields
;
705 fields_str
= total_stat_fields
;
708 fields_str
= (strcasecmp(o_fields_str
, "all") == 0) ?
709 fields_str
: o_fields_str
;
712 oferr
= ofmt_open(fields_str
, flow_s_fields
, ofmtflags
, 0, &ofmt
);
713 flowstat_ofmt_check(oferr
, state
.fs_parsable
, ofmt
);
714 state
.fs_ofmt
= ofmt
;
717 /* Show stats for named flow */
719 (void) query_flow_stats(handle
, &attr
, &state
);
721 /* Show stats for flows on one link */
722 } else if (linkid
!= DATALINK_INVALID_LINKID
) {
723 (void) dladm_walk_flow(query_flow_stats
, handle
, linkid
,
726 /* Show stats for all flows on all links */
728 (void) dladm_walk_datalink_id(query_link_flow_stats
,
729 handle
, &state
, DATALINK_CLASS_ALL
,
730 DATALINK_ANY_MEDIATYPE
, DLADM_OPT_ACTIVE
);
736 (void) fflush(stdout
);
737 cleanup_removed_flows(&state
);
738 (void) sleep(interval
);
748 show_history_date(dladm_usage_t
*history
, void *arg
)
750 show_history_state_t
*state
= (show_history_state_t
*)arg
;
753 dladm_flow_attr_t attr
;
754 dladm_status_t status
;
757 * Only show historical information for existing flows unless '-a'
760 if (!state
->us_showall
&& ((status
= dladm_flow_info(handle
,
761 history
->du_name
, &attr
)) != DLADM_STATUS_OK
)) {
765 stime
= history
->du_stime
;
766 (void) strftime(timebuf
, sizeof (timebuf
), "%m/%d/%Y",
768 (void) printf("%s\n", timebuf
);
770 return (DLADM_STATUS_OK
);
774 show_history_time(dladm_usage_t
*history
, void *arg
)
776 show_history_state_t
*state
= (show_history_state_t
*)arg
;
777 char buf
[DLADM_STRSIZE
];
778 history_l_fields_buf_t ubuf
;
781 dladm_flow_attr_t attr
;
782 dladm_status_t status
;
785 * Only show historical information for existing flows unless '-a'
788 if (!state
->us_showall
&& ((status
= dladm_flow_info(handle
,
789 history
->du_name
, &attr
)) != DLADM_STATUS_OK
)) {
793 if (state
->us_plot
) {
794 if (!state
->us_printheader
) {
795 if (state
->us_first
) {
796 (void) printf("# Time");
797 state
->us_first
= B_FALSE
;
799 (void) printf(" %s", history
->du_name
);
800 if (history
->du_last
) {
802 state
->us_first
= B_TRUE
;
803 state
->us_printheader
= B_TRUE
;
806 if (state
->us_first
) {
807 time
= history
->du_etime
;
808 (void) strftime(buf
, sizeof (buf
), "%T",
810 state
->us_first
= B_FALSE
;
811 (void) printf("%s", buf
);
813 bw
= (double)history
->du_bandwidth
/1000;
814 (void) printf(" %.2f", bw
);
815 if (history
->du_last
) {
817 state
->us_first
= B_TRUE
;
820 return (DLADM_STATUS_OK
);
823 bzero(&ubuf
, sizeof (ubuf
));
825 (void) snprintf(ubuf
.history_l_flow
, sizeof (ubuf
.history_l_flow
), "%s",
827 time
= history
->du_stime
;
828 (void) strftime(buf
, sizeof (buf
), "%T", localtime(&time
));
829 (void) snprintf(ubuf
.history_l_stime
, sizeof (ubuf
.history_l_stime
),
831 time
= history
->du_etime
;
832 (void) strftime(buf
, sizeof (buf
), "%T", localtime(&time
));
833 (void) snprintf(ubuf
.history_l_etime
, sizeof (ubuf
.history_l_etime
),
835 (void) snprintf(ubuf
.history_l_rbytes
, sizeof (ubuf
.history_l_rbytes
),
836 "%llu", history
->du_rbytes
);
837 (void) snprintf(ubuf
.history_l_obytes
, sizeof (ubuf
.history_l_obytes
),
838 "%llu", history
->du_obytes
);
839 (void) snprintf(ubuf
.history_l_bandwidth
,
840 sizeof (ubuf
.history_l_bandwidth
), "%s Mbps",
841 dladm_bw2str(history
->du_bandwidth
, buf
));
843 ofmt_print(state
->us_ofmt
, (void *)&ubuf
);
844 return (DLADM_STATUS_OK
);
848 show_history_res(dladm_usage_t
*history
, void *arg
)
850 show_history_state_t
*state
= (show_history_state_t
*)arg
;
851 char buf
[DLADM_STRSIZE
];
852 history_fields_buf_t ubuf
;
853 dladm_flow_attr_t attr
;
854 dladm_status_t status
;
857 * Only show historical information for existing flows unless '-a'
860 if (!state
->us_showall
&& ((status
= dladm_flow_info(handle
,
861 history
->du_name
, &attr
)) != DLADM_STATUS_OK
)) {
865 bzero(&ubuf
, sizeof (ubuf
));
867 (void) snprintf(ubuf
.history_flow
, sizeof (ubuf
.history_flow
), "%s",
869 (void) snprintf(ubuf
.history_duration
, sizeof (ubuf
.history_duration
),
870 "%llu", history
->du_duration
);
871 (void) snprintf(ubuf
.history_ipackets
, sizeof (ubuf
.history_ipackets
),
872 "%llu", history
->du_ipackets
);
873 (void) snprintf(ubuf
.history_rbytes
, sizeof (ubuf
.history_rbytes
),
874 "%llu", history
->du_rbytes
);
875 (void) snprintf(ubuf
.history_opackets
, sizeof (ubuf
.history_opackets
),
876 "%llu", history
->du_opackets
);
877 (void) snprintf(ubuf
.history_obytes
, sizeof (ubuf
.history_obytes
),
878 "%llu", history
->du_obytes
);
879 (void) snprintf(ubuf
.history_bandwidth
, sizeof (ubuf
.history_bandwidth
),
880 "%s Mbps", dladm_bw2str(history
->du_bandwidth
, buf
));
882 ofmt_print(state
->us_ofmt
, (void *)&ubuf
);
884 return (DLADM_STATUS_OK
);
888 valid_formatspec(char *formatspec_str
)
890 return (strcmp(formatspec_str
, "gnuplot") == 0);
895 do_show_history(int argc
, char *argv
[])
899 dladm_status_t status
;
900 boolean_t d_arg
= B_FALSE
;
903 char *resource
= NULL
;
904 show_history_state_t state
;
905 boolean_t o_arg
= B_FALSE
;
906 boolean_t F_arg
= B_FALSE
;
907 char *fields_str
= NULL
;
908 char *formatspec_str
= NULL
;
910 "flow,duration,ipackets,rbytes,opackets,obytes,bandwidth";
912 "flow,start,end,rbytes,obytes,bandwidth";
915 uint_t ofmtflags
= 0;
917 bzero(&state
, sizeof (show_history_state_t
));
918 state
.us_parsable
= B_FALSE
;
919 state
.us_printheader
= B_FALSE
;
920 state
.us_plot
= B_FALSE
;
921 state
.us_first
= B_TRUE
;
923 while ((opt
= getopt(argc
, argv
, "das:e:o:f:F:")) != -1) {
929 state
.us_showall
= B_TRUE
;
945 state
.us_plot
= F_arg
= B_TRUE
;
946 formatspec_str
= optarg
;
949 die_opterr(optopt
, opt
, usage_ermsg
);
954 die("-h requires a file");
956 if (optind
== (argc
-1)) {
957 dladm_flow_attr_t attr
;
959 resource
= argv
[optind
];
960 if (!state
.us_showall
&&
961 dladm_flow_info(handle
, resource
, &attr
) !=
963 die("invalid flow: '%s'", resource
);
967 if (state
.us_parsable
)
968 ofmtflags
|= OFMT_PARSABLE
;
969 if (resource
== NULL
&& stime
== NULL
&& etime
== NULL
) {
970 if (!o_arg
|| (o_arg
&& strcasecmp(fields_str
, "all") == 0))
971 fields_str
= all_fields
;
972 oferr
= ofmt_open(fields_str
, history_fields
, ofmtflags
,
975 if (!o_arg
|| (o_arg
&& strcasecmp(fields_str
, "all") == 0))
976 fields_str
= all_l_fields
;
977 oferr
= ofmt_open(fields_str
, history_l_fields
, ofmtflags
,
981 flowstat_ofmt_check(oferr
, state
.us_parsable
, ofmt
);
982 state
.us_ofmt
= ofmt
;
985 die("incompatible -d and -F options");
987 if (F_arg
&& !valid_formatspec(formatspec_str
))
988 die("Format specifier %s not supported", formatspec_str
);
991 /* Print log dates */
992 status
= dladm_usage_dates(show_history_date
,
993 DLADM_LOGTYPE_FLOW
, file
, resource
, &state
);
994 } else if (resource
== NULL
&& stime
== NULL
&& etime
== NULL
&&
997 status
= dladm_usage_summary(show_history_res
,
998 DLADM_LOGTYPE_FLOW
, file
, &state
);
999 } else if (resource
!= NULL
) {
1000 /* Print log entries for named resource */
1001 status
= dladm_walk_usage_res(show_history_time
,
1002 DLADM_LOGTYPE_FLOW
, file
, resource
, stime
, etime
, &state
);
1004 /* Print time and information for each flow */
1005 status
= dladm_walk_usage_time(show_history_time
,
1006 DLADM_LOGTYPE_FLOW
, file
, stime
, etime
, &state
);
1010 if (status
!= DLADM_STATUS_OK
)
1011 die_dlerr(status
, "-h");
1012 dladm_close(handle
);
1016 warn(const char *format
, ...)
1020 format
= gettext(format
);
1021 (void) fprintf(stderr
, "%s: warning: ", progname
);
1023 va_start(alist
, format
);
1024 (void) vfprintf(stderr
, format
, alist
);
1027 (void) putc('\n', stderr
);
1032 die(const char *format
, ...)
1036 format
= gettext(format
);
1037 (void) fprintf(stderr
, "%s: ", progname
);
1039 va_start(alist
, format
);
1040 (void) vfprintf(stderr
, format
, alist
);
1043 (void) putc('\n', stderr
);
1045 /* close dladm handle if it was opened */
1047 dladm_close(handle
);
1055 die("the option -%c cannot be specified more than once", opt
);
1059 die_opterr(int opt
, int opterr
, const char *usage
)
1063 die("option '-%c' requires a value\nusage: %s", opt
,
1068 die("unrecognized option '-%c'\nusage: %s", opt
,
1076 die_dlerr(dladm_status_t err
, const char *format
, ...)
1079 char errmsg
[DLADM_STRSIZE
];
1081 format
= gettext(format
);
1082 (void) fprintf(stderr
, "%s: ", progname
);
1084 va_start(alist
, format
);
1085 (void) vfprintf(stderr
, format
, alist
);
1087 (void) fprintf(stderr
, ": %s\n", dladm_status2str(err
, errmsg
));
1089 /* close dladm handle if it was opened */
1091 dladm_close(handle
);
1098 * default output callback function that, when invoked from dladm_print_output,
1099 * prints string which is offset by of_arg->ofmt_id within buf.
1102 print_default_cb(ofmt_arg_t
*of_arg
, char *buf
, uint_t bufsize
)
1106 value
= (char *)of_arg
->ofmt_cbarg
+ of_arg
->ofmt_id
;
1107 (void) strlcpy(buf
, value
, bufsize
);
1112 flowstat_ofmt_check(ofmt_status_t oferr
, boolean_t parsable
,
1115 char buf
[OFMT_BUFSIZE
];
1117 if (oferr
== OFMT_SUCCESS
)
1119 (void) ofmt_strerror(ofmt
, oferr
, buf
, sizeof (buf
));
1121 * All errors are considered fatal in parsable mode.
1122 * NOMEM errors are always fatal, regardless of mode.
1123 * For other errors, we print diagnostics in human-readable
1124 * mode and processs what we can.
1126 if (parsable
|| oferr
== OFMT_ENOFIELDS
) {