From: Pablo Neira Ayuso <pablo@netfilter.org>
To: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Cc: netfilter-devel@vger.kernel.org
Subject: Re: [PATCH 10/14] netfilter: ipset: Introduce RCU locking in the list type
Date: Tue, 2 Dec 2014 19:35:39 +0100 [thread overview]
Message-ID: <20141202183539.GC4504@salvia> (raw)
In-Reply-To: <1417373825-3734-11-git-send-email-kadlec@blackhole.kfki.hu>
On Sun, Nov 30, 2014 at 07:57:01PM +0100, Jozsef Kadlecsik wrote:
> Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
> ---
> net/netfilter/ipset/ip_set_list_set.c | 386 ++++++++++++++++------------------
> 1 file changed, 182 insertions(+), 204 deletions(-)
>
> diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
> index f8f6828..323115a 100644
> --- a/net/netfilter/ipset/ip_set_list_set.c
> +++ b/net/netfilter/ipset/ip_set_list_set.c
> @@ -9,6 +9,7 @@
>
> #include <linux/module.h>
> #include <linux/ip.h>
> +#include <linux/rculist.h>
> #include <linux/skbuff.h>
> #include <linux/errno.h>
>
> @@ -27,6 +28,8 @@ MODULE_ALIAS("ip_set_list:set");
>
> /* Member elements */
> struct set_elem {
> + struct rcu_head rcu;
> + struct list_head list;
I think rcu_barrier() in the module removal path is missing to make
sure call_rcu() is called before the module is gone.
> ip_set_id_t id;
> };
>
> @@ -41,12 +44,9 @@ struct list_set {
> u32 size; /* size of set list array */
> struct timer_list gc; /* garbage collection */
> struct net *net; /* namespace */
> - struct set_elem members[0]; /* the set members */
> + struct list_head members; /* the set members */
> };
>
> -#define list_set_elem(set, map, id) \
> - (struct set_elem *)((void *)(map)->members + (id) * (set)->dsize)
> -
> static int
> list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
> const struct xt_action_param *par,
> @@ -54,17 +54,14 @@ list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
> {
> struct list_set *map = set->data;
> struct set_elem *e;
> - u32 i, cmdflags = opt->cmdflags;
> + u32 cmdflags = opt->cmdflags;
> int ret;
>
> /* Don't lookup sub-counters at all */
> opt->cmdflags &= ~IPSET_FLAG_MATCH_COUNTERS;
> if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)
> opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE;
> - for (i = 0; i < map->size; i++) {
> - e = list_set_elem(set, map, i);
> - if (e->id == IPSET_INVALID_ID)
> - return 0;
> + list_for_each_entry_rcu(e, &map->members, list) {
> if (SET_WITH_TIMEOUT(set) &&
> ip_set_timeout_expired(ext_timeout(e, set)))
> continue;
> @@ -91,13 +88,9 @@ list_set_kadd(struct ip_set *set, const struct sk_buff *skb,
> {
> struct list_set *map = set->data;
> struct set_elem *e;
> - u32 i;
> int ret;
>
> - for (i = 0; i < map->size; i++) {
> - e = list_set_elem(set, map, i);
> - if (e->id == IPSET_INVALID_ID)
> - return 0;
> + list_for_each_entry_rcu(e, &map->members, list) {
>From net/netfilter/ipset/ip_set_core.c I can see this kadd() will be
called under spin_lock_bh(), so you can just use
list_for_each_entry(). The _rcu() variant protects the reader side,
but this code is only invoked from the writer side (no changes are
guaranteed to happen there).
> if (SET_WITH_TIMEOUT(set) &&
> ip_set_timeout_expired(ext_timeout(e, set)))
> continue;
> @@ -115,13 +108,9 @@ list_set_kdel(struct ip_set *set, const struct sk_buff *skb,
> {
> struct list_set *map = set->data;
> struct set_elem *e;
> - u32 i;
> int ret;
>
> - for (i = 0; i < map->size; i++) {
> - e = list_set_elem(set, map, i);
> - if (e->id == IPSET_INVALID_ID)
> - return 0;
> + list_for_each_entry_rcu(e, &map->members, list) {
> if (SET_WITH_TIMEOUT(set) &&
> ip_set_timeout_expired(ext_timeout(e, set)))
> continue;
> @@ -138,110 +127,65 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
> enum ipset_adt adt, struct ip_set_adt_opt *opt)
> {
> struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
> + int ret = -EINVAL;
>
> + rcu_read_lock();
> switch (adt) {
> case IPSET_TEST:
> - return list_set_ktest(set, skb, par, opt, &ext);
> + ret = list_set_ktest(set, skb, par, opt, &ext);
> + break;
> case IPSET_ADD:
> - return list_set_kadd(set, skb, par, opt, &ext);
> + ret = list_set_kadd(set, skb, par, opt, &ext);
> + break;
> case IPSET_DEL:
> - return list_set_kdel(set, skb, par, opt, &ext);
> + ret = list_set_kdel(set, skb, par, opt, &ext);
> + break;
> default:
> break;
> }
> - return -EINVAL;
> -}
> + rcu_read_unlock();
>
> -static bool
> -id_eq(const struct ip_set *set, u32 i, ip_set_id_t id)
> -{
> - const struct list_set *map = set->data;
> - const struct set_elem *e;
> -
> - if (i >= map->size)
> - return 0;
> -
> - e = list_set_elem(set, map, i);
> - return !!(e->id == id &&
> - !(SET_WITH_TIMEOUT(set) &&
> - ip_set_timeout_expired(ext_timeout(e, set))));
> + return ret;
> }
>
> -static int
> -list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d,
> - const struct ip_set_ext *ext)
> -{
> - struct list_set *map = set->data;
> - struct set_elem *e = list_set_elem(set, map, i);
> -
> - if (e->id != IPSET_INVALID_ID) {
> - if (i == map->size - 1) {
> - /* Last element replaced: e.g. add new,before,last */
> - ip_set_put_byindex(map->net, e->id);
> - ip_set_ext_destroy(set, e);
> - } else {
> - struct set_elem *x = list_set_elem(set, map,
> - map->size - 1);
> -
> - /* Last element pushed off */
> - if (x->id != IPSET_INVALID_ID) {
> - ip_set_put_byindex(map->net, x->id);
> - ip_set_ext_destroy(set, x);
> - }
> - memmove(list_set_elem(set, map, i + 1), e,
> - set->dsize * (map->size - (i + 1)));
> - /* Extensions must be initialized to zero */
> - memset(e, 0, set->dsize);
> - }
> - }
> -
> - e->id = d->id;
> - if (SET_WITH_TIMEOUT(set))
> - ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
> - if (SET_WITH_COUNTER(set))
> - ip_set_init_counter(ext_counter(e, set), ext);
> - if (SET_WITH_COMMENT(set))
> - ip_set_init_comment(ext_comment(e, set), ext);
> - if (SET_WITH_SKBINFO(set))
> - ip_set_init_skbinfo(ext_skbinfo(e, set), ext);
> - return 0;
> -}
> +/* Userspace interfaces: we are protected by the nfnl mutex */
>
> -static int
> -list_set_del(struct ip_set *set, u32 i)
> +static void
> +__list_set_del(struct ip_set *set, struct set_elem *e)
> {
> struct list_set *map = set->data;
> - struct set_elem *e = list_set_elem(set, map, i);
>
> ip_set_put_byindex(map->net, e->id);
> + /* We may call it, because we don't have a to be destroyed
> + * extension which is used by the kernel.
> + */
> ip_set_ext_destroy(set, e);
> + kfree_rcu(e, rcu);
> +}
>
> - if (i < map->size - 1)
> - memmove(e, list_set_elem(set, map, i + 1),
> - set->dsize * (map->size - (i + 1)));
> +static inline void
> +list_set_del(struct ip_set *set, struct set_elem *e)
> +{
> + list_del_rcu(&e->list);
> + __list_set_del(set, e);
> +}
>
> - /* Last element */
> - e = list_set_elem(set, map, map->size - 1);
> - e->id = IPSET_INVALID_ID;
> - return 0;
> +static inline void
> +list_set_replace(struct ip_set *set, struct set_elem *e, struct set_elem *old)
> +{
> + list_replace_rcu(&old->list, &e->list);
> + __list_set_del(set, old);
> }
>
> static void
> set_cleanup_entries(struct ip_set *set)
> {
> struct list_set *map = set->data;
> - struct set_elem *e;
> - u32 i = 0;
> + struct set_elem *e, *n;
>
> - while (i < map->size) {
> - e = list_set_elem(set, map, i);
> - if (e->id != IPSET_INVALID_ID &&
> - ip_set_timeout_expired(ext_timeout(e, set)))
> - list_set_del(set, i);
> - /* Check element moved to position i in next loop */
> - else
> - i++;
> - }
> + list_for_each_entry_safe(e, n, &map->members, list)
> + if (ip_set_timeout_expired(ext_timeout(e, set)))
> + list_set_del(set, e);
> }
>
> static int
> @@ -250,31 +194,45 @@ list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,
> {
> struct list_set *map = set->data;
> struct set_adt_elem *d = value;
> - struct set_elem *e;
> - u32 i;
> + struct set_elem *e, *next, *prev = NULL;
> int ret;
>
> - for (i = 0; i < map->size; i++) {
> - e = list_set_elem(set, map, i);
> - if (e->id == IPSET_INVALID_ID)
> - return 0;
> - else if (SET_WITH_TIMEOUT(set) &&
> - ip_set_timeout_expired(ext_timeout(e, set)))
> + list_for_each_entry(e, &map->members, list) {
> + if (SET_WITH_TIMEOUT(set) &&
> + ip_set_timeout_expired(ext_timeout(e, set)))
> continue;
> - else if (e->id != d->id)
> + else if (e->id != d->id) {
> + prev = e;
> continue;
> + }
>
> if (d->before == 0)
> - return 1;
> - else if (d->before > 0)
> - ret = id_eq(set, i + 1, d->refid);
> - else
> - ret = i > 0 && id_eq(set, i - 1, d->refid);
> + ret = 1;
> + else if (d->before > 0) {
> + next = list_next_entry(e, list);
> + ret = !list_is_last(&e->list, &map->members) &&
> + next->id == d->refid;
> + } else
> + ret = prev != NULL && prev->id == d->refid;
> return ret;
> }
> return 0;
> }
>
> +static void
> +list_set_init_extensions(struct ip_set *set, const struct ip_set_ext *ext,
> + struct set_elem *e)
> +{
> + if (SET_WITH_COUNTER(set))
> + ip_set_init_counter(ext_counter(e, set), ext);
> + if (SET_WITH_COMMENT(set))
> + ip_set_init_comment(ext_comment(e, set), ext);
> + if (SET_WITH_SKBINFO(set))
> + ip_set_init_skbinfo(ext_skbinfo(e, set), ext);
> + /* Update timeout last */
> + if (SET_WITH_TIMEOUT(set))
> + ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
> +}
>
> static int
> list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
> @@ -282,60 +240,82 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
> {
> struct list_set *map = set->data;
> struct set_adt_elem *d = value;
> - struct set_elem *e;
> + struct set_elem *e, *n, *prev, *next;
> bool flag_exist = flags & IPSET_FLAG_EXIST;
> - u32 i, ret = 0;
>
> if (SET_WITH_TIMEOUT(set))
> set_cleanup_entries(set);
>
> - /* Check already added element */
> - for (i = 0; i < map->size; i++) {
> - e = list_set_elem(set, map, i);
> - if (e->id == IPSET_INVALID_ID)
> - goto insert;
> - else if (e->id != d->id)
> + /* Find where to add the new entry */
> + n = prev = next = NULL;
> + list_for_each_entry(e, &map->members, list) {
> + if (SET_WITH_TIMEOUT(set) &&
> + ip_set_timeout_expired(ext_timeout(e, set)))
> continue;
> -
> - if ((d->before > 1 && !id_eq(set, i + 1, d->refid)) ||
> - (d->before < 0 &&
> - (i == 0 || !id_eq(set, i - 1, d->refid))))
> - /* Before/after doesn't match */
> + else if (d->id == e->id)
> + n = e;
> + else if (d->before == 0 || e->id != d->refid)
> + continue;
> + else if (d->before > 0)
> + next = e;
> + else
> + prev = e;
> + }
> + /* Re-add already existing element */
> + if (n) {
> + if ((d->before > 0 && !next) ||
> + (d->before < 0 && !prev))
> return -IPSET_ERR_REF_EXIST;
> if (!flag_exist)
> - /* Can't re-add */
> return -IPSET_ERR_EXIST;
> /* Update extensions */
> - ip_set_ext_destroy(set, e);
> + ip_set_ext_destroy(set, n);
> + list_set_init_extensions(set, ext, n);
>
> - if (SET_WITH_TIMEOUT(set))
> - ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
> - if (SET_WITH_COUNTER(set))
> - ip_set_init_counter(ext_counter(e, set), ext);
> - if (SET_WITH_COMMENT(set))
> - ip_set_init_comment(ext_comment(e, set), ext);
> - if (SET_WITH_SKBINFO(set))
> - ip_set_init_skbinfo(ext_skbinfo(e, set), ext);
> /* Set is already added to the list */
> ip_set_put_byindex(map->net, d->id);
> return 0;
> }
> -insert:
> - ret = -IPSET_ERR_LIST_FULL;
> - for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
> - e = list_set_elem(set, map, i);
> - if (e->id == IPSET_INVALID_ID)
> - ret = d->before != 0 ? -IPSET_ERR_REF_EXIST
> - : list_set_add(set, i, d, ext);
> - else if (e->id != d->refid)
> - continue;
> - else if (d->before > 0)
> - ret = list_set_add(set, i, d, ext);
> - else if (i + 1 < map->size)
> - ret = list_set_add(set, i + 1, d, ext);
> + /* Add new entry */
> + if (d->before == 0) {
> + /* Append */
> + n = list_empty(&map->members) ? NULL :
> + list_last_entry(&map->members, struct set_elem, list);
> + } else if (d->before > 0) {
> + /* Insert after next element */
> + if (!list_is_last(&next->list, &map->members))
> + n = list_next_entry(next, list);
> + } else {
> + /* Insert before prev element */
> + if (prev->list.prev != &map->members)
> + n = list_prev_entry(prev, list);
> }
> -
> - return ret;
> + /* Can we replace a timed out entry? */
> + if (n != NULL &&
> + !(SET_WITH_TIMEOUT(set) &&
> + ip_set_timeout_expired(ext_timeout(n, set))))
> + n = NULL;
> +
> + e = kzalloc(set->dsize, GFP_KERNEL);
> + if (!e)
> + return -ENOMEM;
> + e->id = d->id;
> + INIT_LIST_HEAD(&e->list);
> + list_set_init_extensions(set, ext, e);
> + if (n)
> + list_set_replace(set, e, n);
> + else if (next)
> + list_add_tail_rcu(&e->list, &next->list);
> + else if (prev)
> + list_add_rcu(&e->list, &prev->list);
> + else
> + list_add_tail_rcu(&e->list, &map->members);
> + spin_unlock_bh(&set->lock);
> +
> + synchronize_rcu_bh();
I suspect you don't need this. What is your intention here?
> +
> + spin_lock_bh(&set->lock);
> + return 0;
> }
>
> static int
> @@ -344,32 +324,30 @@ list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext,
> {
> struct list_set *map = set->data;
> struct set_adt_elem *d = value;
> - struct set_elem *e;
> - u32 i;
> -
> - for (i = 0; i < map->size; i++) {
> - e = list_set_elem(set, map, i);
> - if (e->id == IPSET_INVALID_ID)
> - return d->before != 0 ? -IPSET_ERR_REF_EXIST
> - : -IPSET_ERR_EXIST;
> - else if (SET_WITH_TIMEOUT(set) &&
> - ip_set_timeout_expired(ext_timeout(e, set)))
> + struct set_elem *e, *next, *prev = NULL;
> +
> + list_for_each_entry(e, &map->members, list) {
> + if (SET_WITH_TIMEOUT(set) &&
> + ip_set_timeout_expired(ext_timeout(e, set)))
> continue;
> - else if (e->id != d->id)
> + else if (e->id != d->id) {
> + prev = e;
> continue;
> + }
>
> - if (d->before == 0)
> - return list_set_del(set, i);
> - else if (d->before > 0) {
> - if (!id_eq(set, i + 1, d->refid))
> + if (d->before > 0) {
> + next = list_next_entry(e, list);
> + if (list_is_last(&e->list, &map->members) ||
> + next->id != d->refid)
> return -IPSET_ERR_REF_EXIST;
> - return list_set_del(set, i);
> - } else if (i == 0 || !id_eq(set, i - 1, d->refid))
> - return -IPSET_ERR_REF_EXIST;
> - else
> - return list_set_del(set, i);
> + } else if (d->before < 0) {
> + if (prev == NULL || prev->id != d->refid)
> + return -IPSET_ERR_REF_EXIST;
> + }
> + list_set_del(set, e);
> + return 0;
> }
> - return -IPSET_ERR_EXIST;
> + return d->before != 0 ? -IPSET_ERR_REF_EXIST : -IPSET_ERR_EXIST;
> }
>
> static int
> @@ -410,6 +388,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
>
> if (tb[IPSET_ATTR_CADT_FLAGS]) {
> u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
> +
> e.before = f & IPSET_FLAG_BEFORE;
> }
>
> @@ -447,27 +426,26 @@ static void
> list_set_flush(struct ip_set *set)
> {
> struct list_set *map = set->data;
> - struct set_elem *e;
> - u32 i;
> -
> - for (i = 0; i < map->size; i++) {
> - e = list_set_elem(set, map, i);
> - if (e->id != IPSET_INVALID_ID) {
> - ip_set_put_byindex(map->net, e->id);
> - ip_set_ext_destroy(set, e);
> - e->id = IPSET_INVALID_ID;
> - }
> - }
> + struct set_elem *e, *n;
> +
> + list_for_each_entry_safe(e, n, &map->members, list)
> + list_set_del(set, e);
> }
>
> static void
> list_set_destroy(struct ip_set *set)
> {
> struct list_set *map = set->data;
> + struct set_elem *e, *n;
>
> if (SET_WITH_TIMEOUT(set))
> del_timer_sync(&map->gc);
> - list_set_flush(set);
> + list_for_each_entry_safe(e, n, &map->members, list) {
> + list_del(&e->list);
> + ip_set_put_byindex(map->net, e->id);
> + ip_set_ext_destroy(set, e);
> + kfree(e);
> + }
> kfree(map);
>
> set->data = NULL;
> @@ -478,6 +456,11 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
> {
> const struct list_set *map = set->data;
> struct nlattr *nested;
> + struct set_elem *e;
> + u32 n = 0;
> +
> + list_for_each_entry(e, &map->members, list)
> + n++;
>
> nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
> if (!nested)
> @@ -485,7 +468,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
> if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) ||
> nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
> nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
> - htonl(sizeof(*map) + map->size * set->dsize)))
> + htonl(sizeof(*map) + n * set->dsize)))
> goto nla_put_failure;
> if (unlikely(ip_set_put_flags(skb, set)))
> goto nla_put_failure;
> @@ -502,18 +485,20 @@ list_set_list(const struct ip_set *set,
> {
> const struct list_set *map = set->data;
> struct nlattr *atd, *nested;
> - u32 i, first = cb->args[IPSET_CB_ARG0];
> - const struct set_elem *e;
> + u32 i = 0, first = cb->args[IPSET_CB_ARG0];
> + struct set_elem *e;
>
> atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
> if (!atd)
> return -EMSGSIZE;
> - for (; cb->args[IPSET_CB_ARG0] < map->size;
> - cb->args[IPSET_CB_ARG0]++) {
> - i = cb->args[IPSET_CB_ARG0];
> - e = list_set_elem(set, map, i);
> - if (e->id == IPSET_INVALID_ID)
> - goto finish;
> + list_for_each_entry(e, &map->members, list) {
> + if (i == first)
> + break;
> + i++;
> + }
> +
> + list_for_each_entry_from(e, &map->members, list) {
> + i++;
> if (SET_WITH_TIMEOUT(set) &&
> ip_set_timeout_expired(ext_timeout(e, set)))
> continue;
> @@ -532,7 +517,7 @@ list_set_list(const struct ip_set *set,
> goto nla_put_failure;
> ipset_nest_end(skb, nested);
> }
> -finish:
> +
> ipset_nest_end(skb, atd);
> /* Set listing finished */
> cb->args[IPSET_CB_ARG0] = 0;
> @@ -544,6 +529,7 @@ nla_put_failure:
> cb->args[IPSET_CB_ARG0] = 0;
> return -EMSGSIZE;
> }
> + cb->args[IPSET_CB_ARG0] = i - 1;
> ipset_nest_end(skb, atd);
> return 0;
> }
> @@ -580,9 +566,9 @@ list_set_gc(unsigned long ul_set)
> struct ip_set *set = (struct ip_set *) ul_set;
> struct list_set *map = set->data;
>
> - write_lock_bh(&set->lock);
> + spin_lock_bh(&set->lock);
> set_cleanup_entries(set);
> - write_unlock_bh(&set->lock);
> + spin_unlock_bh(&set->lock);
>
> map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
> add_timer(&map->gc);
> @@ -606,24 +592,16 @@ static bool
> init_list_set(struct net *net, struct ip_set *set, u32 size)
> {
> struct list_set *map;
> - struct set_elem *e;
> - u32 i;
>
> - map = kzalloc(sizeof(*map) +
> - min_t(u32, size, IP_SET_LIST_MAX_SIZE) * set->dsize,
> - GFP_KERNEL);
> + map = kzalloc(sizeof(*map), GFP_KERNEL);
> if (!map)
> return false;
>
> map->size = size;
> map->net = net;
> + INIT_LIST_HEAD(&map->members);
> set->data = map;
>
> - for (i = 0; i < size; i++) {
> - e = list_set_elem(set, map, i);
> - e->id = IPSET_INVALID_ID;
> - }
> -
> return true;
> }
>
> --
> 1.8.5.1
>
next prev parent reply other threads:[~2014-12-02 18:33 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-11-30 18:56 [PATCH 00/10] ipset patches for nf-next, v2 Jozsef Kadlecsik
2014-11-30 18:56 ` [PATCH 01/14] netfilter: ipset: Support updating extensions when the set is full Jozsef Kadlecsik
2014-12-02 18:46 ` Pablo Neira Ayuso
2014-12-02 18:50 ` Pablo Neira Ayuso
2014-12-03 11:26 ` Jozsef Kadlecsik
2014-12-03 11:56 ` Pablo Neira Ayuso
2014-11-30 18:56 ` [PATCH 02/14] netfilter: ipset: Alignment problem between 64bit kernel 32bit userspace Jozsef Kadlecsik
2014-11-30 18:56 ` [PATCH 03/14] netfilter: ipset: Indicate when /0 networks are supported Jozsef Kadlecsik
2014-11-30 18:56 ` [PATCH 04/14] netfilter: ipset: Simplify cidr handling for hash:*net* types Jozsef Kadlecsik
2014-11-30 18:56 ` [PATCH 05/14] netfilter: ipset: Allocate the proper size of memory when /0 networks are supported Jozsef Kadlecsik
2014-11-30 18:56 ` [PATCH 06/14] netfilter: ipset: Explicitly add padding elements to hash:net,net and hash:net,port,net Jozsef Kadlecsik
2014-11-30 18:56 ` [PATCH 07/14] netfilter: ipset: Remove rbtree from hash:net,iface in order to run under RCU Jozsef Kadlecsik
2014-12-02 18:23 ` Pablo Neira Ayuso
2014-12-03 10:54 ` Jozsef Kadlecsik
2014-11-30 18:56 ` [PATCH 08/14] netfilter: ipset: Introduce RCU locking instead of rwlock per set in the core Jozsef Kadlecsik
2014-12-02 18:25 ` Pablo Neira Ayuso
2014-12-03 11:01 ` Jozsef Kadlecsik
2014-11-30 18:57 ` [PATCH 09/14] netfilter: ipset: Introduce RCU locking in the bitmap types Jozsef Kadlecsik
2014-11-30 18:57 ` [PATCH 10/14] netfilter: ipset: Introduce RCU locking in the list type Jozsef Kadlecsik
2014-12-02 18:35 ` Pablo Neira Ayuso [this message]
2014-12-02 18:52 ` Pablo Neira Ayuso
2014-12-03 11:17 ` Jozsef Kadlecsik
2014-12-03 11:36 ` Pablo Neira Ayuso
2014-11-30 18:57 ` [PATCH 11/14] netfilter: ipset: Introduce RCU locking in the hash types Jozsef Kadlecsik
2014-12-01 7:59 ` Jesper Dangaard Brouer
2014-12-02 18:40 ` Pablo Neira Ayuso
2014-12-03 11:23 ` Jozsef Kadlecsik
2014-11-30 18:57 ` [PATCH 12/14] netfilter: ipset: styles warned by checkpatch.pl fixed Jozsef Kadlecsik
2014-12-02 18:43 ` Pablo Neira Ayuso
2014-12-03 11:25 ` Jozsef Kadlecsik
2014-11-30 18:57 ` [PATCH 13/14] netfilter: ipset: Fix parallel resizing and listing of the same set Jozsef Kadlecsik
2014-11-30 18:57 ` [PATCH 14/14] netfilter: ipset: Fix sparse warning Jozsef Kadlecsik
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20141202183539.GC4504@salvia \
--to=pablo@netfilter.org \
--cc=kadlec@blackhole.kfki.hu \
--cc=netfilter-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).