[PATCH nf 4/7] netfilter: ipset: add rhltable boilerplate stubs

Florian Westphal <[email protected]>
Newsgroups gmane.comp.security.firewalls.netfilter.devel
Message-ID <[email protected]>
Preparation patch.  ip_set_hash_netiface.c (IP_SET_HASH_WITH_MULTI)
may store distinct elements with the same hash key.  rhashtable doesn't
support this.  For these sets, switch to rhltable which stores identical
hlist heads.  We can then walk the list after lookup to find best match.

Signed-off-by: Florian Westphal <[email protected]>
---
 Was not part of earlier RFC series.

 net/netfilter/ipset/ip_set_hash_gen.h      | 41 +++++++++++++++++++++-
 net/netfilter/ipset/ip_set_hash_netiface.c | 24 +++++++++----
 2 files changed, 58 insertions(+), 7 deletions(-)

diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
index b116b98991cd..c426ccfca520 100644
--- a/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -206,6 +206,7 @@ static const union nf_inet_addr zeromask = {};
 /* Family dependent templates */
 
 #undef ahash_data
+#undef mtype_key_equal
 #undef mtype_data_equal
 #undef mtype_do_data_match
 #undef mtype_data_set_flags
@@ -257,6 +258,9 @@ static const union nf_inet_addr zeromask = {};
 #undef htype
 #undef HKEY
 
+#ifdef IP_SET_HASH_WITH_MULTI
+#define mtype_key_equal	IPSET_TOKEN(MTYPE, _key_equal)
+#endif
 #define mtype_data_equal	IPSET_TOKEN(MTYPE, _data_equal)
 #ifdef IP_SET_HASH_WITH_NETS
 #define mtype_do_data_match	IPSET_TOKEN(MTYPE, _do_data_match)
@@ -320,7 +324,11 @@ static const union nf_inet_addr zeromask = {};
  * allocate as offsetof(struct mtype_rht_elem, elem) + set->dsize bytes.
  */
 struct mtype_rht_elem {
+#ifdef IP_SET_HASH_WITH_MULTI
+	struct rhlist_head node;
+#else
 	struct rhash_head node;
+#endif
 	struct rcu_head rcu;		/* deferred free after removal */
 	struct mtype_elem elem;		/* element data; extensions follow */
 };
