Commit ccf0a4b7 authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by Pablo Neira Ayuso
Browse files

netfilter: ipset: Add bucketsize parameter to all hash types



The parameter defines the upper limit in any hash bucket at adding new entries
from userspace - if the limit would be exceeded, ipset doubles the hash size
and rehashes. It means the set may consume more memory but gives faster
evaluation at matching in the set.

Signed-off-by: default avatarJozsef Kadlecsik <kadlec@netfilter.org>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent a304ea7d
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -198,6 +198,9 @@ struct ip_set_region {
	u32 elements;		/* Number of elements vs timeout */
};

/* The max revision number supported by any set type + 1 */
#define IPSET_REVISION_MAX	9

/* The core set type structure */
struct ip_set_type {
	struct list_head list;
@@ -215,6 +218,8 @@ struct ip_set_type {
	u8 family;
	/* Type revisions */
	u8 revision_min, revision_max;
	/* Revision-specific supported (create) flags */
	u8 create_flags[IPSET_REVISION_MAX+1];
	/* Set features to control swapping */
	u16 features;

+3 −1
Original line number Diff line number Diff line
@@ -96,7 +96,7 @@ enum {
	IPSET_ATTR_HASHSIZE,
	IPSET_ATTR_MAXELEM,
	IPSET_ATTR_NETMASK,
	IPSET_ATTR_PROBES,
	IPSET_ATTR_BUCKETSIZE,	/* was unused IPSET_ATTR_PROBES */
	IPSET_ATTR_RESIZE,
	IPSET_ATTR_SIZE,
	/* Kernel-only */
@@ -214,6 +214,8 @@ enum ipset_cadt_flags {
enum ipset_create_flags {
	IPSET_CREATE_FLAG_BIT_FORCEADD = 0,
	IPSET_CREATE_FLAG_FORCEADD = (1 << IPSET_CREATE_FLAG_BIT_FORCEADD),
	IPSET_CREATE_FLAG_BIT_BUCKETSIZE = 1,
	IPSET_CREATE_FLAG_BUCKETSIZE = (1 << IPSET_CREATE_FLAG_BIT_BUCKETSIZE),
	IPSET_CREATE_FLAG_BIT_MAX = 7,
};

+2 −0
Original line number Diff line number Diff line
@@ -1109,6 +1109,8 @@ static int ip_set_create(struct net *net, struct sock *ctnl,
		ret = -IPSET_ERR_PROTOCOL;
		goto put_out;
	}
	/* Set create flags depending on the type revision */
	set->flags |= set->type->create_flags[revision];

	ret = set->type->create(net, set, tb, flags);
	if (ret != 0)
+23 −15
Original line number Diff line number Diff line
@@ -37,18 +37,18 @@
 */

/* Number of elements to store in an initial array block */
#define AHASH_INIT_SIZE			4
#define AHASH_INIT_SIZE			2
/* Max number of elements to store in an array block */
#define AHASH_MAX_SIZE			(3 * AHASH_INIT_SIZE)
#define AHASH_MAX_SIZE			(6 * AHASH_INIT_SIZE)
/* Max muber of elements in the array block when tuned */
#define AHASH_MAX_TUNED			64

#define AHASH_MAX(h)			((h)->bucketsize)

/* Max number of elements can be tuned */
#ifdef IP_SET_HASH_WITH_MULTI
#define AHASH_MAX(h)			((h)->ahash_max)

static u8
tune_ahash_max(u8 curr, u32 multi)
tune_bucketsize(u8 curr, u32 multi)
{
	u32 n;

@@ -61,12 +61,10 @@ tune_ahash_max(u8 curr, u32 multi)
	 */
	return n > curr && n <= AHASH_MAX_TUNED ? n : curr;
}

#define TUNE_AHASH_MAX(h, multi)	\
	((h)->ahash_max = tune_ahash_max((h)->ahash_max, multi))
#define TUNE_BUCKETSIZE(h, multi)	\
	((h)->bucketsize = tune_bucketsize((h)->bucketsize, multi))
#else
#define AHASH_MAX(h)			AHASH_MAX_SIZE
#define TUNE_AHASH_MAX(h, multi)
#define TUNE_BUCKETSIZE(h, multi)
#endif

/* A hash bucket */
@@ -321,9 +319,7 @@ struct htype {
#ifdef IP_SET_HASH_WITH_MARKMASK
	u32 markmask;		/* markmask value for mark mask to store */
#endif
#ifdef IP_SET_HASH_WITH_MULTI
	u8 ahash_max;		/* max elements in an array block */
#endif
	u8 bucketsize;		/* max elements in an array block */
#ifdef IP_SET_HASH_WITH_NETMASK
	u8 netmask;		/* netmask value for subnets to store */
#endif
@@ -950,7 +946,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
		goto set_full;
	/* Create a new slot */
	if (n->pos >= n->size) {
		TUNE_AHASH_MAX(h, multi);
		TUNE_BUCKETSIZE(h, multi);
		if (n->size >= AHASH_MAX(h)) {
			/* Trigger rehashing */
			mtype_data_next(&h->next, d);
@@ -1305,6 +1301,9 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
	if (nla_put_u32(skb, IPSET_ATTR_MARKMASK, h->markmask))
		goto nla_put_failure;
#endif
	if (set->flags & IPSET_CREATE_FLAG_BUCKETSIZE &&
	    nla_put_u8(skb, IPSET_ATTR_BUCKETSIZE, h->bucketsize))
		goto nla_put_failure;
	if (nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref)) ||
	    nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)) ||
	    nla_put_net32(skb, IPSET_ATTR_ELEMENTS, htonl(elements)))
@@ -1548,7 +1547,16 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
	h->markmask = markmask;
#endif
	get_random_bytes(&h->initval, sizeof(h->initval));

	h->bucketsize = AHASH_MAX_SIZE;
	if (tb[IPSET_ATTR_BUCKETSIZE]) {
		h->bucketsize = nla_get_u8(tb[IPSET_ATTR_BUCKETSIZE]);
		if (h->bucketsize < AHASH_INIT_SIZE)
			h->bucketsize = AHASH_INIT_SIZE;
		else if (h->bucketsize > AHASH_MAX_SIZE)
			h->bucketsize = AHASH_MAX_SIZE;
		else if (h->bucketsize % 2)
			h->bucketsize += 1;
	}
	t->htable_bits = hbits;
	t->maxelem = h->maxelem / ahash_numof_locks(hbits);
	RCU_INIT_POINTER(h->table, t);
+4 −2
Original line number Diff line number Diff line
@@ -23,7 +23,8 @@
/*				1	   Counters support */
/*				2	   Comments support */
/*				3	   Forceadd support */
#define IPSET_TYPE_REV_MAX	4	/* skbinfo support  */
/*				4	   skbinfo support */
#define IPSET_TYPE_REV_MAX	5	/* bucketsize support  */

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
@@ -277,11 +278,12 @@ static struct ip_set_type hash_ip_type __read_mostly = {
	.family		= NFPROTO_UNSPEC,
	.revision_min	= IPSET_TYPE_REV_MIN,
	.revision_max	= IPSET_TYPE_REV_MAX,
	.create_flags[IPSET_TYPE_REV_MAX] = IPSET_CREATE_FLAG_BUCKETSIZE,
	.create		= hash_ip_create,
	.create_policy	= {
		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 },
		[IPSET_ATTR_MAXELEM]	= { .type = NLA_U32 },
		[IPSET_ATTR_PROBES]	= { .type = NLA_U8 },
		[IPSET_ATTR_BUCKETSIZE]	= { .type = NLA_U8 },
		[IPSET_ATTR_RESIZE]	= { .type = NLA_U8  },
		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
		[IPSET_ATTR_NETMASK]	= { .type = NLA_U8  },
Loading