All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] netfilter: ipset: refactor hash types to use address/cidr arrays.
@ 2013-09-03 18:15 Oliver
  2013-09-03 20:27 ` Jozsef Kadlecsik
  0 siblings, 1 reply; 9+ messages in thread
From: Oliver @ 2013-09-03 18:15 UTC (permalink / raw)
  To: netfilter-devel

From: Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>

We now use an array in the structs for hash types so that they can be
arbitrarily expanded to situate as many ip/cidr values as required.

The primary purpose of this change is in preparation for the
hash:net,net ipset type, it otherwise carries no change in
functionality. As an aside, small comparison optimisations could
additionally be made in the future by making a union from the compared
types that encompasses them (such as bundling together cidr values).

Signed-off-by: Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>
---
 kernel/net/netfilter/ipset/ip_set_hash_gen.h       |  90 +++++++++++--------
 kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c | 100 ++++++++++-----------
 kernel/net/netfilter/ipset/ip_set_hash_net.c       |  78 ++++++++--------
 kernel/net/netfilter/ipset/ip_set_hash_netiface.c  |  88 +++++++++---------
 kernel/net/netfilter/ipset/ip_set_hash_netport.c   |  74 +++++++--------
 5 files changed, 220 insertions(+), 210 deletions(-)

diff --git a/kernel/net/netfilter/ipset/ip_set_hash_gen.h b/kernel/net/netfilter/ipset/ip_set_hash_gen.h
index cb6bba2..dff6295 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/kernel/net/netfilter/ipset/ip_set_hash_gen.h
@@ -37,6 +37,10 @@
 /* Max number of elements to store in an array block */
 #define AHASH_MAX_SIZE			(3*AHASH_INIT_SIZE)
 
+#ifndef IPSET_NET_COUNT
+#define IPSET_NET_COUNT		1
+#endif
+
 /* Max number of elements can be tuned */
 #ifdef IP_SET_HASH_WITH_MULTI
 #define AHASH_MAX(h)			((h)->ahash_max)
@@ -79,8 +83,8 @@ struct htable {
 
 /* Book-keeping of the prefixes added to the set */
 struct net_prefixes {
-	u8 cidr;		/* the different cidr values in the set */
-	u32 nets;		/* number of elements per cidr */
+	u8 cidr[IPSET_NET_COUNT];	/* cidr values in the set */
+	u32 nets[IPSET_NET_COUNT];	/* number of elements per cidr */
 };
 
 /* Compute the hash table size */
@@ -296,46 +300,51 @@ struct htype {
 /* Network cidr size book keeping when the hash stores different
  * sized networks */
 static void
-mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
+mtype_add_cidr(struct htype *h, const u8 cidr[], u8 nets_length)
 {
 	int i, j;
+	u8 x;
 
-	/* Add in increasing prefix order, so larger cidr first */
-	for (i = 0, j = -1; i < nets_length && h->nets[i].nets; i++) {
-		if (j != -1)
-			continue;
-		else if (h->nets[i].cidr < cidr)
-			j = i;
-		else if (h->nets[i].cidr == cidr) {
-			h->nets[i].nets++;
-			return;
+	for (x = 0; x < IPSET_NET_COUNT; x++) {
+		/* Add in increasing prefix order, so larger cidr first */
+		for (i = 0, j = -1; i < nets_length && h->nets[i].nets[x]; i++) {
+			if (j != -1)
+				continue;
+			else if (h->nets[i].cidr[x] < CIDR(cidr[x]))
+				j = i;
+			else if (h->nets[i].cidr[x] == CIDR(cidr[x])) {
+				h->nets[i].nets[x]++;
+				goto next;
+			}
 		}
-	}
-	if (j != -1) {
-		for (; i > j; i--) {
-			h->nets[i].cidr = h->nets[i - 1].cidr;
-			h->nets[i].nets = h->nets[i - 1].nets;
+		if (j != -1) {
+			for (; i > j; i--) {
+				h->nets[i].cidr[x] = h->nets[i - 1].cidr[x];
+				h->nets[i].nets[x] = h->nets[i - 1].nets[x];
+			}
 		}
+		h->nets[i].cidr[x] = CIDR(cidr[x]);
+		h->nets[i].nets[x] = 1;
+next:		;
 	}
-	h->nets[i].cidr = cidr;
-	h->nets[i].nets = 1;
 }
 
 static void
-mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length)
+mtype_del_cidr(struct htype *h, const u8 cidr[], u8 nets_length)
 {
-	u8 i, j;
-
-	for (i = 0; i < nets_length - 1 && h->nets[i].cidr != cidr; i++)
-		;
-	h->nets[i].nets--;
+	u8 i, j, x;
+	for (x = 0; x < IPSET_NET_COUNT; x++) {
+		for (i = 0; i < nets_length - 1 && h->nets[i].cidr[x] != CIDR(cidr[x]); i++)
+			;
+		h->nets[i].nets[x]--;
 
-	if (h->nets[i].nets != 0)
-		return;
+		if (h->nets[i].nets[x] != 0)
+			continue;
 
-	for (j = i; j < nets_length - 1 && h->nets[j].nets; j++) {
-		h->nets[j].cidr = h->nets[j + 1].cidr;
-		h->nets[j].nets = h->nets[j + 1].nets;
+		for (j = i; j < nets_length - 1 && h->nets[j].nets[x]; j++) {
+			h->nets[j].cidr[x] = h->nets[j + 1].cidr[x];
+			h->nets[j].nets[x] = h->nets[j + 1].nets[x];
+		}
 	}
 }
 #endif
@@ -454,8 +463,7 @@ mtype_expire(struct htype *h, u8 nets_length, size_t dsize)
 			if (ip_set_timeout_expired(ext_timeout(data, h))) {
 				pr_debug("expired %u/%u\n", i, j);
 #ifdef IP_SET_HASH_WITH_NETS
-				mtype_del_cidr(h, CIDR(data->cidr),
-					       nets_length);
+				mtype_del_cidr(h, data->cidr, nets_length);
 #endif
 				if (j != n->pos - 1)
 					/* Not last one */
@@ -641,8 +649,8 @@ reuse_slot:
 		/* Fill out reused slot */
 		data = ahash_data(n, j, h->dsize);
 #ifdef IP_SET_HASH_WITH_NETS
-		mtype_del_cidr(h, CIDR(data->cidr), NETS_LENGTH(set->family));
-		mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
+		mtype_del_cidr(h, data->cidr, NETS_LENGTH(set->family));
+		mtype_add_cidr(h, d->cidr, NETS_LENGTH(set->family));
 #endif
 	} else {
 		/* Use/create a new slot */
@@ -655,7 +663,7 @@ reuse_slot:
 		}
 		data = ahash_data(n, n->pos++, h->dsize);
 #ifdef IP_SET_HASH_WITH_NETS
-		mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
+		mtype_add_cidr(h, d->cidr, NETS_LENGTH(set->family));
 #endif
 		h->elements++;
 	}
@@ -707,7 +715,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
 		n->pos--;
 		h->elements--;
 #ifdef IP_SET_HASH_WITH_NETS
-		mtype_del_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
+		mtype_del_cidr(h, d->cidr, NETS_LENGTH(set->family));
 #endif
 		if (n->pos + AHASH_INIT_SIZE < n->size) {
 			void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
@@ -759,8 +767,8 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
 	u8 nets_length = NETS_LENGTH(set->family);
 
 	pr_debug("test by nets\n");
-	for (; j < nets_length && h->nets[j].nets && !multi; j++) {
-		mtype_data_netmask(d, h->nets[j].cidr);
+	for (; j < nets_length && h->nets[j].nets[0] && !multi; j++) {
+		mtype_data_netmask(d, h->nets[j].cidr[0]);
 		key = HKEY(d, h->initval, t->htable_bits);
 		n = hbucket(t, key);
 		for (i = 0; i < n->pos; i++) {
@@ -803,7 +811,11 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
 #ifdef IP_SET_HASH_WITH_NETS
 	/* If we test an IP address and not a network address,
 	 * try all possible network sizes */
-	if (CIDR(d->cidr) == SET_HOST_MASK(set->family)) {
+	for (i = 0; i < IPSET_NET_COUNT; i++) {
+		if (CIDR(d->cidr[i]) != SET_HOST_MASK(set->family))
+			break;
+	}
+	if (i == IPSET_NET_COUNT) {
 		ret = mtype_test_cidrs(set, d, ext, mext, flags);
 		goto out;
 	}
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c b/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
index 02ed91e..69e014f 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
@@ -50,10 +50,9 @@ MODULE_ALIAS("ip_set_hash:ip,port,net");
 
 /* Member elements */
 struct hash_ipportnet4_elem {
-	__be32 ip;
-	__be32 ip2;
+	__be32 ip[2];
 	__be16 port;
-	u8 cidr:7;
+	u8 cidr[1];
 	u8 nomatch:1;
 	u8 proto;
 } __attribute__((aligned(sizeof(void*))));
@@ -65,9 +64,9 @@ hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
 			   const struct hash_ipportnet4_elem *ip2,
 			   u32 *multi)
 {
-	return ip1->ip == ip2->ip &&
-	       ip1->ip2 == ip2->ip2 &&
-	       ip1->cidr == ip2->cidr &&
+	return ip1->ip[0] == ip2->ip[0] &&
+	       ip1->ip[1] == ip2->ip[1] &&
+	       ip1->cidr[0] == ip2->cidr[0] &&
 	       ip1->port == ip2->port &&
 	       ip1->proto == ip2->proto;
 }
@@ -93,8 +92,8 @@ hash_ipportnet4_data_reset_flags(struct hash_ipportnet4_elem *elem, u8 *flags)
 static inline void
 hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr)
 {
-	elem->ip2 &= ip_set_netmask(cidr);
-	elem->cidr = cidr - 1;
+	elem->ip[0] &= ip_set_netmask(cidr);
+	elem->cidr[0] = cidr - 1;
 }
 
 static bool
@@ -103,10 +102,10 @@ hash_ipportnet4_data_list(struct sk_buff *skb,
 {
 	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 
-	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
-	    nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip2) ||
+	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) ||
+	    nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip[1]) ||
 	    nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
-	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) ||
+	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[0] + 1) ||
 	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
 	    (flags &&
 	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
@@ -121,9 +120,9 @@ static inline void
 hash_ipportnet4_data_next(struct hash_ipportnet4_elem *next,
 			  const struct hash_ipportnet4_elem *d)
 {
-	next->ip = d->ip;
+	next->ip[0] = d->ip[0];
 	next->port = d->port;
-	next->ip2 = d->ip2;
+	next->ip[1] = d->ip[1];
 }
 
 #define MTYPE		hash_ipportnet4
@@ -139,20 +138,20 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
 	const struct hash_ipportnet *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_ipportnet4_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
+		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] - 1 : HOST_MASK - 1
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 
 	if (adt == IPSET_TEST)
-		e.cidr = HOST_MASK - 1;
+		e.cidr[0] = HOST_MASK - 1;
 
 	if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
 				 &e.port, &e.proto))
 		return -EINVAL;
 
-	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
-	ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2);
-	e.ip2 &= ip_set_netmask(e.cidr + 1);
+	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]);
+	ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip[1]);
+	e.ip[1] &= ip_set_netmask(e.cidr[0] + 1);
 
 	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 }
@@ -163,7 +162,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
 {
 	const struct hash_ipportnet *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
-	struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 };
+	struct hash_ipportnet4_elem e = { .cidr[0] = HOST_MASK - 1 };
 	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
 	u32 ip = 0, ip_to = 0, p = 0, port, port_to;
 	u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;
@@ -196,7 +195,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
 		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
 		if (!cidr || cidr > HOST_MASK)
 			return -IPSET_ERR_INVALID_CIDR;
-		e.cidr = cidr - 1;
+		e.cidr[0] = cidr - 1;
 	}
 
 	if (tb[IPSET_ATTR_PORT])
@@ -226,8 +225,8 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
 	if (adt == IPSET_TEST ||
 	    !(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports ||
 	      tb[IPSET_ATTR_IP2_TO])) {
-		e.ip = htonl(ip);
-		e.ip2 = htonl(ip2_from & ip_set_hostmask(e.cidr + 1));
+		e.ip[0] = htonl(ip);
+		e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[0] + 1));
 		ret = adtfn(set, &e, &ext, &ext, flags);
 		return ip_set_enomatch(ret, flags, adt, set) ? -ret :
 		       ip_set_eexist(ret, flags) ? 0 : ret;
@@ -265,25 +264,25 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
 		if (ip2_from + UINT_MAX == ip2_to)
 			return -IPSET_ERR_HASH_RANGE;
 	} else
-		ip_set_mask_from_to(ip2_from, ip2_to, e.cidr + 1);
+		ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[0] + 1);
 
 	if (retried)
-		ip = ntohl(h->next.ip);
+		ip = ntohl(h->next.ip[0]);
 	for (; !before(ip_to, ip); ip++) {
-		e.ip = htonl(ip);
-		p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
+		e.ip[0] = htonl(ip);
+		p = retried && ip == ntohl(h->next.ip[0]) ? ntohs(h->next.port)
 						       : port;
 		for (; p <= port_to; p++) {
 			e.port = htons(p);
 			ip2 = retried
-			      && ip == ntohl(h->next.ip)
+			      && ip == ntohl(h->next.ip[0])
 			      && p == ntohs(h->next.port)
-				? ntohl(h->next.ip2) : ip2_from;
+				? ntohl(h->next.ip[1]) : ip2_from;
 			while (!after(ip2, ip2_to)) {
-				e.ip2 = htonl(ip2);
+				e.ip[1] = htonl(ip2);
 				ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
 								&cidr);
-				e.cidr = cidr - 1;
+				e.cidr[0] = cidr - 1;
 				ret = adtfn(set, &e, &ext, &ext, flags);
 
 				if (ret && !ip_set_eexist(ret, flags))
@@ -300,10 +299,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
 /* IPv6 variants */
 
 struct hash_ipportnet6_elem {
-	union nf_inet_addr ip;
-	union nf_inet_addr ip2;
+	union nf_inet_addr ip[2];
 	__be16 port;
-	u8 cidr:7;
+	u8 cidr[1];
 	u8 nomatch:1;
 	u8 proto;
 } __attribute__((aligned(sizeof(void*))));
@@ -315,9 +313,9 @@ hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
 			   const struct hash_ipportnet6_elem *ip2,
 			   u32 *multi)
 {
-	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
-	       ipv6_addr_equal(&ip1->ip2.in6, &ip2->ip2.in6) &&
-	       ip1->cidr == ip2->cidr &&
+	return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) &&
+	       ipv6_addr_equal(&ip1->ip[1].in6, &ip2->ip[1].in6) &&
+	       ip1->cidr[0] == ip2->cidr[0] &&
 	       ip1->port == ip2->port &&
 	       ip1->proto == ip2->proto;
 }
@@ -343,8 +341,8 @@ hash_ipportnet6_data_reset_flags(struct hash_ipportnet6_elem *elem, u8 *flags)
 static inline void
 hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr)
 {
-	ip6_netmask(&elem->ip2, cidr);
-	elem->cidr = cidr - 1;
+	ip6_netmask(&elem->ip[1], cidr);
+	elem->cidr[0] = cidr - 1;
 }
 
 static bool
@@ -353,10 +351,10 @@ hash_ipportnet6_data_list(struct sk_buff *skb,
 {
 	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 
-	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
-	    nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) ||
+	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) ||
+	    nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip[1].in6) ||
 	    nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
-	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) ||
+	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[0] + 1) ||
 	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
 	    (flags &&
 	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
@@ -392,20 +390,20 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
 	const struct hash_ipportnet *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_ipportnet6_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
+		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] - 1 : HOST_MASK - 1
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 
 	if (adt == IPSET_TEST)
-		e.cidr = HOST_MASK - 1;
+		e.cidr[0] = HOST_MASK - 1;
 
 	if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
 				 &e.port, &e.proto))
 		return -EINVAL;
 
-	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
-	ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2.in6);
-	ip6_netmask(&e.ip2, e.cidr + 1);
+	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6);
+	ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip[1].in6);
+	ip6_netmask(&e.ip[1], e.cidr[0] + 1);
 
 	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 }
@@ -416,7 +414,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
 {
 	const struct hash_ipportnet *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
-	struct hash_ipportnet6_elem e = { .cidr = HOST_MASK - 1 };
+	struct hash_ipportnet6_elem e = { .cidr[0] = HOST_MASK - 1 };
 	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
 	u32 port, port_to;
 	bool with_ports = false;
@@ -439,12 +437,12 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
 	if (tb[IPSET_ATTR_LINENO])
 		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 
-	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
+	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) ||
 	      ip_set_get_extensions(set, tb, &ext);
 	if (ret)
 		return ret;
 
-	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip2);
+	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip[1]);
 	if (ret)
 		return ret;
 
@@ -452,10 +450,10 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
 		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
 		if (!cidr || cidr > HOST_MASK)
 			return -IPSET_ERR_INVALID_CIDR;
-		e.cidr = cidr - 1;
+		e.cidr[0] = cidr - 1;
 	}
 
-	ip6_netmask(&e.ip2, e.cidr + 1);
+	ip6_netmask(&e.ip[1], e.cidr[0] + 1);
 
 	if (tb[IPSET_ATTR_PORT])
 		e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_net.c b/kernel/net/netfilter/ipset/ip_set_hash_net.c
index 3d2ea5d..adbbca5 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_net.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_net.c
@@ -40,10 +40,10 @@ MODULE_ALIAS("ip_set_hash:net");
 
 /* Member elements  */
 struct hash_net4_elem {
-	__be32 ip;
+	__be32 ip[1];
 	u16 padding0;
 	u8 nomatch;
-	u8 cidr;
+	u8 cidr[1];
 } __attribute__((aligned(sizeof(void*))));
 
 /* Common functions */
@@ -53,8 +53,8 @@ hash_net4_data_equal(const struct hash_net4_elem *ip1,
 		     const struct hash_net4_elem *ip2,
 		     u32 *multi)
 {
-	return ip1->ip == ip2->ip &&
-	       ip1->cidr == ip2->cidr;
+	return ip1->ip[0] == ip2->ip[0] &&
+	       ip1->cidr[0] == ip2->cidr[0];
 }
 
 static inline int
@@ -78,8 +78,8 @@ hash_net4_data_reset_flags(struct hash_net4_elem *elem, u8 *flags)
 static inline void
 hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr)
 {
-	elem->ip &= ip_set_netmask(cidr);
-	elem->cidr = cidr;
+	elem->ip[0] &= ip_set_netmask(cidr);
+	elem->cidr[0] = cidr;
 }
 
 static bool
@@ -87,8 +87,8 @@ hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
 {
 	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 
-	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
-	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
+	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) ||
+	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
 	    (flags &&
 	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
 		goto nla_put_failure;
@@ -102,7 +102,7 @@ static inline void
 hash_net4_data_next(struct hash_net4_elem *next,
 		    const struct hash_net4_elem *d)
 {
-	next->ip = d->ip;
+	next->ip[0] = d->ip[0];
 }
 
 #define MTYPE		hash_net4
@@ -118,17 +118,17 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
 	const struct hash_net *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_net4_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] : HOST_MASK
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 
-	if (e.cidr == 0)
+	if (e.cidr[0] == 0)
 		return -EINVAL;
 	if (adt == IPSET_TEST)
-		e.cidr = HOST_MASK;
+		e.cidr[0] = HOST_MASK;
 
-	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
-	e.ip &= ip_set_netmask(e.cidr);
+	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]);
+	e.ip[0] &= ip_set_netmask(e.cidr[0]);
 
 	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 }
@@ -139,7 +139,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
 {
 	const struct hash_net *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
-	struct hash_net4_elem e = { .cidr = HOST_MASK };
+	struct hash_net4_elem e = { .cidr[0] = HOST_MASK };
 	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
 	u32 ip = 0, ip_to = 0, last;
 	int ret;
@@ -160,8 +160,8 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
 		return ret;
 
 	if (tb[IPSET_ATTR_CIDR]) {
-		e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-		if (!e.cidr || e.cidr > HOST_MASK)
+		e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+		if (!e.cidr[0] || e.cidr[0] > HOST_MASK)
 			return -IPSET_ERR_INVALID_CIDR;
 	}
 
@@ -172,7 +172,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
 	}
 
 	if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
-		e.ip = htonl(ip & ip_set_hostmask(e.cidr));
+		e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0]));
 		ret = adtfn(set, &e, &ext, &ext, flags);
 		return ip_set_enomatch(ret, flags, adt, set) ? -ret:
 		       ip_set_eexist(ret, flags) ? 0 : ret;
@@ -189,10 +189,10 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
 			return -IPSET_ERR_HASH_RANGE;
 	}
 	if (retried)
-		ip = ntohl(h->next.ip);
+		ip = ntohl(h->next.ip[0]);
 	while (!after(ip, ip_to)) {
-		e.ip = htonl(ip);
-		last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
+		e.ip[0] = htonl(ip);
+		last = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
 		ret = adtfn(set, &e, &ext, &ext, flags);
 		if (ret && !ip_set_eexist(ret, flags))
 			return ret;
@@ -206,10 +206,10 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
 /* IPv6 variants */
 
 struct hash_net6_elem {
-	union nf_inet_addr ip;
+	union nf_inet_addr ip[1];
 	u16 padding0;
 	u8 nomatch;
-	u8 cidr;
+	u8 cidr[1];
 } __attribute__((aligned(sizeof(void*))));
 
 /* Common functions */
@@ -219,8 +219,8 @@ hash_net6_data_equal(const struct hash_net6_elem *ip1,
 		     const struct hash_net6_elem *ip2,
 		     u32 *multi)
 {
-	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
-	       ip1->cidr == ip2->cidr;
+	return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) &&
+	       ip1->cidr[0] == ip2->cidr[0];
 }
 
 static inline int
@@ -244,8 +244,8 @@ hash_net6_data_reset_flags(struct hash_net6_elem *elem, u8 *flags)
 static inline void
 hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr)
 {
-	ip6_netmask(&elem->ip, cidr);
-	elem->cidr = cidr;
+	ip6_netmask(&elem->ip[0], cidr);
+	elem->cidr[0] = cidr;
 }
 
 static bool
@@ -253,8 +253,8 @@ hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
 {
 	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 
-	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
-	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
+	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) ||
+	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
 	    (flags &&
 	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
 		goto nla_put_failure;
@@ -288,17 +288,17 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
 	const struct hash_net *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_net6_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] : HOST_MASK
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 
-	if (e.cidr == 0)
+	if (e.cidr[0] == 0)
 		return -EINVAL;
 	if (adt == IPSET_TEST)
-		e.cidr = HOST_MASK;
+		e.cidr[0] = HOST_MASK;
 
-	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
-	ip6_netmask(&e.ip, e.cidr);
+	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6);
+	ip6_netmask(&e.ip[0], e.cidr[0]);
 
 	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 }
@@ -309,7 +309,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
 {
 	const struct hash_net *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
-	struct hash_net6_elem e = { .cidr = HOST_MASK };
+	struct hash_net6_elem e = { .cidr[0] = HOST_MASK };
 	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
 	int ret;
 
@@ -325,18 +325,18 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
 	if (tb[IPSET_ATTR_LINENO])
 		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 
-	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
+	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) ||
 	      ip_set_get_extensions(set, tb, &ext);
 	if (ret)
 		return ret;
 
 	if (tb[IPSET_ATTR_CIDR])
-		e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+		e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 
-	if (!e.cidr || e.cidr > HOST_MASK)
+	if (!e.cidr[0] || e.cidr[0] > HOST_MASK)
 		return -IPSET_ERR_INVALID_CIDR;
 
-	ip6_netmask(&e.ip, e.cidr);
+	ip6_netmask(&e.ip[0], e.cidr[0]);
 
 	if (tb[IPSET_ATTR_CADT_FLAGS]) {
 		u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_netiface.c b/kernel/net/netfilter/ipset/ip_set_hash_netiface.c
index 06cc27b..d41fba1 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_netiface.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_netiface.c
@@ -137,17 +137,17 @@ iface_add(struct rb_root *root, const char **iface)
 /* IPv4 variants */
 
 struct hash_netiface4_elem_hashed {
-	__be32 ip;
+	__be32 ip[1];
 	u8 physdev;
-	u8 cidr;
+	u8 cidr[1];
 	u8 nomatch;
 	u8 elem;
 };
 
 struct hash_netiface4_elem {
-	__be32 ip;
+	__be32 ip[1];
 	u8 physdev;
-	u8 cidr;
+	u8 cidr[1];
 	u8 nomatch;
 	u8 elem;
 	const char *iface;
@@ -160,8 +160,8 @@ 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 ip1->ip[0] == ip2->ip[0] &&
+	       ip1->cidr[0] == ip2->cidr[0] &&
 	       (++*multi) &&
 	       ip1->physdev == ip2->physdev &&
 	       ip1->iface == ip2->iface;
@@ -188,8 +188,8 @@ hash_netiface4_data_reset_flags(struct hash_netiface4_elem *elem, u8 *flags)
 static inline void
 hash_netiface4_data_netmask(struct hash_netiface4_elem *elem, u8 cidr)
 {
-	elem->ip &= ip_set_netmask(cidr);
-	elem->cidr = cidr;
+	elem->ip[0] &= ip_set_netmask(cidr);
+	elem->cidr[0] = cidr;
 }
 
 static bool
@@ -200,8 +200,8 @@ hash_netiface4_data_list(struct sk_buff *skb,
 
 	if (data->nomatch)
 		flags |= IPSET_FLAG_NOMATCH;
-	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
-	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
+	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) ||
+	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
 	    nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
 	    (flags &&
 	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
@@ -216,7 +216,7 @@ static inline void
 hash_netiface4_data_next(struct hash_netiface4_elem *next,
 			 const struct hash_netiface4_elem *d)
 {
-	next->ip = d->ip;
+	next->ip[0] = d->ip[0];
 }
 
 #define MTYPE		hash_netiface4
@@ -233,19 +233,19 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
 	struct hash_netiface *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_netiface4_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
+		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] : HOST_MASK,
 		.elem = 1,
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 	int ret;
 
-	if (e.cidr == 0)
+	if (e.cidr[0] == 0)
 		return -EINVAL;
 	if (adt == IPSET_TEST)
-		e.cidr = HOST_MASK;
+		e.cidr[0] = HOST_MASK;
 
-	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
-	e.ip &= ip_set_netmask(e.cidr);
+	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]);
+	e.ip[0] &= ip_set_netmask(e.cidr[0]);
 
 #define IFACE(dir)	(par->dir ? par->dir->name : NULL)
 #define PHYSDEV(dir)	(nf_bridge->dir ? nf_bridge->dir->name : NULL)
@@ -286,7 +286,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
 {
 	struct hash_netiface *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
-	struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
+	struct hash_netiface4_elem e = { .cidr[0] = HOST_MASK, .elem = 1 };
 	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
 	u32 ip = 0, ip_to = 0, last;
 	char iface[IFNAMSIZ];
@@ -309,8 +309,8 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
 		return ret;
 
 	if (tb[IPSET_ATTR_CIDR]) {
-		e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-		if (e.cidr > HOST_MASK)
+		e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+		if (e.cidr[0] > HOST_MASK)
 			return -IPSET_ERR_INVALID_CIDR;
 	}
 
@@ -334,7 +334,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
 			flags |= (IPSET_FLAG_NOMATCH << 16);
 	}
 	if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
-		e.ip = htonl(ip & ip_set_hostmask(e.cidr));
+		e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0]));
 		ret = adtfn(set, &e, &ext, &ext, flags);
 		return ip_set_enomatch(ret, flags, adt, set) ? -ret :
 		       ip_set_eexist(ret, flags) ? 0 : ret;
@@ -349,13 +349,13 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
 		if (ip + UINT_MAX == ip_to)
 			return -IPSET_ERR_HASH_RANGE;
 	} else
-		ip_set_mask_from_to(ip, ip_to, e.cidr);
+		ip_set_mask_from_to(ip, ip_to, e.cidr[0]);
 
 	if (retried)
-		ip = ntohl(h->next.ip);
+		ip = ntohl(h->next.ip[0]);
 	while (!after(ip, ip_to)) {
-		e.ip = htonl(ip);
-		last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
+		e.ip[0] = htonl(ip);
+		last = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
 		ret = adtfn(set, &e, &ext, &ext, flags);
 
 		if (ret && !ip_set_eexist(ret, flags))
@@ -370,17 +370,17 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
 /* IPv6 variants */
 
 struct hash_netiface6_elem_hashed {
-	union nf_inet_addr ip;
+	union nf_inet_addr ip[1];
 	u8 physdev;
-	u8 cidr;
+	u8 cidr[1];
 	u8 nomatch;
 	u8 elem;
 };
 
 struct hash_netiface6_elem {
-	union nf_inet_addr ip;
+	union nf_inet_addr ip[1];
 	u8 physdev;
-	u8 cidr;
+	u8 cidr[1];
 	u8 nomatch;
 	u8 elem;
 	const char *iface;
@@ -393,8 +393,8 @@ 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 ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) &&
+	       ip1->cidr[0] == ip2->cidr[0] &&
 	       (++*multi) &&
 	       ip1->physdev == ip2->physdev &&
 	       ip1->iface == ip2->iface;
@@ -421,8 +421,8 @@ hash_netiface6_data_reset_flags(struct hash_netiface6_elem *elem, u8 *flags)
 static inline void
 hash_netiface6_data_netmask(struct hash_netiface6_elem *elem, u8 cidr)
 {
-	ip6_netmask(&elem->ip, cidr);
-	elem->cidr = cidr;
+	ip6_netmask(&elem->ip[0], cidr);
+	elem->cidr[0] = cidr;
 }
 
 static bool
@@ -433,8 +433,8 @@ hash_netiface6_data_list(struct sk_buff *skb,
 
 	if (data->nomatch)
 		flags |= IPSET_FLAG_NOMATCH;
-	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
-	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
+	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) ||
+	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
 	    nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
 	    (flags &&
 	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
@@ -471,19 +471,19 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
 	struct hash_netiface *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_netiface6_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
+		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] : HOST_MASK,
 		.elem = 1,
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 	int ret;
 
-	if (e.cidr == 0)
+	if (e.cidr[0] == 0)
 		return -EINVAL;
 	if (adt == IPSET_TEST)
-		e.cidr = HOST_MASK;
+		e.cidr[0] = HOST_MASK;
 
-	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
-	ip6_netmask(&e.ip, e.cidr);
+	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6);
+	ip6_netmask(&e.ip[0], e.cidr[0]);
 
 	if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
 #ifdef CONFIG_BRIDGE_NETFILTER
@@ -520,7 +520,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
 {
 	struct hash_netiface *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
-	struct hash_netiface6_elem e = { .cidr = HOST_MASK, .elem = 1 };
+	struct hash_netiface6_elem e = { .cidr[0] = HOST_MASK, .elem = 1 };
 	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
 	char iface[IFNAMSIZ];
 	int ret;
@@ -538,16 +538,16 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
 	if (tb[IPSET_ATTR_LINENO])
 		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 
-	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
+	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) ||
 	      ip_set_get_extensions(set, tb, &ext);
 	if (ret)
 		return ret;
 
 	if (tb[IPSET_ATTR_CIDR])
-		e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-	if (e.cidr > HOST_MASK)
+		e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+	if (e.cidr[0] > HOST_MASK)
 		return -IPSET_ERR_INVALID_CIDR;
-	ip6_netmask(&e.ip, e.cidr);
+	ip6_netmask(&e.ip[0], e.cidr[0]);
 
 	strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
 	e.iface = iface;
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_netport.c b/kernel/net/netfilter/ipset/ip_set_hash_netport.c
index 570e6b5..cc8a330 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_netport.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_netport.c
@@ -49,10 +49,10 @@ MODULE_ALIAS("ip_set_hash:net,port");
 
 /* Member elements */
 struct hash_netport4_elem {
-	__be32 ip;
+	__be32 ip[1];
 	__be16 port;
 	u8 proto;
-	u8 cidr:7;
+	u8 cidr[1];
 	u8 nomatch:1;
 } __attribute__((aligned(sizeof(void*))));
 
@@ -63,10 +63,10 @@ hash_netport4_data_equal(const struct hash_netport4_elem *ip1,
 			 const struct hash_netport4_elem *ip2,
 			 u32 *multi)
 {
-	return ip1->ip == ip2->ip &&
+	return ip1->ip[0] == ip2->ip[0] &&
 	       ip1->port == ip2->port &&
 	       ip1->proto == ip2->proto &&
-	       ip1->cidr == ip2->cidr;
+	       ip1->cidr[0] == ip2->cidr[0];
 }
 
 static inline int
@@ -90,8 +90,8 @@ hash_netport4_data_reset_flags(struct hash_netport4_elem *elem, u8 *flags)
 static inline void
 hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr)
 {
-	elem->ip &= ip_set_netmask(cidr);
-	elem->cidr = cidr - 1;
+	elem->ip[0] &= ip_set_netmask(cidr);
+	elem->cidr[0] = cidr - 1;
 }
 
 static bool
@@ -100,9 +100,9 @@ hash_netport4_data_list(struct sk_buff *skb,
 {
 	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 
-	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
+	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) ||
 	    nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
-	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr + 1) ||
+	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0] + 1) ||
 	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
 	    (flags &&
 	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
@@ -117,7 +117,7 @@ static inline void
 hash_netport4_data_next(struct hash_netport4_elem *next,
 			const struct hash_netport4_elem *d)
 {
-	next->ip = d->ip;
+	next->ip[0] = d->ip[0];
 	next->port = d->port;
 }
 
@@ -134,19 +134,19 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
 	const struct hash_netport *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_netport4_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
+		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] - 1 : HOST_MASK - 1
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 
 	if (adt == IPSET_TEST)
-		e.cidr = HOST_MASK - 1;
+		e.cidr[0] = HOST_MASK - 1;
 
 	if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
 				 &e.port, &e.proto))
 		return -EINVAL;
 
-	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
-	e.ip &= ip_set_netmask(e.cidr + 1);
+	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]);
+	e.ip[0] &= ip_set_netmask(e.cidr[0] + 1);
 
 	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 }
@@ -157,7 +157,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
 {
 	const struct hash_netport *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
-	struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 };
+	struct hash_netport4_elem e = { .cidr[0] = HOST_MASK - 1 };
 	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
 	u32 port, port_to, p = 0, ip = 0, ip_to = 0, last;
 	bool with_ports = false;
@@ -185,7 +185,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
 		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 		if (!cidr || cidr > HOST_MASK)
 			return -IPSET_ERR_INVALID_CIDR;
-		e.cidr = cidr - 1;
+		e.cidr[0] = cidr - 1;
 	}
 
 	if (tb[IPSET_ATTR_PORT])
@@ -214,7 +214,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
 	}
 
 	if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) {
-		e.ip = htonl(ip & ip_set_hostmask(e.cidr + 1));
+		e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0] + 1));
 		ret = adtfn(set, &e, &ext, &ext, flags);
 		return ip_set_enomatch(ret, flags, adt, set) ? -ret :
 		       ip_set_eexist(ret, flags) ? 0 : ret;
@@ -235,15 +235,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
 		if (ip + UINT_MAX == ip_to)
 			return -IPSET_ERR_HASH_RANGE;
 	} else
-		ip_set_mask_from_to(ip, ip_to, e.cidr + 1);
+		ip_set_mask_from_to(ip, ip_to, e.cidr[0] + 1);
 
 	if (retried)
-		ip = ntohl(h->next.ip);
+		ip = ntohl(h->next.ip[0]);
 	while (!after(ip, ip_to)) {
-		e.ip = htonl(ip);
+		e.ip[0] = htonl(ip);
 		last = ip_set_range_to_cidr(ip, ip_to, &cidr);
-		e.cidr = cidr - 1;
-		p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
+		e.cidr[0] = cidr - 1;
+		p = retried && ip == ntohl(h->next.ip[0]) ? ntohs(h->next.port)
 						       : port;
 		for (; p <= port_to; p++) {
 			e.port = htons(p);
@@ -262,10 +262,10 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
 /* IPv6 variants */
 
 struct hash_netport6_elem {
-	union nf_inet_addr ip;
+	union nf_inet_addr ip[1];
 	__be16 port;
 	u8 proto;
-	u8 cidr:7;
+	u8 cidr[1];
 	u8 nomatch:1;
 } __attribute__((aligned(sizeof(void*))));
 
@@ -276,10 +276,10 @@ hash_netport6_data_equal(const struct hash_netport6_elem *ip1,
 			 const struct hash_netport6_elem *ip2,
 			 u32 *multi)
 {
-	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
+	return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) &&
 	       ip1->port == ip2->port &&
 	       ip1->proto == ip2->proto &&
-	       ip1->cidr == ip2->cidr;
+	       ip1->cidr[0] == ip2->cidr[0];
 }
 
 static inline int
@@ -303,8 +303,8 @@ hash_netport6_data_reset_flags(struct hash_netport6_elem *elem, u8 *flags)
 static inline void
 hash_netport6_data_netmask(struct hash_netport6_elem *elem, u8 cidr)
 {
-	ip6_netmask(&elem->ip, cidr);
-	elem->cidr = cidr - 1;
+	ip6_netmask(&elem->ip[0], cidr);
+	elem->cidr[0] = cidr - 1;
 }
 
 static bool
@@ -313,9 +313,9 @@ hash_netport6_data_list(struct sk_buff *skb,
 {
 	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 
-	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
+	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) ||
 	    nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
-	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr + 1) ||
+	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0] + 1) ||
 	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
 	    (flags &&
 	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
@@ -351,19 +351,19 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
 	const struct hash_netport *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_netport6_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1,
+		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] - 1 : HOST_MASK - 1,
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 
 	if (adt == IPSET_TEST)
-		e.cidr = HOST_MASK - 1;
+		e.cidr[0] = HOST_MASK - 1;
 
 	if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
 				 &e.port, &e.proto))
 		return -EINVAL;
 
-	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
-	ip6_netmask(&e.ip, e.cidr + 1);
+	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6);
+	ip6_netmask(&e.ip[0], e.cidr[0] + 1);
 
 	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 }
@@ -374,7 +374,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
 {
 	const struct hash_netport *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
-	struct hash_netport6_elem e = { .cidr = HOST_MASK  - 1 };
+	struct hash_netport6_elem e = { .cidr[0] = HOST_MASK  - 1 };
 	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
 	u32 port, port_to;
 	bool with_ports = false;
@@ -395,7 +395,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
 	if (tb[IPSET_ATTR_LINENO])
 		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 
-	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
+	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) ||
 	      ip_set_get_extensions(set, tb, &ext);
 	if (ret)
 		return ret;
@@ -404,9 +404,9 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
 		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 		if (!cidr || cidr > HOST_MASK)
 			return -IPSET_ERR_INVALID_CIDR;
-		e.cidr = cidr - 1;
+		e.cidr[0] = cidr - 1;
 	}
-	ip6_netmask(&e.ip, e.cidr + 1);
+	ip6_netmask(&e.ip[0], e.cidr[0] + 1);
 
 	if (tb[IPSET_ATTR_PORT])
 		e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
-- 
1.8.3.2



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] netfilter: ipset: refactor hash types to use address/cidr arrays.
  2013-09-03 18:15 [PATCH v2] netfilter: ipset: refactor hash types to use address/cidr arrays Oliver
@ 2013-09-03 20:27 ` Jozsef Kadlecsik
  2013-09-03 22:06   ` Jozsef Kadlecsik
  0 siblings, 1 reply; 9+ messages in thread
From: Jozsef Kadlecsik @ 2013-09-03 20:27 UTC (permalink / raw)
  To: Oliver; +Cc: netfilter-devel

Hi Oliver,

On Tue, 3 Sep 2013, Oliver wrote:

> From: Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>
> 
> We now use an array in the structs for hash types so that they can be
> arbitrarily expanded to situate as many ip/cidr values as required.
> 
> The primary purpose of this change is in preparation for the
> hash:net,net ipset type, it otherwise carries no change in
> functionality. As an aside, small comparison optimisations could
> additionally be made in the future by making a union from the compared
> types that encompasses them (such as bundling together cidr values).
> 
> Signed-off-by: Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>
> ---
>  kernel/net/netfilter/ipset/ip_set_hash_gen.h       |  90 +++++++++++--------
>  kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c | 100 ++++++++++-----------
>  kernel/net/netfilter/ipset/ip_set_hash_net.c       |  78 ++++++++--------
>  kernel/net/netfilter/ipset/ip_set_hash_netiface.c  |  88 +++++++++---------
>  kernel/net/netfilter/ipset/ip_set_hash_netport.c   |  74 +++++++--------
>  5 files changed, 220 insertions(+), 210 deletions(-)
> 
> diff --git a/kernel/net/netfilter/ipset/ip_set_hash_gen.h b/kernel/net/netfilter/ipset/ip_set_hash_gen.h
> index cb6bba2..dff6295 100644
> --- a/kernel/net/netfilter/ipset/ip_set_hash_gen.h
> +++ b/kernel/net/netfilter/ipset/ip_set_hash_gen.h
> @@ -37,6 +37,10 @@
>  /* Max number of elements to store in an array block */
>  #define AHASH_MAX_SIZE			(3*AHASH_INIT_SIZE)
>  
> +#ifndef IPSET_NET_COUNT
> +#define IPSET_NET_COUNT		1
> +#endif
> +
>  /* Max number of elements can be tuned */
>  #ifdef IP_SET_HASH_WITH_MULTI
>  #define AHASH_MAX(h)			((h)->ahash_max)
> @@ -79,8 +83,8 @@ struct htable {
>  
>  /* Book-keeping of the prefixes added to the set */
>  struct net_prefixes {
> -	u8 cidr;		/* the different cidr values in the set */
> -	u32 nets;		/* number of elements per cidr */
> +	u8 cidr[IPSET_NET_COUNT];	/* cidr values in the set */
> +	u32 nets[IPSET_NET_COUNT];	/* number of elements per cidr */
>  };
>  
>  /* Compute the hash table size */
> @@ -296,46 +300,51 @@ struct htype {
>  /* Network cidr size book keeping when the hash stores different
>   * sized networks */
>  static void
> -mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
> +mtype_add_cidr(struct htype *h, const u8 cidr[], u8 nets_length)

I do remember you asked it and I confused you: no, the hash types need not 
be changed for this (see below), mtype_add_cidr requires just a new arg as 
to which member of the cidr/net array of struct htype to be updated.

>  {
>  	int i, j;
> +	u8 x;
>  
> -	/* Add in increasing prefix order, so larger cidr first */
> -	for (i = 0, j = -1; i < nets_length && h->nets[i].nets; i++) {
> -		if (j != -1)
> -			continue;
> -		else if (h->nets[i].cidr < cidr)
> -			j = i;
> -		else if (h->nets[i].cidr == cidr) {
> -			h->nets[i].nets++;
> -			return;
> +	for (x = 0; x < IPSET_NET_COUNT; x++) {
> +		/* Add in increasing prefix order, so larger cidr first */
> +		for (i = 0, j = -1; i < nets_length && h->nets[i].nets[x]; i++) {
> +			if (j != -1)
> +				continue;
> +			else if (h->nets[i].cidr[x] < CIDR(cidr[x]))
> +				j = i;
> +			else if (h->nets[i].cidr[x] == CIDR(cidr[x])) {
> +				h->nets[i].nets[x]++;
> +				goto next;
> +			}
>  		}
> -	}
> -	if (j != -1) {
> -		for (; i > j; i--) {
> -			h->nets[i].cidr = h->nets[i - 1].cidr;
> -			h->nets[i].nets = h->nets[i - 1].nets;
> +		if (j != -1) {
> +			for (; i > j; i--) {
> +				h->nets[i].cidr[x] = h->nets[i - 1].cidr[x];
> +				h->nets[i].nets[x] = h->nets[i - 1].nets[x];
> +			}
>  		}
> +		h->nets[i].cidr[x] = CIDR(cidr[x]);
> +		h->nets[i].nets[x] = 1;
> +next:		;
>  	}
> -	h->nets[i].cidr = cidr;
> -	h->nets[i].nets = 1;
>  }
>  
>  static void
> -mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length)
> +mtype_del_cidr(struct htype *h, const u8 cidr[], u8 nets_length)
>  {
> -	u8 i, j;
> -
> -	for (i = 0; i < nets_length - 1 && h->nets[i].cidr != cidr; i++)
> -		;
> -	h->nets[i].nets--;
> +	u8 i, j, x;
> +	for (x = 0; x < IPSET_NET_COUNT; x++) {
> +		for (i = 0; i < nets_length - 1 && h->nets[i].cidr[x] != CIDR(cidr[x]); i++)
> +			;
> +		h->nets[i].nets[x]--;
>  
> -	if (h->nets[i].nets != 0)
> -		return;
> +		if (h->nets[i].nets[x] != 0)
> +			continue;
>  
> -	for (j = i; j < nets_length - 1 && h->nets[j].nets; j++) {
> -		h->nets[j].cidr = h->nets[j + 1].cidr;
> -		h->nets[j].nets = h->nets[j + 1].nets;
> +		for (j = i; j < nets_length - 1 && h->nets[j].nets[x]; j++) {
> +			h->nets[j].cidr[x] = h->nets[j + 1].cidr[x];
> +			h->nets[j].nets[x] = h->nets[j + 1].nets[x];
> +		}
>  	}
>  }
>  #endif
> @@ -454,8 +463,7 @@ mtype_expire(struct htype *h, u8 nets_length, size_t dsize)
>  			if (ip_set_timeout_expired(ext_timeout(data, h))) {
>  				pr_debug("expired %u/%u\n", i, j);
>  #ifdef IP_SET_HASH_WITH_NETS
> -				mtype_del_cidr(h, CIDR(data->cidr),
> -					       nets_length);
> +				mtype_del_cidr(h, data->cidr, nets_length);
>  #endif
>  				if (j != n->pos - 1)
>  					/* Not last one */
> @@ -641,8 +649,8 @@ reuse_slot:
>  		/* Fill out reused slot */
>  		data = ahash_data(n, j, h->dsize);
>  #ifdef IP_SET_HASH_WITH_NETS
> -		mtype_del_cidr(h, CIDR(data->cidr), NETS_LENGTH(set->family));
> -		mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
> +		mtype_del_cidr(h, data->cidr, NETS_LENGTH(set->family));
> +		mtype_add_cidr(h, d->cidr, NETS_LENGTH(set->family));
>  #endif
>  	} else {
>  		/* Use/create a new slot */
> @@ -655,7 +663,7 @@ reuse_slot:
>  		}
>  		data = ahash_data(n, n->pos++, h->dsize);
>  #ifdef IP_SET_HASH_WITH_NETS
> -		mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
> +		mtype_add_cidr(h, d->cidr, NETS_LENGTH(set->family));
>  #endif
>  		h->elements++;
>  	}
> @@ -707,7 +715,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
>  		n->pos--;
>  		h->elements--;
>  #ifdef IP_SET_HASH_WITH_NETS
> -		mtype_del_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
> +		mtype_del_cidr(h, d->cidr, NETS_LENGTH(set->family));
>  #endif
>  		if (n->pos + AHASH_INIT_SIZE < n->size) {
>  			void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
> @@ -759,8 +767,8 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
>  	u8 nets_length = NETS_LENGTH(set->family);
>  
>  	pr_debug("test by nets\n");
> -	for (; j < nets_length && h->nets[j].nets && !multi; j++) {
> -		mtype_data_netmask(d, h->nets[j].cidr);
> +	for (; j < nets_length && h->nets[j].nets[0] && !multi; j++) {
> +		mtype_data_netmask(d, h->nets[j].cidr[0]);
>  		key = HKEY(d, h->initval, t->htable_bits);
>  		n = hbucket(t, key);
>  		for (i = 0; i < n->pos; i++) {
> @@ -803,7 +811,11 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
>  #ifdef IP_SET_HASH_WITH_NETS
>  	/* If we test an IP address and not a network address,
>  	 * try all possible network sizes */
> -	if (CIDR(d->cidr) == SET_HOST_MASK(set->family)) {
> +	for (i = 0; i < IPSET_NET_COUNT; i++) {
> +		if (CIDR(d->cidr[i]) != SET_HOST_MASK(set->family))
> +			break;
> +	}
> +	if (i == IPSET_NET_COUNT) {
>  		ret = mtype_test_cidrs(set, d, ext, mext, flags);
>  		goto out;
>  	}
> diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c b/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
> index 02ed91e..69e014f 100644
> --- a/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
> +++ b/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
> @@ -50,10 +50,9 @@ MODULE_ALIAS("ip_set_hash:ip,port,net");
>  
>  /* Member elements */
>  struct hash_ipportnet4_elem {
> -	__be32 ip;
> -	__be32 ip2;
> +	__be32 ip[2];
>  	__be16 port;
> -	u8 cidr:7;
> +	u8 cidr[1];
>  	u8 nomatch:1;
>  	u8 proto;
>  } __attribute__((aligned(sizeof(void*))));

Don't change the cidr to array in the member elemets: that way the 
structure is enlarged unnecessary. This is the confusion I caused, sorry.

Best regards,
Jozsef

> @@ -65,9 +64,9 @@ hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
>  			   const struct hash_ipportnet4_elem *ip2,
>  			   u32 *multi)
>  {
> -	return ip1->ip == ip2->ip &&
> -	       ip1->ip2 == ip2->ip2 &&
> -	       ip1->cidr == ip2->cidr &&
> +	return ip1->ip[0] == ip2->ip[0] &&
> +	       ip1->ip[1] == ip2->ip[1] &&
> +	       ip1->cidr[0] == ip2->cidr[0] &&
>  	       ip1->port == ip2->port &&
>  	       ip1->proto == ip2->proto;
>  }
> @@ -93,8 +92,8 @@ hash_ipportnet4_data_reset_flags(struct hash_ipportnet4_elem *elem, u8 *flags)
>  static inline void
>  hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr)
>  {
> -	elem->ip2 &= ip_set_netmask(cidr);
> -	elem->cidr = cidr - 1;
> +	elem->ip[0] &= ip_set_netmask(cidr);
> +	elem->cidr[0] = cidr - 1;
>  }
>  
>  static bool
> @@ -103,10 +102,10 @@ hash_ipportnet4_data_list(struct sk_buff *skb,
>  {
>  	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
>  
> -	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
> -	    nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip2) ||
> +	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) ||
> +	    nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip[1]) ||
>  	    nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
> -	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) ||
> +	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[0] + 1) ||
>  	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
>  	    (flags &&
>  	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
> @@ -121,9 +120,9 @@ static inline void
>  hash_ipportnet4_data_next(struct hash_ipportnet4_elem *next,
>  			  const struct hash_ipportnet4_elem *d)
>  {
> -	next->ip = d->ip;
> +	next->ip[0] = d->ip[0];
>  	next->port = d->port;
> -	next->ip2 = d->ip2;
> +	next->ip[1] = d->ip[1];
>  }
>  
>  #define MTYPE		hash_ipportnet4
> @@ -139,20 +138,20 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
>  	const struct hash_ipportnet *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
>  	struct hash_ipportnet4_elem e = {
> -		.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
> +		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] - 1 : HOST_MASK - 1
>  	};
>  	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
>  
>  	if (adt == IPSET_TEST)
> -		e.cidr = HOST_MASK - 1;
> +		e.cidr[0] = HOST_MASK - 1;
>  
>  	if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
>  				 &e.port, &e.proto))
>  		return -EINVAL;
>  
> -	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
> -	ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2);
> -	e.ip2 &= ip_set_netmask(e.cidr + 1);
> +	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]);
> +	ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip[1]);
> +	e.ip[1] &= ip_set_netmask(e.cidr[0] + 1);
>  
>  	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
>  }
> @@ -163,7 +162,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
>  {
>  	const struct hash_ipportnet *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
> -	struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 };
> +	struct hash_ipportnet4_elem e = { .cidr[0] = HOST_MASK - 1 };
>  	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
>  	u32 ip = 0, ip_to = 0, p = 0, port, port_to;
>  	u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;
> @@ -196,7 +195,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
>  		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
>  		if (!cidr || cidr > HOST_MASK)
>  			return -IPSET_ERR_INVALID_CIDR;
> -		e.cidr = cidr - 1;
> +		e.cidr[0] = cidr - 1;
>  	}
>  
>  	if (tb[IPSET_ATTR_PORT])
> @@ -226,8 +225,8 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
>  	if (adt == IPSET_TEST ||
>  	    !(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports ||
>  	      tb[IPSET_ATTR_IP2_TO])) {
> -		e.ip = htonl(ip);
> -		e.ip2 = htonl(ip2_from & ip_set_hostmask(e.cidr + 1));
> +		e.ip[0] = htonl(ip);
> +		e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[0] + 1));
>  		ret = adtfn(set, &e, &ext, &ext, flags);
>  		return ip_set_enomatch(ret, flags, adt, set) ? -ret :
>  		       ip_set_eexist(ret, flags) ? 0 : ret;
> @@ -265,25 +264,25 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
>  		if (ip2_from + UINT_MAX == ip2_to)
>  			return -IPSET_ERR_HASH_RANGE;
>  	} else
> -		ip_set_mask_from_to(ip2_from, ip2_to, e.cidr + 1);
> +		ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[0] + 1);
>  
>  	if (retried)
> -		ip = ntohl(h->next.ip);
> +		ip = ntohl(h->next.ip[0]);
>  	for (; !before(ip_to, ip); ip++) {
> -		e.ip = htonl(ip);
> -		p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
> +		e.ip[0] = htonl(ip);
> +		p = retried && ip == ntohl(h->next.ip[0]) ? ntohs(h->next.port)
>  						       : port;
>  		for (; p <= port_to; p++) {
>  			e.port = htons(p);
>  			ip2 = retried
> -			      && ip == ntohl(h->next.ip)
> +			      && ip == ntohl(h->next.ip[0])
>  			      && p == ntohs(h->next.port)
> -				? ntohl(h->next.ip2) : ip2_from;
> +				? ntohl(h->next.ip[1]) : ip2_from;
>  			while (!after(ip2, ip2_to)) {
> -				e.ip2 = htonl(ip2);
> +				e.ip[1] = htonl(ip2);
>  				ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
>  								&cidr);
> -				e.cidr = cidr - 1;
> +				e.cidr[0] = cidr - 1;
>  				ret = adtfn(set, &e, &ext, &ext, flags);
>  
>  				if (ret && !ip_set_eexist(ret, flags))
> @@ -300,10 +299,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
>  /* IPv6 variants */
>  
>  struct hash_ipportnet6_elem {
> -	union nf_inet_addr ip;
> -	union nf_inet_addr ip2;
> +	union nf_inet_addr ip[2];
>  	__be16 port;
> -	u8 cidr:7;
> +	u8 cidr[1];
>  	u8 nomatch:1;
>  	u8 proto;
>  } __attribute__((aligned(sizeof(void*))));
> @@ -315,9 +313,9 @@ hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
>  			   const struct hash_ipportnet6_elem *ip2,
>  			   u32 *multi)
>  {
> -	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
> -	       ipv6_addr_equal(&ip1->ip2.in6, &ip2->ip2.in6) &&
> -	       ip1->cidr == ip2->cidr &&
> +	return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) &&
> +	       ipv6_addr_equal(&ip1->ip[1].in6, &ip2->ip[1].in6) &&
> +	       ip1->cidr[0] == ip2->cidr[0] &&
>  	       ip1->port == ip2->port &&
>  	       ip1->proto == ip2->proto;
>  }
> @@ -343,8 +341,8 @@ hash_ipportnet6_data_reset_flags(struct hash_ipportnet6_elem *elem, u8 *flags)
>  static inline void
>  hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr)
>  {
> -	ip6_netmask(&elem->ip2, cidr);
> -	elem->cidr = cidr - 1;
> +	ip6_netmask(&elem->ip[1], cidr);
> +	elem->cidr[0] = cidr - 1;
>  }
>  
>  static bool
> @@ -353,10 +351,10 @@ hash_ipportnet6_data_list(struct sk_buff *skb,
>  {
>  	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
>  
> -	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
> -	    nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) ||
> +	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) ||
> +	    nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip[1].in6) ||
>  	    nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
> -	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) ||
> +	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[0] + 1) ||
>  	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
>  	    (flags &&
>  	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
> @@ -392,20 +390,20 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
>  	const struct hash_ipportnet *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
>  	struct hash_ipportnet6_elem e = {
> -		.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
> +		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] - 1 : HOST_MASK - 1
>  	};
>  	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
>  
>  	if (adt == IPSET_TEST)
> -		e.cidr = HOST_MASK - 1;
> +		e.cidr[0] = HOST_MASK - 1;
>  
>  	if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
>  				 &e.port, &e.proto))
>  		return -EINVAL;
>  
> -	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
> -	ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2.in6);
> -	ip6_netmask(&e.ip2, e.cidr + 1);
> +	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6);
> +	ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip[1].in6);
> +	ip6_netmask(&e.ip[1], e.cidr[0] + 1);
>  
>  	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
>  }
> @@ -416,7 +414,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
>  {
>  	const struct hash_ipportnet *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
> -	struct hash_ipportnet6_elem e = { .cidr = HOST_MASK - 1 };
> +	struct hash_ipportnet6_elem e = { .cidr[0] = HOST_MASK - 1 };
>  	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
>  	u32 port, port_to;
>  	bool with_ports = false;
> @@ -439,12 +437,12 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
>  	if (tb[IPSET_ATTR_LINENO])
>  		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
>  
> -	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
> +	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) ||
>  	      ip_set_get_extensions(set, tb, &ext);
>  	if (ret)
>  		return ret;
>  
> -	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip2);
> +	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip[1]);
>  	if (ret)
>  		return ret;
>  
> @@ -452,10 +450,10 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
>  		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
>  		if (!cidr || cidr > HOST_MASK)
>  			return -IPSET_ERR_INVALID_CIDR;
> -		e.cidr = cidr - 1;
> +		e.cidr[0] = cidr - 1;
>  	}
>  
> -	ip6_netmask(&e.ip2, e.cidr + 1);
> +	ip6_netmask(&e.ip[1], e.cidr[0] + 1);
>  
>  	if (tb[IPSET_ATTR_PORT])
>  		e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
> diff --git a/kernel/net/netfilter/ipset/ip_set_hash_net.c b/kernel/net/netfilter/ipset/ip_set_hash_net.c
> index 3d2ea5d..adbbca5 100644
> --- a/kernel/net/netfilter/ipset/ip_set_hash_net.c
> +++ b/kernel/net/netfilter/ipset/ip_set_hash_net.c
> @@ -40,10 +40,10 @@ MODULE_ALIAS("ip_set_hash:net");
>  
>  /* Member elements  */
>  struct hash_net4_elem {
> -	__be32 ip;
> +	__be32 ip[1];
>  	u16 padding0;
>  	u8 nomatch;
> -	u8 cidr;
> +	u8 cidr[1];
>  } __attribute__((aligned(sizeof(void*))));
>  
>  /* Common functions */
> @@ -53,8 +53,8 @@ hash_net4_data_equal(const struct hash_net4_elem *ip1,
>  		     const struct hash_net4_elem *ip2,
>  		     u32 *multi)
>  {
> -	return ip1->ip == ip2->ip &&
> -	       ip1->cidr == ip2->cidr;
> +	return ip1->ip[0] == ip2->ip[0] &&
> +	       ip1->cidr[0] == ip2->cidr[0];
>  }
>  
>  static inline int
> @@ -78,8 +78,8 @@ hash_net4_data_reset_flags(struct hash_net4_elem *elem, u8 *flags)
>  static inline void
>  hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr)
>  {
> -	elem->ip &= ip_set_netmask(cidr);
> -	elem->cidr = cidr;
> +	elem->ip[0] &= ip_set_netmask(cidr);
> +	elem->cidr[0] = cidr;
>  }
>  
>  static bool
> @@ -87,8 +87,8 @@ hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
>  {
>  	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
>  
> -	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
> -	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
> +	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) ||
> +	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
>  	    (flags &&
>  	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
>  		goto nla_put_failure;
> @@ -102,7 +102,7 @@ static inline void
>  hash_net4_data_next(struct hash_net4_elem *next,
>  		    const struct hash_net4_elem *d)
>  {
> -	next->ip = d->ip;
> +	next->ip[0] = d->ip[0];
>  }
>  
>  #define MTYPE		hash_net4
> @@ -118,17 +118,17 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
>  	const struct hash_net *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
>  	struct hash_net4_elem e = {
> -		.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
> +		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] : HOST_MASK
>  	};
>  	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
>  
> -	if (e.cidr == 0)
> +	if (e.cidr[0] == 0)
>  		return -EINVAL;
>  	if (adt == IPSET_TEST)
> -		e.cidr = HOST_MASK;
> +		e.cidr[0] = HOST_MASK;
>  
> -	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
> -	e.ip &= ip_set_netmask(e.cidr);
> +	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]);
> +	e.ip[0] &= ip_set_netmask(e.cidr[0]);
>  
>  	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
>  }
> @@ -139,7 +139,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
>  {
>  	const struct hash_net *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
> -	struct hash_net4_elem e = { .cidr = HOST_MASK };
> +	struct hash_net4_elem e = { .cidr[0] = HOST_MASK };
>  	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
>  	u32 ip = 0, ip_to = 0, last;
>  	int ret;
> @@ -160,8 +160,8 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
>  		return ret;
>  
>  	if (tb[IPSET_ATTR_CIDR]) {
> -		e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
> -		if (!e.cidr || e.cidr > HOST_MASK)
> +		e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
> +		if (!e.cidr[0] || e.cidr[0] > HOST_MASK)
>  			return -IPSET_ERR_INVALID_CIDR;
>  	}
>  
> @@ -172,7 +172,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
>  	}
>  
>  	if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
> -		e.ip = htonl(ip & ip_set_hostmask(e.cidr));
> +		e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0]));
>  		ret = adtfn(set, &e, &ext, &ext, flags);
>  		return ip_set_enomatch(ret, flags, adt, set) ? -ret:
>  		       ip_set_eexist(ret, flags) ? 0 : ret;
> @@ -189,10 +189,10 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
>  			return -IPSET_ERR_HASH_RANGE;
>  	}
>  	if (retried)
> -		ip = ntohl(h->next.ip);
> +		ip = ntohl(h->next.ip[0]);
>  	while (!after(ip, ip_to)) {
> -		e.ip = htonl(ip);
> -		last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
> +		e.ip[0] = htonl(ip);
> +		last = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
>  		ret = adtfn(set, &e, &ext, &ext, flags);
>  		if (ret && !ip_set_eexist(ret, flags))
>  			return ret;
> @@ -206,10 +206,10 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
>  /* IPv6 variants */
>  
>  struct hash_net6_elem {
> -	union nf_inet_addr ip;
> +	union nf_inet_addr ip[1];
>  	u16 padding0;
>  	u8 nomatch;
> -	u8 cidr;
> +	u8 cidr[1];
>  } __attribute__((aligned(sizeof(void*))));
>  
>  /* Common functions */
> @@ -219,8 +219,8 @@ hash_net6_data_equal(const struct hash_net6_elem *ip1,
>  		     const struct hash_net6_elem *ip2,
>  		     u32 *multi)
>  {
> -	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
> -	       ip1->cidr == ip2->cidr;
> +	return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) &&
> +	       ip1->cidr[0] == ip2->cidr[0];
>  }
>  
>  static inline int
> @@ -244,8 +244,8 @@ hash_net6_data_reset_flags(struct hash_net6_elem *elem, u8 *flags)
>  static inline void
>  hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr)
>  {
> -	ip6_netmask(&elem->ip, cidr);
> -	elem->cidr = cidr;
> +	ip6_netmask(&elem->ip[0], cidr);
> +	elem->cidr[0] = cidr;
>  }
>  
>  static bool
> @@ -253,8 +253,8 @@ hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
>  {
>  	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
>  
> -	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
> -	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
> +	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) ||
> +	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
>  	    (flags &&
>  	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
>  		goto nla_put_failure;
> @@ -288,17 +288,17 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
>  	const struct hash_net *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
>  	struct hash_net6_elem e = {
> -		.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
> +		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] : HOST_MASK
>  	};
>  	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
>  
> -	if (e.cidr == 0)
> +	if (e.cidr[0] == 0)
>  		return -EINVAL;
>  	if (adt == IPSET_TEST)
> -		e.cidr = HOST_MASK;
> +		e.cidr[0] = HOST_MASK;
>  
> -	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
> -	ip6_netmask(&e.ip, e.cidr);
> +	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6);
> +	ip6_netmask(&e.ip[0], e.cidr[0]);
>  
>  	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
>  }
> @@ -309,7 +309,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
>  {
>  	const struct hash_net *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
> -	struct hash_net6_elem e = { .cidr = HOST_MASK };
> +	struct hash_net6_elem e = { .cidr[0] = HOST_MASK };
>  	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
>  	int ret;
>  
> @@ -325,18 +325,18 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
>  	if (tb[IPSET_ATTR_LINENO])
>  		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
>  
> -	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
> +	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) ||
>  	      ip_set_get_extensions(set, tb, &ext);
>  	if (ret)
>  		return ret;
>  
>  	if (tb[IPSET_ATTR_CIDR])
> -		e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
> +		e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
>  
> -	if (!e.cidr || e.cidr > HOST_MASK)
> +	if (!e.cidr[0] || e.cidr[0] > HOST_MASK)
>  		return -IPSET_ERR_INVALID_CIDR;
>  
> -	ip6_netmask(&e.ip, e.cidr);
> +	ip6_netmask(&e.ip[0], e.cidr[0]);
>  
>  	if (tb[IPSET_ATTR_CADT_FLAGS]) {
>  		u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
> diff --git a/kernel/net/netfilter/ipset/ip_set_hash_netiface.c b/kernel/net/netfilter/ipset/ip_set_hash_netiface.c
> index 06cc27b..d41fba1 100644
> --- a/kernel/net/netfilter/ipset/ip_set_hash_netiface.c
> +++ b/kernel/net/netfilter/ipset/ip_set_hash_netiface.c
> @@ -137,17 +137,17 @@ iface_add(struct rb_root *root, const char **iface)
>  /* IPv4 variants */
>  
>  struct hash_netiface4_elem_hashed {
> -	__be32 ip;
> +	__be32 ip[1];
>  	u8 physdev;
> -	u8 cidr;
> +	u8 cidr[1];
>  	u8 nomatch;
>  	u8 elem;
>  };
>  
>  struct hash_netiface4_elem {
> -	__be32 ip;
> +	__be32 ip[1];
>  	u8 physdev;
> -	u8 cidr;
> +	u8 cidr[1];
>  	u8 nomatch;
>  	u8 elem;
>  	const char *iface;
> @@ -160,8 +160,8 @@ 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 ip1->ip[0] == ip2->ip[0] &&
> +	       ip1->cidr[0] == ip2->cidr[0] &&
>  	       (++*multi) &&
>  	       ip1->physdev == ip2->physdev &&
>  	       ip1->iface == ip2->iface;
> @@ -188,8 +188,8 @@ hash_netiface4_data_reset_flags(struct hash_netiface4_elem *elem, u8 *flags)
>  static inline void
>  hash_netiface4_data_netmask(struct hash_netiface4_elem *elem, u8 cidr)
>  {
> -	elem->ip &= ip_set_netmask(cidr);
> -	elem->cidr = cidr;
> +	elem->ip[0] &= ip_set_netmask(cidr);
> +	elem->cidr[0] = cidr;
>  }
>  
>  static bool
> @@ -200,8 +200,8 @@ hash_netiface4_data_list(struct sk_buff *skb,
>  
>  	if (data->nomatch)
>  		flags |= IPSET_FLAG_NOMATCH;
> -	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
> -	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
> +	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) ||
> +	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
>  	    nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
>  	    (flags &&
>  	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
> @@ -216,7 +216,7 @@ static inline void
>  hash_netiface4_data_next(struct hash_netiface4_elem *next,
>  			 const struct hash_netiface4_elem *d)
>  {
> -	next->ip = d->ip;
> +	next->ip[0] = d->ip[0];
>  }
>  
>  #define MTYPE		hash_netiface4
> @@ -233,19 +233,19 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
>  	struct hash_netiface *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
>  	struct hash_netiface4_elem e = {
> -		.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
> +		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] : HOST_MASK,
>  		.elem = 1,
>  	};
>  	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
>  	int ret;
>  
> -	if (e.cidr == 0)
> +	if (e.cidr[0] == 0)
>  		return -EINVAL;
>  	if (adt == IPSET_TEST)
> -		e.cidr = HOST_MASK;
> +		e.cidr[0] = HOST_MASK;
>  
> -	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
> -	e.ip &= ip_set_netmask(e.cidr);
> +	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]);
> +	e.ip[0] &= ip_set_netmask(e.cidr[0]);
>  
>  #define IFACE(dir)	(par->dir ? par->dir->name : NULL)
>  #define PHYSDEV(dir)	(nf_bridge->dir ? nf_bridge->dir->name : NULL)
> @@ -286,7 +286,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
>  {
>  	struct hash_netiface *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
> -	struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
> +	struct hash_netiface4_elem e = { .cidr[0] = HOST_MASK, .elem = 1 };
>  	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
>  	u32 ip = 0, ip_to = 0, last;
>  	char iface[IFNAMSIZ];
> @@ -309,8 +309,8 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
>  		return ret;
>  
>  	if (tb[IPSET_ATTR_CIDR]) {
> -		e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
> -		if (e.cidr > HOST_MASK)
> +		e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
> +		if (e.cidr[0] > HOST_MASK)
>  			return -IPSET_ERR_INVALID_CIDR;
>  	}
>  
> @@ -334,7 +334,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
>  			flags |= (IPSET_FLAG_NOMATCH << 16);
>  	}
>  	if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
> -		e.ip = htonl(ip & ip_set_hostmask(e.cidr));
> +		e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0]));
>  		ret = adtfn(set, &e, &ext, &ext, flags);
>  		return ip_set_enomatch(ret, flags, adt, set) ? -ret :
>  		       ip_set_eexist(ret, flags) ? 0 : ret;
> @@ -349,13 +349,13 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
>  		if (ip + UINT_MAX == ip_to)
>  			return -IPSET_ERR_HASH_RANGE;
>  	} else
> -		ip_set_mask_from_to(ip, ip_to, e.cidr);
> +		ip_set_mask_from_to(ip, ip_to, e.cidr[0]);
>  
>  	if (retried)
> -		ip = ntohl(h->next.ip);
> +		ip = ntohl(h->next.ip[0]);
>  	while (!after(ip, ip_to)) {
> -		e.ip = htonl(ip);
> -		last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
> +		e.ip[0] = htonl(ip);
> +		last = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
>  		ret = adtfn(set, &e, &ext, &ext, flags);
>  
>  		if (ret && !ip_set_eexist(ret, flags))
> @@ -370,17 +370,17 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
>  /* IPv6 variants */
>  
>  struct hash_netiface6_elem_hashed {
> -	union nf_inet_addr ip;
> +	union nf_inet_addr ip[1];
>  	u8 physdev;
> -	u8 cidr;
> +	u8 cidr[1];
>  	u8 nomatch;
>  	u8 elem;
>  };
>  
>  struct hash_netiface6_elem {
> -	union nf_inet_addr ip;
> +	union nf_inet_addr ip[1];
>  	u8 physdev;
> -	u8 cidr;
> +	u8 cidr[1];
>  	u8 nomatch;
>  	u8 elem;
>  	const char *iface;
> @@ -393,8 +393,8 @@ 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 ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) &&
> +	       ip1->cidr[0] == ip2->cidr[0] &&
>  	       (++*multi) &&
>  	       ip1->physdev == ip2->physdev &&
>  	       ip1->iface == ip2->iface;
> @@ -421,8 +421,8 @@ hash_netiface6_data_reset_flags(struct hash_netiface6_elem *elem, u8 *flags)
>  static inline void
>  hash_netiface6_data_netmask(struct hash_netiface6_elem *elem, u8 cidr)
>  {
> -	ip6_netmask(&elem->ip, cidr);
> -	elem->cidr = cidr;
> +	ip6_netmask(&elem->ip[0], cidr);
> +	elem->cidr[0] = cidr;
>  }
>  
>  static bool
> @@ -433,8 +433,8 @@ hash_netiface6_data_list(struct sk_buff *skb,
>  
>  	if (data->nomatch)
>  		flags |= IPSET_FLAG_NOMATCH;
> -	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
> -	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
> +	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) ||
> +	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
>  	    nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
>  	    (flags &&
>  	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
> @@ -471,19 +471,19 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
>  	struct hash_netiface *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
>  	struct hash_netiface6_elem e = {
> -		.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
> +		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] : HOST_MASK,
>  		.elem = 1,
>  	};
>  	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
>  	int ret;
>  
> -	if (e.cidr == 0)
> +	if (e.cidr[0] == 0)
>  		return -EINVAL;
>  	if (adt == IPSET_TEST)
> -		e.cidr = HOST_MASK;
> +		e.cidr[0] = HOST_MASK;
>  
> -	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
> -	ip6_netmask(&e.ip, e.cidr);
> +	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6);
> +	ip6_netmask(&e.ip[0], e.cidr[0]);
>  
>  	if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
>  #ifdef CONFIG_BRIDGE_NETFILTER
> @@ -520,7 +520,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
>  {
>  	struct hash_netiface *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
> -	struct hash_netiface6_elem e = { .cidr = HOST_MASK, .elem = 1 };
> +	struct hash_netiface6_elem e = { .cidr[0] = HOST_MASK, .elem = 1 };
>  	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
>  	char iface[IFNAMSIZ];
>  	int ret;
> @@ -538,16 +538,16 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
>  	if (tb[IPSET_ATTR_LINENO])
>  		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
>  
> -	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
> +	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) ||
>  	      ip_set_get_extensions(set, tb, &ext);
>  	if (ret)
>  		return ret;
>  
>  	if (tb[IPSET_ATTR_CIDR])
> -		e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
> -	if (e.cidr > HOST_MASK)
> +		e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
> +	if (e.cidr[0] > HOST_MASK)
>  		return -IPSET_ERR_INVALID_CIDR;
> -	ip6_netmask(&e.ip, e.cidr);
> +	ip6_netmask(&e.ip[0], e.cidr[0]);
>  
>  	strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
>  	e.iface = iface;
> diff --git a/kernel/net/netfilter/ipset/ip_set_hash_netport.c b/kernel/net/netfilter/ipset/ip_set_hash_netport.c
> index 570e6b5..cc8a330 100644
> --- a/kernel/net/netfilter/ipset/ip_set_hash_netport.c
> +++ b/kernel/net/netfilter/ipset/ip_set_hash_netport.c
> @@ -49,10 +49,10 @@ MODULE_ALIAS("ip_set_hash:net,port");
>  
>  /* Member elements */
>  struct hash_netport4_elem {
> -	__be32 ip;
> +	__be32 ip[1];
>  	__be16 port;
>  	u8 proto;
> -	u8 cidr:7;
> +	u8 cidr[1];
>  	u8 nomatch:1;
>  } __attribute__((aligned(sizeof(void*))));
>  
> @@ -63,10 +63,10 @@ hash_netport4_data_equal(const struct hash_netport4_elem *ip1,
>  			 const struct hash_netport4_elem *ip2,
>  			 u32 *multi)
>  {
> -	return ip1->ip == ip2->ip &&
> +	return ip1->ip[0] == ip2->ip[0] &&
>  	       ip1->port == ip2->port &&
>  	       ip1->proto == ip2->proto &&
> -	       ip1->cidr == ip2->cidr;
> +	       ip1->cidr[0] == ip2->cidr[0];
>  }
>  
>  static inline int
> @@ -90,8 +90,8 @@ hash_netport4_data_reset_flags(struct hash_netport4_elem *elem, u8 *flags)
>  static inline void
>  hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr)
>  {
> -	elem->ip &= ip_set_netmask(cidr);
> -	elem->cidr = cidr - 1;
> +	elem->ip[0] &= ip_set_netmask(cidr);
> +	elem->cidr[0] = cidr - 1;
>  }
>  
>  static bool
> @@ -100,9 +100,9 @@ hash_netport4_data_list(struct sk_buff *skb,
>  {
>  	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
>  
> -	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
> +	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) ||
>  	    nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
> -	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr + 1) ||
> +	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0] + 1) ||
>  	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
>  	    (flags &&
>  	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
> @@ -117,7 +117,7 @@ static inline void
>  hash_netport4_data_next(struct hash_netport4_elem *next,
>  			const struct hash_netport4_elem *d)
>  {
> -	next->ip = d->ip;
> +	next->ip[0] = d->ip[0];
>  	next->port = d->port;
>  }
>  
> @@ -134,19 +134,19 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
>  	const struct hash_netport *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
>  	struct hash_netport4_elem e = {
> -		.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
> +		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] - 1 : HOST_MASK - 1
>  	};
>  	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
>  
>  	if (adt == IPSET_TEST)
> -		e.cidr = HOST_MASK - 1;
> +		e.cidr[0] = HOST_MASK - 1;
>  
>  	if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
>  				 &e.port, &e.proto))
>  		return -EINVAL;
>  
> -	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
> -	e.ip &= ip_set_netmask(e.cidr + 1);
> +	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]);
> +	e.ip[0] &= ip_set_netmask(e.cidr[0] + 1);
>  
>  	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
>  }
> @@ -157,7 +157,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
>  {
>  	const struct hash_netport *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
> -	struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 };
> +	struct hash_netport4_elem e = { .cidr[0] = HOST_MASK - 1 };
>  	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
>  	u32 port, port_to, p = 0, ip = 0, ip_to = 0, last;
>  	bool with_ports = false;
> @@ -185,7 +185,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
>  		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
>  		if (!cidr || cidr > HOST_MASK)
>  			return -IPSET_ERR_INVALID_CIDR;
> -		e.cidr = cidr - 1;
> +		e.cidr[0] = cidr - 1;
>  	}
>  
>  	if (tb[IPSET_ATTR_PORT])
> @@ -214,7 +214,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
>  	}
>  
>  	if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) {
> -		e.ip = htonl(ip & ip_set_hostmask(e.cidr + 1));
> +		e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0] + 1));
>  		ret = adtfn(set, &e, &ext, &ext, flags);
>  		return ip_set_enomatch(ret, flags, adt, set) ? -ret :
>  		       ip_set_eexist(ret, flags) ? 0 : ret;
> @@ -235,15 +235,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
>  		if (ip + UINT_MAX == ip_to)
>  			return -IPSET_ERR_HASH_RANGE;
>  	} else
> -		ip_set_mask_from_to(ip, ip_to, e.cidr + 1);
> +		ip_set_mask_from_to(ip, ip_to, e.cidr[0] + 1);
>  
>  	if (retried)
> -		ip = ntohl(h->next.ip);
> +		ip = ntohl(h->next.ip[0]);
>  	while (!after(ip, ip_to)) {
> -		e.ip = htonl(ip);
> +		e.ip[0] = htonl(ip);
>  		last = ip_set_range_to_cidr(ip, ip_to, &cidr);
> -		e.cidr = cidr - 1;
> -		p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
> +		e.cidr[0] = cidr - 1;
> +		p = retried && ip == ntohl(h->next.ip[0]) ? ntohs(h->next.port)
>  						       : port;
>  		for (; p <= port_to; p++) {
>  			e.port = htons(p);
> @@ -262,10 +262,10 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
>  /* IPv6 variants */
>  
>  struct hash_netport6_elem {
> -	union nf_inet_addr ip;
> +	union nf_inet_addr ip[1];
>  	__be16 port;
>  	u8 proto;
> -	u8 cidr:7;
> +	u8 cidr[1];
>  	u8 nomatch:1;
>  } __attribute__((aligned(sizeof(void*))));
>  
> @@ -276,10 +276,10 @@ hash_netport6_data_equal(const struct hash_netport6_elem *ip1,
>  			 const struct hash_netport6_elem *ip2,
>  			 u32 *multi)
>  {
> -	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
> +	return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) &&
>  	       ip1->port == ip2->port &&
>  	       ip1->proto == ip2->proto &&
> -	       ip1->cidr == ip2->cidr;
> +	       ip1->cidr[0] == ip2->cidr[0];
>  }
>  
>  static inline int
> @@ -303,8 +303,8 @@ hash_netport6_data_reset_flags(struct hash_netport6_elem *elem, u8 *flags)
>  static inline void
>  hash_netport6_data_netmask(struct hash_netport6_elem *elem, u8 cidr)
>  {
> -	ip6_netmask(&elem->ip, cidr);
> -	elem->cidr = cidr - 1;
> +	ip6_netmask(&elem->ip[0], cidr);
> +	elem->cidr[0] = cidr - 1;
>  }
>  
>  static bool
> @@ -313,9 +313,9 @@ hash_netport6_data_list(struct sk_buff *skb,
>  {
>  	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
>  
> -	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
> +	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) ||
>  	    nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
> -	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr + 1) ||
> +	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0] + 1) ||
>  	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
>  	    (flags &&
>  	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
> @@ -351,19 +351,19 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
>  	const struct hash_netport *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
>  	struct hash_netport6_elem e = {
> -		.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1,
> +		.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] - 1 : HOST_MASK - 1,
>  	};
>  	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
>  
>  	if (adt == IPSET_TEST)
> -		e.cidr = HOST_MASK - 1;
> +		e.cidr[0] = HOST_MASK - 1;
>  
>  	if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
>  				 &e.port, &e.proto))
>  		return -EINVAL;
>  
> -	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
> -	ip6_netmask(&e.ip, e.cidr + 1);
> +	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6);
> +	ip6_netmask(&e.ip[0], e.cidr[0] + 1);
>  
>  	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
>  }
> @@ -374,7 +374,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
>  {
>  	const struct hash_netport *h = set->data;
>  	ipset_adtfn adtfn = set->variant->adt[adt];
> -	struct hash_netport6_elem e = { .cidr = HOST_MASK  - 1 };
> +	struct hash_netport6_elem e = { .cidr[0] = HOST_MASK  - 1 };
>  	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
>  	u32 port, port_to;
>  	bool with_ports = false;
> @@ -395,7 +395,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
>  	if (tb[IPSET_ATTR_LINENO])
>  		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
>  
> -	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
> +	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) ||
>  	      ip_set_get_extensions(set, tb, &ext);
>  	if (ret)
>  		return ret;
> @@ -404,9 +404,9 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
>  		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
>  		if (!cidr || cidr > HOST_MASK)
>  			return -IPSET_ERR_INVALID_CIDR;
> -		e.cidr = cidr - 1;
> +		e.cidr[0] = cidr - 1;
>  	}
> -	ip6_netmask(&e.ip, e.cidr + 1);
> +	ip6_netmask(&e.ip[0], e.cidr[0] + 1);
>  
>  	if (tb[IPSET_ATTR_PORT])
>  		e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
> -- 
> 1.8.3.2
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-
E-mail  : kadlec@blackhole.kfki.hu, kadlecsik.jozsef@wigner.mta.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : Wigner Research Centre for Physics, Hungarian Academy of Sciences
          H-1525 Budapest 114, POB. 49, Hungary

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] netfilter: ipset: refactor hash types to use address/cidr arrays.
  2013-09-03 20:27 ` Jozsef Kadlecsik
