Commit 96f51428 authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik

netfilter: ipset: Introduce RCU locking in bitmap:* types

There's nothing much required because the bitmap types use atomic
bit operations. However the logic of adding elements slightly changed:
first the MAC address updated (which is not atomic), then the element
activated (added). The extensions may call kfree_rcu() therefore we
call rcu_barrier() at module removal.
Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
parent b57b2d1f
...@@ -144,10 +144,12 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, ...@@ -144,10 +144,12 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
if (ret == IPSET_ADD_FAILED) { if (ret == IPSET_ADD_FAILED) {
if (SET_WITH_TIMEOUT(set) && if (SET_WITH_TIMEOUT(set) &&
ip_set_timeout_expired(ext_timeout(x, set))) ip_set_timeout_expired(ext_timeout(x, set))) {
ret = 0; ret = 0;
else if (!(flags & IPSET_FLAG_EXIST)) } else if (!(flags & IPSET_FLAG_EXIST)) {
set_bit(e->id, map->members);
return -IPSET_ERR_EXIST; return -IPSET_ERR_EXIST;
}
/* Element is re-added, cleanup extensions */ /* Element is re-added, cleanup extensions */
ip_set_ext_destroy(set, x); ip_set_ext_destroy(set, x);
} }
...@@ -165,6 +167,10 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, ...@@ -165,6 +167,10 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
ip_set_init_comment(ext_comment(x, set), ext); ip_set_init_comment(ext_comment(x, set), ext);
if (SET_WITH_SKBINFO(set)) if (SET_WITH_SKBINFO(set))
ip_set_init_skbinfo(ext_skbinfo(x, set), ext); ip_set_init_skbinfo(ext_skbinfo(x, set), ext);
/* Activate element */
set_bit(e->id, map->members);
return 0; return 0;
} }
...@@ -203,10 +209,13 @@ mtype_list(const struct ip_set *set, ...@@ -203,10 +209,13 @@ mtype_list(const struct ip_set *set,
struct nlattr *adt, *nested; struct nlattr *adt, *nested;
void *x; void *x;
u32 id, first = cb->args[IPSET_CB_ARG0]; u32 id, first = cb->args[IPSET_CB_ARG0];
int ret = 0;
adt = ipset_nest_start(skb, IPSET_ATTR_ADT); adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!adt) if (!adt)
return -EMSGSIZE; return -EMSGSIZE;
/* Extensions may be replaced */
rcu_read_lock();
for (; cb->args[IPSET_CB_ARG0] < map->elements; for (; cb->args[IPSET_CB_ARG0] < map->elements;
cb->args[IPSET_CB_ARG0]++) { cb->args[IPSET_CB_ARG0]++) {
id = cb->args[IPSET_CB_ARG0]; id = cb->args[IPSET_CB_ARG0];
...@@ -222,9 +231,11 @@ mtype_list(const struct ip_set *set, ...@@ -222,9 +231,11 @@ mtype_list(const struct ip_set *set,
if (!nested) { if (!nested) {
if (id == first) { if (id == first) {
nla_nest_cancel(skb, adt); nla_nest_cancel(skb, adt);
return -EMSGSIZE; ret = -EMSGSIZE;
} else goto out;
goto nla_put_failure; }
goto nla_put_failure;
} }
if (mtype_do_list(skb, map, id, set->dsize)) if (mtype_do_list(skb, map, id, set->dsize))
goto nla_put_failure; goto nla_put_failure;
...@@ -238,16 +249,18 @@ mtype_list(const struct ip_set *set, ...@@ -238,16 +249,18 @@ mtype_list(const struct ip_set *set,
/* Set listing finished */ /* Set listing finished */
cb->args[IPSET_CB_ARG0] = 0; cb->args[IPSET_CB_ARG0] = 0;
return 0; goto out;
nla_put_failure: nla_put_failure:
nla_nest_cancel(skb, nested); nla_nest_cancel(skb, nested);
if (unlikely(id == first)) { if (unlikely(id == first)) {
cb->args[IPSET_CB_ARG0] = 0; cb->args[IPSET_CB_ARG0] = 0;
return -EMSGSIZE; ret = -EMSGSIZE;
} }
ipset_nest_end(skb, adt); ipset_nest_end(skb, adt);
return 0; out:
rcu_read_unlock();
return ret;
} }
static void static void
...@@ -260,7 +273,7 @@ mtype_gc(unsigned long ul_set) ...@@ -260,7 +273,7 @@ mtype_gc(unsigned long ul_set)
/* We run parallel with other readers (test element) /* We run parallel with other readers (test element)
* but adding/deleting new entries is locked out */ * but adding/deleting new entries is locked out */
read_lock_bh(&set->lock); spin_lock_bh(&set->lock);
for (id = 0; id < map->elements; id++) for (id = 0; id < map->elements; id++)
if (mtype_gc_test(id, map, set->dsize)) { if (mtype_gc_test(id, map, set->dsize)) {
x = get_ext(set, map, id); x = get_ext(set, map, id);
...@@ -269,7 +282,7 @@ mtype_gc(unsigned long ul_set) ...@@ -269,7 +282,7 @@ mtype_gc(unsigned long ul_set)
ip_set_ext_destroy(set, x); ip_set_ext_destroy(set, x);
} }
} }
read_unlock_bh(&set->lock); spin_unlock_bh(&set->lock);
map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ; map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
add_timer(&map->gc); add_timer(&map->gc);
......
...@@ -81,7 +81,7 @@ static inline int ...@@ -81,7 +81,7 @@ static inline int
bitmap_ip_do_add(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map, bitmap_ip_do_add(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map,
u32 flags, size_t dsize) u32 flags, size_t dsize)
{ {
return !!test_and_set_bit(e->id, map->members); return !!test_bit(e->id, map->members);
} }
static inline int static inline int
...@@ -376,6 +376,7 @@ bitmap_ip_init(void) ...@@ -376,6 +376,7 @@ bitmap_ip_init(void)
static void __exit static void __exit
bitmap_ip_fini(void) bitmap_ip_fini(void)
{ {
rcu_barrier();
ip_set_type_unregister(&bitmap_ip_type); ip_set_type_unregister(&bitmap_ip_type);
} }
......
...@@ -147,15 +147,23 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e, ...@@ -147,15 +147,23 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
struct bitmap_ipmac_elem *elem; struct bitmap_ipmac_elem *elem;
elem = get_elem(map->extensions, e->id, dsize); elem = get_elem(map->extensions, e->id, dsize);
if (test_and_set_bit(e->id, map->members)) { if (test_bit(e->id, map->members)) {
if (elem->filled == MAC_FILLED) { if (elem->filled == MAC_FILLED) {
if (e->ether && (flags & IPSET_FLAG_EXIST)) if (e->ether &&
(flags & IPSET_FLAG_EXIST) &&
!ether_addr_equal(e->ether, elem->ether)) {
/* memcpy isn't atomic */
clear_bit(e->id, map->members);
smp_mb__after_atomic();
memcpy(elem->ether, e->ether, ETH_ALEN); memcpy(elem->ether, e->ether, ETH_ALEN);
}
return IPSET_ADD_FAILED; return IPSET_ADD_FAILED;
} else if (!e->ether) } else if (!e->ether)
/* Already added without ethernet address */ /* Already added without ethernet address */
return IPSET_ADD_FAILED; return IPSET_ADD_FAILED;
/* Fill the MAC address and trigger the timer activation */ /* Fill the MAC address and trigger the timer activation */
clear_bit(e->id, map->members);
smp_mb__after_atomic();
memcpy(elem->ether, e->ether, ETH_ALEN); memcpy(elem->ether, e->ether, ETH_ALEN);
elem->filled = MAC_FILLED; elem->filled = MAC_FILLED;
return IPSET_ADD_START_STORED_TIMEOUT; return IPSET_ADD_START_STORED_TIMEOUT;
...@@ -413,6 +421,7 @@ bitmap_ipmac_init(void) ...@@ -413,6 +421,7 @@ bitmap_ipmac_init(void)
static void __exit static void __exit
bitmap_ipmac_fini(void) bitmap_ipmac_fini(void)
{ {
rcu_barrier();
ip_set_type_unregister(&bitmap_ipmac_type); ip_set_type_unregister(&bitmap_ipmac_type);
} }
......
...@@ -73,7 +73,7 @@ static inline int ...@@ -73,7 +73,7 @@ static inline int
bitmap_port_do_add(const struct bitmap_port_adt_elem *e, bitmap_port_do_add(const struct bitmap_port_adt_elem *e,
struct bitmap_port *map, u32 flags, size_t dsize) struct bitmap_port *map, u32 flags, size_t dsize)
{ {
return !!test_and_set_bit(e->id, map->members); return !!test_bit(e->id, map->members);
} }
static inline int static inline int
...@@ -306,6 +306,7 @@ bitmap_port_init(void) ...@@ -306,6 +306,7 @@ bitmap_port_init(void)
static void __exit static void __exit
bitmap_port_fini(void) bitmap_port_fini(void)
{ {
rcu_barrier();
ip_set_type_unregister(&bitmap_port_type); ip_set_type_unregister(&bitmap_port_type);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment