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: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
This commit is contained in:
Jozsef Kadlecsik 2015-06-13 14:39:59 +02:00
parent b57b2d1fa5
commit 96f51428c4
4 changed files with 38 additions and 14 deletions

View File

@ -144,10 +144,12 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
if (ret == IPSET_ADD_FAILED) {
if (SET_WITH_TIMEOUT(set) &&
ip_set_timeout_expired(ext_timeout(x, set)))
ip_set_timeout_expired(ext_timeout(x, set))) {
ret = 0;
else if (!(flags & IPSET_FLAG_EXIST))
} else if (!(flags & IPSET_FLAG_EXIST)) {
set_bit(e->id, map->members);
return -IPSET_ERR_EXIST;
}
/* Element is re-added, cleanup extensions */
ip_set_ext_destroy(set, x);
}
@ -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);
if (SET_WITH_SKBINFO(set))
ip_set_init_skbinfo(ext_skbinfo(x, set), ext);
/* Activate element */
set_bit(e->id, map->members);
return 0;
}
@ -203,10 +209,13 @@ mtype_list(const struct ip_set *set,
struct nlattr *adt, *nested;
void *x;
u32 id, first = cb->args[IPSET_CB_ARG0];
int ret = 0;
adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!adt)
return -EMSGSIZE;
/* Extensions may be replaced */
rcu_read_lock();
for (; cb->args[IPSET_CB_ARG0] < map->elements;
cb->args[IPSET_CB_ARG0]++) {
id = cb->args[IPSET_CB_ARG0];
@ -222,9 +231,11 @@ mtype_list(const struct ip_set *set,
if (!nested) {
if (id == first) {
nla_nest_cancel(skb, adt);
return -EMSGSIZE;
} else
goto nla_put_failure;
ret = -EMSGSIZE;
goto out;
}
goto nla_put_failure;
}
if (mtype_do_list(skb, map, id, set->dsize))
goto nla_put_failure;
@ -238,16 +249,18 @@ mtype_list(const struct ip_set *set,
/* Set listing finished */
cb->args[IPSET_CB_ARG0] = 0;
return 0;
goto out;
nla_put_failure:
nla_nest_cancel(skb, nested);
if (unlikely(id == first)) {
cb->args[IPSET_CB_ARG0] = 0;
return -EMSGSIZE;
ret = -EMSGSIZE;
}
ipset_nest_end(skb, adt);
return 0;
out:
rcu_read_unlock();
return ret;
}
static void
@ -260,7 +273,7 @@ mtype_gc(unsigned long ul_set)
/* We run parallel with other readers (test element)
* 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++)
if (mtype_gc_test(id, map, set->dsize)) {
x = get_ext(set, map, id);
@ -269,7 +282,7 @@ mtype_gc(unsigned long ul_set)
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;
add_timer(&map->gc);

View File

@ -81,7 +81,7 @@ static inline int
bitmap_ip_do_add(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *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
@ -376,6 +376,7 @@ bitmap_ip_init(void)
static void __exit
bitmap_ip_fini(void)
{
rcu_barrier();
ip_set_type_unregister(&bitmap_ip_type);
}

View File

@ -147,15 +147,23 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
struct bitmap_ipmac_elem *elem;
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 (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);
}
return IPSET_ADD_FAILED;
} else if (!e->ether)
/* Already added without ethernet address */
return IPSET_ADD_FAILED;
/* 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);
elem->filled = MAC_FILLED;
return IPSET_ADD_START_STORED_TIMEOUT;
@ -413,6 +421,7 @@ bitmap_ipmac_init(void)
static void __exit
bitmap_ipmac_fini(void)
{
rcu_barrier();
ip_set_type_unregister(&bitmap_ipmac_type);
}

View File

@ -73,7 +73,7 @@ static inline int
bitmap_port_do_add(const struct bitmap_port_adt_elem *e,
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
@ -306,6 +306,7 @@ bitmap_port_init(void)
static void __exit
bitmap_port_fini(void)
{
rcu_barrier();
ip_set_type_unregister(&bitmap_port_type);
}