Add -o,--sort option to perform flows sorting by rate/bytes/pkts. Add -d,--dir option to choose the direction to sort (default is dst).
is_visible is used only to show sorted flows to do not show newer appeared flows with rate 0 at the head of list. Signed-off-by: Vadim Kochan <[email protected]> --- flowtop.8 | 20 ++++++++++++ flowtop.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 120 insertions(+), 9 deletions(-) diff --git a/flowtop.8 b/flowtop.8 index 1367e6e..bd636d1 100644 --- a/flowtop.8 +++ b/flowtop.8 @@ -117,6 +117,26 @@ Also show source information of the flow, not only destination information. .SS -b, --bits Show flow rates in bits per second instead of bytes per second. .PP +.SS -o, --sort <type> (default no sorting) +Sort flows by type (see -d,--dir option): +.in +4 +.sp +r,rate - sort by rate +.sp +b,bytes - sort by number of bytes +.sp +p,pkts - sort by number of packets +.in -4 +.PP +.SS -d, --dir <dir> (default dst) +Specify flows direction (sorting, etc): +.in +4 +.sp +s,src - use source direction +.sp +d,dst - use destination direction +.in -4 +.PP .SS -u, --update The built-in database update mechanism will be invoked to get Maxmind's latest database. To configure search locations for databases, the file diff --git a/flowtop.c b/flowtop.c index 6496e44..c67b683 100644 --- a/flowtop.c +++ b/flowtop.c @@ -117,6 +117,13 @@ enum rate_units { RATE_BYTES }; +enum sort_type { + SORT_NONE, + SORT_RATE, + SORT_BYTES, + SORT_PKTS +}; + static volatile bool is_flow_collecting; static volatile sig_atomic_t sigint = 0; static int what = INCLUDE_IPV4 | INCLUDE_IPV6 | INCLUDE_TCP; @@ -128,8 +135,10 @@ static bool show_src = false; static bool resolve_dns = true; static bool resolve_geoip = true; static enum rate_units rate_type = RATE_BYTES; +static enum flow_direction flow_dir = FLOW_DIR_DST; +static enum sort_type sort_by = SORT_NONE; -static const char *short_options = "vhTUsDIS46ut:nGb"; +static const char *short_options = "vhTUsDIS46ut:nGbo:d:"; static const struct option long_options[] = { {"ipv4", no_argument, NULL, '4'}, {"ipv6", no_argument, NULL, '6'}, @@ -142,6 +151,8 @@ static const struct option long_options[] = { {"no-geoip", no_argument, NULL, 'G'}, {"show-src", no_argument, NULL, 's'}, {"bits", no_argument, NULL, 'b'}, + {"sort", required_argument, NULL, 'o'}, + {"dir", required_argument, NULL, 'd'}, {"update", no_argument, NULL, 'u'}, {"interval", required_argument, NULL, 't'}, {"version", no_argument, NULL, 'v'}, @@ -278,6 +289,13 @@ static void help(void) " -G|--no-geoip Don't perform GeoIP lookup\n" " -s|--show-src Also show source, not only dest\n" " -b|--bits Show rates in bits/s instead of bytes/s\n" + " -o|--sort <type> Sort flows by type (default no sorting):\n" + " r,rate - sort by rate\n" + " b,bytes - sort by number of bytes\n" + " p,pkts - sort by number of packets\n" + " -d|--dir <dir> Specify flows direction (default dst):\n" + " s,src - source direction\n" + " d,dst - destination direction\n" " -u|--update Update GeoIP databases\n" " -t|--interval <time> Refresh time in seconds (default 1s)\n" " -v|--version Print version and exit\n" @@ -1126,7 +1144,8 @@ static void presenter_screen_update(WINDOW *screen, struct flow_list *fl, "Is netfilter running?)"); for (; n; n = rcu_dereference(n->next)) { - n->is_visible = false; + if (!n->is_visible) + continue; if (presenter_flow_wrong_state(n)) continue; @@ -1142,8 +1161,6 @@ static void presenter_screen_update(WINDOW *screen, struct flow_list *fl, continue; } - n->is_visible = true; - presenter_screen_do_line(screen, n, &line); line++; @@ -1295,6 +1312,62 @@ static void conntrack_tstamp_enable(void) } } +static void flow_list_sort(struct flow_list *fl, struct flow_entry *n) +{ + struct flow_entry *head; + + if (sort_by == SORT_NONE) + return; + + synchronize_rcu(); + spinlock_lock(&flow_list.lock); + + head = rcu_dereference(fl->head); + if (!head) + return; + if (!rcu_dereference(head->next)) + return; + + flow_list_remove_entry(fl, n); + + for (; head; head = rcu_dereference(head->next)) { + if (sort_by == SORT_RATE) { + if (flow_dir == FLOW_DIR_SRC) { + if (n->rate_bytes_src > head->rate_bytes_src) + break; + } else if (flow_dir == FLOW_DIR_DST) { + if (n->rate_bytes_dst > head->rate_bytes_dst) + break; + } + } else if (sort_by == SORT_BYTES) { + if (flow_dir == FLOW_DIR_SRC) { + if (n->bytes_src > head->bytes_src) + break; + } else if (flow_dir == FLOW_DIR_DST) { + if (n->bytes_dst > head->bytes_dst) + break; + } + } else if (sort_by == SORT_PKTS) { + if (flow_dir == FLOW_DIR_SRC) { + if (n->pkts_src > head->pkts_src) + break; + } else if (flow_dir == FLOW_DIR_DST) { + if (n->pkts_dst > head->pkts_dst) + break; + } + } + } + + if (!head) + head = rcu_dereference(n->prev); + else + head = rcu_dereference(head->prev); + + flow_list_insert_entry(fl, head, n); + + spinlock_unlock(&flow_list.lock); +} + static int flow_update_cb(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data __maybe_unused) { @@ -1314,6 +1387,10 @@ static int flow_update_cb(enum nf_conntrack_msg_type type, flow_entry_update_time(n); flow_entry_from_ct(n, ct); + flow_list_sort(&flow_list, n); + + n->is_visible = true; + return NFCT_CB_CONTINUE; } @@ -1322,12 +1399,8 @@ static void collector_refresh_flows(struct nfct_handle *handle) struct flow_entry *n; n = rcu_dereference(flow_list.head); - for (; n; n = rcu_dereference(n->next)) { - if (!n->is_visible) - continue; - + for (; n; n = rcu_dereference(n->next)) nfct_query(handle, NFCT_Q_GET, n->ct); - } } static void collector_create_filter(struct nfct_handle *nfct) @@ -1586,6 +1659,24 @@ int main(int argc, char **argv) case 'G': resolve_geoip = false; break; + case 'o': + if (*optarg == 'r' || strcmp(optarg, "rate") == 0) + sort_by = SORT_RATE; + else if (*optarg == 'b' || strcmp(optarg, "bytes") == 0) + sort_by = SORT_BYTES; + else if (*optarg == 'p' || strcmp(optarg, "pkts") == 0) + sort_by = SORT_PKTS; + else + help(); + break; + case 'd': + if (*optarg == 's' || strcmp(optarg, "src") == 0) + flow_dir = FLOW_DIR_SRC; + else if (*optarg == 'd' || strcmp(optarg, "dst") == 0) + flow_dir = FLOW_DIR_DST; + else + help(); + break; case 'h': help(); break; -- 2.6.1 -- You received this message because you are subscribed to the Google Groups "netsniff-ng" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