@ 2013-09-03 22:06   ` Jozsef Kadlecsik
  2013-09-04  5:21     ` Oliver
  0 siblings, 1 reply; 9+ messages in thread
From: Jozsef Kadlecsik @ 2013-09-03 22:06 UTC (permalink / raw)
  To: Oliver; +Cc: netfilter-devel

On Tue, 3 Sep 2013, Jozsef Kadlecsik wrote:

> On Tue, 3 Sep 2013, Oliver wrote:
[...] 
> > -mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
> > +mtype_add_cidr(struct htype *h, const u8 cidr[], u8 nets_length)
> 
> I do remember you asked it and I confused you: no, the hash types need not 
> be changed for this (see below), mtype_add_cidr requires just a new arg as 
> to which member of the cidr/net array of struct htype to be updated.

I was thinking about something like this (untested, unchecked):

diff --git a/kernel/include/linux/netfilter/ipset/ip_set.h b/kernel/include/linux/netfilter/ipset/ip_set.h
index f974f35..03f99d6 100644
--- a/kernel/include/linux/netfilter/ipset/ip_set.h
+++ b/kernel/include/linux/netfilter/ipset/ip_set.h
@@ -399,6 +399,8 @@ bitmap_bytes(u32 a, u32 b)
 	{ .bytes = ULLONG_MAX, .packets = ULLONG_MAX,	\
 	  .timeout = (map)->timeout }
 
