Thanks for the patch and sorry for the delay in reply.

I'm not too familiar with the RCU list interface, but from a quick
glance this looks OK in general. A few remarks below.

Daniel, if you have time could you maybe have a quick look?

On 2017-01-09 at 07:26:07 +0100, Vadim Kochan <vadi...@gmail.com> wrote:
> list.h provides generic Linux-like linked list API which also supports
> RCU list operations.
> 
> Also additionally was removed the spinlock which is not needed for
> RCU-list operations, for the list_del_rcu(...) case it is needed
> additionally call synchronize_rcu(...) before free the flow entry.
> 
> Because of full RCU support now flows are freed after grace-period via
> calling synchronize_rcu() and these removed-and-ready-to-free entries
> are kept in separate struct list_head.

Do we really need the separate free list? Couldn't we add a struct
rcu_head to struct flow_entry instead and then use something along the
lines of:

static void flow_entry_xfree_rcu(struct rcu_head *rcu)
{
        struct flow_entry *entry = caa_container_of(rcu, struct flow_entry, 
rcu_head);
        flow_entry_free(entry);
}

call_rcu(&entry->rcu_head, free_entry_rcu);

to free the entries after the RCU grace period?

> Signed-off-by: Vadim Kochan <vadi...@gmail.com>

> ---
>  flowtop.c | 121 
> +++++++++++++++++++++++---------------------------------------
>  1 file changed, 44 insertions(+), 77 deletions(-)
> 
> diff --git a/flowtop.c b/flowtop.c
> index f48f5c8..a5ac2bb 100644
> --- a/flowtop.c
>+++ b/flowtop.c

The #include "locking.h" should be removed as non of the symbols defined
there are used anymore in flowtop.c

