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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.