+#define IP_SET_INIT_CIDR(a, b) ((a) ? (a) : (b))
+
 #define IPSET_CONCAT(a, b)		a##b
 #define IPSET_TOKEN(a, b)		IPSET_CONCAT(a, b)
 
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_gen.h b/kernel/net/netfilter/ipset/ip_set_hash_gen.h
index c694079..596fcb6 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/kernel/net/netfilter/ipset/ip_set_hash_gen.h
@@ -77,10 +77,14 @@ struct htable {
 
 #define hbucket(h, i)		(&((h)->bucket[i]))
 
+#ifndef IPSET_NET_COUNT
+#define IPSET_NET_COUNT		1
+#endif
+
 /* Book-keeping of the prefixes added to the set */
 struct net_prefixes {
-	u8 cidr;		/* the different cidr values in the set */
-	u32 nets;		/* number of elements per cidr */
+	u32 nets[IPSET_NET_COUNT]; /* number of elements per cidr */
+	u8 cidr[IPSET_NET_COUNT];  /* the different cidr values in the set */
 };
 
 /* Compute the hash table size */
@@ -165,13 +169,13 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
 #define SET_HOST_MASK(family)	(family == AF_INET ? 32 : 128)
 
 #ifdef IP_SET_HASH_WITH_MULTI
-#define NETS_LENGTH(family)	(SET_HOST_MASK(family) + 1)
+#define NLEN(family)		(SET_HOST_MASK(family) + 1)
 #else
-#define NETS_LENGTH(family)	SET_HOST_MASK(family)
+#define NLEN(family)		SET_HOST_MASK(family)
 #endif
 
 #else
-#define NETS_LENGTH(family)	0
+#define NLEN(family)		0
 #endif /* IP_SET_HASH_WITH_NETS */
 
 #define ext_timeout(e, h)	\
@@ -296,46 +300,46 @@ struct htype {
 /* Network cidr size book keeping when the hash stores different
  * sized networks */
 static void
-mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
+mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n)
 {
 	int i, j;
 
 	/* Add in increasing prefix order, so larger cidr first */
-	for (i = 0, j = -1; i < nets_length && h->nets[i].nets; i++) {
+	for (i = 0, j = -1; i < nets_length && h->nets[i].nets[n]; i++) {
 		if (j != -1)
 			continue;
-		else if (h->nets[i].cidr < cidr)
+		else if (h->nets[i].cidr[n] < cidr)
 			j = i;
-		else if (h->nets[i].cidr == cidr) {
-			h->nets[i].nets++;
+		else if (h->nets[i].cidr[n] == cidr) {
+			h->nets[i].nets[n]++;
 			return;
 		}
 	}
 	if (j != -1) {
 		for (; i > j; i--) {
-			h->nets[i].cidr = h->nets[i - 1].cidr;
-			h->nets[i].nets = h->nets[i - 1].nets;
+			h->nets[i].cidr[n] = h->nets[i - 1].cidr[n];
+			h->nets[i].nets[n] = h->nets[i - 1].nets[n];
 		}
 	}
-	h->nets[i].cidr = cidr;
-	h->nets[i].nets = 1;
+	h->nets[i].cidr[n] = cidr;
+	h->nets[i].nets[n] = 1;
 }
 
 static void
-mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length)
+mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n)
 {
 	u8 i, j;
 
-	for (i = 0; i < nets_length - 1 && h->nets[i].cidr != cidr; i++)
+	for (i = 0; i < nets_length - 1 && h->nets[i].cidr[n] != cidr; i++)
 		;
-	h->nets[i].nets--;
+	h->nets[i].nets[n]--;
 
-	if (h->nets[i].nets != 0)
+	if (h->nets[i].nets[n] != 0)
 		return;
 
-	for (j = i; j < nets_length - 1 && h->nets[j].nets; j++) {
-		h->nets[j].cidr = h->nets[j + 1].cidr;
-		h->nets[j].nets = h->nets[j + 1].nets;
+	for (j = i; j < nets_length - 1 && h->nets[j].nets[n]; j++) {
+		h->nets[j].cidr[n] = h->nets[j + 1].cidr[n];
+		h->nets[j].nets[n] = h->nets[j + 1].nets[n];
 	}
 }
 #endif
@@ -378,8 +382,7 @@ mtype_flush(struct ip_set *set)
 		}
 	}
 #ifdef IP_SET_HASH_WITH_NETS
