summaryrefslogtreecommitdiff
path: root/flowtop.c
diff options
context:
space:
mode:
authorVadim Kochan <vadim4j@gmail.com>2017-05-27 18:30:08 +0300
committerTobias Klauser <tklauser@distanz.ch>2017-05-30 09:26:30 +0200
commit83f11c231626f79433a021c526ffa1ac7521ae36 (patch)
tree72a3e0cfb3efd9e34455c8ad5d670a2e08900112 /flowtop.c
parent90b9483c806f0571988581c1712c7ca236c4a38c (diff)
flowtop: Improve and unify up/down scrolling
Move scrolling logic to the ui.c module, it requires to have some data iteration provided in flowtop.c and delegated to ui.c part. So approach is that now flowtop provides 2 additional callbacks for: 1) Iterate over flows/procs list 2) Draw flow/proc on each iteration which is controlled from ui.c it allows to unify scrolling logic and delegate it to the ui.c, in the future it should allow to easy handle press event on selected row and drow some additional information, or draw a cursor line per selected row. Also fixed case when down scrolling was bigger that printed rows, not it is handled by ui part. Signed-off-by: Vadim Kochan <vadim4j@gmail.com> Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
Diffstat (limited to 'flowtop.c')
-rw-r--r--flowtop.c166
1 files changed, 76 insertions, 90 deletions
diff --git a/flowtop.c b/flowtop.c
index 1caae9e..00937e1 100644
--- a/flowtop.c
+++ b/flowtop.c
@@ -118,8 +118,6 @@ enum flow_direction {
# define ATTR_TIMESTAMP_STOP 64
#endif
-#define SCROLL_MAX 1000
-
#define INCLUDE_IPV4 (1 << 0)
#define INCLUDE_IPV6 (1 << 1)
#define INCLUDE_UDP (1 << 2)
@@ -156,7 +154,6 @@ static struct sysctl_params_ctx sysctl = { -1, -1 };
static unsigned int cols, rows;
static WINDOW *screen;
-static int skip_lines;
static unsigned int interval = 1;
static bool show_src = false;
@@ -190,12 +187,25 @@ enum tbl_proc_col {
static struct ui_table flows_tbl;
static struct ui_table procs_tbl;
+static struct ui_table *curr_tbl;
enum tab_entry {
TAB_FLOWS,
TAB_PROCS,
};
+#define list_first_or_next(__ptr, __head, __entry) \
+({ \
+ struct cds_list_head *h; \
+ if (!__ptr) \
+ h = rcu_dereference((__head)->next); \
+ else if (rcu_dereference(__ptr->__entry.next) == (__head)) \
+ return NULL; \
+ else \
+ h = rcu_dereference(__ptr->__entry.next); \
+ cds_list_entry(h, __typeof(* (__ptr)), __entry); \
+})
+
static const char *short_options = "vhTUsDIS46ut:nGb";
static const struct option long_options[] = {
{"ipv4", no_argument, NULL, '4'},
@@ -1013,45 +1023,45 @@ static void print_flow_peer_info(const struct flow_entry *n, enum flow_direction
tmp, sizeof(tmp) - 1));
}
-static void draw_flow_entry(const struct flow_entry *n)
+static void draw_flow_entry(struct ui_table *tbl, const void *data)
{
+ const struct flow_entry *n = data;
char tmp[128];
- ui_table_row_add(&flows_tbl);
+ ui_table_row_add(tbl);
/* Application */
- ui_table_row_col_set(&flows_tbl, TBL_FLOW_PROCESS,
- n->proc ? n->proc->name : "");
+ ui_table_row_col_set(tbl, TBL_FLOW_PROCESS, n->proc ? n->proc->name : "");
/* PID */
slprintf(tmp, sizeof(tmp), "%.d", n->proc ? n->proc->pid : 0);
- ui_table_row_col_set(&flows_tbl, TBL_FLOW_PID, tmp);
+ ui_table_row_col_set(tbl, TBL_FLOW_PID, tmp);
/* L4 protocol */
- ui_table_row_col_set(&flows_tbl, TBL_FLOW_PROTO, l4proto2str[n->l4_proto]);
+ ui_table_row_col_set(tbl, TBL_FLOW_PROTO, l4proto2str[n->l4_proto]);
/* L4 protocol state */
- ui_table_row_col_set(&flows_tbl, TBL_FLOW_STATE, flow_state2str(n));
+ ui_table_row_col_set(tbl, TBL_FLOW_STATE, flow_state2str(n));
/* Time */
time2str(n->timestamp_start, tmp, sizeof(tmp));
- ui_table_row_col_set(&flows_tbl, TBL_FLOW_TIME, tmp);
+ ui_table_row_col_set(tbl, TBL_FLOW_TIME, tmp);
print_flow_peer_info(n, show_src ? FLOW_DIR_SRC : FLOW_DIR_DST);
- ui_table_row_show(&flows_tbl);
+ ui_table_row_show(tbl);
if (show_src) {
- ui_table_row_add(&flows_tbl);
+ ui_table_row_add(tbl);
- ui_table_row_col_set(&flows_tbl, TBL_FLOW_PROCESS, "");
- ui_table_row_col_set(&flows_tbl, TBL_FLOW_PID, "");
- ui_table_row_col_set(&flows_tbl, TBL_FLOW_PROTO, "");
- ui_table_row_col_set(&flows_tbl, TBL_FLOW_STATE, "");
- ui_table_row_col_set(&flows_tbl, TBL_FLOW_TIME, "");
+ ui_table_row_col_set(tbl, TBL_FLOW_PROCESS, "");
+ ui_table_row_col_set(tbl, TBL_FLOW_PID, "");
+ ui_table_row_col_set(tbl, TBL_FLOW_PROTO, "");
+ ui_table_row_col_set(tbl, TBL_FLOW_STATE, "");
+ ui_table_row_col_set(tbl, TBL_FLOW_TIME, "");
print_flow_peer_info(n, FLOW_DIR_DST);
- ui_table_row_show(&flows_tbl);
+ ui_table_row_show(tbl);
}
}
@@ -1115,10 +1125,10 @@ static inline bool presenter_flow_wrong_state(struct flow_entry *n)
return true;
}
-static void draw_filter_status(char *title, int count, int skip_lines)
+static void draw_filter_status(struct ui_table *tbl, char *title)
{
mvwprintw(screen, 1, 0, "%*s", COLS - 1, " ");
- mvwprintw(screen, 1, 2, "%s(%u) for ", title, count);
+ mvwprintw(screen, 1, 2, "%s(%u) for ", title, ui_table_data_count(tbl));
if (what & INCLUDE_IPV4)
printw("IPv4,");
@@ -1139,60 +1149,31 @@ static void draw_filter_status(char *title, int count, int skip_lines)
if (show_active_only)
printw("Active,");
- printw(" [+%d]", skip_lines);
+ printw(" [+%d]", ui_table_scroll_height(tbl));
if (is_flow_collecting)
printw(" [Collecting flows ...]");
}
-static void draw_flows(WINDOW *screen, struct flow_list *fl,
- int skip_lines)
+static void draw_flows(WINDOW *screen, struct flow_list *fl)
{
- int row_width = show_src ? 2 : 1;
- unsigned int flows = 0;
- unsigned int line = 4;
- int skip = skip_lines;
- struct flow_entry *n;
-
rcu_read_lock();
if (cds_list_empty(&fl->head))
- mvwprintw(screen, line, 2, "(No sessions! "
+ mvwprintw(screen, 4, 2, "(No sessions! "
"Is netfilter running?)");
- ui_table_clear(&flows_tbl);
- ui_table_header_print(&flows_tbl);
-
- cds_list_for_each_entry_rcu(n, &fl->head, entry) {
- if (!n->is_visible)
- continue;
- if (presenter_flow_wrong_state(n))
- continue;
-
- /* count only flows which might be showed */
- flows++;
-
- if (line + row_width >= rows)
- continue;
- if (--skip >= 0)
- continue;
-
- draw_flow_entry(n);
- line += row_width;
- }
+ ui_table_data_bind(&flows_tbl);
rcu_read_unlock();
- mvwprintw(screen, 1, 0, "%*s", COLS - 1, " ");
- mvwprintw(screen, 1, 2, "Kernel netfilter flows(%u) for ", flows);
-
- draw_filter_status("Kernel netfilter flows", flows, skip_lines);
+ draw_filter_status(&flows_tbl, "Kernel netfilter flows");
}
-static void draw_proc_entry(struct proc_entry *p)
+static void draw_proc_entry(struct ui_table *tbl, const void *data)
{
- struct ui_table *tbl = &procs_tbl;;
+ const struct proc_entry *p = data;
char tmp[128];
ui_table_row_add(tbl);
@@ -1227,33 +1208,15 @@ static void draw_proc_entry(struct proc_entry *p)
ui_table_row_show(tbl);
}
-static void draw_procs(WINDOW *screen, struct flow_list *fl,
- int skip_lines)
+static void draw_procs(WINDOW *screen, struct flow_list *fl)
{
- struct proc_entry *proc, *tmp;
- unsigned int line = 4;
- int skip = skip_lines;
- int procs = 0;
-
rcu_read_lock();
- ui_table_clear(&procs_tbl);
- ui_table_header_print(&procs_tbl);
-
- cds_list_for_each_entry_safe(proc, tmp, &proc_list.head, entry) {
- if (line + 1 >= rows)
- continue;
- if (--skip >= 0)
- continue;
-
- draw_proc_entry(proc);
- procs++;
- line++;
- }
+ ui_table_data_bind(&procs_tbl);
rcu_read_unlock();
- draw_filter_status("Processes", procs, skip_lines);
+ draw_filter_status(&procs_tbl, "Processes");
}
static void draw_help(void)
@@ -1355,6 +1318,17 @@ static void show_option_toggle(int opt)
}
}
+void * flows_iter(void *data)
+{
+ struct flow_entry *n = data;
+
+ do {
+ n = list_first_or_next(n, &flow_list.head, entry);
+ } while (n && (!n->is_visible || presenter_flow_wrong_state(n)));
+
+ return n;
+}
+
static void flows_table_init(struct ui_table *tbl)
{
ui_table_init(tbl);
@@ -1382,6 +1356,16 @@ static void flows_table_init(struct ui_table *tbl)
ui_table_col_color_set(tbl, TBL_FLOW_STATE, COLOR(YELLOW, BLACK));
ui_table_header_color_set(&flows_tbl, COLOR(BLACK, GREEN));
+
+ ui_table_data_bind_set(tbl, draw_flow_entry);
+ ui_table_data_iter_set(tbl, flows_iter);
+}
+
+void * procs_iter(void *data)
+{
+ struct proc_entry *p = data;
+
+ return list_first_or_next(p, &proc_list.head, entry);
}
static void procs_table_init(struct ui_table *tbl)
@@ -1413,6 +1397,9 @@ static void procs_table_init(struct ui_table *tbl)
ui_table_col_color_set(tbl, TBL_PROC_RATE_DST, COLOR(BLUE, BLACK));
ui_table_header_color_set(tbl, COLOR(BLACK, GREEN));
+
+ ui_table_data_bind_set(tbl, draw_proc_entry);
+ ui_table_data_iter_set(tbl, procs_iter);
}
static void tab_main_on_open(struct ui_tab *tab, enum ui_tab_event_t evt, uint32_t id)
@@ -1420,10 +1407,13 @@ static void tab_main_on_open(struct ui_tab *tab, enum ui_tab_event_t evt, uint32
if (evt != UI_TAB_EVT_OPEN)
return;
- if (id == TAB_FLOWS)
- draw_flows(screen, &flow_list, skip_lines);
- else if (id == TAB_PROCS)
- draw_procs(screen, &flow_list, skip_lines);
+ if (id == TAB_FLOWS) {
+ draw_flows(screen, &flow_list);
+ curr_tbl = &flows_tbl;
+ } else if (id == TAB_PROCS) {
+ draw_procs(screen, &flow_list);
+ curr_tbl = &procs_tbl;
+ }
}
static void presenter(void)
@@ -1470,24 +1460,20 @@ static void presenter(void)
case KEY_UP:
case 'u':
case 'k':
- skip_lines--;
- if (skip_lines < 0)
- skip_lines = 0;
+ ui_table_event_send(curr_tbl, UI_EVT_SCROLL_UP);
break;
case KEY_DOWN:
case 'd':
case 'j':
- skip_lines++;
- if (skip_lines > SCROLL_MAX)
- skip_lines = SCROLL_MAX;
+ ui_table_event_send(curr_tbl, UI_EVT_SCROLL_DOWN);
break;
case KEY_LEFT:
case 'h':
- ui_table_event_send(&flows_tbl, UI_EVT_SCROLL_LEFT);
+ ui_table_event_send(curr_tbl, UI_EVT_SCROLL_LEFT);
break;
case KEY_RIGHT:
case 'l':
- ui_table_event_send(&flows_tbl, UI_EVT_SCROLL_RIGHT);
+ ui_table_event_send(curr_tbl, UI_EVT_SCROLL_RIGHT);
break;
case 'b':
if (rate_type == RATE_BYTES)