[netsniff-ng] [PATCH] flowtop: Show flow rate of bytes & pkts

2015-10-22 Thread Vadim Kochan
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

2015-10-22 Thread vkochan
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

2015-10-22 Thread Tobias Klauser
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