-	memset(h->nets, 0, sizeof(struct net_prefixes)
-			   * NETS_LENGTH(set->family));
+	memset(h->nets, 0, sizeof(struct net_prefixes) * NLEN(set->family));
 #endif
 	h->elements = 0;
 }
@@ -455,7 +458,7 @@ mtype_expire(struct htype *h, u8 nets_length, size_t dsize)
 				pr_debug("expired %u/%u\n", i, j);
 #ifdef IP_SET_HASH_WITH_NETS
 				mtype_del_cidr(h, CIDR(data->cidr),
-					       nets_length);
+					       nets_length, 0);
 #endif
 				if (j != n->pos - 1)
 					/* Not last one */
@@ -490,7 +493,7 @@ mtype_gc(unsigned long ul_set)
 
 	pr_debug("called\n");
 	write_lock_bh(&set->lock);
-	mtype_expire(h, NETS_LENGTH(set->family), h->dsize);
+	mtype_expire(h, NLEN(set->family), h->dsize);
 	write_unlock_bh(&set->lock);
 
 	h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
@@ -519,8 +522,7 @@ mtype_resize(struct ip_set *set, bool retried)
 	if (SET_WITH_TIMEOUT(set) && !retried) {
 		i = h->elements;
 		write_lock_bh(&set->lock);
-		mtype_expire(set->data, NETS_LENGTH(set->family),
-			     h->dsize);
+		mtype_expire(set->data, NLEN(set->family), h->dsize);
 		write_unlock_bh(&set->lock);
 		if (h->elements < i)
 			return 0;
@@ -603,7 +605,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
 
 	if (SET_WITH_TIMEOUT(set) && h->elements >= h->maxelem)
 		/* FIXME: when set is full, we slow down here */
-		mtype_expire(h, NETS_LENGTH(set->family), h->dsize);
+		mtype_expire(h, NLEN(set->family), h->dsize);
 
 	if (h->elements >= h->maxelem) {
 		if (net_ratelimit())
@@ -641,8 +643,8 @@ reuse_slot:
 		/* Fill out reused slot */
 		data = ahash_data(n, j, h->dsize);
 #ifdef IP_SET_HASH_WITH_NETS
-		mtype_del_cidr(h, CIDR(data->cidr), NETS_LENGTH(set->family));
-		mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
+		mtype_del_cidr(h, CIDR(data->cidr), NLEN(set->family), 0);
+		mtype_add_cidr(h, CIDR(d->cidr), NLEN(set->family), 0);
 #endif
 	} else {
 		/* Use/create a new slot */
@@ -655,7 +657,7 @@ reuse_slot:
 		}
 		data = ahash_data(n, n->pos++, h->dsize);
 #ifdef IP_SET_HASH_WITH_NETS
-		mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
+		mtype_add_cidr(h, CIDR(d->cidr), NLEN(set->family), 0);
 #endif
 		h->elements++;
 	}
