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 flow_chain_s
{
58 char fc_flowname
[MAXFLOWNAMELEN
];
61 struct flow_chain_s
*fc_next
;
64 typedef struct show_flow_state
{
65 flow_chain_t
*fs_flowchain
;
66 ofmt_handle_t fs_ofmt
;
68 boolean_t fs_parsable
;
71 typedef struct show_history_state_s
{
73 boolean_t us_parsable
;
74 boolean_t us_printheader
;
77 ofmt_handle_t us_ofmt
;
78 } show_history_state_t
;
80 static void do_show_history(int, char **);
82 static int query_flow_stats(dladm_handle_t
, dladm_flow_attr_t
*, void *);
83 static int query_link_flow_stats(dladm_handle_t
, datalink_id_t
, void *);
85 static void die(const char *, ...);
86 static void die_optdup(int);
87 static void die_opterr(int, int, const char *);
88 static void die_dlerr(dladm_status_t
, const char *, ...);
89 static void warn(const char *, ...);
91 /* callback functions for printing output */
92 static ofmt_cb_t print_default_cb
, print_flow_stats_cb
;
94 #define NULL_OFMT {NULL, 0, 0, NULL}
97 * structures for flowstat (printing live statistics)
107 } flow_s_field_index_t
;
109 static ofmt_field_t flow_s_fields
[] = {
110 /* name, field width, index, callback */
111 { "FLOW", 15, FLOW_S_FLOW
, print_flow_stats_cb
},
112 { "IPKTS", 8, FLOW_S_IPKTS
, print_flow_stats_cb
},
113 { "RBYTES", 8, FLOW_S_RBYTES
, print_flow_stats_cb
},
114 { "IERRS", 8, FLOW_S_IERRORS
, print_flow_stats_cb
},
115 { "OPKTS", 8, FLOW_S_OPKTS
, print_flow_stats_cb
},
116 { "OBYTES", 8, FLOW_S_OBYTES
, print_flow_stats_cb
},
117 { "OERRS", 8, FLOW_S_OERRORS
, print_flow_stats_cb
},
121 typedef struct flow_args_s
{
123 flow_stat_t
*flow_s_stat
;
125 boolean_t flow_s_parsable
;
129 * structures for 'flowstat -h'
131 typedef struct history_fields_buf_s
{
132 char history_flow
[12];
133 char history_duration
[10];
134 char history_ipackets
[9];
135 char history_rbytes
[10];
136 char history_opackets
[9];
137 char history_obytes
[10];
138 char history_bandwidth
[14];
139 } history_fields_buf_t
;
141 static ofmt_field_t history_fields
[] = {
142 /* name, field width, offset */
144 offsetof(history_fields_buf_t
, history_flow
), print_default_cb
},
146 offsetof(history_fields_buf_t
, history_duration
), print_default_cb
},
148 offsetof(history_fields_buf_t
, history_ipackets
), print_default_cb
},
150 offsetof(history_fields_buf_t
, history_rbytes
), print_default_cb
},
152 offsetof(history_fields_buf_t
, history_opackets
), print_default_cb
},
154 offsetof(history_fields_buf_t
, history_obytes
), print_default_cb
},
156 offsetof(history_fields_buf_t
, history_bandwidth
), print_default_cb
},
160 typedef struct history_l_fields_buf_s
{
161 char history_l_flow
[12];
162 char history_l_stime
[13];
163 char history_l_etime
[13];
164 char history_l_rbytes
[8];
165 char history_l_obytes
[8];
166 char history_l_bandwidth
[14];
167 } history_l_fields_buf_t
;
169 static ofmt_field_t history_l_fields
[] = {
170 /* name, field width, offset */
172 offsetof(history_l_fields_buf_t
, history_l_flow
), print_default_cb
},
174 offsetof(history_l_fields_buf_t
, history_l_stime
), print_default_cb
},
176 offsetof(history_l_fields_buf_t
, history_l_etime
), print_default_cb
},
178 offsetof(history_l_fields_buf_t
, history_l_rbytes
), print_default_cb
},
180 offsetof(history_l_fields_buf_t
, history_l_obytes
), print_default_cb
},
182 offsetof(history_l_fields_buf_t
, history_l_bandwidth
),
187 static char *progname
;
190 * Handle to libdladm. Opened in main() before the sub-command
191 * specific function is called.
193 static dladm_handle_t handle
= NULL
;
195 const char *usage_ermsg
= "flowstat [-r | -t] [-i interval] "
197 " flowstat [-A] [-i interval] [-p] [ -o field[,...]]\n"
198 " [-u R|K|M|G|T|P] [-l link] [flow]\n"
199 " flowstat -h [-a] [-d] [-F format]"
200 " [-s <DD/MM/YYYY,HH:MM:SS>]\n"
201 " [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> "
207 (void) fprintf(stderr
, "%s\n", gettext(usage_ermsg
));
209 /* close dladm handle if it was opened */
217 flowstat_unit(char *oarg
, char *unit
)
219 if ((strcmp(oarg
, "R") == 0) || (strcmp(oarg
, "K") == 0) ||
220 (strcmp(oarg
, "M") == 0) || (strcmp(oarg
, "G") == 0) ||
221 (strcmp(oarg
, "T") == 0) || (strcmp(oarg
, "P") == 0)) {
230 map_to_units(char *buf
, uint_t bufsize
, double num
, char unit
,
234 (void) snprintf(buf
, bufsize
, "%.0lf", num
);
241 for (index
= 0; (int)(num
/1000) != 0; index
++, num
/= 1000)
261 /* Largest unit supported */
269 /* Already raw numbers */
279 num
/= (1000*1000*1000);
282 num
/= (1000.0*1000.0*1000.0*1000.0);
285 /* Largest unit supported */
287 num
/= (1000.0*1000.0*1000.0*1000.0*1000.0);
293 (void) snprintf(buf
, bufsize
, " %7.0lf%c", num
, unit
);
295 (void) snprintf(buf
, bufsize
, " %6.2lf%c", num
, unit
);
299 get_flow_prev_stat(const char *flowname
, void *arg
)
301 show_flow_state_t
*state
= arg
;
302 flow_chain_t
*flow_curr
= NULL
;
304 /* Scan prev flowname list and look for entry matching this entry */
305 for (flow_curr
= state
->fs_flowchain
; flow_curr
;
306 flow_curr
= flow_curr
->fc_next
) {
307 if (strcmp(flow_curr
->fc_flowname
, flowname
) == 0)
311 /* New flow, add it */
312 if (flow_curr
== NULL
) {
313 flow_curr
= (flow_chain_t
*)malloc(sizeof (flow_chain_t
));
314 if (flow_curr
== NULL
)
316 (void) strncpy(flow_curr
->fc_flowname
, flowname
,
318 flow_curr
->fc_stat
= NULL
;
319 flow_curr
->fc_next
= state
->fs_flowchain
;
320 state
->fs_flowchain
= flow_curr
;
327 * Number of flows may change while flowstat -i is executing.
328 * Free memory allocated for flows that are no longer there.
329 * Prepare for next iteration by marking visited = false for
330 * existing stat entries.
333 cleanup_removed_flows(show_flow_state_t
*state
)
337 flow_chain_t
*tofree
;
339 /* Delete all nodes from the list that have fc_visited marked false */
340 fcurr
= state
->fs_flowchain
;
341 while (fcurr
!= NULL
) {
342 if (fcurr
->fc_visited
) {
343 fcurr
->fc_visited
= B_FALSE
;
345 fcurr
= fcurr
->fc_next
;
349 /* Is it head of the list? */
350 if (fcurr
== state
->fs_flowchain
)
351 state
->fs_flowchain
= fcurr
->fc_next
;
353 fprev
->fc_next
= fcurr
->fc_next
;
355 /* fprev remains the same */
357 fcurr
= fcurr
->fc_next
;
359 /* Free stats memory for the removed flow */
360 dladm_flow_stat_free(tofree
->fc_stat
);
366 print_flow_stats_cb(ofmt_arg_t
*of_arg
, char *buf
, uint_t bufsize
)
368 flow_args_t
*fargs
= of_arg
->ofmt_cbarg
;
369 flow_stat_t
*diff_stats
= fargs
->flow_s_stat
;
370 char unit
= fargs
->flow_s_unit
;
371 boolean_t parsable
= fargs
->flow_s_parsable
;
373 switch (of_arg
->ofmt_id
) {
375 (void) snprintf(buf
, bufsize
, "%s", fargs
->flow_s_flow
);
378 map_to_units(buf
, bufsize
, diff_stats
->fl_ipackets
, unit
,
382 map_to_units(buf
, bufsize
, diff_stats
->fl_rbytes
, unit
,
386 map_to_units(buf
, bufsize
, diff_stats
->fl_ierrors
, unit
,
390 map_to_units(buf
, bufsize
, diff_stats
->fl_opackets
, unit
,
394 map_to_units(buf
, bufsize
, diff_stats
->fl_obytes
, unit
,
398 map_to_units(buf
, bufsize
, diff_stats
->fl_oerrors
, unit
,
402 die("invalid input");
410 query_flow_stats(dladm_handle_t handle
, dladm_flow_attr_t
*attr
, void *arg
)
412 show_flow_state_t
*state
= arg
;
413 flow_chain_t
*flow_node
;
414 flow_stat_t
*curr_stat
;
415 flow_stat_t
*prev_stat
;
416 flow_stat_t
*diff_stat
;
417 char *flowname
= attr
->fa_flowname
;
420 /* Get previous stats for the flow */
421 flow_node
= get_flow_prev_stat(flowname
, arg
);
422 if (flow_node
== NULL
)
425 flow_node
->fc_visited
= B_TRUE
;
426 prev_stat
= flow_node
->fc_stat
;
428 /* Query library for current stats */
429 curr_stat
= dladm_flow_stat_query(flowname
);
430 if (curr_stat
== NULL
)
433 /* current stats - prev iteration stats */
434 diff_stat
= dladm_flow_stat_diff(curr_stat
, prev_stat
);
436 /* Free prev stats */
437 dladm_flow_stat_free(prev_stat
);
439 /* Prev <- curr stats */
440 flow_node
->fc_stat
= curr_stat
;
442 if (diff_stat
== NULL
)
446 fargs
.flow_s_flow
= flowname
;
447 fargs
.flow_s_stat
= diff_stat
;
448 fargs
.flow_s_unit
= state
->fs_unit
;
449 fargs
.flow_s_parsable
= state
->fs_parsable
;
450 ofmt_print(state
->fs_ofmt
, &fargs
);
452 /* Free diff stats */
453 dladm_flow_stat_free(diff_stat
);
455 return (DLADM_WALK_CONTINUE
);
459 * Wrapper of dladm_walk_flow(query_flow_stats,...) to make it usable for
460 * dladm_walk_datalink_id(). Used for showing flow stats for
461 * all flows on all links.
464 query_link_flow_stats(dladm_handle_t dh
, datalink_id_t linkid
, void * arg
)
466 if (dladm_walk_flow(query_flow_stats
, dh
, linkid
, arg
, B_FALSE
)
468 return (DLADM_WALK_CONTINUE
);
470 return (DLADM_WALK_TERMINATE
);
474 print_all_stats(name_value_stat_entry_t
*stat_entry
)
476 name_value_stat_t
*curr_stat
;
478 printf("%s\n", stat_entry
->nve_header
);
480 for (curr_stat
= stat_entry
->nve_stats
; curr_stat
!= NULL
;
481 curr_stat
= curr_stat
->nv_nextstat
) {
482 printf("\t%15s", curr_stat
->nv_statname
);
483 printf("\t%15llu\n", curr_stat
->nv_statval
);
489 dump_one_flow_stats(dladm_handle_t handle
, dladm_flow_attr_t
*attr
, void *arg
)
491 char *flowname
= attr
->fa_flowname
;
494 stat
= dladm_flow_stat_query_all(flowname
);
497 print_all_stats(stat
);
498 dladm_flow_stat_query_all_free(stat
);
501 return (DLADM_WALK_CONTINUE
);
505 * Wrapper of dladm_walk_flow(query_flow_stats,...) to make it usable for
506 * dladm_walk_datalink_id(). Used for showing flow stats for
507 * all flows on all links.
510 dump_link_flow_stats(dladm_handle_t dh
, datalink_id_t linkid
, void * arg
)
512 if (dladm_walk_flow(dump_one_flow_stats
, dh
, linkid
, arg
, B_FALSE
)
514 return (DLADM_WALK_CONTINUE
);
516 return (DLADM_WALK_TERMINATE
);
520 dump_all_flow_stats(dladm_flow_attr_t
*attrp
, void *arg
, datalink_id_t linkid
,
523 /* Show stats for named flow */
525 (void) dump_one_flow_stats(handle
, attrp
, arg
);
527 /* Show stats for flows on one link */
528 } else if (linkid
!= DATALINK_INVALID_LINKID
) {
529 (void) dladm_walk_flow(dump_one_flow_stats
, handle
, linkid
,
532 /* Show stats for all flows on all links */
534 (void) dladm_walk_datalink_id(dump_link_flow_stats
,
535 handle
, arg
, DATALINK_CLASS_ALL
,
536 DATALINK_ANY_MEDIATYPE
, DLADM_OPT_ACTIVE
);
541 main(int argc
, char *argv
[])
543 dladm_status_t status
;
545 boolean_t r_arg
= B_FALSE
;
546 boolean_t t_arg
= B_FALSE
;
547 boolean_t p_arg
= B_FALSE
;
548 boolean_t i_arg
= B_FALSE
;
549 boolean_t o_arg
= B_FALSE
;
550 boolean_t u_arg
= B_FALSE
;
551 boolean_t A_arg
= B_FALSE
;
552 boolean_t flow_arg
= B_FALSE
;
553 datalink_id_t linkid
= DATALINK_ALL_LINKID
;
554 char linkname
[MAXLINKNAMELEN
];
555 char flowname
[MAXFLOWNAMELEN
];
556 uint32_t interval
= 0;
558 show_flow_state_t state
;
559 char *fields_str
= NULL
;
560 char *o_fields_str
= NULL
;
562 char *total_stat_fields
=
563 "flow,ipkts,rbytes,ierrs,opkts,obytes,oerrs";
564 char *rx_stat_fields
=
565 "flow,ipkts,rbytes,ierrs";
566 char *tx_stat_fields
=
567 "flow,opkts,obytes,oerrs";
571 uint_t ofmtflags
= OFMT_RIGHTJUST
;
573 dladm_flow_attr_t attr
;
575 (void) setlocale(LC_ALL
, "");
576 #if !defined(TEXT_DOMAIN)
577 #define TEXT_DOMAIN "SYS_TEST"
579 (void) textdomain(TEXT_DOMAIN
);
583 /* Open the libdladm handle */
584 if ((status
= dladm_open(&handle
)) != DLADM_STATUS_OK
)
585 die_dlerr(status
, "could not open /dev/dld");
587 bzero(&state
, sizeof (state
));
590 while ((option
= getopt_long(argc
, argv
, ":rtApi:o:u:l:h",
591 NULL
, NULL
)) != -1) {
622 if (!dladm_str2interval(optarg
, &interval
))
623 die("invalid interval value '%s'", optarg
);
627 o_fields_str
= optarg
;
634 if (!flowstat_unit(optarg
, &unit
))
635 die("invalid unit value '%s',"
636 "unit must be R|K|M|G|T|P", optarg
);
639 if (strlcpy(linkname
, optarg
, MAXLINKNAMELEN
)
641 die("link name too long\n");
642 if (dladm_name2info(handle
, linkname
, &linkid
, NULL
,
643 NULL
, NULL
) != DLADM_STATUS_OK
)
644 die("invalid link '%s'", linkname
);
647 if (r_arg
|| t_arg
|| p_arg
|| o_arg
|| u_arg
||
649 die("the option -h is not compatible with "
650 "-r, -t, -p, -o, -u, -i, -A");
652 do_show_history(argc
, argv
);
656 die_opterr(optopt
, option
, usage_ermsg
);
662 die("the option -t and -r are not compatible");
665 die("the option -u and -p are not compatible");
668 die("-p requires -o");
670 if (p_arg
&& strcasecmp(o_fields_str
, "all") == 0)
671 die("\"-o all\" is invalid with -p");
674 (r_arg
|| t_arg
|| p_arg
|| o_arg
|| u_arg
|| i_arg
))
675 die("the option -A is not compatible with "
676 "-r, -t, -p, -o, -u, -i");
678 /* get flow name (optional last argument) */
679 if (optind
== (argc
-1)) {
680 if (strlcpy(flowname
, argv
[optind
], MAXFLOWNAMELEN
)
682 die("flow name too long");
684 } else if (optind
!= argc
) {
689 dladm_flow_info(handle
, flowname
, &attr
) != DLADM_STATUS_OK
)
690 die("invalid flow %s", flowname
);
693 dump_all_flow_stats(&attr
, &state
, linkid
, flow_arg
);
697 state
.fs_unit
= unit
;
698 state
.fs_parsable
= p_arg
;
700 if (state
.fs_parsable
)
701 ofmtflags
|= OFMT_PARSABLE
;
704 fields_str
= rx_stat_fields
;
706 fields_str
= tx_stat_fields
;
708 fields_str
= total_stat_fields
;
711 fields_str
= (strcasecmp(o_fields_str
, "all") == 0) ?
712 fields_str
: o_fields_str
;
715 oferr
= ofmt_open(fields_str
, flow_s_fields
, ofmtflags
, 0, &ofmt
);
716 ofmt_check(oferr
, state
.fs_parsable
, ofmt
, die
, warn
);
717 state
.fs_ofmt
= ofmt
;
720 /* Show stats for named flow */
722 (void) query_flow_stats(handle
, &attr
, &state
);
724 /* Show stats for flows on one link */
725 } else if (linkid
!= DATALINK_INVALID_LINKID
) {
726 (void) dladm_walk_flow(query_flow_stats
, handle
, linkid
,
729 /* Show stats for all flows on all links */
731 (void) dladm_walk_datalink_id(query_link_flow_stats
,
732 handle
, &state
, DATALINK_CLASS_ALL
,
733 DATALINK_ANY_MEDIATYPE
, DLADM_OPT_ACTIVE
);
739 (void) fflush(stdout
);
740 cleanup_removed_flows(&state
);
741 (void) sleep(interval
);
751 show_history_date(dladm_usage_t
*history
, void *arg
)
753 show_history_state_t
*state
= (show_history_state_t
*)arg
;
756 dladm_flow_attr_t attr
;
757 dladm_status_t status
;
760 * Only show historical information for existing flows unless '-a'
763 if (!state
->us_showall
&& ((status
= dladm_flow_info(handle
,
764 history
->du_name
, &attr
)) != DLADM_STATUS_OK
)) {
768 stime
= history
->du_stime
;
769 (void) strftime(timebuf
, sizeof (timebuf
), "%m/%d/%Y",
771 (void) printf("%s\n", timebuf
);
773 return (DLADM_STATUS_OK
);
777 show_history_time(dladm_usage_t
*history
, void *arg
)
779 show_history_state_t
*state
= (show_history_state_t
*)arg
;
780 char buf
[DLADM_STRSIZE
];
781 history_l_fields_buf_t ubuf
;
784 dladm_flow_attr_t attr
;
785 dladm_status_t status
;
788 * Only show historical information for existing flows unless '-a'
791 if (!state
->us_showall
&& ((status
= dladm_flow_info(handle
,
792 history
->du_name
, &attr
)) != DLADM_STATUS_OK
)) {
796 if (state
->us_plot
) {
797 if (!state
->us_printheader
) {
798 if (state
->us_first
) {
799 (void) printf("# Time");
800 state
->us_first
= B_FALSE
;
802 (void) printf(" %s", history
->du_name
);
803 if (history
->du_last
) {
805 state
->us_first
= B_TRUE
;
806 state
->us_printheader
= B_TRUE
;
809 if (state
->us_first
) {
810 time
= history
->du_etime
;
811 (void) strftime(buf
, sizeof (buf
), "%T",
813 state
->us_first
= B_FALSE
;
814 (void) printf("%s", buf
);
816 bw
= (double)history
->du_bandwidth
/1000;
817 (void) printf(" %.2f", bw
);
818 if (history
->du_last
) {
820 state
->us_first
= B_TRUE
;
823 return (DLADM_STATUS_OK
);
826 bzero(&ubuf
, sizeof (ubuf
));
828 (void) snprintf(ubuf
.history_l_flow
, sizeof (ubuf
.history_l_flow
), "%s",
830 time
= history
->du_stime
;
831 (void) strftime(buf
, sizeof (buf
), "%T", localtime(&time
));
832 (void) snprintf(ubuf
.history_l_stime
, sizeof (ubuf
.history_l_stime
),
834 time
= history
->du_etime
;
835 (void) strftime(buf
, sizeof (buf
), "%T", localtime(&time
));
836 (void) snprintf(ubuf
.history_l_etime
, sizeof (ubuf
.history_l_etime
),
838 (void) snprintf(ubuf
.history_l_rbytes
, sizeof (ubuf
.history_l_rbytes
),
839 "%llu", history
->du_rbytes
);
840 (void) snprintf(ubuf
.history_l_obytes
, sizeof (ubuf
.history_l_obytes
),
841 "%llu", history
->du_obytes
);
842 (void) snprintf(ubuf
.history_l_bandwidth
,
843 sizeof (ubuf
.history_l_bandwidth
), "%s Mbps",
844 dladm_bw2str(history
->du_bandwidth
, buf
));
846 ofmt_print(state
->us_ofmt
, (void *)&ubuf
);
847 return (DLADM_STATUS_OK
);
851 show_history_res(dladm_usage_t
*history
, void *arg
)
853 show_history_state_t
*state
= (show_history_state_t
*)arg
;
854 char buf
[DLADM_STRSIZE
];
855 history_fields_buf_t ubuf
;
856 dladm_flow_attr_t attr
;
857 dladm_status_t status
;
860 * Only show historical information for existing flows unless '-a'
863 if (!state
->us_showall
&& ((status
= dladm_flow_info(handle
,
864 history
->du_name
, &attr
)) != DLADM_STATUS_OK
)) {
868 bzero(&ubuf
, sizeof (ubuf
));
870 (void) snprintf(ubuf
.history_flow
, sizeof (ubuf
.history_flow
), "%s",
872 (void) snprintf(ubuf
.history_duration
, sizeof (ubuf
.history_duration
),
873 "%llu", history
->du_duration
);
874 (void) snprintf(ubuf
.history_ipackets
, sizeof (ubuf
.history_ipackets
),
875 "%llu", history
->du_ipackets
);
876 (void) snprintf(ubuf
.history_rbytes
, sizeof (ubuf
.history_rbytes
),
877 "%llu", history
->du_rbytes
);
878 (void) snprintf(ubuf
.history_opackets
, sizeof (ubuf
.history_opackets
),
879 "%llu", history
->du_opackets
);
880 (void) snprintf(ubuf
.history_obytes
, sizeof (ubuf
.history_obytes
),
881 "%llu", history
->du_obytes
);
882 (void) snprintf(ubuf
.history_bandwidth
, sizeof (ubuf
.history_bandwidth
),
883 "%s Mbps", dladm_bw2str(history
->du_bandwidth
, buf
));
885 ofmt_print(state
->us_ofmt
, (void *)&ubuf
);
887 return (DLADM_STATUS_OK
);
891 valid_formatspec(char *formatspec_str
)
893 return (strcmp(formatspec_str
, "gnuplot") == 0);
898 do_show_history(int argc
, char *argv
[])
902 dladm_status_t status
;
903 boolean_t d_arg
= B_FALSE
;
906 char *resource
= NULL
;
907 show_history_state_t state
;
908 boolean_t o_arg
= B_FALSE
;
909 boolean_t F_arg
= B_FALSE
;
910 char *fields_str
= NULL
;
911 char *formatspec_str
= NULL
;
913 "flow,duration,ipackets,rbytes,opackets,obytes,bandwidth";
915 "flow,start,end,rbytes,obytes,bandwidth";
918 uint_t ofmtflags
= 0;
920 bzero(&state
, sizeof (show_history_state_t
));
921 state
.us_parsable
= B_FALSE
;
922 state
.us_printheader
= B_FALSE
;
923 state
.us_plot
= B_FALSE
;
924 state
.us_first
= B_TRUE
;
926 while ((opt
= getopt(argc
, argv
, "das:e:o:f:F:")) != -1) {
932 state
.us_showall
= B_TRUE
;
948 state
.us_plot
= F_arg
= B_TRUE
;
949 formatspec_str
= optarg
;
952 die_opterr(optopt
, opt
, usage_ermsg
);
957 die("-h requires a file");
959 if (optind
== (argc
-1)) {
960 dladm_flow_attr_t attr
;
962 resource
= argv
[optind
];
963 if (!state
.us_showall
&&
964 dladm_flow_info(handle
, resource
, &attr
) !=
966 die("invalid flow: '%s'", resource
);
970 if (state
.us_parsable
)
971 ofmtflags
|= OFMT_PARSABLE
;
972 if (resource
== NULL
&& stime
== NULL
&& etime
== NULL
) {
973 if (!o_arg
|| (o_arg
&& strcasecmp(fields_str
, "all") == 0))
974 fields_str
= all_fields
;
975 oferr
= ofmt_open(fields_str
, history_fields
, ofmtflags
,
978 if (!o_arg
|| (o_arg
&& strcasecmp(fields_str
, "all") == 0))
979 fields_str
= all_l_fields
;
980 oferr
= ofmt_open(fields_str
, history_l_fields
, ofmtflags
,
984 ofmt_check(oferr
, state
.us_parsable
, ofmt
, die
, warn
);
985 state
.us_ofmt
= ofmt
;
988 die("incompatible -d and -F options");
990 if (F_arg
&& !valid_formatspec(formatspec_str
))
991 die("Format specifier %s not supported", formatspec_str
);
994 /* Print log dates */
995 status
= dladm_usage_dates(show_history_date
,
996 DLADM_LOGTYPE_FLOW
, file
, resource
, &state
);
997 } else if (resource
== NULL
&& stime
== NULL
&& etime
== NULL
&&
1000 status
= dladm_usage_summary(show_history_res
,
1001 DLADM_LOGTYPE_FLOW
, file
, &state
);
1002 } else if (resource
!= NULL
) {
1003 /* Print log entries for named resource */
1004 status
= dladm_walk_usage_res(show_history_time
,
1005 DLADM_LOGTYPE_FLOW
, file
, resource
, stime
, etime
, &state
);
1007 /* Print time and information for each flow */
1008 status
= dladm_walk_usage_time(show_history_time
,
1009 DLADM_LOGTYPE_FLOW
, file
, stime
, etime
, &state
);
1013 if (status
!= DLADM_STATUS_OK
)
1014 die_dlerr(status
, "-h");
1015 dladm_close(handle
);
1019 warn(const char *format
, ...)
1023 format
= gettext(format
);
1024 (void) fprintf(stderr
, "%s: warning: ", progname
);
1026 va_start(alist
, format
);
1027 (void) vfprintf(stderr
, format
, alist
);
1030 (void) putc('\n', stderr
);
1035 die(const char *format
, ...)
1039 format
= gettext(format
);
1040 (void) fprintf(stderr
, "%s: ", progname
);
1042 va_start(alist
, format
);
1043 (void) vfprintf(stderr
, format
, alist
);
1046 (void) putc('\n', stderr
);
1048 /* close dladm handle if it was opened */
1050 dladm_close(handle
);
1058 die("the option -%c cannot be specified more than once", opt
);
1062 die_opterr(int opt
, int opterr
, const char *usage
)
1066 die("option '-%c' requires a value\nusage: %s", opt
,
1071 die("unrecognized option '-%c'\nusage: %s", opt
,
1079 die_dlerr(dladm_status_t err
, const char *format
, ...)
1082 char errmsg
[DLADM_STRSIZE
];
1084 format
= gettext(format
);
1085 (void) fprintf(stderr
, "%s: ", progname
);
1087 va_start(alist
, format
);
1088 (void) vfprintf(stderr
, format
, alist
);
1090 (void) fprintf(stderr
, ": %s\n", dladm_status2str(err
, errmsg
));
1092 /* close dladm handle if it was opened */
1094 dladm_close(handle
);
1101 * default output callback function that, when invoked from dladm_print_output,
1102 * prints string which is offset by of_arg->ofmt_id within buf.
1105 print_default_cb(ofmt_arg_t
*of_arg
, char *buf
, uint_t bufsize
)
1109 value
= (char *)of_arg
->ofmt_cbarg
+ of_arg
->ofmt_id
;
1110 (void) strlcpy(buf
, value
, bufsize
);