Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+23 −10
Original line number Diff line number Diff line
@@ -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,8 +231,10 @@ mtype_list(const struct ip_set *set,
		if (!nested) {
			if (id == first) {
				nla_nest_cancel(skb, adt);
				return -EMSGSIZE;
			} else
				ret = -EMSGSIZE;
				goto out;
			}

			goto nla_put_failure;
		}
		if (mtype_do_list(skb, map, id, set->dsize))
@@ -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);
+2 −1
Original line number Diff line number Diff line
@@ -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);
}

+11 −2
Original line number Diff line number Diff line
@@ -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);
}

+2 −1
Original line number Diff line number Diff line
@@ -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);
}