@@ -707,7 +709,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
 		n->pos--;
 		h->elements--;
 #ifdef IP_SET_HASH_WITH_NETS
-		mtype_del_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
+		mtype_del_cidr(h, CIDR(d->cidr), NLEN(set->family), 0);
 #endif
 		if (n->pos + AHASH_INIT_SIZE < n->size) {
 			void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
@@ -756,11 +758,11 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
 	struct mtype_elem *data;
 	int i, j = 0;
 	u32 key, multi = 0;
-	u8 nets_length = NETS_LENGTH(set->family);
+	u8 nets_length = NLEN(set->family);
 
 	pr_debug("test by nets\n");
-	for (; j < nets_length && h->nets[j].nets && !multi; j++) {
-		mtype_data_netmask(d, h->nets[j].cidr);
+	for (; j < nets_length && h->nets[j].nets[0] && !multi; j++) {
+		mtype_data_netmask(d, h->nets[j].cidr[0]);
 		key = HKEY(d, h->initval, t->htable_bits);
 		n = hbucket(t, key);
 		for (i = 0; i < n->pos; i++) {
@@ -835,7 +837,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
 	size_t memsize;
 
 	t = rcu_dereference_bh_nfnl(h->table);
-	memsize = mtype_ahash_memsize(h, t, NETS_LENGTH(set->family));
+	memsize = mtype_ahash_memsize(h, t, NLEN(set->family));
 
 	nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
 	if (!nested)
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c b/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
index f111558..6ce5a8e 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
@@ -170,7 +170,7 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
 	const struct hash_ipportnet *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_ipportnet4_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
+		.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1,
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 
@@ -454,7 +454,7 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
 	const struct hash_ipportnet *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_ipportnet6_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
+		.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1,
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_net.c b/kernel/net/netfilter/ipset/ip_set_hash_net.c
index 0a64dad..ec1c7dc 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_net.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_net.c
@@ -143,7 +143,7 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
 	const struct hash_net *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_net4_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+		.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 
@@ -338,7 +338,7 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
 	const struct hash_net *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_net6_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+		.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_netiface.c b/kernel/net/netfilter/ipset/ip_set_hash_netiface.c
index 846371b..814b4e3 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_netiface.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_netiface.c
@@ -265,7 +265,7 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
 	struct hash_netiface *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_netiface4_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
+		.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
 		.elem = 1,
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
@@ -534,7 +534,7 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
 	struct hash_netiface *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_netiface6_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
+		.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
 		.elem = 1,
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_netport.c b/kernel/net/netfilter/ipset/ip_set_hash_netport.c
index d98a685..3bd923d 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_netport.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_netport.c
@@ -162,7 +162,7 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
 	const struct hash_netport *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_netport4_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
+		.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1,
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 
@@ -407,7 +407,7 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
 	const struct hash_netport *h = set->data;
 	ipset_adtfn adtfn = set->variant->adt[adt];
 	struct hash_netport6_elem e = {
-		.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1,
+		.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1,
 	};
 	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 

Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlecsik.jozsef@wigner.mta.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : Wigner Research Centre for Physics, Hungarian Academy of Sciences
          H-1525 Budapest 114, POB. 49, Hungary

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] netfilter: ipset: refactor hash types to use address/cidr arrays.
  2013-09-03 22:06   ` Jozsef Kadlecsik
@ 2013-09-04  5:21     ` Oliver
  2013-09-04 17:20       ` Jozsef Kadlecsik
  0 siblings, 1 reply; 9+ messages in thread
From: Oliver @ 2013-09-04  5:21 UTC (permalink / raw)
  To: Jozsef Kadlecsik; +Cc: netfilter-devel

On Wednesday 04 September 2013 00:06:01 Jozsef Kadlecsik wrote:
> On Tue, 3 Sep 2013, Jozsef Kadlecsik wrote:
> > On Tue, 3 Sep 2013, Oliver wrote:
> [...]
> 
> > > -mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
> > > +mtype_add_cidr(struct htype *h, const u8 cidr[], u8 nets_length)
> > 
> > I do remember you asked it and I confused you: no, the hash types need not
> > be changed for this (see below), mtype_add_cidr requires just a new arg as
> > to which member of the cidr/net array of struct htype to be updated.
> 
> I was thinking about something like this (untested, unchecked):

<snip>

> @@ -296,46 +300,46 @@ struct htype {
>  /* Network cidr size book keeping when the hash stores different
>   * sized networks */
>  static void
> -mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
> +mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n)

Ok, I see what you were envisioning now - I'm not entirely sure if the benefit 
of not having to modify the existing hash structs outweighs the cost of having 
to insert special cases in the generic header - especially now considering 
each hash only consists of a single struct for each address family.

Essentially, this is going to be something of a tradeoff; if it's left like it 
is now, all the existing single calls to mtype_add_cidr/mtype_del_cidr don't 
require any modification since the loop inside them handles CIDR for N number 
of nets simply by virtue of whatever you #define IPSET_NET_COUNT to be.

On the other hand, if we want to avoid changing the existing *net* hashes to 
conform to the array style, it'll require special cases that execute multiple 
calls to mtype_add_cidr and mtype_del_cidr - the blow could be softened by 
sticking a loop around it, but that's effectively going to be a small chunk of 
code duplication in order to get there. Part of the confusion I would say was 
that I figured you wanted to deduplicate the code as much as possible, so with 
that I went all-out and refactored the entire lot of existing types 
accordingly.

So, the way I see it... go with what we have right now, less code duplication, 
smaller code in general or have special cases for IPSET_NET_COUNT > 1.

Let me know what you think, I'm not massively concerned either way, but my 
vote would be for how it is now (quelle surprise?)

Thanks,
Oliver.

P.S. I've made a bunch of corrections to the comments extension and rebased it 
against all these general fixes and improvements, so I'll give it another once-
over and patch-bomb the mailing list with it later.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] netfilter: ipset: refactor hash types to use address/cidr arrays.
  2013-09-04  5:21     ` Oliver
@ 2013-09-04 17:20       ` Jozsef Kadlecsik
  2013-09-05 23:31         ` Oliver
  0 siblings, 1 reply; 9+ messages in thread
From: Jozsef Kadlecsik @ 2013-09-04 17:20 UTC (permalink / raw)
  To: Oliver; +Cc: netfilter-devel

On Wed, 4 Sep 2013, Oliver wrote:

> On Wednesday 04 September 2013 00:06:01 Jozsef Kadlecsik wrote:
> > On Tue, 3 Sep 2013, Jozsef Kadlecsik wrote:
> > > On Tue, 3 Sep 2013, Oliver wrote:
> > [...]
> > 
> > > > -mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
> > > > +mtype_add_cidr(struct htype *h, const u8 cidr[], u8 nets_length)
> > > 
> > > I do remember you asked it and I confused you: no, the hash types need not
> > > be changed for this (see below), mtype_add_cidr requires just a new arg as
> > > to which member of the cidr/net array of struct htype to be updated.
> > 
> > I was thinking about something like this (untested, unchecked):
> 
> <snip>
> 
> > @@ -296,46 +300,46 @@ struct htype {
> >  /* Network cidr size book keeping when the hash stores different
> >   * sized networks */
> >  static void
> > -mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
> > +mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n)
> 
> Ok, I see what you were envisioning now - I'm not entirely sure if the 
> benefit of not having to modify the existing hash structs outweighs the 
> cost of having to insert special cases in the generic header - 
> especially now considering each hash only consists of a single struct 
> for each address family.

I committed and pushed it to the ipset git tree. The special cases are 
going to be enabled by #ifdef conditions, so the common case is kept as 
simple as possible.
 
> Essentially, this is going to be something of a tradeoff; if it's left 
> like it is now, all the existing single calls to 
> mtype_add_cidr/mtype_del_cidr don't require any modification since the 
> loop inside them handles CIDR for N number of nets simply by virtue of 
> whatever you #define IPSET_NET_COUNT to be.
>
> On the other hand, if we want to avoid changing the existing *net* hashes to 
> conform to the array style, it'll require special cases that execute multiple 
> calls to mtype_add_cidr and mtype_del_cidr - the blow could be softened by 
> sticking a loop around it, but that's effectively going to be a small chunk of 
> code duplication in order to get there. Part of the confusion I would say was 
> that I figured you wanted to deduplicate the code as much as possible, so with 
> that I went all-out and refactored the entire lot of existing types 
> accordingly.
> 
> So, the way I see it... go with what we have right now, less code duplication, 
> smaller code in general or have special cases for IPSET_NET_COUNT > 1.
> 
> Let me know what you think, I'm not massively concerned either way, but my 
> vote would be for how it is now (quelle surprise?)
> 
> Thanks,
> Oliver.
> 
> P.S. I've made a bunch of corrections to the comments extension and 
> rebased it against all these general fixes and improvements, so I'll 
> give it another once- over and patch-bomb the mailing list with it 
> later.

Please wait a little bit with sending the comments extensions: I'm working 
on the extensions infratructure.

Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlecsik.jozsef@wigner.mta.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : Wigner Research Centre for Physics, Hungarian Academy of Sciences
          H-1525 Budapest 114, POB. 49, Hungary

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] netfilter: ipset: refactor hash types to use address/cidr arrays.
  2013-09-04 17:20       ` Jozsef Kadlecsik
@ 2013-09-05 23:31         ` Oliver
  2013-09-06 18:00           ` Jozsef Kadlecsik
  0 siblings, 1 reply; 9+ messages in thread
From: Oliver @ 2013-09-05 23:31 UTC (permalink / raw)
  To: Jozsef Kadlecsik; +Cc: netfilter-devel

On Wednesday 04 September 2013 19:20:35 Jozsef Kadlecsik wrote:

<snip>

> > > 
> > > -mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
> > > +mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n)
> > 
> > Ok, I see what you were envisioning now - I'm not entirely sure if the
> > benefit of not having to modify the existing hash structs outweighs the
> > cost of having to insert special cases in the generic header -
> > especially now considering each hash only consists of a single struct
> > for each address family.
> 
> I committed and pushed it to the ipset git tree. The special cases are
> going to be enabled by #ifdef conditions, so the common case is kept as
> simple as possible.

Alright, I took a look at the changes - I'll wait for the extension cleanup 
then send out a rebased version of hash:net,net since that's presumably going 
to be the difference between having to declare struct combinations for the 
various extensions versus not having to do it. I'm very intrigued to see what 
you can come up with that's shorter than my rework :P

On a related note - I was thinking about the impact of recursively walking the 
CIDRs and it did occur to me that this operation is very parallelisable - 
however, I found that when I ran ipset -T on the set, the in-kernel code is 
running in an interrupt context (somehow, I couldn't see what made it like 
that), which means it's not possible to spin up kthreads (unless there's 
something that I don't know about) - when testing of an ipset is called via 
xt_set, is that also running in an interrupt context? if not, it could be 
parallelised quite nicely, which I anticipate would give some gains on 
multicore systems, and especially for IPv6, one would think.

Kind Regards,
Oliver.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] netfilter: ipset: refactor hash types to use address/cidr arrays.
  2013-09-05 23:31         ` Oliver
@ 2013-09-06 18:00           ` Jozsef Kadlecsik
  2013-09-06 20:43             ` Oliver
  0 siblings, 1 reply; 9+ messages in thread
From: Jozsef Kadlecsik @ 2013-09-06 18:00 UTC (permalink / raw)
  To: Oliver; +Cc: netfilter-devel

Hi Oliver,

On Fri, 6 Sep 2013, Oliver wrote:

> Alright, I took a look at the changes - I'll wait for the extension 
> cleanup then send out a rebased version of hash:net,net since that's 
> presumably going to be the difference between having to declare struct 
> combinations for the various extensions versus not having to do it. I'm 
> very intrigued to see what you can come up with that's shorter than my 
> rework :P

There's a technical problem with your refactoring patchset (it doesn't 
prevent unaligned access to extension members), and a design issue: the 
data about the extensions (offsets) should belong to the core. There's 
still code duplication between the bitmap and hash types in it when even 
the list type is missing. The solution means an overall rearrangig and 
that's what I'm working on.
 
> On a related note - I was thinking about the impact of recursively 
> walking the CIDRs and it did occur to me that this operation is very 
> parallelisable - however, I found that when I ran ipset -T on the set, 
> the in-kernel code is running in an interrupt context (somehow, I 
> couldn't see what made it like that), which means it's not possible to 
> spin up kthreads (unless there's something that I don't know about) - 
> when testing of an ipset is called via xt_set, is that also running in 
> an interrupt context? if not, it could be parallelised quite nicely, 
> which I anticipate would give some gains on multicore systems, and 
> especially for IPv6, one would think.

How could the walking of the CIDRs be parallellized, when the lookup must 
follow the priority of the networks? (With the exception of checking 
multiple same sized networks.)

Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlecsik.jozsef@wigner.mta.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : Wigner Research Centre for Physics, Hungarian Academy of Sciences
          H-1525 Budapest 114, POB. 49, Hungary

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] netfilter: ipset: refactor hash types to use address/cidr arrays.
  2013-09-06 18:00           ` Jozsef Kadlecsik
@ 2013-09-06 20:43             ` Oliver
  2013-09-10  8:01               ` Jozsef Kadlecsik
  0 siblings, 1 reply; 9+ messages in thread
From: Oliver @ 2013-09-06 20:43 UTC (permalink / raw)
  To: Jozsef Kadlecsik; +Cc: netfilter-devel

On Friday 06 September 2013 20:00:19 Jozsef Kadlecsik wrote:
> Hi Oliver,
> 
> On Fri, 6 Sep 2013, Oliver wrote:
> > Alright, I took a look at the changes - I'll wait for the extension
> > cleanup then send out a rebased version of hash:net,net since that's
> > presumably going to be the difference between having to declare struct
> > combinations for the various extensions versus not having to do it. I'm
> > very intrigued to see what you can come up with that's shorter than my
> > rework :P
> 
> There's a technical problem with your refactoring patchset (it doesn't
> prevent unaligned access to extension members), and a design issue: the
> data about the extensions (offsets) should belong to the core. There's
> still code duplication between the bitmap and hash types in it when even
> the list type is missing. The solution means an overall rearrangig and
> that's what I'm working on.

Sounds good. I was working under the expectation that explicitly setting the 
alignment of extension structs wasn't that big of a deal, but I agree that 
it's better if it doesn't need to be manually taken care of and moving more 
stuff into the core would definitely improve things.

> 
> > On a related note - I was thinking about the impact of recursively
> > walking the CIDRs and it did occur to me that this operation is very
> > parallelisable - however, I found that when I ran ipset -T on the set,
> > the in-kernel code is running in an interrupt context (somehow, I
> > couldn't see what made it like that), which means it's not possible to
> > spin up kthreads (unless there's something that I don't know about) -
> > when testing of an ipset is called via xt_set, is that also running in
> > an interrupt context? if not, it could be parallelised quite nicely,
> > which I anticipate would give some gains on multicore systems, and
> > especially for IPv6, one would think.
> 
> How could the walking of the CIDRs be parallellized, when the lookup must
> follow the priority of the networks? (With the exception of checking
> multiple same sized networks.)

Well, pretty easily... as the most basic (albeit not necessarily most resource 
efficient) example: you spin up a kthread for every CIDR size and then check the 
return value of each kthread you spun up in order that you started them - the 
first result you get to that has a non-zero return value is obviously the one 
you require and you're done. Naturally the time saving here is coming from the 
hash table searches for every given CIDR size being done in parallel; the 
thread controller code is still going to iterate, but it's just checking a 
return code.

I already took a stab at this, but it's currently impossible because the 
moment kthread_create_on_node() is called and goes into 
sched_setscheduler_nocheck(), it triggers BUG_ON(in_interrupt()) - I poked 
through all the base code but I don't see exactly how or why we're inside an 
interrupt context when responding to ipset userspace commands.

Kind Regards,
Oliver.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] netfilter: ipset: refactor hash types to use address/cidr arrays.
  2013-09-06 20:43             ` Oliver
@ 2013-09-10  8:01               ` Jozsef Kadlecsik
  0 siblings, 0 replies; 9+ messages in thread
From: Jozsef Kadlecsik @ 2013-09-10  8:01 UTC (permalink / raw)
  To: Oliver; +Cc: netfilter-devel

On Fri, 6 Sep 2013, Oliver wrote:

> On Friday 06 September 2013 20:00:19 Jozsef Kadlecsik wrote:
> > Hi Oliver,
> > 
> > On Fri, 6 Sep 2013, Oliver wrote:
> > > Alright, I took a look at the changes - I'll wait for the extension
> > > cleanup then send out a rebased version of hash:net,net since that's
> > > presumably going to be the difference between having to declare struct
> > > combinations for the various extensions versus not having to do it. I'm
> > > very intrigued to see what you can come up with that's shorter than my
> > > rework :P
> > 
> > There's a technical problem with your refactoring patchset (it doesn't
> > prevent unaligned access to extension members), and a design issue: the
> > data about the extensions (offsets) should belong to the core. There's
> > still code duplication between the bitmap and hash types in it when even
> > the list type is missing. The solution means an overall rearrangig and
> > that's what I'm working on.
> 
> Sounds good. I was working under the expectation that explicitly setting the 
> alignment of extension structs wasn't that big of a deal, but I agree that 
> it's better if it doesn't need to be manually taken care of and moving more 
> stuff into the core would definitely improve things.

I pushed out the patches to the ipset git tree: the support of extensions 
which need per-data cleanup is there.

I think first you should adapt and submit the comment extension (at the 
places where you check the comment length and reject oversized ones, 
indicate the allowed length in the error message). Add tests at least for 
one of bitmap, hash and list types: add/delete/test elements with 
comments, list and verify the list output, flush, destroy, save and 
restore. Then the hash:net,net type may follow.
 
> > > On a related note - I was thinking about the impact of recursively
> > > walking the CIDRs and it did occur to me that this operation is very
> > > parallelisable - however, I found that when I ran ipset -T on the set,
> > > the in-kernel code is running in an interrupt context (somehow, I
> > > couldn't see what made it like that), which means it's not possible to
> > > spin up kthreads (unless there's something that I don't know about) -
> > > when testing of an ipset is called via xt_set, is that also running in
> > > an interrupt context? if not, it could be parallelised quite nicely,
> > > which I anticipate would give some gains on multicore systems, and
> > > especially for IPv6, one would think.
> > 
> > How could the walking of the CIDRs be parallellized, when the lookup must
> > follow the priority of the networks? (With the exception of checking
> > multiple same sized networks.)
> 
> Well, pretty easily... as the most basic (albeit not necessarily most 
> resource efficient) example: you spin up a kthread for every CIDR size 
> and then check the return value of each kthread you spun up in order 
> that you started them - the first result you get to that has a non-zero 
> return value is obviously the one you require and you're done. Naturally 
> the time saving here is coming from the hash table searches for every 
> given CIDR size being done in parallel; the thread controller code is 
> still going to iterate, but it's just checking a return code.

It might be a good idea or a bad one: the management of the kthreads may 
cost more in performance than iterating through the CIDR sizes. A thorough 
testing could tell the difference.
 
> I already took a stab at this, but it's currently impossible because the 
> moment kthread_create_on_node() is called and goes into 
> sched_setscheduler_nocheck(), it triggers BUG_ON(in_interrupt()) - I poked 
> through all the base code but I don't see exactly how or why we're inside an 
> interrupt context when responding to ipset userspace commands.

It's a socket-based communication, I believe that's the reason.

Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlecsik.jozsef@wigner.mta.hu
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : Wigner Research Centre for Physics, Hungarian Academy of Sciences
          H-1525 Budapest 114, POB. 49, Hungary

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2013-09-10  8:01 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-09-03 18:15 [PATCH v2] netfilter: ipset: refactor hash types to use address/cidr arrays Oliver
2013-09-03 20:27 ` Jozsef Kadlecsik
2013-09-03 22:06   ` Jozsef Kadlecsik
2013-09-04  5:21     ` Oliver
2013-09-04 17:20       ` Jozsef Kadlecsik
2013-09-05 23:31         ` Oliver
2013-09-06 18:00           ` Jozsef Kadlecsik
2013-09-06 20:43             ` Oliver
2013-09-10  8:01               ` Jozsef Kadlecsik

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.