@@ -355,10 +363,15 @@ static u32 mtype_rht_obj_hashfn(const void *obj, u32 len, u32 seed)
 static int mtype_rht_cmpfn(struct rhashtable_compare_arg *arg, const void *obj)
 {
 	const struct mtype_rht_elem *e = obj;
+#ifdef IP_SET_HASH_WITH_MULTI
+	return !mtype_key_equal(&e->elem,
+				(const struct mtype_elem *)arg->key);
+#else
 	u32 multi = 0;
 
 	return !mtype_data_equal(&e->elem,
-				 (const struct mtype_elem *)arg->key, &multi);
+				(const struct mtype_elem *)arg->key, &multi);
+#endif
 }
 
 static const struct rhashtable_params mtype_rht_params = {
@@ -383,7 +396,11 @@ static const struct rhashtable_params mtype_rht_params = {
 /* The generic hash structure */
 struct htype {
 	struct htable __rcu *table; /* the hash table */
+#ifdef IP_SET_HASH_WITH_MULTI
+	struct rhltable rhlt;	/* the hashlist table */
+#else
 	struct rhashtable ht;	/* the hash table */
+#endif
 	struct net_prefixes __rcu *rnets[IPSET_NET_COUNT]; /* cidr prefixes */
 	struct htable_gc gc;	/* gc workqueue */
 	u32 maxelem;		/* max elements in the hash */
@@ -402,6 +419,16 @@ struct htype {
 	struct mtype_elem next; /* temporary storage for uadd */
 };
 
+#ifdef IP_SET_HASH_WITH_MULTI
+#define ipset_hash_nelems(h) atomic_read(&(h)->rhlt.ht.nelems)
+#define ipset_hash_walk_enter(h, iter)	rhltable_walk_enter(&(h)->rhlt, (iter))
+#define ipset_hash_remove(h, e) rhltable_remove(&(h)->rhlt, &(e)->node, mtype_rht_params)
+#else
+#define ipset_hash_nelems(h) atomic_read(&(h)->ht.nelems)
+#define ipset_hash_walk_enter(h, iter)	rhashtable_walk_enter(&(h)->ht, (iter))
+#define ipset_hash_remove(h, e) rhashtable_remove_fast(&(h)->ht, &(e)->node, mtype_rht_params)
+#endif
+
 /* ADD|DEL entries saved during resize */
 struct mtype_resize_ad {
 	struct list_head list;
@@ -669,7 +696,11 @@ mtype_destroy(struct ip_set *set)
 	struct htable *t = (__force struct htable *)h->table;
 	struct list_head *l, *lt;
 
+#ifdef IP_SET_HASH_WITH_MULTI
+	rhltable_free_and_destroy(&h->rhlt, mtype_flush_elem, set);
+#else
 	rhashtable_free_and_destroy(&h->ht, mtype_flush_elem, set);
+#endif
 
 	list_for_each_safe(l, lt, &t->ad) {
 		list_del(l);
@@ -1856,7 +1887,11 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
 	/* maxsize: maximum bucket table size to expand to */
 	params.max_size = maxelem;
 
+#ifdef IP_SET_HASH_WITH_MULTI
+	err = rhltable_init(&h->rhlt, &params);
+#else
 	err = rhashtable_init(&h->ht, &params);
+#endif
 	if (err)
 		goto free_h;
 
@@ -1958,7 +1993,11 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
 free_t:
 	ip_set_free(t);
 free_rht:
+#ifdef IP_SET_HASH_WITH_MULTI
+	rhltable_free_and_destroy(&h->rhlt, mtype_flush_elem, set);
+#else
 	rhashtable_free_and_destroy(&h->ht, mtype_flush_elem, set);
+#endif
 free_h:
 	kfree(h);
 	return -ENOMEM;
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c
index b602cc43565d..edadd6307675 100644
--- a/net/netfilter/ipset/ip_set_hash_netiface.c
+++ b/net/netfilter/ipset/ip_set_hash_netiface.c
@@ -63,16 +63,22 @@ struct hash_netiface4_elem {
 };
 
 /* Common functions */
+static bool
+hash_netiface4_key_equal(const struct hash_netiface4_elem *ip1,
+			 const struct hash_netiface4_elem *ip2)
+{
+	return ip1->ip == ip2->ip &&
+	       ip1->cidr == ip2->cidr &&
+	       ip1->physdev == ip2->physdev;
+}
 
 static bool
 hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1,
 			  const struct hash_netiface4_elem *ip2,
 			  u32 *multi)
 {
-	return ip1->ip == ip2->ip &&
-	       ip1->cidr == ip2->cidr &&
+	return hash_netiface4_key_equal(ip1, ip2) &&
 	       (++*multi) &&
-	       ip1->physdev == ip2->physdev &&
 	       (ip1->wildcard ?
 		strncmp(ip1->iface, ip2->iface, strlen(ip1->iface)) == 0 :
 		strcmp(ip1->iface, ip2->iface) == 0);
@@ -297,16 +303,22 @@ struct hash_netiface6_elem {
 };
 
 /* Common functions */
+static bool
+hash_netiface6_key_equal(const struct hash_netiface6_elem *ip1,
+			 const struct hash_netiface6_elem *ip2)
+{
+	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
+	       ip1->cidr == ip2->cidr &&
+	       ip1->physdev == ip2->physdev;
+}
 
 static bool
 hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1,
 			  const struct hash_netiface6_elem *ip2,
 			  u32 *multi)
 {
-	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
-	       ip1->cidr == ip2->cidr &&
+	return hash_netiface6_key_equal(ip1, ip2) &&
 	       (++*multi) &&
-	       ip1->physdev == ip2->physdev &&
 	       (ip1->wildcard ?
 		strncmp(ip1->iface, ip2->iface, strlen(ip1->iface)) == 0 :
 		strcmp(ip1->iface, ip2->iface) == 0);
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.