> @@ -51,6 +51,9 @@
>  #endif
>  
>  struct flow_entry {
> +     struct list_head entry;
> +     struct list_head free;
> +
>       uint32_t flow_id, use, status;
>       uint8_t  l3_proto, l4_proto;
>       uint32_t ip4_src_addr, ip4_dst_addr;
> @@ -65,7 +68,6 @@ struct flow_entry {
>       char city_src[128], city_dst[128];
>       char rev_dns_src[256], rev_dns_dst[256];
>       char procname[256];
> -     struct flow_entry *next;
>       int inode;
>       unsigned int procnum;
>       bool is_visible;
> @@ -78,8 +80,8 @@ struct flow_entry {
>  };
>  
>  struct flow_list {
> -     struct flow_entry *head;
> -     struct spinlock lock;
> +     struct list_head head;
> +     struct list_head free;
>  };
>  
>  enum flow_direction {
> @@ -355,15 +357,15 @@ static inline struct flow_entry *flow_entry_xalloc(void)
>  static inline void flow_entry_xfree(struct flow_entry *n)
>  {
>       if (n->ct)
> -             nfct_destroy(n->ct);
> +             xfree(n->ct);

This would leak memory allocated internally in struct nf_contrack, no?
What's the reason for this change?

>       xfree(n);
>  }
>  
>  static inline void flow_list_init(struct flow_list *fl)
>  {
> -     fl->head = NULL;
> -     spinlock_init(&fl->lock);
> +     INIT_LIST_HEAD(&fl->head);
> +     INIT_LIST_HEAD(&fl->free);
>  }
>  
>  static inline bool nfct_is_dns(const struct nf_conntrack *ct)
> @@ -392,84 +394,60 @@ static void flow_list_new_entry(struct flow_list *fl, 
> const struct nf_conntrack
>       flow_entry_from_ct(n, ct);
>       flow_entry_get_extended(n);
>  
> -     rcu_assign_pointer(n->next, fl->head);
> -     rcu_assign_pointer(fl->head, n);
> +     list_add_rcu(&n->entry, &fl->head);
>  
>       n->is_visible = true;
>  }
>  
> -static struct flow_entry *flow_list_find_id(struct flow_list *fl,
> -                                         uint32_t id)
> +static struct flow_entry *flow_list_find_id(struct flow_list *fl, uint32_t 
> id)
>  {
> -     struct flow_entry *n = rcu_dereference(fl->head);
> +     struct flow_entry *n;
>  
> -     while (n != NULL) {
> +     list_for_each_entry_rcu(n, &fl->head, entry) {
q
>               if (n->flow_id == id)
>                       return n;
> -
> -             n = rcu_dereference(n->next);
>       }
>  
>       return NULL;
>  }
>  
> -static struct flow_entry *flow_list_find_prev_id(const struct flow_list *fl,
> -                                              uint32_t id)
> +static void flow_list_del_entry(struct flow_list *fl, const struct 
> nf_conntrack *ct)
>  {
> -     struct flow_entry *prev = rcu_dereference(fl->head), *next;
> -
> -     if (prev->flow_id == id)
> -             return NULL;
> -
> -     while ((next = rcu_dereference(prev->next)) != NULL) {
> -             if (next->flow_id == id)
> -                     return prev;
> +     struct flow_entry *n;
>  
> -             prev = next;
> +     n = flow_list_find_id(fl, nfct_get_attr_u32(ct, ATTR_ID));
> +     if (n) {
> +             list_del_rcu(&n->entry);
> +             list_add_rcu(&n->free, &fl->free);

Here would be the call_rcu() outlined above (instead of list_add_rcu)

>       }
> -
> -     return NULL;
>  }
>  
> -static void flow_list_destroy_entry(struct flow_list *fl,
> -                                 const struct nf_conntrack *ct)
> +static void flow_list_clear(struct flow_list *fl)
>  {
> -     struct flow_entry *n1, *n2;
> -     uint32_t id = nfct_get_attr_u32(ct, ATTR_ID);
> -
> -     n1 = flow_list_find_id(fl, id);
> -     if (n1) {
> -             n2 = flow_list_find_prev_id(fl, id);
> -             if (n2) {
> -                     rcu_assign_pointer(n2->next, n1->next);
> -                     n1->next = NULL;
> -
> -                     flow_entry_xfree(n1);
> -             } else {
> -                     struct flow_entry *next = fl->head->next;
> +     struct flow_entry *n, *tmp;
>  
> -                     flow_entry_xfree(fl->head);
> -                     fl->head = next;
> -             }
> +     list_for_each_entry_safe(n, tmp, &fl->head, entry) {
> +             list_del_rcu(&n->entry);
> +             list_add_rcu(&n->free, &fl->free);

Same here.

>       }
>  }
>  
> -static void flow_list_destroy(struct flow_list *fl)
> +static void flow_list_free(struct flow_list *fl)
>  {
> -     struct flow_entry *n;
> +     struct flow_entry *n, *tmp;
>  
>       synchronize_rcu();
> -     spinlock_lock(&flow_list.lock);
>  
> -     while (fl->head != NULL) {
> -             n = rcu_dereference(fl->head->next);
> -             fl->head->next = NULL;
> -
> -             flow_entry_xfree(fl->head);
> -             rcu_assign_pointer(fl->head, n);
> +     list_for_each_entry_safe(n, tmp, &fl->free, free) {
> +             list_del(&n->free);
> +             flow_entry_xfree(n);
>       }
> +}
>  
> -     spinlock_unlock(&flow_list.lock);
> +static void flow_list_destroy(struct flow_list *fl)
> +{
> +     flow_list_clear(fl);
> +     flow_list_free(fl);
>  }
>  
>  static void flow_entry_find_process(struct flow_entry *n)
> @@ -1044,15 +1022,14 @@ static void draw_flows(WINDOW *screen, struct 
> flow_list *fl,
>  
>       rcu_read_lock();
>  
> -     n = rcu_dereference(fl->head);
> -     if (!n)
> +     if (list_empty(&fl->head))
>               mvwprintw(screen, line, 2, "(No sessions! "
>                         "Is netfilter running?)");
>  
>       ui_table_clear(&flows_tbl);
>       ui_table_header_print(&flows_tbl);
>  
> -     for (; n; n = rcu_dereference(n->next)) {
> +     list_for_each_entry_rcu(n, &fl->head, entry) {
>               if (!n->is_visible)
>                       continue;
>               if (presenter_flow_wrong_state(n))
> @@ -1415,9 +1392,6 @@ static int flow_event_cb(enum nf_conntrack_msg_type 
> type,
>       if (sigint)
>               return NFCT_CB_STOP;
>  
> -     synchronize_rcu();
> -     spinlock_lock(&flow_list.lock);
> -
>       switch (type) {
>       case NFCT_T_NEW:
>               flow_list_new_entry(&flow_list, ct);
> @@ -1426,14 +1400,12 @@ static int flow_event_cb(enum nf_conntrack_msg_type 
> type,
>               flow_list_update_entry(&flow_list, ct);
>               break;
>       case NFCT_T_DESTROY:
> -             flow_list_destroy_entry(&flow_list, ct);
> +             flow_list_del_entry(&flow_list, ct);
>               break;
>       default:
>               break;
>       }
>  
> -     spinlock_unlock(&flow_list.lock);
> -
>       if (sigint)
>               return NFCT_CB_STOP;
>  
> @@ -1444,8 +1416,7 @@ 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))
> +     list_for_each_entry_rcu(n, &flow_list.head, entry)
>               nfct_query(handle, NFCT_Q_GET, n->ct);
>  }
>  
> @@ -1500,9 +1471,6 @@ static int flow_dump_cb(enum nf_conntrack_msg_type type 
> __maybe_unused,
>       if (sigint)
>               return NFCT_CB_STOP;
>  
> -     synchronize_rcu();
> -     spinlock_lock(&flow_list.lock);
> -
>       if (!(what & ~(INCLUDE_IPV4 | INCLUDE_IPV6)))
>               goto check_addr;
>  
> @@ -1558,7 +1526,6 @@ check_addr:
>       flow_list_new_entry(&flow_list, ct);
>  
>  skip_flow:
> -     spinlock_unlock(&flow_list.lock);
>       return NFCT_CB_CONTINUE;
>  }
>  
> @@ -1635,18 +1602,18 @@ static void *collector(void *null __maybe_unused)
>                               continue;
>  
>                       panic("Error while polling: %s\n", strerror(errno));
> -             } else if (status == 0) {
> -                     continue;
> +             } else if (status != 0) {
> +                     if (poll_fd[0].revents & POLLIN)
> +                             nfct_catch(ct_event);
>               }
>  
> -             if (poll_fd[0].revents & POLLIN)
> -                     nfct_catch(ct_event);
> +             if (!list_empty(&flow_list.free))
> +                     flow_list_free(&flow_list);
>       }
>  
> -     rcu_unregister_thread();
> -
>       flow_list_destroy(&flow_list);
> -     spinlock_destroy(&flow_list.lock);
> +
> +     rcu_unregister_thread();
>  
>       nfct_close(ct_event);
>  
> -- 
> 2.11.0
> 

-- 
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 netsniff-ng+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to