[netsniff-ng] [PATCH] flowtop: Show flow rate of bytes & pkts
From: Vadim Kochan Calculate & print the rate of src/dst bytes & pkts. Also changed refresh flows time to 1s so the rate info will be not disappeared very soon. Signed-off-by: Vadim Kochan --- RFC -> PATCH: 1) Return int64_t instead of double in time_after_us 2) Removed not needed alignment 3) Removed not needed braces around 'if' 4) Removed change for bandw2str (will go in separate patch) flowtop.c | 81 ++- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/flowtop.c b/flowtop.c index 9df4bdb..187b34d 100644 --- a/flowtop.c +++ b/flowtop.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -64,6 +65,11 @@ struct flow_entry { unsigned int procnum; bool is_visible; struct nf_conntrack *ct; + struct timeval last_update; + double rate_bytes_src; + double rate_bytes_dst; + double rate_pkts_src; + double rate_pkts_dst; }; struct flow_list { @@ -197,6 +203,18 @@ static const struct nfct_filter_ipv6 filter_ipv6 = { .mask = { 0x, 0x, 0x, 0x }, }; +static int64_t time_after_us(struct timeval *tv) +{ + struct timeval now; + + gettimeofday(&now, NULL); + + now.tv_sec -= tv->tv_sec; + now.tv_usec -= tv->tv_usec; + + return now.tv_sec * 100 + now.tv_usec; +} + static void signal_handler(int number) { switch (number) { @@ -252,6 +270,28 @@ static void version(void) die(); } +static void flow_entry_update_time(struct flow_entry *n) +{ + gettimeofday(&n->last_update, NULL); +} + +static void flow_entry_calc_rate(struct flow_entry *n, struct nf_conntrack *ct) +{ + uint64_t bytes_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_BYTES); + uint64_t bytes_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_BYTES); + uint64_t pkts_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_PACKETS); + uint64_t pkts_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_PACKETS); + double sec = time_after_us(&n->last_update) / 100.0; + + if (sec <= 0) + return; + + n->rate_bytes_src = (bytes_src - n->bytes_src) / sec; + n->rate_bytes_dst = (bytes_dst - n->bytes_dst) / sec; + n->rate_pkts_src = (pkts_src - n->pkts_src) / sec; + n->rate_pkts_dst = (pkts_dst - n->pkts_dst) / sec; +} + static inline struct flow_entry *flow_entry_xalloc(void) { return xzmalloc(sizeof(struct flow_entry)); @@ -293,6 +333,7 @@ static void flow_list_new_entry(struct flow_list *fl, struct nf_conntrack *ct) n->ct = nfct_clone(ct); + flow_entry_update_time(n); flow_entry_from_ct(n, ct); flow_entry_get_extended(n); @@ -747,14 +788,36 @@ static char *bandw2str(double bytes, char *buf, size_t len) return buf; } -static void presenter_print_counters(uint64_t bytes, uint64_t pkts, int color) +static char *rate2str(double rate, char *buf, size_t len) +{ + if (rate > 10.) + snprintf(buf, len, "%.1fGb/s", rate / 10.); + else if (rate > 100.) + snprintf(buf, len, "%.1fMb/s", rate / 100.); + else if (rate > 1000.) + snprintf(buf, len, "%.1fKb/s", rate / 1000.); + else + snprintf(buf, len, "%gB/s", rate); + + return buf; +} + +static void presenter_print_counters(uint64_t bytes, uint64_t pkts, +double rate_bytes, double rate_pkts, +int color) { char bytes_str[64]; printw(" -> ("); attron(COLOR_PAIR(color)); - printw("%"PRIu64" pkts, ", pkts); - printw("%s bytes", bandw2str(bytes, bytes_str, sizeof(bytes_str) - 1)); + printw("%"PRIu64" pkts", pkts); + if (rate_pkts) + printw("(%.1fpps)", rate_pkts); + + printw(", %s bytes", bandw2str(bytes, bytes_str, sizeof(bytes_str) - 1)); + if (rate_bytes) + printw("(%s)", rate2str(rate_bytes, bytes_str, + sizeof(bytes_str) - 1)); attroff(COLOR_PAIR(color)); printw(")"); } @@ -872,7 +935,9 @@ static void presenter_screen_do_line(WINDOW *screen, struct flow_entry *n, } if (n->pkts_src > 0 && n->bytes_src > 0) - presenter_print_counters(n->bytes_src, n->pkts_src, 1); + presenter_print_counters(n->bytes_src, n->pkts_src, +n->rate_bytes_src, +n->rate_pkts_src, 1); printw(" => "); } @@ -898,7 +963,9 @@ static void presenter_screen_do_line(WINDOW *screen, struct flow_entry *n, } if (n->pkts_dst > 0 && n->bytes_dst > 0) - presenter_print_counters(n->bytes_dst, n->pkts_dst, 2); +
[netsniff-ng] Re: [RFC] flowtop: Show flow rate of bytes & pkts
On Thu, Oct 22, 2015 at 10:03:58AM +0200, Tobias Klauser wrote: > On 2015-10-20 at 19:46:07 +0200, Vadim Kochan wrote: > > Calculate & print the rate of src/dst bytes & pkts. > > Also changed refresh flows time to 1s so the rate > > info will be not disappeared very soon. > > Looks good to me in general and I like the idea. A few minor comments > below. > > > Signed-off-by: Vadim Kochan > > --- > > flowtop.c | 90 > > --- > > 1 file changed, 80 insertions(+), 10 deletions(-) > > > > diff --git a/flowtop.c b/flowtop.c > > index 9df4bdb..c348e33 100644 > > --- a/flowtop.c > > +++ b/flowtop.c > > @@ -19,6 +19,7 @@ > > #include > > #include > > #include > > +#include > > #include > > #include > > #include > > @@ -64,6 +65,11 @@ struct flow_entry { > > unsigned int procnum; > > bool is_visible; > > struct nf_conntrack *ct; > > + struct timeval last_update; > > + double rate_bytes_src; > > + double rate_bytes_dst; > > + double rate_pkts_src; > > + double rate_pkts_dst; > > }; > > > > struct flow_list { > > @@ -197,6 +203,18 @@ static const struct nfct_filter_ipv6 filter_ipv6 = { > > .mask = { 0x, 0x, 0x, 0x }, > > }; > > > > +static double time_after_us(struct timeval *tv) > > No need to return a double here. Make this an int64_t... > > > +{ > > + struct timeval now; > > + > > + gettimeofday(&now, NULL); > > + > > + now.tv_sec -= tv->tv_sec; > > + now.tv_usec -= tv->tv_usec; > > + > > + return (now.tv_sec * 100.0 + now.tv_usec); > > +} > > + > > static void signal_handler(int number) > > { > > switch (number) { > > @@ -252,6 +270,28 @@ static void version(void) > > die(); > > } > > > > +static void flow_entry_update_time(struct flow_entry *n) > > +{ > > + gettimeofday(&n->last_update, NULL); > > +} > > + > > +static void flow_entry_calc_rate(struct flow_entry *n, struct nf_conntrack > > *ct) > > +{ > > + uint64_t bytes_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_BYTES); > > + uint64_t bytes_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_BYTES); > > + uint64_t pkts_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_PACKETS); > > + uint64_t pkts_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_PACKETS); > > + double sec = time_after_us(&n->last_update) / 100.0; > > ...here it will become a double anyhow. > > > + > > + if (sec <= 0) > > + return; > > + > > + n->rate_bytes_src = (bytes_src - n->bytes_src) / sec; > > + n->rate_bytes_dst = (bytes_dst - n->bytes_dst) / sec; > > + n->rate_pkts_src = (pkts_src - n->pkts_src) / sec; > > + n->rate_pkts_dst = (pkts_dst - n->pkts_dst) / sec; > > I don't think we need the alignment here, it's readable enough without > the extra spaces. > > > +} > > + > > static inline struct flow_entry *flow_entry_xalloc(void) > > { > > return xzmalloc(sizeof(struct flow_entry)); > > @@ -293,6 +333,7 @@ static void flow_list_new_entry(struct flow_list *fl, > > struct nf_conntrack *ct) > > > > n->ct = nfct_clone(ct); > > > > + flow_entry_update_time(n); > > flow_entry_from_ct(n, ct); > > flow_entry_get_extended(n); > > > > @@ -736,25 +777,48 @@ static uint16_t presenter_get_port(uint16_t src, > > uint16_t dst, bool is_tcp) > > static char *bandw2str(double bytes, char *buf, size_t len) > > { > > if (bytes > 10.) > > - snprintf(buf, len, "%.1fG", bytes / 10.); > > + snprintf(buf, len, "%.1fGb", bytes / 10.); > > else if (bytes > 100.) > > - snprintf(buf, len, "%.1fM", bytes / 100.); > > + snprintf(buf, len, "%.1fMb", bytes / 100.); > > else if (bytes > 1000.) > > - snprintf(buf, len, "%.1fK", bytes / 1000.); > > + snprintf(buf, len, "%.1fKb", bytes / 1000.); > > else > > - snprintf(buf, len, "%g", bytes); > > + snprintf(buf, len, "%g bytes", bytes); > > Please split this change out into a separate preparatory patch as it is > not directly related to the rate change. This makes it easier to review > and bisect. > > > > > return buf; > > } > > > > -static void presenter_print_counters(uint64_t bytes, uint64_t pkts, int > > color) > > +static char *rate2str(double rate, char *buf, size_t len) > > +{ > > + if (rate > 10.) > > + snprintf(buf, len, "%.1fGb/s", rate / 10.); > > + else if (rate > 100.) > > + snprintf(buf, len, "%.1fMb/s", rate / 100.); > > + else if (rate > 1000.) > > + snprintf(buf, len, "%.1fKb/s", rate / 1000.); > > + else > > + snprintf(buf, len, "%gB/s", rate); > > + > > + return buf; > > +} > > + > > +static void presenter_print_counters(uint64_t bytes, uint64_t pkts, > > +double rate_bytes, double rate_pkts, > > +int color) > > { > > char bytes_st
[netsniff-ng] Re: [RFC] flowtop: Show flow rate of bytes & pkts
On 2015-10-20 at 19:46:07 +0200, Vadim Kochan wrote: > Calculate & print the rate of src/dst bytes & pkts. > Also changed refresh flows time to 1s so the rate > info will be not disappeared very soon. Looks good to me in general and I like the idea. A few minor comments below. > Signed-off-by: Vadim Kochan > --- > flowtop.c | 90 > --- > 1 file changed, 80 insertions(+), 10 deletions(-) > > diff --git a/flowtop.c b/flowtop.c > index 9df4bdb..c348e33 100644 > --- a/flowtop.c > +++ b/flowtop.c > @@ -19,6 +19,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -64,6 +65,11 @@ struct flow_entry { > unsigned int procnum; > bool is_visible; > struct nf_conntrack *ct; > + struct timeval last_update; > + double rate_bytes_src; > + double rate_bytes_dst; > + double rate_pkts_src; > + double rate_pkts_dst; > }; > > struct flow_list { > @@ -197,6 +203,18 @@ static const struct nfct_filter_ipv6 filter_ipv6 = { > .mask = { 0x, 0x, 0x, 0x }, > }; > > +static double time_after_us(struct timeval *tv) No need to return a double here. Make this an int64_t... > +{ > + struct timeval now; > + > + gettimeofday(&now, NULL); > + > + now.tv_sec -= tv->tv_sec; > + now.tv_usec -= tv->tv_usec; > + > + return (now.tv_sec * 100.0 + now.tv_usec); > +} > + > static void signal_handler(int number) > { > switch (number) { > @@ -252,6 +270,28 @@ static void version(void) > die(); > } > > +static void flow_entry_update_time(struct flow_entry *n) > +{ > + gettimeofday(&n->last_update, NULL); > +} > + > +static void flow_entry_calc_rate(struct flow_entry *n, struct nf_conntrack > *ct) > +{ > + uint64_t bytes_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_BYTES); > + uint64_t bytes_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_BYTES); > + uint64_t pkts_src = nfct_get_attr_u64(ct, ATTR_ORIG_COUNTER_PACKETS); > + uint64_t pkts_dst = nfct_get_attr_u64(ct, ATTR_REPL_COUNTER_PACKETS); > + double sec = time_after_us(&n->last_update) / 100.0; ...here it will become a double anyhow. > + > + if (sec <= 0) > + return; > + > + n->rate_bytes_src = (bytes_src - n->bytes_src) / sec; > + n->rate_bytes_dst = (bytes_dst - n->bytes_dst) / sec; > + n->rate_pkts_src = (pkts_src - n->pkts_src) / sec; > + n->rate_pkts_dst = (pkts_dst - n->pkts_dst) / sec; I don't think we need the alignment here, it's readable enough without the extra spaces. > +} > + > static inline struct flow_entry *flow_entry_xalloc(void) > { > return xzmalloc(sizeof(struct flow_entry)); > @@ -293,6 +333,7 @@ static void flow_list_new_entry(struct flow_list *fl, > struct nf_conntrack *ct) > > n->ct = nfct_clone(ct); > > + flow_entry_update_time(n); > flow_entry_from_ct(n, ct); > flow_entry_get_extended(n); > > @@ -736,25 +777,48 @@ static uint16_t presenter_get_port(uint16_t src, > uint16_t dst, bool is_tcp) > static char *bandw2str(double bytes, char *buf, size_t len) > { > if (bytes > 10.) > - snprintf(buf, len, "%.1fG", bytes / 10.); > + snprintf(buf, len, "%.1fGb", bytes / 10.); > else if (bytes > 100.) > - snprintf(buf, len, "%.1fM", bytes / 100.); > + snprintf(buf, len, "%.1fMb", bytes / 100.); > else if (bytes > 1000.) > - snprintf(buf, len, "%.1fK", bytes / 1000.); > + snprintf(buf, len, "%.1fKb", bytes / 1000.); > else > - snprintf(buf, len, "%g", bytes); > + snprintf(buf, len, "%g bytes", bytes); Please split this change out into a separate preparatory patch as it is not directly related to the rate change. This makes it easier to review and bisect. > > return buf; > } > > -static void presenter_print_counters(uint64_t bytes, uint64_t pkts, int > color) > +static char *rate2str(double rate, char *buf, size_t len) > +{ > + if (rate > 10.) > + snprintf(buf, len, "%.1fGb/s", rate / 10.); > + else if (rate > 100.) > + snprintf(buf, len, "%.1fMb/s", rate / 100.); > + else if (rate > 1000.) > + snprintf(buf, len, "%.1fKb/s", rate / 1000.); > + else > + snprintf(buf, len, "%gB/s", rate); > + > + return buf; > +} > + > +static void presenter_print_counters(uint64_t bytes, uint64_t pkts, > + double rate_bytes, double rate_pkts, > + int color) > { > char bytes_str[64]; > > printw(" -> ("); > attron(COLOR_PAIR(color)); > - printw("%"PRIu64" pkts, ", pkts); > - printw("%s bytes", bandw2str(bytes, bytes_str, sizeof(bytes_str) - 1)); > + printw("%"PRIu64" pkts", pkts); > + if (rate_pk