diff options
Diffstat (limited to 'net/netfilter/ipset')
21 files changed, 2482 insertions, 1477 deletions
diff --git a/net/netfilter/ipset/Kconfig b/net/netfilter/ipset/Kconfig index ba36c283d83..2f7f5c32c6f 100644 --- a/net/netfilter/ipset/Kconfig +++ b/net/netfilter/ipset/Kconfig @@ -1,7 +1,7 @@  menuconfig IP_SET  	tristate "IP set support"  	depends on INET && NETFILTER -	depends on NETFILTER_NETLINK +	select NETFILTER_NETLINK  	help  	  This option adds IP set support to the kernel.  	  In order to define and use the sets, you need the userspace utility @@ -21,7 +21,7 @@ config IP_SET_MAX  	  You can define here default value of the maximum number   	  of IP sets for the kernel. -	  The value can be overriden by the 'max_sets' module +	  The value can be overridden by the 'max_sets' module  	  parameter of the 'ip_set' module.  config IP_SET_BITMAP_IP @@ -61,6 +61,15 @@ config IP_SET_HASH_IP  	  To compile it as a module, choose M here.  If unsure, say N. +config IP_SET_HASH_IPMARK +	tristate "hash:ip,mark set support" +	depends on IP_SET +	help +	  This option adds the hash:ip,mark set type support, by which one +	  can store IPv4/IPv6 address and mark pairs. + +	  To compile it as a module, choose M here.  If unsure, say N. +  config IP_SET_HASH_IPPORT  	tristate "hash:ip,port set support"  	depends on IP_SET @@ -90,6 +99,15 @@ config IP_SET_HASH_IPPORTNET  	  To compile it as a module, choose M here.  If unsure, say N. +config IP_SET_HASH_NETPORTNET +	tristate "hash:net,port,net set support" +	depends on IP_SET +	help +	  This option adds the hash:net,port,net set type support, by which +	  one can store two IPv4/IPv6 subnets, and a protocol/port in a set. + +	  To compile it as a module, choose M here.  If unsure, say N. +  config IP_SET_HASH_NET  	tristate "hash:net set support"  	depends on IP_SET @@ -99,6 +117,15 @@ config IP_SET_HASH_NET  	  To compile it as a module, choose M here.  If unsure, say N. +config IP_SET_HASH_NETNET +	tristate "hash:net,net set support" +	depends on IP_SET +	help +	  This option adds the hash:net,net  set type support, by which +	  one can store IPv4/IPv6 network address/prefix pairs in a set. + +	  To compile it as a module, choose M here.  If unsure, say N. +  config IP_SET_HASH_NETPORT  	tristate "hash:net,port set support"  	depends on IP_SET diff --git a/net/netfilter/ipset/Makefile b/net/netfilter/ipset/Makefile index 6e965ecd544..231f10196cb 100644 --- a/net/netfilter/ipset/Makefile +++ b/net/netfilter/ipset/Makefile @@ -14,12 +14,15 @@ obj-$(CONFIG_IP_SET_BITMAP_PORT) += ip_set_bitmap_port.o  # hash types  obj-$(CONFIG_IP_SET_HASH_IP) += ip_set_hash_ip.o +obj-$(CONFIG_IP_SET_HASH_IPMARK) += ip_set_hash_ipmark.o  obj-$(CONFIG_IP_SET_HASH_IPPORT) += ip_set_hash_ipport.o  obj-$(CONFIG_IP_SET_HASH_IPPORTIP) += ip_set_hash_ipportip.o  obj-$(CONFIG_IP_SET_HASH_IPPORTNET) += ip_set_hash_ipportnet.o  obj-$(CONFIG_IP_SET_HASH_NET) += ip_set_hash_net.o  obj-$(CONFIG_IP_SET_HASH_NETPORT) += ip_set_hash_netport.o  obj-$(CONFIG_IP_SET_HASH_NETIFACE) += ip_set_hash_netiface.o +obj-$(CONFIG_IP_SET_HASH_NETNET) += ip_set_hash_netnet.o +obj-$(CONFIG_IP_SET_HASH_NETPORTNET) += ip_set_hash_netportnet.o  # list types  obj-$(CONFIG_IP_SET_LIST_SET) += ip_set_list_set.o diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h index 25243379b88..f2c7d83dc23 100644 --- a/net/netfilter/ipset/ip_set_bitmap_gen.h +++ b/net/netfilter/ipset/ip_set_bitmap_gen.h @@ -8,38 +8,32 @@  #ifndef __IP_SET_BITMAP_IP_GEN_H  #define __IP_SET_BITMAP_IP_GEN_H -#define CONCAT(a, b)		a##b -#define TOKEN(a,b)		CONCAT(a, b) - -#define mtype_do_test		TOKEN(MTYPE, _do_test) -#define mtype_gc_test		TOKEN(MTYPE, _gc_test) -#define mtype_is_filled		TOKEN(MTYPE, _is_filled) -#define mtype_do_add		TOKEN(MTYPE, _do_add) -#define mtype_do_del		TOKEN(MTYPE, _do_del) -#define mtype_do_list		TOKEN(MTYPE, _do_list) -#define mtype_do_head		TOKEN(MTYPE, _do_head) -#define mtype_adt_elem		TOKEN(MTYPE, _adt_elem) -#define mtype_add_timeout	TOKEN(MTYPE, _add_timeout) -#define mtype_gc_init		TOKEN(MTYPE, _gc_init) -#define mtype_kadt		TOKEN(MTYPE, _kadt) -#define mtype_uadt		TOKEN(MTYPE, _uadt) -#define mtype_destroy		TOKEN(MTYPE, _destroy) -#define mtype_flush		TOKEN(MTYPE, _flush) -#define mtype_head		TOKEN(MTYPE, _head) -#define mtype_same_set		TOKEN(MTYPE, _same_set) -#define mtype_elem		TOKEN(MTYPE, _elem) -#define mtype_test		TOKEN(MTYPE, _test) -#define mtype_add		TOKEN(MTYPE, _add) -#define mtype_del		TOKEN(MTYPE, _del) -#define mtype_list		TOKEN(MTYPE, _list) -#define mtype_gc		TOKEN(MTYPE, _gc) +#define mtype_do_test		IPSET_TOKEN(MTYPE, _do_test) +#define mtype_gc_test		IPSET_TOKEN(MTYPE, _gc_test) +#define mtype_is_filled		IPSET_TOKEN(MTYPE, _is_filled) +#define mtype_do_add		IPSET_TOKEN(MTYPE, _do_add) +#define mtype_ext_cleanup	IPSET_TOKEN(MTYPE, _ext_cleanup) +#define mtype_do_del		IPSET_TOKEN(MTYPE, _do_del) +#define mtype_do_list		IPSET_TOKEN(MTYPE, _do_list) +#define mtype_do_head		IPSET_TOKEN(MTYPE, _do_head) +#define mtype_adt_elem		IPSET_TOKEN(MTYPE, _adt_elem) +#define mtype_add_timeout	IPSET_TOKEN(MTYPE, _add_timeout) +#define mtype_gc_init		IPSET_TOKEN(MTYPE, _gc_init) +#define mtype_kadt		IPSET_TOKEN(MTYPE, _kadt) +#define mtype_uadt		IPSET_TOKEN(MTYPE, _uadt) +#define mtype_destroy		IPSET_TOKEN(MTYPE, _destroy) +#define mtype_flush		IPSET_TOKEN(MTYPE, _flush) +#define mtype_head		IPSET_TOKEN(MTYPE, _head) +#define mtype_same_set		IPSET_TOKEN(MTYPE, _same_set) +#define mtype_elem		IPSET_TOKEN(MTYPE, _elem) +#define mtype_test		IPSET_TOKEN(MTYPE, _test) +#define mtype_add		IPSET_TOKEN(MTYPE, _add) +#define mtype_del		IPSET_TOKEN(MTYPE, _del) +#define mtype_list		IPSET_TOKEN(MTYPE, _list) +#define mtype_gc		IPSET_TOKEN(MTYPE, _gc)  #define mtype			MTYPE -#define ext_timeout(e, m)	\ -	(unsigned long *)((e) + (m)->offset[IPSET_OFFSET_TIMEOUT]) -#define ext_counter(e, m)	\ -	(struct ip_set_counter *)((e) + (m)->offset[IPSET_OFFSET_COUNTER]) -#define get_ext(map, id)	((map)->extensions + (map)->dsize * (id)) +#define get_ext(set, map, id)	((map)->extensions + (set)->dsize * (id))  static void  mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set)) @@ -49,11 +43,22 @@ mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))  	init_timer(&map->gc);  	map->gc.data = (unsigned long) set;  	map->gc.function = gc; -	map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; +	map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;  	add_timer(&map->gc);  }  static void +mtype_ext_cleanup(struct ip_set *set) +{ +	struct mtype *map = set->data; +	u32 id; + +	for (id = 0; id < map->elements; id++) +		if (test_bit(id, map->members)) +			ip_set_ext_destroy(set, get_ext(set, map, id)); +} + +static void  mtype_destroy(struct ip_set *set)  {  	struct mtype *map = set->data; @@ -62,8 +67,11 @@ mtype_destroy(struct ip_set *set)  		del_timer_sync(&map->gc);  	ip_set_free(map->members); -	if (map->dsize) +	if (set->dsize) { +		if (set->extensions & IPSET_EXT_DESTROY) +			mtype_ext_cleanup(set);  		ip_set_free(map->extensions); +	}  	kfree(map);  	set->data = NULL; @@ -74,6 +82,8 @@ mtype_flush(struct ip_set *set)  {  	struct mtype *map = set->data; +	if (set->extensions & IPSET_EXT_DESTROY) +		mtype_ext_cleanup(set);  	memset(map->members, 0, map->memsize);  } @@ -91,12 +101,9 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)  	    nla_put_net32(skb, IPSET_ATTR_MEMSIZE,  			  htonl(sizeof(*map) +  				map->memsize + -				map->dsize * map->elements)) || -	    (SET_WITH_TIMEOUT(set) && -	     nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) || -	    (SET_WITH_COUNTER(set) && -	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, -			   htonl(IPSET_FLAG_WITH_COUNTERS)))) +				set->dsize * map->elements))) +		goto nla_put_failure; +	if (unlikely(ip_set_put_flags(skb, set)))  		goto nla_put_failure;  	ipset_nest_end(skb, nested); @@ -111,16 +118,16 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,  {  	struct mtype *map = set->data;  	const struct mtype_adt_elem *e = value; -	void *x = get_ext(map, e->id); -	int ret = mtype_do_test(e, map); +	void *x = get_ext(set, map, e->id); +	int ret = mtype_do_test(e, map, set->dsize);  	if (ret <= 0)  		return ret;  	if (SET_WITH_TIMEOUT(set) && -	    ip_set_timeout_expired(ext_timeout(x, map))) +	    ip_set_timeout_expired(ext_timeout(x, set)))  		return 0;  	if (SET_WITH_COUNTER(set)) -		ip_set_update_counter(ext_counter(x, map), ext, mext, flags); +		ip_set_update_counter(ext_counter(x, set), ext, mext, flags);  	return 1;  } @@ -130,26 +137,30 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,  {  	struct mtype *map = set->data;  	const struct mtype_adt_elem *e = value; -	void *x = get_ext(map, e->id); -	int ret = mtype_do_add(e, map, flags); +	void *x = get_ext(set, map, e->id); +	int ret = mtype_do_add(e, map, flags, set->dsize);  	if (ret == IPSET_ADD_FAILED) {  		if (SET_WITH_TIMEOUT(set) && -		    ip_set_timeout_expired(ext_timeout(x, map))) +		    ip_set_timeout_expired(ext_timeout(x, set)))  			ret = 0;  		else if (!(flags & IPSET_FLAG_EXIST))  			return -IPSET_ERR_EXIST; +		/* Element is re-added, cleanup extensions */ +		ip_set_ext_destroy(set, x);  	}  	if (SET_WITH_TIMEOUT(set))  #ifdef IP_SET_BITMAP_STORED_TIMEOUT -		mtype_add_timeout(ext_timeout(x, map), e, ext, map, ret); +		mtype_add_timeout(ext_timeout(x, set), e, ext, set, map, ret);  #else -		ip_set_timeout_set(ext_timeout(x, map), ext->timeout); +		ip_set_timeout_set(ext_timeout(x, set), ext->timeout);  #endif  	if (SET_WITH_COUNTER(set)) -		ip_set_init_counter(ext_counter(x, map), ext); +		ip_set_init_counter(ext_counter(x, set), ext); +	if (SET_WITH_COMMENT(set)) +		ip_set_init_comment(ext_comment(x, set), ext);  	return 0;  } @@ -159,16 +170,27 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,  {  	struct mtype *map = set->data;  	const struct mtype_adt_elem *e = value; -	const void *x = get_ext(map, e->id); +	void *x = get_ext(set, map, e->id); -	if (mtype_do_del(e, map) || -	    (SET_WITH_TIMEOUT(set) && -	     ip_set_timeout_expired(ext_timeout(x, map)))) +	if (mtype_do_del(e, map)) +		return -IPSET_ERR_EXIST; + +	ip_set_ext_destroy(set, x); +	if (SET_WITH_TIMEOUT(set) && +	    ip_set_timeout_expired(ext_timeout(x, set)))  		return -IPSET_ERR_EXIST;  	return 0;  } +#ifndef IP_SET_BITMAP_STORED_TIMEOUT +static inline bool +mtype_is_filled(const struct mtype_elem *x) +{ +	return true; +} +#endif +  static int  mtype_list(const struct ip_set *set,  	   struct sk_buff *skb, struct netlink_callback *cb) @@ -176,20 +198,21 @@ mtype_list(const struct ip_set *set,  	struct mtype *map = set->data;  	struct nlattr *adt, *nested;  	void *x; -	u32 id, first = cb->args[2]; +	u32 id, first = cb->args[IPSET_CB_ARG0];  	adt = ipset_nest_start(skb, IPSET_ATTR_ADT);  	if (!adt)  		return -EMSGSIZE; -	for (; cb->args[2] < map->elements; cb->args[2]++) { -		id = cb->args[2]; -		x = get_ext(map, id); +	for (; cb->args[IPSET_CB_ARG0] < map->elements; +	     cb->args[IPSET_CB_ARG0]++) { +		id = cb->args[IPSET_CB_ARG0]; +		x = get_ext(set, map, id);  		if (!test_bit(id, map->members) ||  		    (SET_WITH_TIMEOUT(set) &&  #ifdef IP_SET_BITMAP_STORED_TIMEOUT  		     mtype_is_filled((const struct mtype_elem *) x) &&  #endif -		     ip_set_timeout_expired(ext_timeout(x, map)))) +		     ip_set_timeout_expired(ext_timeout(x, set))))  			continue;  		nested = ipset_nest_start(skb, IPSET_ATTR_DATA);  		if (!nested) { @@ -199,40 +222,27 @@ mtype_list(const struct ip_set *set,  			} else  				goto nla_put_failure;  		} -		if (mtype_do_list(skb, map, id)) +		if (mtype_do_list(skb, map, id, set->dsize))  			goto nla_put_failure; -		if (SET_WITH_TIMEOUT(set)) { -#ifdef IP_SET_BITMAP_STORED_TIMEOUT -			if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, -					  htonl(ip_set_timeout_stored(map, id, -							ext_timeout(x, map))))) -				goto nla_put_failure; -#else -			if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, -					  htonl(ip_set_timeout_get( -							ext_timeout(x, map))))) -				goto nla_put_failure; -#endif -		} -		if (SET_WITH_COUNTER(set) && -		    ip_set_put_counter(skb, ext_counter(x, map))) +		if (ip_set_put_extensions(skb, set, x, +		    mtype_is_filled((const struct mtype_elem *) x)))  			goto nla_put_failure;  		ipset_nest_end(skb, nested);  	}  	ipset_nest_end(skb, adt);  	/* Set listing finished */ -	cb->args[2] = 0; +	cb->args[IPSET_CB_ARG0] = 0;  	return 0;  nla_put_failure:  	nla_nest_cancel(skb, nested); -	ipset_nest_end(skb, adt);  	if (unlikely(id == first)) { -		cb->args[2] = 0; +		cb->args[IPSET_CB_ARG0] = 0;  		return -EMSGSIZE;  	} +	ipset_nest_end(skb, adt);  	return 0;  } @@ -241,21 +251,23 @@ mtype_gc(unsigned long ul_set)  {  	struct ip_set *set = (struct ip_set *) ul_set;  	struct mtype *map = set->data; -	const void *x; +	void *x;  	u32 id;  	/* We run parallel with other readers (test element)  	 * but adding/deleting new entries is locked out */  	read_lock_bh(&set->lock);  	for (id = 0; id < map->elements; id++) -		if (mtype_gc_test(id, map)) { -			x = get_ext(map, id); -			if (ip_set_timeout_expired(ext_timeout(x, map))) +		if (mtype_gc_test(id, map, set->dsize)) { +			x = get_ext(set, map, id); +			if (ip_set_timeout_expired(ext_timeout(x, set))) {  				clear_bit(id, map->members); +				ip_set_ext_destroy(set, x); +			}  		}  	read_unlock_bh(&set->lock); -	map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; +	map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;  	add_timer(&map->gc);  } diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c index f1a8128bef0..6f1f9f49480 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ip.c +++ b/net/netfilter/ipset/ip_set_bitmap_ip.c @@ -25,12 +25,13 @@  #include <linux/netfilter/ipset/ip_set.h>  #include <linux/netfilter/ipset/ip_set_bitmap.h> -#define REVISION_MIN	0 -#define REVISION_MAX	1	/* Counter support added */ +#define IPSET_TYPE_REV_MIN	0 +/*				1	   Counter support added */ +#define IPSET_TYPE_REV_MAX	2	/* Comment support added */  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -IP_SET_MODULE_DESC("bitmap:ip", REVISION_MIN, REVISION_MAX); +IP_SET_MODULE_DESC("bitmap:ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);  MODULE_ALIAS("ip_set_bitmap:ip");  #define MTYPE		bitmap_ip @@ -44,10 +45,7 @@ struct bitmap_ip {  	u32 elements;		/* number of max elements in the set */  	u32 hosts;		/* number of hosts in a subnet */  	size_t memsize;		/* members size */ -	size_t dsize;		/* extensions struct size */ -	size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */  	u8 netmask;		/* subnet netmask */ -	u32 timeout;		/* timeout parameter */  	struct timer_list gc;	/* garbage collection */  }; @@ -65,20 +63,21 @@ ip_to_id(const struct bitmap_ip *m, u32 ip)  /* Common functions */  static inline int -bitmap_ip_do_test(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map) +bitmap_ip_do_test(const struct bitmap_ip_adt_elem *e, +		  struct bitmap_ip *map, size_t dsize)  {  	return !!test_bit(e->id, map->members);  }  static inline int -bitmap_ip_gc_test(u16 id, const struct bitmap_ip *map) +bitmap_ip_gc_test(u16 id, const struct bitmap_ip *map, size_t dsize)  {  	return !!test_bit(id, map->members);  }  static inline int  bitmap_ip_do_add(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map, -		 u32 flags) +		 u32 flags, size_t dsize)  {  	return !!test_and_set_bit(e->id, map->members);  } @@ -90,7 +89,8 @@ bitmap_ip_do_del(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map)  }  static inline int -bitmap_ip_do_list(struct sk_buff *skb, const struct bitmap_ip *map, u32 id) +bitmap_ip_do_list(struct sk_buff *skb, const struct bitmap_ip *map, u32 id, +		  size_t dsize)  {  	return nla_put_ipaddr4(skb, IPSET_ATTR_IP,  			htonl(map->first_ip + id * map->hosts)); @@ -113,7 +113,7 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,  	struct bitmap_ip *map = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct bitmap_ip_adt_elem e = { }; -	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	u32 ip;  	ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC)); @@ -131,9 +131,9 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],  {  	struct bitmap_ip *map = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt]; -	u32 ip, ip_to; +	u32 ip = 0, ip_to = 0;  	struct bitmap_ip_adt_elem e = { }; -	struct ip_set_ext ext = IP_SET_INIT_UEXT(map); +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);  	int ret = 0;  	if (unlikely(!tb[IPSET_ATTR_IP] || @@ -200,7 +200,7 @@ bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)  	return x->first_ip == y->first_ip &&  	       x->last_ip == y->last_ip &&  	       x->netmask == y->netmask && -	       x->timeout == y->timeout && +	       a->timeout == b->timeout &&  	       a->extensions == b->extensions;  } @@ -209,25 +209,6 @@ bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)  struct bitmap_ip_elem {  }; -/* Timeout variant */ - -struct bitmap_ipt_elem { -	unsigned long timeout; -}; - -/* Plain variant with counter */ - -struct bitmap_ipc_elem { -	struct ip_set_counter counter; -}; - -/* Timeout variant with counter */ - -struct bitmap_ipct_elem { -	unsigned long timeout; -	struct ip_set_counter counter; -}; -  #include "ip_set_bitmap_gen.h"  /* Create bitmap:ip type of sets */ @@ -240,8 +221,8 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,  	map->members = ip_set_alloc(map->memsize);  	if (!map->members)  		return false; -	if (map->dsize) { -		map->extensions = ip_set_alloc(map->dsize * elements); +	if (set->dsize) { +		map->extensions = ip_set_alloc(set->dsize * elements);  		if (!map->extensions) {  			kfree(map->members);  			return false; @@ -252,7 +233,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,  	map->elements = elements;  	map->hosts = hosts;  	map->netmask = netmask; -	map->timeout = IPSET_NO_TIMEOUT; +	set->timeout = IPSET_NO_TIMEOUT;  	set->data = map;  	set->family = NFPROTO_IPV4; @@ -261,10 +242,11 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,  }  static int -bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) +bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[], +		 u32 flags)  {  	struct bitmap_ip *map; -	u32 first_ip, last_ip, hosts, cadt_flags = 0; +	u32 first_ip = 0, last_ip = 0, hosts;  	u64 elements;  	u8 netmask = 32;  	int ret; @@ -336,61 +318,15 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)  	map->memsize = bitmap_bytes(0, elements - 1);  	set->variant = &bitmap_ip; -	if (tb[IPSET_ATTR_CADT_FLAGS]) -		cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); -	if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) { -		set->extensions |= IPSET_EXT_COUNTER; -		if (tb[IPSET_ATTR_TIMEOUT]) { -			map->dsize = sizeof(struct bitmap_ipct_elem); -			map->offset[IPSET_OFFSET_TIMEOUT] = -				offsetof(struct bitmap_ipct_elem, timeout); -			map->offset[IPSET_OFFSET_COUNTER] = -				offsetof(struct bitmap_ipct_elem, counter); - -			if (!init_map_ip(set, map, first_ip, last_ip, -					 elements, hosts, netmask)) { -				kfree(map); -				return -ENOMEM; -			} - -			map->timeout = ip_set_timeout_uget( -				tb[IPSET_ATTR_TIMEOUT]); -			set->extensions |= IPSET_EXT_TIMEOUT; - -			bitmap_ip_gc_init(set, bitmap_ip_gc); -		} else { -			map->dsize = sizeof(struct bitmap_ipc_elem); -			map->offset[IPSET_OFFSET_COUNTER] = -				offsetof(struct bitmap_ipc_elem, counter); - -			if (!init_map_ip(set, map, first_ip, last_ip, -					 elements, hosts, netmask)) { -				kfree(map); -				return -ENOMEM; -			} -		} -	} else if (tb[IPSET_ATTR_TIMEOUT]) { -		map->dsize = sizeof(struct bitmap_ipt_elem); -		map->offset[IPSET_OFFSET_TIMEOUT] = -			offsetof(struct bitmap_ipt_elem, timeout); - -		if (!init_map_ip(set, map, first_ip, last_ip, -				 elements, hosts, netmask)) { -			kfree(map); -			return -ENOMEM; -		} - -		map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); -		set->extensions |= IPSET_EXT_TIMEOUT; - +	set->dsize = ip_set_elem_len(set, tb, 0); +	if (!init_map_ip(set, map, first_ip, last_ip, +			 elements, hosts, netmask)) { +		kfree(map); +		return -ENOMEM; +	} +	if (tb[IPSET_ATTR_TIMEOUT]) { +		set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);  		bitmap_ip_gc_init(set, bitmap_ip_gc); -	} else { -		map->dsize = 0; -		if (!init_map_ip(set, map, first_ip, last_ip, -				 elements, hosts, netmask)) { -			kfree(map); -			return -ENOMEM; -		}  	}  	return 0;  } @@ -401,8 +337,8 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {  	.features	= IPSET_TYPE_IP,  	.dimension	= IPSET_DIM_ONE,  	.family		= NFPROTO_IPV4, -	.revision_min	= REVISION_MIN, -	.revision_max	= REVISION_MAX, +	.revision_min	= IPSET_TYPE_REV_MIN, +	.revision_max	= IPSET_TYPE_REV_MAX,  	.create		= bitmap_ip_create,  	.create_policy	= {  		[IPSET_ATTR_IP]		= { .type = NLA_NESTED }, @@ -420,6 +356,7 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {  		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },  		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },  		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 }, +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING },  	},  	.me		= THIS_MODULE,  }; diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c index 3b30e0bef89..740eabededd 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c +++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c @@ -25,12 +25,13 @@  #include <linux/netfilter/ipset/ip_set.h>  #include <linux/netfilter/ipset/ip_set_bitmap.h> -#define REVISION_MIN	0 -#define REVISION_MAX	1	/* Counter support added */ +#define IPSET_TYPE_REV_MIN	0 +/*				1	   Counter support added */ +#define IPSET_TYPE_REV_MAX	2	/* Comment support added */  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -IP_SET_MODULE_DESC("bitmap:ip,mac", REVISION_MIN, REVISION_MAX); +IP_SET_MODULE_DESC("bitmap:ip,mac", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);  MODULE_ALIAS("ip_set_bitmap:ip,mac");  #define MTYPE		bitmap_ipmac @@ -48,11 +49,8 @@ struct bitmap_ipmac {  	u32 first_ip;		/* host byte order, included in range */  	u32 last_ip;		/* host byte order, included in range */  	u32 elements;		/* number of max elements in the set */ -	u32 timeout;		/* timeout value */ -	struct timer_list gc;	/* garbage collector */  	size_t memsize;		/* members size */ -	size_t dsize;		/* size of element */ -	size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */ +	struct timer_list gc;	/* garbage collector */  };  /* ADT structure for generic function args */ @@ -82,13 +80,13 @@ get_elem(void *extensions, u16 id, size_t dsize)  static inline int  bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e, -		     const struct bitmap_ipmac *map) +		     const struct bitmap_ipmac *map, size_t dsize)  {  	const struct bitmap_ipmac_elem *elem;  	if (!test_bit(e->id, map->members))  		return 0; -	elem = get_elem(map->extensions, e->id, map->dsize); +	elem = get_elem(map->extensions, e->id, dsize);  	if (elem->filled == MAC_FILLED)  		return e->ether == NULL ||  		       ether_addr_equal(e->ether, elem->ether); @@ -97,13 +95,13 @@ bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,  }  static inline int -bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map) +bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize)  {  	const struct bitmap_ipmac_elem *elem;  	if (!test_bit(id, map->members))  		return 0; -	elem = get_elem(map->extensions, id, map->dsize); +	elem = get_elem(map->extensions, id, dsize);  	/* Timer not started for the incomplete elements */  	return elem->filled == MAC_FILLED;  } @@ -117,13 +115,13 @@ bitmap_ipmac_is_filled(const struct bitmap_ipmac_elem *elem)  static inline int  bitmap_ipmac_add_timeout(unsigned long *timeout,  			 const struct bitmap_ipmac_adt_elem *e, -			 const struct ip_set_ext *ext, +			 const struct ip_set_ext *ext, struct ip_set *set,  			 struct bitmap_ipmac *map, int mode)  {  	u32 t = ext->timeout;  	if (mode == IPSET_ADD_START_STORED_TIMEOUT) { -		if (t == map->timeout) +		if (t == set->timeout)  			/* Timeout was not specified, get stored one */  			t = *timeout;  		ip_set_timeout_set(timeout, t); @@ -142,11 +140,11 @@ bitmap_ipmac_add_timeout(unsigned long *timeout,  static inline int  bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e, -		    struct bitmap_ipmac *map, u32 flags) +		    struct bitmap_ipmac *map, u32 flags, size_t dsize)  {  	struct bitmap_ipmac_elem *elem; -	elem = get_elem(map->extensions, e->id, map->dsize); +	elem = get_elem(map->extensions, e->id, dsize);  	if (test_and_set_bit(e->id, map->members)) {  		if (elem->filled == MAC_FILLED) {  			if (e->ether && (flags & IPSET_FLAG_EXIST)) @@ -178,22 +176,12 @@ bitmap_ipmac_do_del(const struct bitmap_ipmac_adt_elem *e,  	return !test_and_clear_bit(e->id, map->members);  } -static inline unsigned long -ip_set_timeout_stored(struct bitmap_ipmac *map, u32 id, unsigned long *timeout) -{ -	const struct bitmap_ipmac_elem *elem = -		get_elem(map->extensions, id, map->dsize); - -	return elem->filled == MAC_FILLED ? ip_set_timeout_get(timeout) : -					    *timeout; -} -  static inline int  bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map, -		     u32 id) +		     u32 id, size_t dsize)  {  	const struct bitmap_ipmac_elem *elem = -		get_elem(map->extensions, id, map->dsize); +		get_elem(map->extensions, id, dsize);  	return nla_put_ipaddr4(skb, IPSET_ATTR_IP,  			       htonl(map->first_ip + id)) || @@ -216,7 +204,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,  	struct bitmap_ipmac *map = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct bitmap_ipmac_adt_elem e = {}; -	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	u32 ip;  	/* MAC can be src only */ @@ -245,8 +233,8 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],  	const struct bitmap_ipmac *map = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct bitmap_ipmac_adt_elem e = {}; -	struct ip_set_ext ext = IP_SET_INIT_UEXT(map); -	u32 ip; +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +	u32 ip = 0;  	int ret = 0;  	if (unlikely(!tb[IPSET_ATTR_IP] || @@ -285,43 +273,12 @@ bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b)  	return x->first_ip == y->first_ip &&  	       x->last_ip == y->last_ip && -	       x->timeout == y->timeout && +	       a->timeout == b->timeout &&  	       a->extensions == b->extensions;  }  /* Plain variant */ -/* Timeout variant */ - -struct bitmap_ipmact_elem { -	struct { -		unsigned char ether[ETH_ALEN]; -		unsigned char filled; -	} __attribute__ ((aligned)); -	unsigned long timeout; -}; - -/* Plain variant with counter */ - -struct bitmap_ipmacc_elem { -	struct { -		unsigned char ether[ETH_ALEN]; -		unsigned char filled; -	} __attribute__ ((aligned)); -	struct ip_set_counter counter; -}; - -/* Timeout variant with counter */ - -struct bitmap_ipmacct_elem { -	struct { -		unsigned char ether[ETH_ALEN]; -		unsigned char filled; -	} __attribute__ ((aligned)); -	unsigned long timeout; -	struct ip_set_counter counter; -}; -  #include "ip_set_bitmap_gen.h"  /* Create bitmap:ip,mac type of sets */ @@ -330,11 +287,11 @@ static bool  init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,  	       u32 first_ip, u32 last_ip, u32 elements)  { -	map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize); +	map->members = ip_set_alloc(map->memsize);  	if (!map->members)  		return false; -	if (map->dsize) { -		map->extensions = ip_set_alloc(map->dsize * elements); +	if (set->dsize) { +		map->extensions = ip_set_alloc(set->dsize * elements);  		if (!map->extensions) {  			kfree(map->members);  			return false; @@ -343,7 +300,7 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,  	map->first_ip = first_ip;  	map->last_ip = last_ip;  	map->elements = elements; -	map->timeout = IPSET_NO_TIMEOUT; +	set->timeout = IPSET_NO_TIMEOUT;  	set->data = map;  	set->family = NFPROTO_IPV4; @@ -352,10 +309,10 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,  }  static int -bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[], +bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],  		    u32 flags)  { -	u32 first_ip, last_ip, cadt_flags = 0; +	u32 first_ip = 0, last_ip = 0;  	u64 elements;  	struct bitmap_ipmac *map;  	int ret; @@ -399,57 +356,15 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],  	map->memsize = bitmap_bytes(0, elements - 1);  	set->variant = &bitmap_ipmac; -	if (tb[IPSET_ATTR_CADT_FLAGS]) -		cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); -	if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) { -		set->extensions |= IPSET_EXT_COUNTER; -		if (tb[IPSET_ATTR_TIMEOUT]) { -			map->dsize = sizeof(struct bitmap_ipmacct_elem); -			map->offset[IPSET_OFFSET_TIMEOUT] = -				offsetof(struct bitmap_ipmacct_elem, timeout); -			map->offset[IPSET_OFFSET_COUNTER] = -				offsetof(struct bitmap_ipmacct_elem, counter); - -			if (!init_map_ipmac(set, map, first_ip, last_ip, -					    elements)) { -				kfree(map); -				return -ENOMEM; -			} -			map->timeout = ip_set_timeout_uget( -				tb[IPSET_ATTR_TIMEOUT]); -			set->extensions |= IPSET_EXT_TIMEOUT; -			bitmap_ipmac_gc_init(set, bitmap_ipmac_gc); -		} else { -			map->dsize = sizeof(struct bitmap_ipmacc_elem); -			map->offset[IPSET_OFFSET_COUNTER] = -				offsetof(struct bitmap_ipmacc_elem, counter); - -			if (!init_map_ipmac(set, map, first_ip, last_ip, -					    elements)) { -				kfree(map); -				return -ENOMEM; -			} -		} -	} else if (tb[IPSET_ATTR_TIMEOUT]) { -		map->dsize = sizeof(struct bitmap_ipmact_elem); -		map->offset[IPSET_OFFSET_TIMEOUT] = -			offsetof(struct bitmap_ipmact_elem, timeout); - -		if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) { -			kfree(map); -			return -ENOMEM; -		} -		map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); -		set->extensions |= IPSET_EXT_TIMEOUT; +	set->dsize = ip_set_elem_len(set, tb, +				     sizeof(struct bitmap_ipmac_elem)); +	if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) { +		kfree(map); +		return -ENOMEM; +	} +	if (tb[IPSET_ATTR_TIMEOUT]) { +		set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);  		bitmap_ipmac_gc_init(set, bitmap_ipmac_gc); -	} else { -		map->dsize = sizeof(struct bitmap_ipmac_elem); - -		if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) { -			kfree(map); -			return -ENOMEM; -		} -		set->variant = &bitmap_ipmac;  	}  	return 0;  } @@ -460,8 +375,8 @@ static struct ip_set_type bitmap_ipmac_type = {  	.features	= IPSET_TYPE_IP | IPSET_TYPE_MAC,  	.dimension	= IPSET_DIM_TWO,  	.family		= NFPROTO_IPV4, -	.revision_min	= REVISION_MIN, -	.revision_max	= REVISION_MAX, +	.revision_min	= IPSET_TYPE_REV_MIN, +	.revision_max	= IPSET_TYPE_REV_MAX,  	.create		= bitmap_ipmac_create,  	.create_policy	= {  		[IPSET_ATTR_IP]		= { .type = NLA_NESTED }, @@ -478,6 +393,7 @@ static struct ip_set_type bitmap_ipmac_type = {  		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },  		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },  		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 }, +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING },  	},  	.me		= THIS_MODULE,  }; diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c index 8207d1fda52..cf99676e69f 100644 --- a/net/netfilter/ipset/ip_set_bitmap_port.c +++ b/net/netfilter/ipset/ip_set_bitmap_port.c @@ -20,12 +20,13 @@  #include <linux/netfilter/ipset/ip_set_bitmap.h>  #include <linux/netfilter/ipset/ip_set_getport.h> -#define REVISION_MIN	0 -#define REVISION_MAX	1	/* Counter support added */ +#define IPSET_TYPE_REV_MIN	0 +/*				1	   Counter support added */ +#define IPSET_TYPE_REV_MAX	2	/* Comment support added */  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -IP_SET_MODULE_DESC("bitmap:port", REVISION_MIN, REVISION_MAX); +IP_SET_MODULE_DESC("bitmap:port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);  MODULE_ALIAS("ip_set_bitmap:port");  #define MTYPE		bitmap_port @@ -38,9 +39,6 @@ struct bitmap_port {  	u16 last_port;		/* host byte order, included in range */  	u32 elements;		/* number of max elements in the set */  	size_t memsize;		/* members size */ -	size_t dsize;		/* extensions struct size */ -	size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */ -	u32 timeout;		/* timeout parameter */  	struct timer_list gc;	/* garbage collection */  }; @@ -59,20 +57,20 @@ port_to_id(const struct bitmap_port *m, u16 port)  static inline int  bitmap_port_do_test(const struct bitmap_port_adt_elem *e, -		    const struct bitmap_port *map) +		    const struct bitmap_port *map, size_t dsize)  {  	return !!test_bit(e->id, map->members);  }  static inline int -bitmap_port_gc_test(u16 id, const struct bitmap_port *map) +bitmap_port_gc_test(u16 id, const struct bitmap_port *map, size_t dsize)  {  	return !!test_bit(id, map->members);  }  static inline int  bitmap_port_do_add(const struct bitmap_port_adt_elem *e, -		   struct bitmap_port *map, u32 flags) +		   struct bitmap_port *map, u32 flags, size_t dsize)  {  	return !!test_and_set_bit(e->id, map->members);  } @@ -85,7 +83,8 @@ bitmap_port_do_del(const struct bitmap_port_adt_elem *e,  }  static inline int -bitmap_port_do_list(struct sk_buff *skb, const struct bitmap_port *map, u32 id) +bitmap_port_do_list(struct sk_buff *skb, const struct bitmap_port *map, u32 id, +		    size_t dsize)  {  	return nla_put_net16(skb, IPSET_ATTR_PORT,  			     htons(map->first_port + id)); @@ -106,7 +105,7 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,  	struct bitmap_port *map = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct bitmap_port_adt_elem e = {}; -	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	__be16 __port;  	u16 port = 0; @@ -131,7 +130,7 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],  	struct bitmap_port *map = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct bitmap_port_adt_elem e = {}; -	struct ip_set_ext ext = IP_SET_INIT_UEXT(map); +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);  	u32 port;	/* wraparound */  	u16 port_to;  	int ret = 0; @@ -191,7 +190,7 @@ bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)  	return x->first_port == y->first_port &&  	       x->last_port == y->last_port && -	       x->timeout == y->timeout && +	       a->timeout == b->timeout &&  	       a->extensions == b->extensions;  } @@ -200,25 +199,6 @@ bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)  struct bitmap_port_elem {  }; -/* Timeout variant */ - -struct bitmap_portt_elem { -	unsigned long timeout; -}; - -/* Plain variant with counter */ - -struct bitmap_portc_elem { -	struct ip_set_counter counter; -}; - -/* Timeout variant with counter */ - -struct bitmap_portct_elem { -	unsigned long timeout; -	struct ip_set_counter counter; -}; -  #include "ip_set_bitmap_gen.h"  /* Create bitmap:ip type of sets */ @@ -230,8 +210,8 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,  	map->members = ip_set_alloc(map->memsize);  	if (!map->members)  		return false; -	if (map->dsize) { -		map->extensions = ip_set_alloc(map->dsize * map->elements); +	if (set->dsize) { +		map->extensions = ip_set_alloc(set->dsize * map->elements);  		if (!map->extensions) {  			kfree(map->members);  			return false; @@ -239,7 +219,7 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,  	}  	map->first_port = first_port;  	map->last_port = last_port; -	map->timeout = IPSET_NO_TIMEOUT; +	set->timeout = IPSET_NO_TIMEOUT;  	set->data = map;  	set->family = NFPROTO_UNSPEC; @@ -248,11 +228,11 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,  }  static int -bitmap_port_create(struct ip_set *set, struct nlattr *tb[], u32 flags) +bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[], +		   u32 flags)  {  	struct bitmap_port *map;  	u16 first_port, last_port; -	u32 cadt_flags = 0;  	if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||  		     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) || @@ -274,55 +254,16 @@ bitmap_port_create(struct ip_set *set, struct nlattr *tb[], u32 flags)  		return -ENOMEM;  	map->elements = last_port - first_port + 1; -	map->memsize = map->elements * sizeof(unsigned long); +	map->memsize = bitmap_bytes(0, map->elements);  	set->variant = &bitmap_port; -	if (tb[IPSET_ATTR_CADT_FLAGS]) -		cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); -	if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) { -		set->extensions |= IPSET_EXT_COUNTER; -		if (tb[IPSET_ATTR_TIMEOUT]) { -			map->dsize = sizeof(struct bitmap_portct_elem); -			map->offset[IPSET_OFFSET_TIMEOUT] = -				offsetof(struct bitmap_portct_elem, timeout); -			map->offset[IPSET_OFFSET_COUNTER] = -				offsetof(struct bitmap_portct_elem, counter); -			if (!init_map_port(set, map, first_port, last_port)) { -				kfree(map); -				return -ENOMEM; -			} - -			map->timeout = -				ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); -			set->extensions |= IPSET_EXT_TIMEOUT; -			bitmap_port_gc_init(set, bitmap_port_gc); -		} else { -			map->dsize = sizeof(struct bitmap_portc_elem); -			map->offset[IPSET_OFFSET_COUNTER] = -				offsetof(struct bitmap_portc_elem, counter); -			if (!init_map_port(set, map, first_port, last_port)) { -				kfree(map); -				return -ENOMEM; -			} -		} -	} else if (tb[IPSET_ATTR_TIMEOUT]) { -		map->dsize = sizeof(struct bitmap_portt_elem); -		map->offset[IPSET_OFFSET_TIMEOUT] = -			offsetof(struct bitmap_portt_elem, timeout); -		if (!init_map_port(set, map, first_port, last_port)) { -			kfree(map); -			return -ENOMEM; -		} - -		map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); -		set->extensions |= IPSET_EXT_TIMEOUT; +	set->dsize = ip_set_elem_len(set, tb, 0); +	if (!init_map_port(set, map, first_port, last_port)) { +		kfree(map); +		return -ENOMEM; +	} +	if (tb[IPSET_ATTR_TIMEOUT]) { +		set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);  		bitmap_port_gc_init(set, bitmap_port_gc); -	} else { -		map->dsize = 0; -		if (!init_map_port(set, map, first_port, last_port)) { -			kfree(map); -			return -ENOMEM; -		} -  	}  	return 0;  } @@ -333,8 +274,8 @@ static struct ip_set_type bitmap_port_type = {  	.features	= IPSET_TYPE_PORT,  	.dimension	= IPSET_DIM_ONE,  	.family		= NFPROTO_UNSPEC, -	.revision_min	= REVISION_MIN, -	.revision_max	= REVISION_MAX, +	.revision_min	= IPSET_TYPE_REV_MIN, +	.revision_max	= IPSET_TYPE_REV_MAX,  	.create		= bitmap_port_create,  	.create_policy	= {  		[IPSET_ATTR_PORT]	= { .type = NLA_U16 }, @@ -349,6 +290,7 @@ static struct ip_set_type bitmap_port_type = {  		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },  		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },  		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 }, +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING },  	},  	.me		= THIS_MODULE,  }; diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index f2e30fb31e7..ec8114fae50 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -17,6 +17,8 @@  #include <linux/spinlock.h>  #include <linux/rculist.h>  #include <net/netlink.h> +#include <net/net_namespace.h> +#include <net/netns/generic.h>  #include <linux/netfilter.h>  #include <linux/netfilter/x_tables.h> @@ -27,8 +29,17 @@ static LIST_HEAD(ip_set_type_list);		/* all registered set types */  static DEFINE_MUTEX(ip_set_type_mutex);		/* protects ip_set_type_list */  static DEFINE_RWLOCK(ip_set_ref_lock);		/* protects the set refs */ -static struct ip_set * __rcu *ip_set_list;	/* all individual sets */ -static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */ +struct ip_set_net { +	struct ip_set * __rcu *ip_set_list;	/* all individual sets */ +	ip_set_id_t	ip_set_max;	/* max number of sets */ +	int		is_deleted;	/* deleted by ip_set_net_exit */ +}; +static int ip_set_net_id __read_mostly; + +static inline struct ip_set_net *ip_set_pernet(struct net *net) +{ +	return net_generic(net, ip_set_net_id); +}  #define IP_SET_INC	64  #define STREQ(a, b)	(strncmp(a, b, IPSET_MAXNAMELEN) == 0) @@ -43,10 +54,10 @@ MODULE_DESCRIPTION("core IP set support");  MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET);  /* When the nfnl mutex is held: */ -#define nfnl_dereference(p)		\ +#define ip_set_dereference(p)		\  	rcu_dereference_protected(p, 1) -#define nfnl_set(id)			\ -	nfnl_dereference(ip_set_list)[id] +#define ip_set(inst, id)		\ +	ip_set_dereference((inst)->ip_set_list)[id]  /*   * The set types are implemented in modules and registered set types @@ -260,10 +271,7 @@ ip_set_free(void *members)  {  	pr_debug("%p: free with %s\n", members,  		 is_vmalloc_addr(members) ? "vfree" : "kfree"); -	if (is_vmalloc_addr(members)) -		vfree(members); -	else -		kfree(members); +	kvfree(members);  }  EXPORT_SYMBOL_GPL(ip_set_free); @@ -315,6 +323,62 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr)  }  EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6); +typedef void (*destroyer)(void *); +/* ipset data extension types, in size order */ + +const struct ip_set_ext_type ip_set_extensions[] = { +	[IPSET_EXT_ID_COUNTER] = { +		.type	= IPSET_EXT_COUNTER, +		.flag	= IPSET_FLAG_WITH_COUNTERS, +		.len	= sizeof(struct ip_set_counter), +		.align	= __alignof__(struct ip_set_counter), +	}, +	[IPSET_EXT_ID_TIMEOUT] = { +		.type	= IPSET_EXT_TIMEOUT, +		.len	= sizeof(unsigned long), +		.align	= __alignof__(unsigned long), +	}, +	[IPSET_EXT_ID_COMMENT] = { +		.type	 = IPSET_EXT_COMMENT | IPSET_EXT_DESTROY, +		.flag	 = IPSET_FLAG_WITH_COMMENT, +		.len	 = sizeof(struct ip_set_comment), +		.align	 = __alignof__(struct ip_set_comment), +		.destroy = (destroyer) ip_set_comment_free, +	}, +}; +EXPORT_SYMBOL_GPL(ip_set_extensions); + +static inline bool +add_extension(enum ip_set_ext_id id, u32 flags, struct nlattr *tb[]) +{ +	return ip_set_extensions[id].flag ? +		(flags & ip_set_extensions[id].flag) : +		!!tb[IPSET_ATTR_TIMEOUT]; +} + +size_t +ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len) +{ +	enum ip_set_ext_id id; +	size_t offset = 0; +	u32 cadt_flags = 0; + +	if (tb[IPSET_ATTR_CADT_FLAGS]) +		cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); +	if (cadt_flags & IPSET_FLAG_WITH_FORCEADD) +		set->flags |= IPSET_CREATE_FLAG_FORCEADD; +	for (id = 0; id < IPSET_EXT_ID_MAX; id++) { +		if (!add_extension(id, cadt_flags, tb)) +			continue; +		offset += ALIGN(len + offset, ip_set_extensions[id].align); +		set->offset[id] = offset; +		set->extensions |= ip_set_extensions[id].type; +		offset += ip_set_extensions[id].len; +	} +	return len + offset; +} +EXPORT_SYMBOL_GPL(ip_set_elem_len); +  int  ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],  		      struct ip_set_ext *ext) @@ -334,6 +398,12 @@ ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],  			ext->packets = be64_to_cpu(nla_get_be64(  						   tb[IPSET_ATTR_PACKETS]));  	} +	if (tb[IPSET_ATTR_COMMENT]) { +		if (!(set->extensions & IPSET_EXT_COMMENT)) +			return -IPSET_ERR_COMMENT; +		ext->comment = ip_set_comment_uget(tb[IPSET_ATTR_COMMENT]); +	} +  	return 0;  }  EXPORT_SYMBOL_GPL(ip_set_get_extensions); @@ -374,13 +444,14 @@ __ip_set_put(struct ip_set *set)   */  static inline struct ip_set * -ip_set_rcu_get(ip_set_id_t index) +ip_set_rcu_get(struct net *net, ip_set_id_t index)  {  	struct ip_set *set; +	struct ip_set_net *inst = ip_set_pernet(net);  	rcu_read_lock();  	/* ip_set_list itself needs to be protected */ -	set = rcu_dereference(ip_set_list)[index]; +	set = rcu_dereference(inst->ip_set_list)[index];  	rcu_read_unlock();  	return set; @@ -390,7 +461,8 @@ int  ip_set_test(ip_set_id_t index, const struct sk_buff *skb,  	    const struct xt_action_param *par, struct ip_set_adt_opt *opt)  { -	struct ip_set *set = ip_set_rcu_get(index); +	struct ip_set *set = ip_set_rcu_get( +			dev_net(par->in ? par->in : par->out), index);  	int ret = 0;  	BUG_ON(set == NULL); @@ -428,7 +500,8 @@ int  ip_set_add(ip_set_id_t index, const struct sk_buff *skb,  	   const struct xt_action_param *par, struct ip_set_adt_opt *opt)  { -	struct ip_set *set = ip_set_rcu_get(index); +	struct ip_set *set = ip_set_rcu_get( +			dev_net(par->in ? par->in : par->out), index);  	int ret;  	BUG_ON(set == NULL); @@ -436,7 +509,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,  	if (opt->dim < set->type->dimension ||  	    !(opt->family == set->family || set->family == NFPROTO_UNSPEC)) -		return 0; +		return -IPSET_ERR_TYPE_MISMATCH;  	write_lock_bh(&set->lock);  	ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt); @@ -450,7 +523,8 @@ int  ip_set_del(ip_set_id_t index, const struct sk_buff *skb,  	   const struct xt_action_param *par, struct ip_set_adt_opt *opt)  { -	struct ip_set *set = ip_set_rcu_get(index); +	struct ip_set *set = ip_set_rcu_get( +			dev_net(par->in ? par->in : par->out), index);  	int ret = 0;  	BUG_ON(set == NULL); @@ -458,7 +532,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,  	if (opt->dim < set->type->dimension ||  	    !(opt->family == set->family || set->family == NFPROTO_UNSPEC)) -		return 0; +		return -IPSET_ERR_TYPE_MISMATCH;  	write_lock_bh(&set->lock);  	ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt); @@ -474,14 +548,15 @@ EXPORT_SYMBOL_GPL(ip_set_del);   *   */  ip_set_id_t -ip_set_get_byname(const char *name, struct ip_set **set) +ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)  {  	ip_set_id_t i, index = IPSET_INVALID_ID;  	struct ip_set *s; +	struct ip_set_net *inst = ip_set_pernet(net);  	rcu_read_lock(); -	for (i = 0; i < ip_set_max; i++) { -		s = rcu_dereference(ip_set_list)[i]; +	for (i = 0; i < inst->ip_set_max; i++) { +		s = rcu_dereference(inst->ip_set_list)[i];  		if (s != NULL && STREQ(s->name, name)) {  			__ip_set_get(s);  			index = i; @@ -501,17 +576,26 @@ EXPORT_SYMBOL_GPL(ip_set_get_byname);   * to be valid, after calling this function.   *   */ -void -ip_set_put_byindex(ip_set_id_t index) + +static inline void +__ip_set_put_byindex(struct ip_set_net *inst, ip_set_id_t index)  {  	struct ip_set *set;  	rcu_read_lock(); -	set = rcu_dereference(ip_set_list)[index]; +	set = rcu_dereference(inst->ip_set_list)[index];  	if (set != NULL)  		__ip_set_put(set);  	rcu_read_unlock();  } + +void +ip_set_put_byindex(struct net *net, ip_set_id_t index) +{ +	struct ip_set_net *inst = ip_set_pernet(net); + +	__ip_set_put_byindex(inst, index); +}  EXPORT_SYMBOL_GPL(ip_set_put_byindex);  /* @@ -522,9 +606,9 @@ EXPORT_SYMBOL_GPL(ip_set_put_byindex);   *   */  const char * -ip_set_name_byindex(ip_set_id_t index) +ip_set_name_byindex(struct net *net, ip_set_id_t index)  { -	const struct ip_set *set = ip_set_rcu_get(index); +	const struct ip_set *set = ip_set_rcu_get(net, index);  	BUG_ON(set == NULL);  	BUG_ON(set->ref == 0); @@ -540,48 +624,22 @@ EXPORT_SYMBOL_GPL(ip_set_name_byindex);   */  /* - * Find set by name, reference it once. The reference makes sure the - * thing pointed to, does not go away under our feet. - * - * The nfnl mutex is used in the function. - */ -ip_set_id_t -ip_set_nfnl_get(const char *name) -{ -	ip_set_id_t i, index = IPSET_INVALID_ID; -	struct ip_set *s; - -	nfnl_lock(NFNL_SUBSYS_IPSET); -	for (i = 0; i < ip_set_max; i++) { -		s = nfnl_set(i); -		if (s != NULL && STREQ(s->name, name)) { -			__ip_set_get(s); -			index = i; -			break; -		} -	} -	nfnl_unlock(NFNL_SUBSYS_IPSET); - -	return index; -} -EXPORT_SYMBOL_GPL(ip_set_nfnl_get); - -/*   * Find set by index, reference it once. The reference makes sure the   * thing pointed to, does not go away under our feet.   *   * The nfnl mutex is used in the function.   */  ip_set_id_t -ip_set_nfnl_get_byindex(ip_set_id_t index) +ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index)  {  	struct ip_set *set; +	struct ip_set_net *inst = ip_set_pernet(net); -	if (index > ip_set_max) +	if (index > inst->ip_set_max)  		return IPSET_INVALID_ID;  	nfnl_lock(NFNL_SUBSYS_IPSET); -	set = nfnl_set(index); +	set = ip_set(inst, index);  	if (set)  		__ip_set_get(set);  	else @@ -600,13 +658,17 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_get_byindex);   * The nfnl mutex is used in the function.   */  void -ip_set_nfnl_put(ip_set_id_t index) +ip_set_nfnl_put(struct net *net, ip_set_id_t index)  {  	struct ip_set *set; +	struct ip_set_net *inst = ip_set_pernet(net); +  	nfnl_lock(NFNL_SUBSYS_IPSET); -	set = nfnl_set(index); -	if (set != NULL) -		__ip_set_put(set); +	if (!inst->is_deleted) { /* already deleted from ip_set_net_exit() */ +		set = ip_set(inst, index); +		if (set != NULL) +			__ip_set_put(set); +	}  	nfnl_unlock(NFNL_SUBSYS_IPSET);  }  EXPORT_SYMBOL_GPL(ip_set_nfnl_put); @@ -664,14 +726,14 @@ static const struct nla_policy ip_set_create_policy[IPSET_ATTR_CMD_MAX + 1] = {  };  static struct ip_set * -find_set_and_id(const char *name, ip_set_id_t *id) +find_set_and_id(struct ip_set_net *inst, const char *name, ip_set_id_t *id)  {  	struct ip_set *set = NULL;  	ip_set_id_t i;  	*id = IPSET_INVALID_ID; -	for (i = 0; i < ip_set_max; i++) { -		set = nfnl_set(i); +	for (i = 0; i < inst->ip_set_max; i++) { +		set = ip_set(inst, i);  		if (set != NULL && STREQ(set->name, name)) {  			*id = i;  			break; @@ -681,22 +743,23 @@ find_set_and_id(const char *name, ip_set_id_t *id)  }  static inline struct ip_set * -find_set(const char *name) +find_set(struct ip_set_net *inst, const char *name)  {  	ip_set_id_t id; -	return find_set_and_id(name, &id); +	return find_set_and_id(inst, name, &id);  }  static int -find_free_id(const char *name, ip_set_id_t *index, struct ip_set **set) +find_free_id(struct ip_set_net *inst, const char *name, ip_set_id_t *index, +	     struct ip_set **set)  {  	struct ip_set *s;  	ip_set_id_t i;  	*index = IPSET_INVALID_ID; -	for (i = 0;  i < ip_set_max; i++) { -		s = nfnl_set(i); +	for (i = 0;  i < inst->ip_set_max; i++) { +		s = ip_set(inst, i);  		if (s == NULL) {  			if (*index == IPSET_INVALID_ID)  				*index = i; @@ -725,6 +788,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,  	      const struct nlmsghdr *nlh,  	      const struct nlattr * const attr[])  { +	struct net *net = sock_net(ctnl); +	struct ip_set_net *inst = ip_set_pernet(net);  	struct ip_set *set, *clash = NULL;  	ip_set_id_t index = IPSET_INVALID_ID;  	struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {}; @@ -783,7 +848,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,  		goto put_out;  	} -	ret = set->type->create(set, tb, flags); +	ret = set->type->create(net, set, tb, flags);  	if (ret != 0)  		goto put_out; @@ -794,7 +859,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,  	 * by the nfnl mutex. Find the first free index in ip_set_list  	 * and check clashing.  	 */ -	ret = find_free_id(set->name, &index, &clash); +	ret = find_free_id(inst, set->name, &index, &clash);  	if (ret == -EEXIST) {  		/* If this is the same set and requested, ignore error */  		if ((flags & IPSET_FLAG_EXIST) && @@ -807,9 +872,9 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,  		goto cleanup;  	} else if (ret == -IPSET_ERR_MAX_SETS) {  		struct ip_set **list, **tmp; -		ip_set_id_t i = ip_set_max + IP_SET_INC; +		ip_set_id_t i = inst->ip_set_max + IP_SET_INC; -		if (i < ip_set_max || i == IPSET_INVALID_ID) +		if (i < inst->ip_set_max || i == IPSET_INVALID_ID)  			/* Wraparound */  			goto cleanup; @@ -817,14 +882,14 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,  		if (!list)  			goto cleanup;  		/* nfnl mutex is held, both lists are valid */ -		tmp = nfnl_dereference(ip_set_list); -		memcpy(list, tmp, sizeof(struct ip_set *) * ip_set_max); -		rcu_assign_pointer(ip_set_list, list); +		tmp = ip_set_dereference(inst->ip_set_list); +		memcpy(list, tmp, sizeof(struct ip_set *) * inst->ip_set_max); +		rcu_assign_pointer(inst->ip_set_list, list);  		/* Make sure all current packets have passed through */  		synchronize_net();  		/* Use new list */ -		index = ip_set_max; -		ip_set_max = i; +		index = inst->ip_set_max; +		inst->ip_set_max = i;  		kfree(tmp);  		ret = 0;  	} else if (ret) @@ -834,7 +899,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,  	 * Finally! Add our shiny new set to the list, and be done.  	 */  	pr_debug("create: '%s' created with index %u!\n", set->name, index); -	nfnl_set(index) = set; +	ip_set(inst, index) = set;  	return ret; @@ -857,12 +922,12 @@ ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] = {  };  static void -ip_set_destroy_set(ip_set_id_t index) +ip_set_destroy_set(struct ip_set_net *inst, ip_set_id_t index)  { -	struct ip_set *set = nfnl_set(index); +	struct ip_set *set = ip_set(inst, index);  	pr_debug("set: %s\n",  set->name); -	nfnl_set(index) = NULL; +	ip_set(inst, index) = NULL;  	/* Must call it without holding any lock */  	set->variant->destroy(set); @@ -875,6 +940,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,  	       const struct nlmsghdr *nlh,  	       const struct nlattr * const attr[])  { +	struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));  	struct ip_set *s;  	ip_set_id_t i;  	int ret = 0; @@ -894,21 +960,22 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,  	 */  	read_lock_bh(&ip_set_ref_lock);  	if (!attr[IPSET_ATTR_SETNAME]) { -		for (i = 0; i < ip_set_max; i++) { -			s = nfnl_set(i); +		for (i = 0; i < inst->ip_set_max; i++) { +			s = ip_set(inst, i);  			if (s != NULL && s->ref) {  				ret = -IPSET_ERR_BUSY;  				goto out;  			}  		}  		read_unlock_bh(&ip_set_ref_lock); -		for (i = 0; i < ip_set_max; i++) { -			s = nfnl_set(i); +		for (i = 0; i < inst->ip_set_max; i++) { +			s = ip_set(inst, i);  			if (s != NULL) -				ip_set_destroy_set(i); +				ip_set_destroy_set(inst, i);  		}  	} else { -		s = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME]), &i); +		s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]), +				    &i);  		if (s == NULL) {  			ret = -ENOENT;  			goto out; @@ -918,7 +985,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,  		}  		read_unlock_bh(&ip_set_ref_lock); -		ip_set_destroy_set(i); +		ip_set_destroy_set(inst, i);  	}  	return 0;  out: @@ -943,6 +1010,7 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb,  	     const struct nlmsghdr *nlh,  	     const struct nlattr * const attr[])  { +	struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));  	struct ip_set *s;  	ip_set_id_t i; @@ -950,13 +1018,13 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb,  		return -IPSET_ERR_PROTOCOL;  	if (!attr[IPSET_ATTR_SETNAME]) { -		for (i = 0; i < ip_set_max; i++) { -			s = nfnl_set(i); +		for (i = 0; i < inst->ip_set_max; i++) { +			s = ip_set(inst, i);  			if (s != NULL)  				ip_set_flush_set(s);  		}  	} else { -		s = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); +		s = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));  		if (s == NULL)  			return -ENOENT; @@ -982,6 +1050,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,  	      const struct nlmsghdr *nlh,  	      const struct nlattr * const attr[])  { +	struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));  	struct ip_set *set, *s;  	const char *name2;  	ip_set_id_t i; @@ -992,7 +1061,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,  		     attr[IPSET_ATTR_SETNAME2] == NULL))  		return -IPSET_ERR_PROTOCOL; -	set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); +	set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));  	if (set == NULL)  		return -ENOENT; @@ -1003,8 +1072,8 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,  	}  	name2 = nla_data(attr[IPSET_ATTR_SETNAME2]); -	for (i = 0; i < ip_set_max; i++) { -		s = nfnl_set(i); +	for (i = 0; i < inst->ip_set_max; i++) { +		s = ip_set(inst, i);  		if (s != NULL && STREQ(s->name, name2)) {  			ret = -IPSET_ERR_EXIST_SETNAME2;  			goto out; @@ -1031,6 +1100,7 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,  	    const struct nlmsghdr *nlh,  	    const struct nlattr * const attr[])  { +	struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));  	struct ip_set *from, *to;  	ip_set_id_t from_id, to_id;  	char from_name[IPSET_MAXNAMELEN]; @@ -1040,11 +1110,13 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,  		     attr[IPSET_ATTR_SETNAME2] == NULL))  		return -IPSET_ERR_PROTOCOL; -	from = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME]), &from_id); +	from = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]), +			       &from_id);  	if (from == NULL)  		return -ENOENT; -	to = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME2]), &to_id); +	to = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME2]), +			     &to_id);  	if (to == NULL)  		return -IPSET_ERR_EXIST_SETNAME2; @@ -1061,8 +1133,8 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,  	write_lock_bh(&ip_set_ref_lock);  	swap(from->ref, to->ref); -	nfnl_set(from_id) = to; -	nfnl_set(to_id) = from; +	ip_set(inst, from_id) = to; +	ip_set(inst, to_id) = from;  	write_unlock_bh(&ip_set_ref_lock);  	return 0; @@ -1081,9 +1153,12 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,  static int  ip_set_dump_done(struct netlink_callback *cb)  { -	if (cb->args[2]) { -		pr_debug("release set %s\n", nfnl_set(cb->args[1])->name); -		ip_set_put_byindex((ip_set_id_t) cb->args[1]); +	struct ip_set_net *inst = (struct ip_set_net *)cb->args[IPSET_CB_NET]; +	if (cb->args[IPSET_CB_ARG0]) { +		pr_debug("release set %s\n", +			 ip_set(inst, cb->args[IPSET_CB_INDEX])->name); +		__ip_set_put_byindex(inst, +			(ip_set_id_t) cb->args[IPSET_CB_INDEX]);  	}  	return 0;  } @@ -1101,7 +1176,7 @@ dump_attrs(struct nlmsghdr *nlh)  }  static int -dump_init(struct netlink_callback *cb) +dump_init(struct netlink_callback *cb, struct ip_set_net *inst)  {  	struct nlmsghdr *nlh = nlmsg_hdr(cb->skb);  	int min_len = nlmsg_total_size(sizeof(struct nfgenmsg)); @@ -1114,21 +1189,22 @@ dump_init(struct netlink_callback *cb)  	nla_parse(cda, IPSET_ATTR_CMD_MAX,  		  attr, nlh->nlmsg_len - min_len, ip_set_setname_policy); -	/* cb->args[0] : dump single set/all sets -	 *         [1] : set index -	 *         [..]: type specific +	/* cb->args[IPSET_CB_NET]:	net namespace +	 *         [IPSET_CB_DUMP]:	dump single set/all sets +	 *         [IPSET_CB_INDEX]: 	set index +	 *         [IPSET_CB_ARG0]:	type specific  	 */  	if (cda[IPSET_ATTR_SETNAME]) {  		struct ip_set *set; -		set = find_set_and_id(nla_data(cda[IPSET_ATTR_SETNAME]), +		set = find_set_and_id(inst, nla_data(cda[IPSET_ATTR_SETNAME]),  				      &index);  		if (set == NULL)  			return -ENOENT;  		dump_type = DUMP_ONE; -		cb->args[1] = index; +		cb->args[IPSET_CB_INDEX] = index;  	} else  		dump_type = DUMP_ALL; @@ -1136,7 +1212,8 @@ dump_init(struct netlink_callback *cb)  		u32 f = ip_set_get_h32(cda[IPSET_ATTR_FLAGS]);  		dump_type |= (f << 16);  	} -	cb->args[0] = dump_type; +	cb->args[IPSET_CB_NET] = (unsigned long)inst; +	cb->args[IPSET_CB_DUMP] = dump_type;  	return 0;  } @@ -1148,11 +1225,12 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)  	struct ip_set *set = NULL;  	struct nlmsghdr *nlh = NULL;  	unsigned int flags = NETLINK_CB(cb->skb).portid ? NLM_F_MULTI : 0; +	struct ip_set_net *inst = ip_set_pernet(sock_net(skb->sk));  	u32 dump_type, dump_flags;  	int ret = 0; -	if (!cb->args[0]) { -		ret = dump_init(cb); +	if (!cb->args[IPSET_CB_DUMP]) { +		ret = dump_init(cb, inst);  		if (ret < 0) {  			nlh = nlmsg_hdr(cb->skb);  			/* We have to create and send the error message @@ -1163,18 +1241,19 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)  		}  	} -	if (cb->args[1] >= ip_set_max) +	if (cb->args[IPSET_CB_INDEX] >= inst->ip_set_max)  		goto out; -	dump_type = DUMP_TYPE(cb->args[0]); -	dump_flags = DUMP_FLAGS(cb->args[0]); -	max = dump_type == DUMP_ONE ? cb->args[1] + 1 : ip_set_max; +	dump_type = DUMP_TYPE(cb->args[IPSET_CB_DUMP]); +	dump_flags = DUMP_FLAGS(cb->args[IPSET_CB_DUMP]); +	max = dump_type == DUMP_ONE ? cb->args[IPSET_CB_INDEX] + 1 +				    : inst->ip_set_max;  dump_last: -	pr_debug("args[0]: %u %u args[1]: %ld\n", -		 dump_type, dump_flags, cb->args[1]); -	for (; cb->args[1] < max; cb->args[1]++) { -		index = (ip_set_id_t) cb->args[1]; -		set = nfnl_set(index); +	pr_debug("dump type, flag: %u %u index: %ld\n", +		 dump_type, dump_flags, cb->args[IPSET_CB_INDEX]); +	for (; cb->args[IPSET_CB_INDEX] < max; cb->args[IPSET_CB_INDEX]++) { +		index = (ip_set_id_t) cb->args[IPSET_CB_INDEX]; +		set = ip_set(inst, index);  		if (set == NULL) {  			if (dump_type == DUMP_ONE) {  				ret = -ENOENT; @@ -1190,7 +1269,7 @@ dump_last:  		     !!(set->type->features & IPSET_DUMP_LAST)))  			continue;  		pr_debug("List set: %s\n", set->name); -		if (!cb->args[2]) { +		if (!cb->args[IPSET_CB_ARG0]) {  			/* Start listing: make sure set won't be destroyed */  			pr_debug("reference set\n");  			__ip_set_get(set); @@ -1207,7 +1286,7 @@ dump_last:  			goto nla_put_failure;  		if (dump_flags & IPSET_FLAG_LIST_SETNAME)  			goto next_set; -		switch (cb->args[2]) { +		switch (cb->args[IPSET_CB_ARG0]) {  		case 0:  			/* Core header data */  			if (nla_put_string(skb, IPSET_ATTR_TYPENAME, @@ -1227,7 +1306,7 @@ dump_last:  			read_lock_bh(&set->lock);  			ret = set->variant->list(set, skb, cb);  			read_unlock_bh(&set->lock); -			if (!cb->args[2]) +			if (!cb->args[IPSET_CB_ARG0])  				/* Set is done, proceed with next one */  				goto next_set;  			goto release_refcount; @@ -1236,8 +1315,8 @@ dump_last:  	/* If we dump all sets, continue with dumping last ones */  	if (dump_type == DUMP_ALL) {  		dump_type = DUMP_LAST; -		cb->args[0] = dump_type | (dump_flags << 16); -		cb->args[1] = 0; +		cb->args[IPSET_CB_DUMP] = dump_type | (dump_flags << 16); +		cb->args[IPSET_CB_INDEX] = 0;  		goto dump_last;  	}  	goto out; @@ -1246,15 +1325,15 @@ nla_put_failure:  	ret = -EFAULT;  next_set:  	if (dump_type == DUMP_ONE) -		cb->args[1] = IPSET_INVALID_ID; +		cb->args[IPSET_CB_INDEX] = IPSET_INVALID_ID;  	else -		cb->args[1]++; +		cb->args[IPSET_CB_INDEX]++;  release_refcount:  	/* If there was an error or set is done, release set */ -	if (ret || !cb->args[2]) { -		pr_debug("release set %s\n", nfnl_set(index)->name); -		ip_set_put_byindex(index); -		cb->args[2] = 0; +	if (ret || !cb->args[IPSET_CB_ARG0]) { +		pr_debug("release set %s\n", ip_set(inst, index)->name); +		__ip_set_put_byindex(inst, index); +		cb->args[IPSET_CB_ARG0] = 0;  	}  out:  	if (nlh) { @@ -1356,6 +1435,7 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb,  	    const struct nlmsghdr *nlh,  	    const struct nlattr * const attr[])  { +	struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));  	struct ip_set *set;  	struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};  	const struct nlattr *nla; @@ -1374,7 +1454,7 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb,  		       attr[IPSET_ATTR_LINENO] == NULL))))  		return -IPSET_ERR_PROTOCOL; -	set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); +	set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));  	if (set == NULL)  		return -ENOENT; @@ -1410,6 +1490,7 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb,  	    const struct nlmsghdr *nlh,  	    const struct nlattr * const attr[])  { +	struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));  	struct ip_set *set;  	struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};  	const struct nlattr *nla; @@ -1428,7 +1509,7 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb,  		       attr[IPSET_ATTR_LINENO] == NULL))))  		return -IPSET_ERR_PROTOCOL; -	set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); +	set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));  	if (set == NULL)  		return -ENOENT; @@ -1464,6 +1545,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,  	     const struct nlmsghdr *nlh,  	     const struct nlattr * const attr[])  { +	struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));  	struct ip_set *set;  	struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};  	int ret = 0; @@ -1474,7 +1556,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,  		     !flag_nested(attr[IPSET_ATTR_DATA])))  		return -IPSET_ERR_PROTOCOL; -	set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); +	set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));  	if (set == NULL)  		return -ENOENT; @@ -1499,6 +1581,7 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb,  	      const struct nlmsghdr *nlh,  	      const struct nlattr * const attr[])  { +	struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));  	const struct ip_set *set;  	struct sk_buff *skb2;  	struct nlmsghdr *nlh2; @@ -1508,7 +1591,7 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb,  		     attr[IPSET_ATTR_SETNAME] == NULL))  		return -IPSET_ERR_PROTOCOL; -	set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); +	set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));  	if (set == NULL)  		return -ENOENT; @@ -1733,8 +1816,10 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)  	unsigned int *op;  	void *data;  	int copylen = *len, ret = 0; +	struct net *net = sock_net(sk); +	struct ip_set_net *inst = ip_set_pernet(net); -	if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) +	if (!ns_capable(net->user_ns, CAP_NET_ADMIN))  		return -EPERM;  	if (optval != SO_IP_SET)  		return -EBADF; @@ -1783,22 +1868,39 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)  		}  		req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0';  		nfnl_lock(NFNL_SUBSYS_IPSET); -		find_set_and_id(req_get->set.name, &id); +		find_set_and_id(inst, req_get->set.name, &id);  		req_get->set.index = id;  		nfnl_unlock(NFNL_SUBSYS_IPSET);  		goto copy;  	} +	case IP_SET_OP_GET_FNAME: { +		struct ip_set_req_get_set_family *req_get = data; +		ip_set_id_t id; + +		if (*len != sizeof(struct ip_set_req_get_set_family)) { +			ret = -EINVAL; +			goto done; +		} +		req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0'; +		nfnl_lock(NFNL_SUBSYS_IPSET); +		find_set_and_id(inst, req_get->set.name, &id); +		req_get->set.index = id; +		if (id != IPSET_INVALID_ID) +			req_get->family = ip_set(inst, id)->family; +		nfnl_unlock(NFNL_SUBSYS_IPSET); +		goto copy; +	}  	case IP_SET_OP_GET_BYINDEX: {  		struct ip_set_req_get_set *req_get = data;  		struct ip_set *set;  		if (*len != sizeof(struct ip_set_req_get_set) || -		    req_get->set.index >= ip_set_max) { +		    req_get->set.index >= inst->ip_set_max) {  			ret = -EINVAL;  			goto done;  		}  		nfnl_lock(NFNL_SUBSYS_IPSET); -		set = nfnl_set(req_get->set.index); +		set = ip_set(inst, req_get->set.index);  		strncpy(req_get->set.name, set ? set->name : "",  			IPSET_MAXNAMELEN);  		nfnl_unlock(NFNL_SUBSYS_IPSET); @@ -1827,49 +1929,81 @@ static struct nf_sockopt_ops so_set __read_mostly = {  	.owner		= THIS_MODULE,  }; -static int __init -ip_set_init(void) +static int __net_init +ip_set_net_init(struct net *net)  { +	struct ip_set_net *inst = ip_set_pernet(net);  	struct ip_set **list; -	int ret; -	if (max_sets) -		ip_set_max = max_sets; -	if (ip_set_max >= IPSET_INVALID_ID) -		ip_set_max = IPSET_INVALID_ID - 1; +	inst->ip_set_max = max_sets ? max_sets : CONFIG_IP_SET_MAX; +	if (inst->ip_set_max >= IPSET_INVALID_ID) +		inst->ip_set_max = IPSET_INVALID_ID - 1; -	list = kzalloc(sizeof(struct ip_set *) * ip_set_max, GFP_KERNEL); +	list = kzalloc(sizeof(struct ip_set *) * inst->ip_set_max, GFP_KERNEL);  	if (!list)  		return -ENOMEM; +	inst->is_deleted = 0; +	rcu_assign_pointer(inst->ip_set_list, list); +	return 0; +} + +static void __net_exit +ip_set_net_exit(struct net *net) +{ +	struct ip_set_net *inst = ip_set_pernet(net); + +	struct ip_set *set = NULL; +	ip_set_id_t i; + +	inst->is_deleted = 1; /* flag for ip_set_nfnl_put */ + +	for (i = 0; i < inst->ip_set_max; i++) { +		set = ip_set(inst, i); +		if (set != NULL) +			ip_set_destroy_set(inst, i); +	} +	kfree(rcu_dereference_protected(inst->ip_set_list, 1)); +} + +static struct pernet_operations ip_set_net_ops = { +	.init	= ip_set_net_init, +	.exit   = ip_set_net_exit, +	.id	= &ip_set_net_id, +	.size	= sizeof(struct ip_set_net) +}; -	rcu_assign_pointer(ip_set_list, list); -	ret = nfnetlink_subsys_register(&ip_set_netlink_subsys); + +static int __init +ip_set_init(void) +{ +	int ret = nfnetlink_subsys_register(&ip_set_netlink_subsys);  	if (ret != 0) {  		pr_err("ip_set: cannot register with nfnetlink.\n"); -		kfree(list);  		return ret;  	}  	ret = nf_register_sockopt(&so_set);  	if (ret != 0) {  		pr_err("SO_SET registry failed: %d\n", ret);  		nfnetlink_subsys_unregister(&ip_set_netlink_subsys); -		kfree(list);  		return ret;  	} - -	pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL); +	ret = register_pernet_subsys(&ip_set_net_ops); +	if (ret) { +		pr_err("ip_set: cannot register pernet_subsys.\n"); +		nf_unregister_sockopt(&so_set); +		nfnetlink_subsys_unregister(&ip_set_netlink_subsys); +		return ret; +	} +	pr_info("ip_set: protocol %u\n", IPSET_PROTOCOL);  	return 0;  }  static void __exit  ip_set_fini(void)  { -	struct ip_set **list = rcu_dereference_protected(ip_set_list, 1); - -	/* There can't be any existing set */ +	unregister_pernet_subsys(&ip_set_net_ops);  	nf_unregister_sockopt(&so_set);  	nfnetlink_subsys_unregister(&ip_set_netlink_subsys); -	kfree(list);  	pr_debug("these are the famous last words\n");  } diff --git a/net/netfilter/ipset/ip_set_getport.c b/net/netfilter/ipset/ip_set_getport.c index dac156f819a..29fb01ddff9 100644 --- a/net/netfilter/ipset/ip_set_getport.c +++ b/net/netfilter/ipset/ip_set_getport.c @@ -102,9 +102,25 @@ ip_set_get_ip4_port(const struct sk_buff *skb, bool src,  	int protocol = iph->protocol;  	/* See comments at tcp_match in ip_tables.c */ -	if (protocol <= 0 || (ntohs(iph->frag_off) & IP_OFFSET)) +	if (protocol <= 0)  		return false; +	if (ntohs(iph->frag_off) & IP_OFFSET) +		switch (protocol) { +		case IPPROTO_TCP: +		case IPPROTO_SCTP: +		case IPPROTO_UDP: +		case IPPROTO_UDPLITE: +		case IPPROTO_ICMP: +			/* Port info not available for fragment offset > 0 */ +			return false; +		default: +			/* Other protocols doesn't have ports, +			   so we can match fragments */ +			*proto = protocol; +			return true; +		} +  	return get_port(skb, protocol, protooff, src, port, proto);  }  EXPORT_SYMBOL_GPL(ip_set_get_ip4_port); diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h index 707bc520d62..61c7fb05280 100644 --- a/net/netfilter/ipset/ip_set_hash_gen.h +++ b/net/netfilter/ipset/ip_set_hash_gen.h @@ -15,8 +15,7 @@  #define rcu_dereference_bh(p)	rcu_dereference(p)  #endif -#define CONCAT(a, b)		a##b -#define TOKEN(a, b)		CONCAT(a, b) +#define rcu_dereference_bh_nfnl(p)	rcu_dereference_bh_check(p, 1)  /* Hashing which uses arrays to resolve clashing. The hash table is resized   * (doubled) when searching becomes too long. @@ -78,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 */ @@ -114,23 +117,6 @@ htable_bits(u32 hashsize)  	return bits;  } -/* Destroy the hashtable part of the set */ -static void -ahash_destroy(struct htable *t) -{ -	struct hbucket *n; -	u32 i; - -	for (i = 0; i < jhash_size(t->htable_bits); i++) { -		n = hbucket(t, i); -		if (n->size) -			/* FIXME: use slab cache */ -			kfree(n->value); -	} - -	ip_set_free(t); -} -  static int  hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)  { @@ -156,30 +142,30 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)  }  #ifdef IP_SET_HASH_WITH_NETS +#if IPSET_NET_COUNT > 1 +#define __CIDR(cidr, i)		(cidr[i]) +#else +#define __CIDR(cidr, i)		(cidr) +#endif  #ifdef IP_SET_HASH_WITH_NETS_PACKED  /* When cidr is packed with nomatch, cidr - 1 is stored in the entry */ -#define CIDR(cidr)		(cidr + 1) +#define CIDR(cidr, i)		(__CIDR(cidr, i) + 1)  #else -#define CIDR(cidr)		(cidr) +#define CIDR(cidr, i)		(__CIDR(cidr, i))  #endif  #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)	\ -(unsigned long *)(((void *)(e)) + (h)->offset[IPSET_OFFSET_TIMEOUT]) -#define ext_counter(e, h)	\ -(struct ip_set_counter *)(((void *)(e)) + (h)->offset[IPSET_OFFSET_COUNTER]) -  #endif /* _IP_SET_HASH_GEN_H */  /* Family dependent templates */ @@ -194,6 +180,8 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)  #undef mtype_data_next  #undef mtype_elem +#undef mtype_ahash_destroy +#undef mtype_ext_cleanup  #undef mtype_add_cidr  #undef mtype_del_cidr  #undef mtype_ahash_memsize @@ -220,41 +208,43 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)  #undef HKEY -#define mtype_data_equal	TOKEN(MTYPE, _data_equal) +#define mtype_data_equal	IPSET_TOKEN(MTYPE, _data_equal)  #ifdef IP_SET_HASH_WITH_NETS -#define mtype_do_data_match	TOKEN(MTYPE, _do_data_match) +#define mtype_do_data_match	IPSET_TOKEN(MTYPE, _do_data_match)  #else  #define mtype_do_data_match(d)	1  #endif -#define mtype_data_set_flags	TOKEN(MTYPE, _data_set_flags) -#define mtype_data_reset_flags	TOKEN(MTYPE, _data_reset_flags) -#define mtype_data_netmask	TOKEN(MTYPE, _data_netmask) -#define mtype_data_list		TOKEN(MTYPE, _data_list) -#define mtype_data_next		TOKEN(MTYPE, _data_next) -#define mtype_elem		TOKEN(MTYPE, _elem) -#define mtype_add_cidr		TOKEN(MTYPE, _add_cidr) -#define mtype_del_cidr		TOKEN(MTYPE, _del_cidr) -#define mtype_ahash_memsize	TOKEN(MTYPE, _ahash_memsize) -#define mtype_flush		TOKEN(MTYPE, _flush) -#define mtype_destroy		TOKEN(MTYPE, _destroy) -#define mtype_gc_init		TOKEN(MTYPE, _gc_init) -#define mtype_same_set		TOKEN(MTYPE, _same_set) -#define mtype_kadt		TOKEN(MTYPE, _kadt) -#define mtype_uadt		TOKEN(MTYPE, _uadt) +#define mtype_data_set_flags	IPSET_TOKEN(MTYPE, _data_set_flags) +#define mtype_data_reset_elem	IPSET_TOKEN(MTYPE, _data_reset_elem) +#define mtype_data_reset_flags	IPSET_TOKEN(MTYPE, _data_reset_flags) +#define mtype_data_netmask	IPSET_TOKEN(MTYPE, _data_netmask) +#define mtype_data_list		IPSET_TOKEN(MTYPE, _data_list) +#define mtype_data_next		IPSET_TOKEN(MTYPE, _data_next) +#define mtype_elem		IPSET_TOKEN(MTYPE, _elem) +#define mtype_ahash_destroy	IPSET_TOKEN(MTYPE, _ahash_destroy) +#define mtype_ext_cleanup	IPSET_TOKEN(MTYPE, _ext_cleanup) +#define mtype_add_cidr		IPSET_TOKEN(MTYPE, _add_cidr) +#define mtype_del_cidr		IPSET_TOKEN(MTYPE, _del_cidr) +#define mtype_ahash_memsize	IPSET_TOKEN(MTYPE, _ahash_memsize) +#define mtype_flush		IPSET_TOKEN(MTYPE, _flush) +#define mtype_destroy		IPSET_TOKEN(MTYPE, _destroy) +#define mtype_gc_init		IPSET_TOKEN(MTYPE, _gc_init) +#define mtype_same_set		IPSET_TOKEN(MTYPE, _same_set) +#define mtype_kadt		IPSET_TOKEN(MTYPE, _kadt) +#define mtype_uadt		IPSET_TOKEN(MTYPE, _uadt)  #define mtype			MTYPE -#define mtype_elem		TOKEN(MTYPE, _elem) -#define mtype_add		TOKEN(MTYPE, _add) -#define mtype_del		TOKEN(MTYPE, _del) -#define mtype_test_cidrs	TOKEN(MTYPE, _test_cidrs) -#define mtype_test		TOKEN(MTYPE, _test) -#define mtype_expire		TOKEN(MTYPE, _expire) -#define mtype_resize		TOKEN(MTYPE, _resize) -#define mtype_head		TOKEN(MTYPE, _head) -#define mtype_list		TOKEN(MTYPE, _list) -#define mtype_gc		TOKEN(MTYPE, _gc) -#define mtype_variant		TOKEN(MTYPE, _variant) -#define mtype_data_match	TOKEN(MTYPE, _data_match) +#define mtype_add		IPSET_TOKEN(MTYPE, _add) +#define mtype_del		IPSET_TOKEN(MTYPE, _del) +#define mtype_test_cidrs	IPSET_TOKEN(MTYPE, _test_cidrs) +#define mtype_test		IPSET_TOKEN(MTYPE, _test) +#define mtype_expire		IPSET_TOKEN(MTYPE, _expire) +#define mtype_resize		IPSET_TOKEN(MTYPE, _resize) +#define mtype_head		IPSET_TOKEN(MTYPE, _head) +#define mtype_list		IPSET_TOKEN(MTYPE, _list) +#define mtype_gc		IPSET_TOKEN(MTYPE, _gc) +#define mtype_variant		IPSET_TOKEN(MTYPE, _variant) +#define mtype_data_match	IPSET_TOKEN(MTYPE, _data_match)  #ifndef HKEY_DATALEN  #define HKEY_DATALEN		sizeof(struct mtype_elem) @@ -269,13 +259,13 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)  /* The generic hash structure */  struct htype { -	struct htable *table;	/* the hash table */ +	struct htable __rcu *table; /* the hash table */  	u32 maxelem;		/* max elements in the hash */  	u32 elements;		/* current element (vs timeout) */  	u32 initval;		/* random jhash init value */ -	u32 timeout;		/* timeout value, if enabled */ -	size_t dsize;		/* data struct size */ -	size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */ +#ifdef IP_SET_HASH_WITH_MARKMASK +	u32 markmask;		/* markmask value for mark mask to store */ +#endif  	struct timer_list gc;	/* garbage collection when timeout enabled */  	struct mtype_elem next; /* temporary storage for uadd */  #ifdef IP_SET_HASH_WITH_MULTI @@ -297,49 +287,49 @@ 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, net_end = nets_length - 1;  	for (i = 0; i < nets_length; i++) { -	        if (h->nets[i].cidr != cidr) +	        if (h->nets[i].cidr[n] != cidr)  	                continue; -                if (h->nets[i].nets > 1 || i == net_end || -                    h->nets[i + 1].nets == 0) { -                        h->nets[i].nets--; +                if (h->nets[i].nets[n] > 1 || i == net_end || +                    h->nets[i + 1].nets[n] == 0) { +                        h->nets[i].nets[n]--;                          return;                  } -                for (j = i; j < net_end && 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 < net_end && 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];                  } -                h->nets[j].nets = 0; +                h->nets[j].nets[n] = 0;                  return;  	}  } @@ -347,10 +337,10 @@ mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length)  /* Calculate the actual memory size of the set data */  static size_t -mtype_ahash_memsize(const struct htype *h, u8 nets_length) +mtype_ahash_memsize(const struct htype *h, const struct htable *t, +		    u8 nets_length, size_t dsize)  {  	u32 i; -	struct htable *t = h->table;  	size_t memsize = sizeof(*h)  			 + sizeof(*t)  #ifdef IP_SET_HASH_WITH_NETS @@ -359,35 +349,70 @@ mtype_ahash_memsize(const struct htype *h, u8 nets_length)  			 + jhash_size(t->htable_bits) * sizeof(struct hbucket);  	for (i = 0; i < jhash_size(t->htable_bits); i++) -		memsize += t->bucket[i].size * h->dsize; +		memsize += t->bucket[i].size * dsize;  	return memsize;  } +/* Get the ith element from the array block n */ +#define ahash_data(n, i, dsize)	\ +	((struct mtype_elem *)((n)->value + ((i) * (dsize)))) + +static void +mtype_ext_cleanup(struct ip_set *set, struct hbucket *n) +{ +	int i; + +	for (i = 0; i < n->pos; i++) +		ip_set_ext_destroy(set, ahash_data(n, i, set->dsize)); +} +  /* Flush a hash type of set: destroy all elements */  static void  mtype_flush(struct ip_set *set)  {  	struct htype *h = set->data; -	struct htable *t = h->table; +	struct htable *t;  	struct hbucket *n;  	u32 i; +	t = rcu_dereference_bh_nfnl(h->table);  	for (i = 0; i < jhash_size(t->htable_bits); i++) {  		n = hbucket(t, i);  		if (n->size) { +			if (set->extensions & IPSET_EXT_DESTROY) +				mtype_ext_cleanup(set, n);  			n->size = n->pos = 0;  			/* FIXME: use slab cache */  			kfree(n->value);  		}  	}  #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;  } +/* Destroy the hashtable part of the set */ +static void +mtype_ahash_destroy(struct ip_set *set, struct htable *t, bool ext_destroy) +{ +	struct hbucket *n; +	u32 i; + +	for (i = 0; i < jhash_size(t->htable_bits); i++) { +		n = hbucket(t, i); +		if (n->size) { +			if (set->extensions & IPSET_EXT_DESTROY && ext_destroy) +				mtype_ext_cleanup(set, n); +			/* FIXME: use slab cache */ +			kfree(n->value); +		} +	} + +	ip_set_free(t); +} +  /* Destroy a hash type of set */  static void  mtype_destroy(struct ip_set *set) @@ -397,7 +422,7 @@ mtype_destroy(struct ip_set *set)  	if (set->extensions & IPSET_EXT_TIMEOUT)  		del_timer_sync(&h->gc); -	ahash_destroy(h->table); +	mtype_ahash_destroy(set, rcu_dereference_bh_nfnl(h->table), true);  #ifdef IP_SET_HASH_WITH_RBTREE  	rbtree_destroy(&h->rbtree);  #endif @@ -414,10 +439,10 @@ mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))  	init_timer(&h->gc);  	h->gc.data = (unsigned long) set;  	h->gc.function = gc; -	h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ; +	h->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;  	add_timer(&h->gc);  	pr_debug("gc initialized, run in every %u\n", -		 IPSET_GC_PERIOD(h->timeout)); +		 IPSET_GC_PERIOD(set->timeout));  }  static bool @@ -428,37 +453,43 @@ mtype_same_set(const struct ip_set *a, const struct ip_set *b)  	/* Resizing changes htable_bits, so we ignore it */  	return x->maxelem == y->maxelem && -	       x->timeout == y->timeout && +	       a->timeout == b->timeout &&  #ifdef IP_SET_HASH_WITH_NETMASK  	       x->netmask == y->netmask &&  #endif +#ifdef IP_SET_HASH_WITH_MARKMASK +	       x->markmask == y->markmask && +#endif  	       a->extensions == b->extensions;  } -/* Get the ith element from the array block n */ -#define ahash_data(n, i, dsize)	\ -	((struct mtype_elem *)((n)->value + ((i) * (dsize)))) -  /* Delete expired elements from the hashtable */  static void -mtype_expire(struct htype *h, u8 nets_length, size_t dsize) +mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)  { -	struct htable *t = h->table; +	struct htable *t;  	struct hbucket *n;  	struct mtype_elem *data;  	u32 i;  	int j; +#ifdef IP_SET_HASH_WITH_NETS +	u8 k; +#endif +	rcu_read_lock_bh(); +	t = rcu_dereference_bh(h->table);  	for (i = 0; i < jhash_size(t->htable_bits); i++) {  		n = hbucket(t, i);  		for (j = 0; j < n->pos; j++) {  			data = ahash_data(n, j, dsize); -			if (ip_set_timeout_expired(ext_timeout(data, h))) { +			if (ip_set_timeout_expired(ext_timeout(data, set))) {  				pr_debug("expired %u/%u\n", i, j);  #ifdef IP_SET_HASH_WITH_NETS -				mtype_del_cidr(h, CIDR(data->cidr), -					       nets_length); +				for (k = 0; k < IPSET_NET_COUNT; k++) +					mtype_del_cidr(h, CIDR(data->cidr, k), +						       nets_length, k);  #endif +				ip_set_ext_destroy(set, data);  				if (j != n->pos - 1)  					/* Not last one */  					memcpy(data, @@ -481,6 +512,7 @@ mtype_expire(struct htype *h, u8 nets_length, size_t dsize)  			n->value = tmp;  		}  	} +	rcu_read_unlock_bh();  }  static void @@ -491,10 +523,10 @@ 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(set, h, NLEN(set->family), set->dsize);  	write_unlock_bh(&set->lock); -	h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ; +	h->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;  	add_timer(&h->gc);  } @@ -505,7 +537,7 @@ static int  mtype_resize(struct ip_set *set, bool retried)  {  	struct htype *h = set->data; -	struct htable *t, *orig = h->table; +	struct htable *t, *orig = rcu_dereference_bh_nfnl(h->table);  	u8 htable_bits = orig->htable_bits;  #ifdef IP_SET_HASH_WITH_NETS  	u8 flags; @@ -520,8 +552,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, set->data, NLEN(set->family), set->dsize);  		write_unlock_bh(&set->lock);  		if (h->elements < i)  			return 0; @@ -548,25 +579,25 @@ retry:  	for (i = 0; i < jhash_size(orig->htable_bits); i++) {  		n = hbucket(orig, i);  		for (j = 0; j < n->pos; j++) { -			data = ahash_data(n, j, h->dsize); +			data = ahash_data(n, j, set->dsize);  #ifdef IP_SET_HASH_WITH_NETS  			flags = 0;  			mtype_data_reset_flags(data, &flags);  #endif  			m = hbucket(t, HKEY(data, h->initval, htable_bits)); -			ret = hbucket_elem_add(m, AHASH_MAX(h), h->dsize); +			ret = hbucket_elem_add(m, AHASH_MAX(h), set->dsize);  			if (ret < 0) {  #ifdef IP_SET_HASH_WITH_NETS  				mtype_data_reset_flags(data, &flags);  #endif  				read_unlock_bh(&set->lock); -				ahash_destroy(t); +				mtype_ahash_destroy(set, t, false);  				if (ret == -EAGAIN)  					goto retry;  				return ret;  			} -			d = ahash_data(m, m->pos++, h->dsize); -			memcpy(d, data, h->dsize); +			d = ahash_data(m, m->pos++, set->dsize); +			memcpy(d, data, set->dsize);  #ifdef IP_SET_HASH_WITH_NETS  			mtype_data_reset_flags(d, &flags);  #endif @@ -581,7 +612,7 @@ retry:  	pr_debug("set %s resized from %u (%p) to %u (%p)\n", set->name,  		 orig->htable_bits, orig, t->htable_bits, t); -	ahash_destroy(orig); +	mtype_ahash_destroy(set, orig, false);  	return 0;  } @@ -602,9 +633,21 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,  	bool flag_exist = flags & IPSET_FLAG_EXIST;  	u32 key, multi = 0; +	if (h->elements >= h->maxelem && SET_WITH_FORCEADD(set)) { +		rcu_read_lock_bh(); +		t = rcu_dereference_bh(h->table); +		key = HKEY(value, h->initval, t->htable_bits); +		n = hbucket(t,key); +		if (n->pos) { +			/* Choosing the first entry in the array to replace */ +			j = 0; +			goto reuse_slot; +		} +		rcu_read_unlock_bh(); +	}  	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(set, h, NLEN(set->family), set->dsize);  	if (h->elements >= h->maxelem) {  		if (net_ratelimit()) @@ -618,11 +661,11 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,  	key = HKEY(value, h->initval, t->htable_bits);  	n = hbucket(t, key);  	for (i = 0; i < n->pos; i++) { -		data = ahash_data(n, i, h->dsize); +		data = ahash_data(n, i, set->dsize);  		if (mtype_data_equal(data, d, &multi)) {  			if (flag_exist ||  			    (SET_WITH_TIMEOUT(set) && -			     ip_set_timeout_expired(ext_timeout(data, h)))) { +			     ip_set_timeout_expired(ext_timeout(data, set)))) {  				/* Just the extensions could be overwritten */  				j = i;  				goto reuse_slot; @@ -633,30 +676,37 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,  		}  		/* Reuse first timed out entry */  		if (SET_WITH_TIMEOUT(set) && -		    ip_set_timeout_expired(ext_timeout(data, h)) && +		    ip_set_timeout_expired(ext_timeout(data, set)) &&  		    j != AHASH_MAX(h) + 1)  			j = i;  	}  reuse_slot:  	if (j != AHASH_MAX(h) + 1) {  		/* Fill out reused slot */ -		data = ahash_data(n, j, h->dsize); +		data = ahash_data(n, j, set->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)); +		for (i = 0; i < IPSET_NET_COUNT; i++) { +			mtype_del_cidr(h, CIDR(data->cidr, i), +				       NLEN(set->family), i); +			mtype_add_cidr(h, CIDR(d->cidr, i), +				       NLEN(set->family), i); +		}  #endif +		ip_set_ext_destroy(set, data);  	} else {  		/* Use/create a new slot */  		TUNE_AHASH_MAX(h, multi); -		ret = hbucket_elem_add(n, AHASH_MAX(h), h->dsize); +		ret = hbucket_elem_add(n, AHASH_MAX(h), set->dsize);  		if (ret != 0) {  			if (ret == -EAGAIN)  				mtype_data_next(&h->next, d);  			goto out;  		} -		data = ahash_data(n, n->pos++, h->dsize); +		data = ahash_data(n, n->pos++, set->dsize);  #ifdef IP_SET_HASH_WITH_NETS -		mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family)); +		for (i = 0; i < IPSET_NET_COUNT; i++) +			mtype_add_cidr(h, CIDR(d->cidr, i), NLEN(set->family), +				       i);  #endif  		h->elements++;  	} @@ -665,9 +715,11 @@ reuse_slot:  	mtype_data_set_flags(data, flags);  #endif  	if (SET_WITH_TIMEOUT(set)) -		ip_set_timeout_set(ext_timeout(data, h), ext->timeout); +		ip_set_timeout_set(ext_timeout(data, set), ext->timeout);  	if (SET_WITH_COUNTER(set)) -		ip_set_init_counter(ext_counter(data, h), ext); +		ip_set_init_counter(ext_counter(data, set), ext); +	if (SET_WITH_COMMENT(set)) +		ip_set_init_comment(ext_comment(data, set), ext);  out:  	rcu_read_unlock_bh(); @@ -682,47 +734,60 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,  	  struct ip_set_ext *mext, u32 flags)  {  	struct htype *h = set->data; -	struct htable *t = h->table; +	struct htable *t;  	const struct mtype_elem *d = value;  	struct mtype_elem *data;  	struct hbucket *n; -	int i; +	int i, ret = -IPSET_ERR_EXIST; +#ifdef IP_SET_HASH_WITH_NETS +	u8 j; +#endif  	u32 key, multi = 0; +	rcu_read_lock_bh(); +	t = rcu_dereference_bh(h->table);  	key = HKEY(value, h->initval, t->htable_bits);  	n = hbucket(t, key);  	for (i = 0; i < n->pos; i++) { -		data = ahash_data(n, i, h->dsize); +		data = ahash_data(n, i, set->dsize);  		if (!mtype_data_equal(data, d, &multi))  			continue;  		if (SET_WITH_TIMEOUT(set) && -		    ip_set_timeout_expired(ext_timeout(data, h))) -			return -IPSET_ERR_EXIST; +		    ip_set_timeout_expired(ext_timeout(data, set))) +			goto out;  		if (i != n->pos - 1)  			/* Not last one */ -			memcpy(data, ahash_data(n, n->pos - 1, h->dsize), -			       h->dsize); +			memcpy(data, ahash_data(n, n->pos - 1, set->dsize), +			       set->dsize);  		n->pos--;  		h->elements--;  #ifdef IP_SET_HASH_WITH_NETS -		mtype_del_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family)); +		for (j = 0; j < IPSET_NET_COUNT; j++) +			mtype_del_cidr(h, CIDR(d->cidr, j), NLEN(set->family), +				       j);  #endif +		ip_set_ext_destroy(set, data);  		if (n->pos + AHASH_INIT_SIZE < n->size) {  			void *tmp = kzalloc((n->size - AHASH_INIT_SIZE) -					    * h->dsize, +					    * set->dsize,  					    GFP_ATOMIC); -			if (!tmp) -				return 0; +			if (!tmp) { +				ret = 0; +				goto out; +			}  			n->size -= AHASH_INIT_SIZE; -			memcpy(tmp, n->value, n->size * h->dsize); +			memcpy(tmp, n->value, n->size * set->dsize);  			kfree(n->value);  			n->value = tmp;  		} -		return 0; +		ret = 0; +		goto out;  	} -	return -IPSET_ERR_EXIST; +out: +	rcu_read_unlock_bh(); +	return ret;  }  static inline int @@ -730,8 +795,7 @@ mtype_data_match(struct mtype_elem *data, const struct ip_set_ext *ext,  		 struct ip_set_ext *mext, struct ip_set *set, u32 flags)  {  	if (SET_WITH_COUNTER(set)) -		ip_set_update_counter(ext_counter(data, -						  (struct htype *)(set->data)), +		ip_set_update_counter(ext_counter(data, set),  				      ext, mext, flags);  	return mtype_do_data_match(data);  } @@ -745,25 +809,38 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,  		 struct ip_set_ext *mext, u32 flags)  {  	struct htype *h = set->data; -	struct htable *t = h->table; +	struct htable *t = rcu_dereference_bh(h->table);  	struct hbucket *n;  	struct mtype_elem *data; +#if IPSET_NET_COUNT == 2 +	struct mtype_elem orig = *d; +	int i, j = 0, k; +#else  	int i, j = 0; +#endif  	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++) { +#if IPSET_NET_COUNT == 2 +		mtype_data_reset_elem(d, &orig); +		mtype_data_netmask(d, h->nets[j].cidr[0], false); +		for (k = 0; k < nets_length && h->nets[k].nets[1] && !multi; +		     k++) { +			mtype_data_netmask(d, h->nets[k].cidr[1], true); +#else +		mtype_data_netmask(d, h->nets[j].cidr[0]); +#endif  		key = HKEY(d, h->initval, t->htable_bits);  		n = hbucket(t, key);  		for (i = 0; i < n->pos; i++) { -			data = ahash_data(n, i, h->dsize); +			data = ahash_data(n, i, set->dsize);  			if (!mtype_data_equal(data, d, &multi))  				continue;  			if (SET_WITH_TIMEOUT(set)) {  				if (!ip_set_timeout_expired( -							ext_timeout(data, h))) +						ext_timeout(data, set)))  					return mtype_data_match(data, ext,  								mext, set,  								flags); @@ -774,6 +851,9 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,  				return mtype_data_match(data, ext,  							mext, set, flags);  		} +#if IPSET_NET_COUNT == 2 +		} +#endif  	}  	return 0;  } @@ -785,30 +865,41 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,  	   struct ip_set_ext *mext, u32 flags)  {  	struct htype *h = set->data; -	struct htable *t = h->table; +	struct htable *t;  	struct mtype_elem *d = value;  	struct hbucket *n;  	struct mtype_elem *data; -	int i; +	int i, ret = 0;  	u32 key, multi = 0; +	rcu_read_lock_bh(); +	t = rcu_dereference_bh(h->table);  #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)) -		return mtype_test_cidrs(set, d, ext, mext, flags); +	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; +	}  #endif  	key = HKEY(d, h->initval, t->htable_bits);  	n = hbucket(t, key);  	for (i = 0; i < n->pos; i++) { -		data = ahash_data(n, i, h->dsize); +		data = ahash_data(n, i, set->dsize);  		if (mtype_data_equal(data, d, &multi) &&  		    !(SET_WITH_TIMEOUT(set) && -		      ip_set_timeout_expired(ext_timeout(data, h)))) -			return mtype_data_match(data, ext, mext, set, flags); +		      ip_set_timeout_expired(ext_timeout(data, set)))) { +			ret = mtype_data_match(data, ext, mext, set, flags); +			goto out; +		}  	} -	return 0; +out: +	rcu_read_unlock_bh(); +	return ret;  }  /* Reply a HEADER request: fill out the header part of the set */ @@ -816,18 +907,18 @@ static int  mtype_head(struct ip_set *set, struct sk_buff *skb)  {  	const struct htype *h = set->data; +	const struct htable *t;  	struct nlattr *nested;  	size_t memsize; -	read_lock_bh(&set->lock); -	memsize = mtype_ahash_memsize(h, NETS_LENGTH(set->family)); -	read_unlock_bh(&set->lock); +	t = rcu_dereference_bh_nfnl(h->table); +	memsize = mtype_ahash_memsize(h, t, NLEN(set->family), set->dsize);  	nested = ipset_nest_start(skb, IPSET_ATTR_DATA);  	if (!nested)  		goto nla_put_failure;  	if (nla_put_net32(skb, IPSET_ATTR_HASHSIZE, -			  htonl(jhash_size(h->table->htable_bits))) || +			  htonl(jhash_size(t->htable_bits))) ||  	    nla_put_net32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem)))  		goto nla_put_failure;  #ifdef IP_SET_HASH_WITH_NETMASK @@ -835,13 +926,14 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)  	    nla_put_u8(skb, IPSET_ATTR_NETMASK, h->netmask))  		goto nla_put_failure;  #endif +#ifdef IP_SET_HASH_WITH_MARKMASK +	if (nla_put_u32(skb, IPSET_ATTR_MARKMASK, h->markmask)) +		goto nla_put_failure; +#endif  	if (nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) || -	    nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)) || -	    ((set->extensions & IPSET_EXT_TIMEOUT) && -	     nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout))) || -	    ((set->extensions & IPSET_EXT_COUNTER) && -	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, -			   htonl(IPSET_FLAG_WITH_COUNTERS)))) +	    nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize))) +		goto nla_put_failure; +	if (unlikely(ip_set_put_flags(skb, set)))  		goto nla_put_failure;  	ipset_nest_end(skb, nested); @@ -856,11 +948,11 @@ mtype_list(const struct ip_set *set,  	   struct sk_buff *skb, struct netlink_callback *cb)  {  	const struct htype *h = set->data; -	const struct htable *t = h->table; +	const struct htable *t = rcu_dereference_bh_nfnl(h->table);  	struct nlattr *atd, *nested;  	const struct hbucket *n;  	const struct mtype_elem *e; -	u32 first = cb->args[2]; +	u32 first = cb->args[IPSET_CB_ARG0];  	/* We assume that one hash bucket fills into one page */  	void *incomplete;  	int i; @@ -869,20 +961,22 @@ mtype_list(const struct ip_set *set,  	if (!atd)  		return -EMSGSIZE;  	pr_debug("list hash set %s\n", set->name); -	for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) { +	for (; cb->args[IPSET_CB_ARG0] < jhash_size(t->htable_bits); +	     cb->args[IPSET_CB_ARG0]++) {  		incomplete = skb_tail_pointer(skb); -		n = hbucket(t, cb->args[2]); -		pr_debug("cb->args[2]: %lu, t %p n %p\n", cb->args[2], t, n); +		n = hbucket(t, cb->args[IPSET_CB_ARG0]); +		pr_debug("cb->arg bucket: %lu, t %p n %p\n", +			 cb->args[IPSET_CB_ARG0], t, n);  		for (i = 0; i < n->pos; i++) { -			e = ahash_data(n, i, h->dsize); +			e = ahash_data(n, i, set->dsize);  			if (SET_WITH_TIMEOUT(set) && -			    ip_set_timeout_expired(ext_timeout(e, h))) +			    ip_set_timeout_expired(ext_timeout(e, set)))  				continue;  			pr_debug("list hash %lu hbucket %p i %u, data %p\n", -				 cb->args[2], n, i, e); +				 cb->args[IPSET_CB_ARG0], n, i, e);  			nested = ipset_nest_start(skb, IPSET_ATTR_DATA);  			if (!nested) { -				if (cb->args[2] == first) { +				if (cb->args[IPSET_CB_ARG0] == first) {  					nla_nest_cancel(skb, atd);  					return -EMSGSIZE;  				} else @@ -890,43 +984,37 @@ mtype_list(const struct ip_set *set,  			}  			if (mtype_data_list(skb, e))  				goto nla_put_failure; -			if (SET_WITH_TIMEOUT(set) && -			    nla_put_net32(skb, IPSET_ATTR_TIMEOUT, -					  htonl(ip_set_timeout_get( -						ext_timeout(e, h))))) -				goto nla_put_failure; -			if (SET_WITH_COUNTER(set) && -			    ip_set_put_counter(skb, ext_counter(e, h))) +			if (ip_set_put_extensions(skb, set, e, true))  				goto nla_put_failure;  			ipset_nest_end(skb, nested);  		}  	}  	ipset_nest_end(skb, atd);  	/* Set listing finished */ -	cb->args[2] = 0; +	cb->args[IPSET_CB_ARG0] = 0;  	return 0;  nla_put_failure:  	nlmsg_trim(skb, incomplete); -	ipset_nest_end(skb, atd); -	if (unlikely(first == cb->args[2])) { +	if (unlikely(first == cb->args[IPSET_CB_ARG0])) {  		pr_warning("Can't list set %s: one bucket does not fit into "  			   "a message. Please report it!\n", set->name); -		cb->args[2] = 0; +		cb->args[IPSET_CB_ARG0] = 0;  		return -EMSGSIZE;  	} +	ipset_nest_end(skb, atd);  	return 0;  }  static int -TOKEN(MTYPE, _kadt)(struct ip_set *set, const struct sk_buff *skb, -	      const struct xt_action_param *par, -	      enum ipset_adt adt, struct ip_set_adt_opt *opt); +IPSET_TOKEN(MTYPE, _kadt)(struct ip_set *set, const struct sk_buff *skb, +	    const struct xt_action_param *par, +	    enum ipset_adt adt, struct ip_set_adt_opt *opt);  static int -TOKEN(MTYPE, _uadt)(struct ip_set *set, struct nlattr *tb[], -	      enum ipset_adt adt, u32 *lineno, u32 flags, bool retried); +IPSET_TOKEN(MTYPE, _uadt)(struct ip_set *set, struct nlattr *tb[], +	    enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);  static const struct ip_set_type_variant mtype_variant = {  	.kadt	= mtype_kadt, @@ -946,19 +1034,27 @@ static const struct ip_set_type_variant mtype_variant = {  #ifdef IP_SET_EMIT_CREATE  static int -TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags) +IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, +			    struct nlattr *tb[], u32 flags)  {  	u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; -	u32 cadt_flags = 0; +#ifdef IP_SET_HASH_WITH_MARKMASK +	u32 markmask; +#endif  	u8 hbits;  #ifdef IP_SET_HASH_WITH_NETMASK  	u8 netmask;  #endif  	size_t hsize;  	struct HTYPE *h; +	struct htable *t;  	if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))  		return -IPSET_ERR_INVALID_FAMILY; + +#ifdef IP_SET_HASH_WITH_MARKMASK +	markmask = 0xffffffff; +#endif  #ifdef IP_SET_HASH_WITH_NETMASK  	netmask = set->family == NFPROTO_IPV4 ? 32 : 128;  	pr_debug("Create set %s with family %s\n", @@ -967,6 +1063,9 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags)  	if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||  		     !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) || +#ifdef IP_SET_HASH_WITH_MARKMASK +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_MARKMASK) || +#endif  		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||  		     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))  		return -IPSET_ERR_PROTOCOL; @@ -990,6 +1089,14 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags)  			return -IPSET_ERR_INVALID_NETMASK;  	}  #endif +#ifdef IP_SET_HASH_WITH_MARKMASK +	if (tb[IPSET_ATTR_MARKMASK]) { +		markmask = ntohl(nla_get_u32(tb[IPSET_ATTR_MARKMASK])); + +		if ((markmask > 4294967295u) || markmask == 0) +			return -IPSET_ERR_INVALID_MARKMASK; +	} +#endif  	hsize = sizeof(*h);  #ifdef IP_SET_HASH_WITH_NETS @@ -1004,8 +1111,11 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags)  #ifdef IP_SET_HASH_WITH_NETMASK  	h->netmask = netmask;  #endif +#ifdef IP_SET_HASH_WITH_MARKMASK +	h->markmask = markmask; +#endif  	get_random_bytes(&h->initval, sizeof(h->initval)); -	h->timeout = IPSET_NO_TIMEOUT; +	set->timeout = IPSET_NO_TIMEOUT;  	hbits = htable_bits(hashsize);  	hsize = htable_size(hbits); @@ -1013,91 +1123,37 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags)  		kfree(h);  		return -ENOMEM;  	} -	h->table = ip_set_alloc(hsize); -	if (!h->table) { +	t = ip_set_alloc(hsize); +	if (!t) {  		kfree(h);  		return -ENOMEM;  	} -	h->table->htable_bits = hbits; +	t->htable_bits = hbits; +	rcu_assign_pointer(h->table, t);  	set->data = h; -	if (set->family ==  NFPROTO_IPV4) -		set->variant = &TOKEN(HTYPE, 4_variant); -	else -		set->variant = &TOKEN(HTYPE, 6_variant); - -	if (tb[IPSET_ATTR_CADT_FLAGS]) -		cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); -	if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) { -		set->extensions |= IPSET_EXT_COUNTER; -		if (tb[IPSET_ATTR_TIMEOUT]) { -			h->timeout = -				ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); -			set->extensions |= IPSET_EXT_TIMEOUT; -			if (set->family == NFPROTO_IPV4) { -				h->dsize = -					sizeof(struct TOKEN(HTYPE, 4ct_elem)); -				h->offset[IPSET_OFFSET_TIMEOUT] = -					offsetof(struct TOKEN(HTYPE, 4ct_elem), -						 timeout); -				h->offset[IPSET_OFFSET_COUNTER] = -					offsetof(struct TOKEN(HTYPE, 4ct_elem), -						 counter); -				TOKEN(HTYPE, 4_gc_init)(set, -					TOKEN(HTYPE, 4_gc)); -			} else { -				h->dsize = -					sizeof(struct TOKEN(HTYPE, 6ct_elem)); -				h->offset[IPSET_OFFSET_TIMEOUT] = -					offsetof(struct TOKEN(HTYPE, 6ct_elem), -						 timeout); -				h->offset[IPSET_OFFSET_COUNTER] = -					offsetof(struct TOKEN(HTYPE, 6ct_elem), -						 counter); -				TOKEN(HTYPE, 6_gc_init)(set, -					TOKEN(HTYPE, 6_gc)); -			} -		} else { -			if (set->family == NFPROTO_IPV4) { -				h->dsize = -					sizeof(struct TOKEN(HTYPE, 4c_elem)); -				h->offset[IPSET_OFFSET_COUNTER] = -					offsetof(struct TOKEN(HTYPE, 4c_elem), -						 counter); -			} else { -				h->dsize = -					sizeof(struct TOKEN(HTYPE, 6c_elem)); -				h->offset[IPSET_OFFSET_COUNTER] = -					offsetof(struct TOKEN(HTYPE, 6c_elem), -						 counter); -			} -		} -	} else if (tb[IPSET_ATTR_TIMEOUT]) { -		h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); -		set->extensions |= IPSET_EXT_TIMEOUT; -		if (set->family == NFPROTO_IPV4) { -			h->dsize = sizeof(struct TOKEN(HTYPE, 4t_elem)); -			h->offset[IPSET_OFFSET_TIMEOUT] = -				offsetof(struct TOKEN(HTYPE, 4t_elem), -					 timeout); -			TOKEN(HTYPE, 4_gc_init)(set, TOKEN(HTYPE, 4_gc)); -		} else { -			h->dsize = sizeof(struct TOKEN(HTYPE, 6t_elem)); -			h->offset[IPSET_OFFSET_TIMEOUT] = -				offsetof(struct TOKEN(HTYPE, 6t_elem), -					 timeout); -			TOKEN(HTYPE, 6_gc_init)(set, TOKEN(HTYPE, 6_gc)); -		} +	if (set->family == NFPROTO_IPV4) { +		set->variant = &IPSET_TOKEN(HTYPE, 4_variant); +		set->dsize = ip_set_elem_len(set, tb, +				sizeof(struct IPSET_TOKEN(HTYPE, 4_elem)));  	} else { +		set->variant = &IPSET_TOKEN(HTYPE, 6_variant); +		set->dsize = ip_set_elem_len(set, tb, +				sizeof(struct IPSET_TOKEN(HTYPE, 6_elem))); +	} +	if (tb[IPSET_ATTR_TIMEOUT]) { +		set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);  		if (set->family == NFPROTO_IPV4) -			h->dsize = sizeof(struct TOKEN(HTYPE, 4_elem)); +			IPSET_TOKEN(HTYPE, 4_gc_init)(set, +				IPSET_TOKEN(HTYPE, 4_gc));  		else -			h->dsize = sizeof(struct TOKEN(HTYPE, 6_elem)); +			IPSET_TOKEN(HTYPE, 6_gc_init)(set, +				IPSET_TOKEN(HTYPE, 6_gc));  	}  	pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n", -		 set->name, jhash_size(h->table->htable_bits), -		 h->table->htable_bits, h->maxelem, set->data, h->table); +		 set->name, jhash_size(t->htable_bits), +		 t->htable_bits, h->maxelem, set->data, t);  	return 0;  } diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c index c74e6e14cd9..dd40607f878 100644 --- a/net/netfilter/ipset/ip_set_hash_ip.c +++ b/net/netfilter/ipset/ip_set_hash_ip.c @@ -23,19 +23,21 @@  #include <linux/netfilter/ipset/ip_set.h>  #include <linux/netfilter/ipset/ip_set_hash.h> -#define REVISION_MIN	0 -#define REVISION_MAX	1	/* Counters support */ +#define IPSET_TYPE_REV_MIN	0 +/*				1	   Counters support */ +/*				2	   Comments support */ +#define IPSET_TYPE_REV_MAX	3	/* Forceadd support */  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -IP_SET_MODULE_DESC("hash:ip", REVISION_MIN, REVISION_MAX); +IP_SET_MODULE_DESC("hash:ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);  MODULE_ALIAS("ip_set_hash:ip");  /* Type specific function prefix */  #define HTYPE		hash_ip  #define IP_SET_HASH_WITH_NETMASK -/* IPv4 variants */ +/* IPv4 variant */  /* Member elements */  struct hash_ip4_elem { @@ -43,22 +45,6 @@ struct hash_ip4_elem {  	__be32 ip;  }; -struct hash_ip4t_elem { -	__be32 ip; -	unsigned long timeout; -}; - -struct hash_ip4c_elem { -	__be32 ip; -	struct ip_set_counter counter; -}; - -struct hash_ip4ct_elem { -	__be32 ip; -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  /* Common functions */  static inline bool @@ -99,7 +85,7 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,  	const struct hash_ip *h = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct hash_ip4_elem e = {}; -	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	__be32 ip;  	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip); @@ -118,8 +104,8 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],  	const struct hash_ip *h = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct hash_ip4_elem e = {}; -	struct ip_set_ext ext = IP_SET_INIT_UEXT(h); -	u32 ip, ip_to, hosts; +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +	u32 ip = 0, ip_to = 0, hosts;  	int ret = 0;  	if (unlikely(!tb[IPSET_ATTR_IP] || @@ -178,29 +164,13 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],  	return ret;  } -/* IPv6 variants */ +/* IPv6 variant */  /* Member elements */  struct hash_ip6_elem {  	union nf_inet_addr ip;  }; -struct hash_ip6t_elem { -	union nf_inet_addr ip; -	unsigned long timeout; -}; - -struct hash_ip6c_elem { -	union nf_inet_addr ip; -	struct ip_set_counter counter; -}; - -struct hash_ip6ct_elem { -	union nf_inet_addr ip; -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  /* Common functions */  static inline bool @@ -253,7 +223,7 @@ hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,  	const struct hash_ip *h = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct hash_ip6_elem e = {}; -	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);  	hash_ip6_netmask(&e.ip, h->netmask); @@ -270,7 +240,7 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],  	const struct hash_ip *h = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct hash_ip6_elem e = {}; -	struct ip_set_ext ext = IP_SET_INIT_UEXT(h); +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);  	int ret;  	if (unlikely(!tb[IPSET_ATTR_IP] || @@ -304,8 +274,8 @@ static struct ip_set_type hash_ip_type __read_mostly = {  	.features	= IPSET_TYPE_IP,  	.dimension	= IPSET_DIM_ONE,  	.family		= NFPROTO_UNSPEC, -	.revision_min	= REVISION_MIN, -	.revision_max	= REVISION_MAX, +	.revision_min	= IPSET_TYPE_REV_MIN, +	.revision_max	= IPSET_TYPE_REV_MAX,  	.create		= hash_ip_create,  	.create_policy	= {  		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 }, @@ -324,6 +294,7 @@ static struct ip_set_type hash_ip_type __read_mostly = {  		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },  		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },  		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 }, +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING },  	},  	.me		= THIS_MODULE,  }; diff --git a/net/netfilter/ipset/ip_set_hash_ipmark.c b/net/netfilter/ipset/ip_set_hash_ipmark.c new file mode 100644 index 00000000000..4eff0a29725 --- /dev/null +++ b/net/netfilter/ipset/ip_set_hash_ipmark.c @@ -0,0 +1,321 @@ +/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> + * Copyright (C) 2013 Smoothwall Ltd. <vytas.dauksa@smoothwall.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* Kernel module implementing an IP set type: the hash:ip,mark type */ + +#include <linux/jhash.h> +#include <linux/module.h> +#include <linux/ip.h> +#include <linux/skbuff.h> +#include <linux/errno.h> +#include <linux/random.h> +#include <net/ip.h> +#include <net/ipv6.h> +#include <net/netlink.h> +#include <net/tcp.h> + +#include <linux/netfilter.h> +#include <linux/netfilter/ipset/pfxlen.h> +#include <linux/netfilter/ipset/ip_set.h> +#include <linux/netfilter/ipset/ip_set_hash.h> + +#define IPSET_TYPE_REV_MIN	0 +#define IPSET_TYPE_REV_MAX	1	/* Forceadd support */ + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vytas Dauksa <vytas.dauksa@smoothwall.net>"); +IP_SET_MODULE_DESC("hash:ip,mark", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); +MODULE_ALIAS("ip_set_hash:ip,mark"); + +/* Type specific function prefix */ +#define HTYPE		hash_ipmark +#define IP_SET_HASH_WITH_MARKMASK + +/* IPv4 variant */ + +/* Member elements */ +struct hash_ipmark4_elem { +	__be32 ip; +	__u32 mark; +}; + +/* Common functions */ + +static inline bool +hash_ipmark4_data_equal(const struct hash_ipmark4_elem *ip1, +			const struct hash_ipmark4_elem *ip2, +			u32 *multi) +{ +	return ip1->ip == ip2->ip && +	       ip1->mark == ip2->mark; +} + +static bool +hash_ipmark4_data_list(struct sk_buff *skb, +		       const struct hash_ipmark4_elem *data) +{ +	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) || +	    nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark))) +		goto nla_put_failure; +	return 0; + +nla_put_failure: +	return 1; +} + +static inline void +hash_ipmark4_data_next(struct hash_ipmark4_elem *next, +		       const struct hash_ipmark4_elem *d) +{ +	next->ip = d->ip; +} + +#define MTYPE           hash_ipmark4 +#define PF              4 +#define HOST_MASK       32 +#define HKEY_DATALEN	sizeof(struct hash_ipmark4_elem) +#include "ip_set_hash_gen.h" + +static int +hash_ipmark4_kadt(struct ip_set *set, const struct sk_buff *skb, +		  const struct xt_action_param *par, +		  enum ipset_adt adt, struct ip_set_adt_opt *opt) +{ +	const struct hash_ipmark *h = set->data; +	ipset_adtfn adtfn = set->variant->adt[adt]; +	struct hash_ipmark4_elem e = { }; +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +	e.mark = skb->mark; +	e.mark &= h->markmask; + +	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip); +	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); +} + +static int +hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], +		  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) +{ +	const struct hash_ipmark *h = set->data; +	ipset_adtfn adtfn = set->variant->adt[adt]; +	struct hash_ipmark4_elem e = { }; +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +	u32 ip, ip_to = 0; +	int ret; + +	if (unlikely(!tb[IPSET_ATTR_IP] || +		     !ip_set_attr_netorder(tb, IPSET_ATTR_MARK) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) +		return -IPSET_ERR_PROTOCOL; + +	if (tb[IPSET_ATTR_LINENO]) +		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); + +	ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip) || +	      ip_set_get_extensions(set, tb, &ext); +	if (ret) +		return ret; + +	e.mark = ntohl(nla_get_u32(tb[IPSET_ATTR_MARK])); +	e.mark &= h->markmask; + +	if (adt == IPSET_TEST || +	    !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR])) { +		ret = adtfn(set, &e, &ext, &ext, flags); +		return ip_set_eexist(ret, flags) ? 0 : ret; +	} + +	ip_to = ip = ntohl(e.ip); +	if (tb[IPSET_ATTR_IP_TO]) { +		ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); +		if (ret) +			return ret; +		if (ip > ip_to) +			swap(ip, ip_to); +	} else if (tb[IPSET_ATTR_CIDR]) { +		u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); + +		if (!cidr || cidr > 32) +			return -IPSET_ERR_INVALID_CIDR; +		ip_set_mask_from_to(ip, ip_to, cidr); +	} + +	if (retried) +		ip = ntohl(h->next.ip); +	for (; !before(ip_to, ip); ip++) { +		e.ip = htonl(ip); +		ret = adtfn(set, &e, &ext, &ext, flags); + +		if (ret && !ip_set_eexist(ret, flags)) +			return ret; +		else +			ret = 0; +	} +	return ret; +} + +/* IPv6 variant */ + +struct hash_ipmark6_elem { +	union nf_inet_addr ip; +	__u32 mark; +}; + +/* Common functions */ + +static inline bool +hash_ipmark6_data_equal(const struct hash_ipmark6_elem *ip1, +			const struct hash_ipmark6_elem *ip2, +			u32 *multi) +{ +	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) && +	       ip1->mark == ip2->mark; +} + +static bool +hash_ipmark6_data_list(struct sk_buff *skb, +		       const struct hash_ipmark6_elem *data) +{ +	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) || +	    nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark))) +		goto nla_put_failure; +	return 0; + +nla_put_failure: +	return 1; +} + +static inline void +hash_ipmark6_data_next(struct hash_ipmark4_elem *next, +		       const struct hash_ipmark6_elem *d) +{ +} + +#undef MTYPE +#undef PF +#undef HOST_MASK +#undef HKEY_DATALEN + +#define MTYPE		hash_ipmark6 +#define PF		6 +#define HOST_MASK	128 +#define HKEY_DATALEN	sizeof(struct hash_ipmark6_elem) +#define	IP_SET_EMIT_CREATE +#include "ip_set_hash_gen.h" + + +static int +hash_ipmark6_kadt(struct ip_set *set, const struct sk_buff *skb, +		  const struct xt_action_param *par, +		  enum ipset_adt adt, struct ip_set_adt_opt *opt) +{ +	const struct hash_ipmark *h = set->data; +	ipset_adtfn adtfn = set->variant->adt[adt]; +	struct hash_ipmark6_elem e = { }; +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +	e.mark = skb->mark; +	e.mark &= h->markmask; + +	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); +	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); +} + +static int +hash_ipmark6_uadt(struct ip_set *set, struct nlattr *tb[], +		  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) +{ +	const struct hash_ipmark *h = set->data; +	ipset_adtfn adtfn = set->variant->adt[adt]; +	struct hash_ipmark6_elem e = { }; +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +	int ret; + +	if (unlikely(!tb[IPSET_ATTR_IP] || +		     !ip_set_attr_netorder(tb, IPSET_ATTR_MARK) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || +		     tb[IPSET_ATTR_IP_TO] || +		     tb[IPSET_ATTR_CIDR])) +		return -IPSET_ERR_PROTOCOL; + +	if (tb[IPSET_ATTR_LINENO]) +		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); + +	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) || +	      ip_set_get_extensions(set, tb, &ext); +	if (ret) +		return ret; + +	e.mark = ntohl(nla_get_u32(tb[IPSET_ATTR_MARK])); +	e.mark &= h->markmask; + +	if (adt == IPSET_TEST) { +		ret = adtfn(set, &e, &ext, &ext, flags); +		return ip_set_eexist(ret, flags) ? 0 : ret; +	} + +	ret = adtfn(set, &e, &ext, &ext, flags); +	if (ret && !ip_set_eexist(ret, flags)) +		return ret; +	else +		ret = 0; + +	return ret; +} + +static struct ip_set_type hash_ipmark_type __read_mostly = { +	.name		= "hash:ip,mark", +	.protocol	= IPSET_PROTOCOL, +	.features	= IPSET_TYPE_IP | IPSET_TYPE_MARK, +	.dimension	= IPSET_DIM_TWO, +	.family		= NFPROTO_UNSPEC, +	.revision_min	= IPSET_TYPE_REV_MIN, +	.revision_max	= IPSET_TYPE_REV_MAX, +	.create		= hash_ipmark_create, +	.create_policy	= { +		[IPSET_ATTR_MARKMASK]	= { .type = NLA_U32 }, +		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 }, +		[IPSET_ATTR_MAXELEM]	= { .type = NLA_U32 }, +		[IPSET_ATTR_PROBES]	= { .type = NLA_U8 }, +		[IPSET_ATTR_RESIZE]	= { .type = NLA_U8  }, +		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 }, +		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 }, +	}, +	.adt_policy	= { +		[IPSET_ATTR_IP]		= { .type = NLA_NESTED }, +		[IPSET_ATTR_IP_TO]	= { .type = NLA_NESTED }, +		[IPSET_ATTR_MARK]	= { .type = NLA_U32 }, +		[IPSET_ATTR_CIDR]	= { .type = NLA_U8 }, +		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 }, +		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 }, +		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 }, +		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 }, +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING }, +	}, +	.me		= THIS_MODULE, +}; + +static int __init +hash_ipmark_init(void) +{ +	return ip_set_type_register(&hash_ipmark_type); +} + +static void __exit +hash_ipmark_fini(void) +{ +	ip_set_type_unregister(&hash_ipmark_type); +} + +module_init(hash_ipmark_init); +module_exit(hash_ipmark_fini); diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c index 7a2d2bd98d0..7597b82a8b0 100644 --- a/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/net/netfilter/ipset/ip_set_hash_ipport.c @@ -24,19 +24,21 @@  #include <linux/netfilter/ipset/ip_set_getport.h>  #include <linux/netfilter/ipset/ip_set_hash.h> -#define REVISION_MIN	0 -/*			1    SCTP and UDPLITE support added */ -#define REVISION_MAX	2 /* Counters support added */ +#define IPSET_TYPE_REV_MIN	0 +/*				1    SCTP and UDPLITE support added */ +/*				2    Counters support added */ +/*				3    Comments support added */ +#define IPSET_TYPE_REV_MAX	4 /* Forceadd support added */  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -IP_SET_MODULE_DESC("hash:ip,port", REVISION_MIN, REVISION_MAX); +IP_SET_MODULE_DESC("hash:ip,port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);  MODULE_ALIAS("ip_set_hash:ip,port");  /* Type specific function prefix */  #define HTYPE		hash_ipport -/* IPv4 variants */ +/* IPv4 variant */  /* Member elements */  struct hash_ipport4_elem { @@ -46,31 +48,6 @@ struct hash_ipport4_elem {  	u8 padding;  }; -struct hash_ipport4t_elem { -	__be32 ip; -	__be16 port; -	u8 proto; -	u8 padding; -	unsigned long timeout; -}; - -struct hash_ipport4c_elem { -	__be32 ip; -	__be16 port; -	u8 proto; -	u8 padding; -	struct ip_set_counter counter; -}; - -struct hash_ipport4ct_elem { -	__be32 ip; -	__be16 port; -	u8 proto; -	u8 padding; -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  /* Common functions */  static inline bool @@ -116,10 +93,9 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,  		  const struct xt_action_param *par,  		  enum ipset_adt adt, struct ip_set_adt_opt *opt)  { -	const struct hash_ipport *h = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct hash_ipport4_elem e = { }; -	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,  				 &e.port, &e.proto)) @@ -136,8 +112,8 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],  	const struct hash_ipport *h = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct hash_ipport4_elem e = { }; -	struct ip_set_ext ext = IP_SET_INIT_UEXT(h); -	u32 ip, ip_to, p = 0, port, port_to; +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +	u32 ip, ip_to = 0, p = 0, port, port_to;  	bool with_ports = false;  	int ret; @@ -222,7 +198,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],  	return ret;  } -/* IPv6 variants */ +/* IPv6 variant */  struct hash_ipport6_elem {  	union nf_inet_addr ip; @@ -231,31 +207,6 @@ struct hash_ipport6_elem {  	u8 padding;  }; -struct hash_ipport6t_elem { -	union nf_inet_addr ip; -	__be16 port; -	u8 proto; -	u8 padding; -	unsigned long timeout; -}; - -struct hash_ipport6c_elem { -	union nf_inet_addr ip; -	__be16 port; -	u8 proto; -	u8 padding; -	struct ip_set_counter counter; -}; - -struct hash_ipport6ct_elem { -	union nf_inet_addr ip; -	__be16 port; -	u8 proto; -	u8 padding; -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  /* Common functions */  static inline bool @@ -306,10 +257,9 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,  		  const struct xt_action_param *par,  		  enum ipset_adt adt, struct ip_set_adt_opt *opt)  { -	const struct hash_ipport *h = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct hash_ipport6_elem e = { }; -	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,  				 &e.port, &e.proto)) @@ -326,7 +276,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],  	const struct hash_ipport *h = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct hash_ipport6_elem e = { }; -	struct ip_set_ext ext = IP_SET_INIT_UEXT(h); +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);  	u32 port, port_to;  	bool with_ports = false;  	int ret; @@ -396,8 +346,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = {  	.features	= IPSET_TYPE_IP | IPSET_TYPE_PORT,  	.dimension	= IPSET_DIM_TWO,  	.family		= NFPROTO_UNSPEC, -	.revision_min	= REVISION_MIN, -	.revision_max	= REVISION_MAX, +	.revision_min	= IPSET_TYPE_REV_MIN, +	.revision_max	= IPSET_TYPE_REV_MAX,  	.create		= hash_ipport_create,  	.create_policy	= {  		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 }, @@ -419,6 +369,7 @@ static struct ip_set_type hash_ipport_type __read_mostly = {  		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },  		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },  		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 }, +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING },  	},  	.me		= THIS_MODULE,  }; diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c index 34e8a1acce4..672655ffd57 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/net/netfilter/ipset/ip_set_hash_ipportip.c @@ -24,19 +24,21 @@  #include <linux/netfilter/ipset/ip_set_getport.h>  #include <linux/netfilter/ipset/ip_set_hash.h> -#define REVISION_MIN	0 -/*			1    SCTP and UDPLITE support added */ -#define REVISION_MAX	2 /* Counters support added */ +#define IPSET_TYPE_REV_MIN	0 +/*				1    SCTP and UDPLITE support added */ +/*				2    Counters support added */ +/*				3    Comments support added */ +#define IPSET_TYPE_REV_MAX	4 /* Forceadd support added */  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -IP_SET_MODULE_DESC("hash:ip,port,ip", REVISION_MIN, REVISION_MAX); +IP_SET_MODULE_DESC("hash:ip,port,ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);  MODULE_ALIAS("ip_set_hash:ip,port,ip");  /* Type specific function prefix */  #define HTYPE		hash_ipportip -/* IPv4 variants */ +/* IPv4 variant */  /* Member elements  */  struct hash_ipportip4_elem { @@ -47,34 +49,6 @@ struct hash_ipportip4_elem {  	u8 padding;  }; -struct hash_ipportip4t_elem { -	__be32 ip; -	__be32 ip2; -	__be16 port; -	u8 proto; -	u8 padding; -	unsigned long timeout; -}; - -struct hash_ipportip4c_elem { -	__be32 ip; -	__be32 ip2; -	__be16 port; -	u8 proto; -	u8 padding; -	struct ip_set_counter counter; -}; - -struct hash_ipportip4ct_elem { -	__be32 ip; -	__be32 ip2; -	__be16 port; -	u8 proto; -	u8 padding; -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  static inline bool  hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,  			  const struct hash_ipportip4_elem *ip2, @@ -120,10 +94,9 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,  		    const struct xt_action_param *par,  		    enum ipset_adt adt, struct ip_set_adt_opt *opt)  { -	const struct hash_ipportip *h = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct hash_ipportip4_elem e = { }; -	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,  				 &e.port, &e.proto)) @@ -141,8 +114,8 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],  	const struct hash_ipportip *h = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct hash_ipportip4_elem e = { }; -	struct ip_set_ext ext = IP_SET_INIT_UEXT(h); -	u32 ip, ip_to, p = 0, port, port_to; +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +	u32 ip, ip_to = 0, p = 0, port, port_to;  	bool with_ports = false;  	int ret; @@ -231,7 +204,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],  	return ret;  } -/* IPv6 variants */ +/* IPv6 variant */  struct hash_ipportip6_elem {  	union nf_inet_addr ip; @@ -241,34 +214,6 @@ struct hash_ipportip6_elem {  	u8 padding;  }; -struct hash_ipportip6t_elem { -	union nf_inet_addr ip; -	union nf_inet_addr ip2; -	__be16 port; -	u8 proto; -	u8 padding; -	unsigned long timeout; -}; - -struct hash_ipportip6c_elem { -	union nf_inet_addr ip; -	union nf_inet_addr ip2; -	__be16 port; -	u8 proto; -	u8 padding; -	struct ip_set_counter counter; -}; - -struct hash_ipportip6ct_elem { -	union nf_inet_addr ip; -	union nf_inet_addr ip2; -	__be16 port; -	u8 proto; -	u8 padding; -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  /* Common functions */  static inline bool @@ -319,10 +264,9 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,  		    const struct xt_action_param *par,  		    enum ipset_adt adt, struct ip_set_adt_opt *opt)  { -	const struct hash_ipportip *h = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct hash_ipportip6_elem e = { }; -	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,  				 &e.port, &e.proto)) @@ -340,7 +284,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],  	const struct hash_ipportip *h = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct hash_ipportip6_elem e = { }; -	struct ip_set_ext ext = IP_SET_INIT_UEXT(h); +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);  	u32 port, port_to;  	bool with_ports = false;  	int ret; @@ -414,8 +358,8 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {  	.features	= IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,  	.dimension	= IPSET_DIM_THREE,  	.family		= NFPROTO_UNSPEC, -	.revision_min	= REVISION_MIN, -	.revision_max	= REVISION_MAX, +	.revision_min	= IPSET_TYPE_REV_MIN, +	.revision_max	= IPSET_TYPE_REV_MAX,  	.create		= hash_ipportip_create,  	.create_policy	= {  		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 }, @@ -437,6 +381,7 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {  		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },  		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },  		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 }, +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING },  	},  	.me		= THIS_MODULE,  }; diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index f15f3e28b9c..7308d84f927 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c @@ -24,15 +24,17 @@  #include <linux/netfilter/ipset/ip_set_getport.h>  #include <linux/netfilter/ipset/ip_set_hash.h> -#define REVISION_MIN	0 -/*			1    SCTP and UDPLITE support added */ -/*			2    Range as input support for IPv4 added */ -/*			3    nomatch flag support added */ -#define REVISION_MAX	4 /* Counters support added */ +#define IPSET_TYPE_REV_MIN	0 +/*				1    SCTP and UDPLITE support added */ +/*				2    Range as input support for IPv4 added */ +/*				3    nomatch flag support added */ +/*				4    Counters support added */ +/*				5    Comments support added */ +#define IPSET_TYPE_REV_MAX	6 /* Forceadd support added */  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -IP_SET_MODULE_DESC("hash:ip,port,net", REVISION_MIN, REVISION_MAX); +IP_SET_MODULE_DESC("hash:ip,port,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);  MODULE_ALIAS("ip_set_hash:ip,port,net");  /* Type specific function prefix */ @@ -46,7 +48,7 @@ MODULE_ALIAS("ip_set_hash:ip,port,net");  #define IP_SET_HASH_WITH_PROTO  #define IP_SET_HASH_WITH_NETS -/* IPv4 variants */ +/* IPv4 variant */  /* Member elements */  struct hash_ipportnet4_elem { @@ -58,37 +60,6 @@ struct hash_ipportnet4_elem {  	u8 proto;  }; -struct hash_ipportnet4t_elem { -	__be32 ip; -	__be32 ip2; -	__be16 port; -	u8 cidr:7; -	u8 nomatch:1; -	u8 proto; -	unsigned long timeout; -}; - -struct hash_ipportnet4c_elem { -	__be32 ip; -	__be32 ip2; -	__be16 port; -	u8 cidr:7; -	u8 nomatch:1; -	u8 proto; -	struct ip_set_counter counter; -}; - -struct hash_ipportnet4ct_elem { -	__be32 ip; -	__be32 ip2; -	__be16 port; -	u8 cidr:7; -	u8 nomatch:1; -	u8 proto; -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  /* Common functions */  static inline bool @@ -170,9 +141,9 @@ 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); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	if (adt == IPSET_TEST)  		e.cidr = HOST_MASK - 1; @@ -195,9 +166,9 @@ 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 ip_set_ext ext = IP_SET_INIT_UEXT(h); -	u32 ip, ip_to, p = 0, port, port_to; -	u32 ip2_from, ip2_to, ip2_last, ip2; +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +	u32 ip = 0, ip_to = 0, p = 0, port, port_to; +	u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;  	bool with_ports = false;  	u8 cidr;  	int ret; @@ -272,7 +243,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],  		if (ip > ip_to)  			swap(ip, ip_to);  	} else if (tb[IPSET_ATTR_CIDR]) { -		u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); +		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);  		if (!cidr || cidr > 32)  			return -IPSET_ERR_INVALID_CIDR; @@ -306,9 +277,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],  						       : port;  		for (; p <= port_to; p++) {  			e.port = htons(p); -			ip2 = retried -			      && ip == ntohl(h->next.ip) -			      && p == ntohs(h->next.port) +			ip2 = retried && +			      ip == ntohl(h->next.ip) && +			      p == ntohs(h->next.port)  				? ntohl(h->next.ip2) : ip2_from;  			while (!after(ip2, ip2_to)) {  				e.ip2 = htonl(ip2); @@ -328,7 +299,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],  	return ret;  } -/* IPv6 variants */ +/* IPv6 variant */  struct hash_ipportnet6_elem {  	union nf_inet_addr ip; @@ -339,37 +310,6 @@ struct hash_ipportnet6_elem {  	u8 proto;  }; -struct hash_ipportnet6t_elem { -	union nf_inet_addr ip; -	union nf_inet_addr ip2; -	__be16 port; -	u8 cidr:7; -	u8 nomatch:1; -	u8 proto; -	unsigned long timeout; -}; - -struct hash_ipportnet6c_elem { -	union nf_inet_addr ip; -	union nf_inet_addr ip2; -	__be16 port; -	u8 cidr:7; -	u8 nomatch:1; -	u8 proto; -	struct ip_set_counter counter; -}; - -struct hash_ipportnet6ct_elem { -	union nf_inet_addr ip; -	union nf_inet_addr ip2; -	__be16 port; -	u8 cidr:7; -	u8 nomatch:1; -	u8 proto; -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  /* Common functions */  static inline bool @@ -454,9 +394,9 @@ 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); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	if (adt == IPSET_TEST)  		e.cidr = HOST_MASK - 1; @@ -479,7 +419,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 ip_set_ext ext = IP_SET_INIT_UEXT(h); +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);  	u32 port, port_to;  	bool with_ports = false;  	u8 cidr; @@ -574,8 +514,8 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {  			  IPSET_TYPE_NOMATCH,  	.dimension	= IPSET_DIM_THREE,  	.family		= NFPROTO_UNSPEC, -	.revision_min	= REVISION_MIN, -	.revision_max	= REVISION_MAX, +	.revision_min	= IPSET_TYPE_REV_MIN, +	.revision_max	= IPSET_TYPE_REV_MAX,  	.create		= hash_ipportnet_create,  	.create_policy	= {  		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 }, @@ -600,6 +540,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {  		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },  		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },  		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 }, +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING },  	},  	.me		= THIS_MODULE,  }; diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c index 223e9f546d0..4c7d495783a 100644 --- a/net/netfilter/ipset/ip_set_hash_net.c +++ b/net/netfilter/ipset/ip_set_hash_net.c @@ -22,21 +22,23 @@  #include <linux/netfilter/ipset/ip_set.h>  #include <linux/netfilter/ipset/ip_set_hash.h> -#define REVISION_MIN	0 -/*			1    Range as input support for IPv4 added */ -/*			2    nomatch flag support added */ -#define REVISION_MAX	3 /* Counters support added */ +#define IPSET_TYPE_REV_MIN	0 +/*				1    Range as input support for IPv4 added */ +/*				2    nomatch flag support added */ +/*				3    Counters support added */ +/*				4    Comments support added */ +#define IPSET_TYPE_REV_MAX	5 /* Forceadd support added */  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -IP_SET_MODULE_DESC("hash:net", REVISION_MIN, REVISION_MAX); +IP_SET_MODULE_DESC("hash:net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);  MODULE_ALIAS("ip_set_hash:net");  /* Type specific function prefix */  #define HTYPE		hash_net  #define IP_SET_HASH_WITH_NETS -/* IPv4 variants */ +/* IPv4 variant */  /* Member elements  */  struct hash_net4_elem { @@ -46,31 +48,6 @@ struct hash_net4_elem {  	u8 cidr;  }; -struct hash_net4t_elem { -	__be32 ip; -	u16 padding0; -	u8 nomatch; -	u8 cidr; -	unsigned long timeout; -}; - -struct hash_net4c_elem { -	__be32 ip; -	u16 padding0; -	u8 nomatch; -	u8 cidr; -	struct ip_set_counter counter; -}; - -struct hash_net4ct_elem { -	__be32 ip; -	u16 padding0; -	u8 nomatch; -	u8 cidr; -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  /* Common functions */  static inline bool @@ -143,9 +120,9 @@ 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); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	if (e.cidr == 0)  		return -EINVAL; @@ -165,8 +142,8 @@ 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 ip_set_ext ext = IP_SET_INIT_UEXT(h); -	u32 ip = 0, ip_to, last; +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +	u32 ip = 0, ip_to = 0, last;  	int ret;  	if (unlikely(!tb[IPSET_ATTR_IP] || @@ -228,7 +205,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],  	return ret;  } -/* IPv6 variants */ +/* IPv6 variant */  struct hash_net6_elem {  	union nf_inet_addr ip; @@ -237,31 +214,6 @@ struct hash_net6_elem {  	u8 cidr;  }; -struct hash_net6t_elem { -	union nf_inet_addr ip; -	u16 padding0; -	u8 nomatch; -	u8 cidr; -	unsigned long timeout; -}; - -struct hash_net6c_elem { -	union nf_inet_addr ip; -	u16 padding0; -	u8 nomatch; -	u8 cidr; -	struct ip_set_counter counter; -}; - -struct hash_net6ct_elem { -	union nf_inet_addr ip; -	u16 padding0; -	u8 nomatch; -	u8 cidr; -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  /* Common functions */  static inline bool @@ -338,9 +290,9 @@ 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); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	if (e.cidr == 0)  		return -EINVAL; @@ -357,10 +309,9 @@ static int  hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],  	       enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)  { -	const struct hash_net *h = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct hash_net6_elem e = { .cidr = HOST_MASK }; -	struct ip_set_ext ext = IP_SET_INIT_UEXT(h); +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);  	int ret;  	if (unlikely(!tb[IPSET_ATTR_IP] || @@ -406,8 +357,8 @@ static struct ip_set_type hash_net_type __read_mostly = {  	.features	= IPSET_TYPE_IP | IPSET_TYPE_NOMATCH,  	.dimension	= IPSET_DIM_ONE,  	.family		= NFPROTO_UNSPEC, -	.revision_min	= REVISION_MIN, -	.revision_max	= REVISION_MAX, +	.revision_min	= IPSET_TYPE_REV_MIN, +	.revision_max	= IPSET_TYPE_REV_MAX,  	.create		= hash_net_create,  	.create_policy	= {  		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 }, @@ -425,6 +376,7 @@ static struct ip_set_type hash_net_type __read_mostly = {  		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },  		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },  		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 }, +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING },  	},  	.me		= THIS_MODULE,  }; diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c index 7d798d5d5cd..db2606805b3 100644 --- a/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/net/netfilter/ipset/ip_set_hash_netiface.c @@ -23,14 +23,16 @@  #include <linux/netfilter/ipset/ip_set.h>  #include <linux/netfilter/ipset/ip_set_hash.h> -#define REVISION_MIN	0 -/*			1    nomatch flag support added */ -/*			2    /0 support added */ -#define REVISION_MAX	3 /* Counters support added */ +#define IPSET_TYPE_REV_MIN	0 +/*				1    nomatch flag support added */ +/*				2    /0 support added */ +/*				3    Counters support added */ +/*				4    Comments support added */ +#define IPSET_TYPE_REV_MAX	5 /* Forceadd support added */  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -IP_SET_MODULE_DESC("hash:net,iface", REVISION_MIN, REVISION_MAX); +IP_SET_MODULE_DESC("hash:net,iface", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);  MODULE_ALIAS("ip_set_hash:net,iface");  /* Interface name rbtree */ @@ -45,31 +47,12 @@ struct iface_node {  static void  rbtree_destroy(struct rb_root *root)  { -	struct rb_node *p, *n = root->rb_node; -	struct iface_node *node; - -	/* Non-recursive destroy, like in ext3 */ -	while (n) { -		if (n->rb_left) { -			n = n->rb_left; -			continue; -		} -		if (n->rb_right) { -			n = n->rb_right; -			continue; -		} -		p = rb_parent(n); -		node = rb_entry(n, struct iface_node, node); -		if (!p) -			*root = RB_ROOT; -		else if (p->rb_left == n) -			p->rb_left = NULL; -		else if (p->rb_right == n) -			p->rb_right = NULL; +	struct iface_node *node, *next; +	rbtree_postorder_for_each_entry_safe(node, next, root, node)  		kfree(node); -		n = p; -	} + +	*root = RB_ROOT;  }  static int @@ -134,7 +117,7 @@ iface_add(struct rb_root *root, const char **iface)  #define STREQ(a, b)	(strcmp(a, b) == 0) -/* IPv4 variants */ +/* IPv4 variant */  struct hash_netiface4_elem_hashed {  	__be32 ip; @@ -144,7 +127,7 @@ struct hash_netiface4_elem_hashed {  	u8 elem;  }; -/* Member elements without timeout */ +/* Member elements */  struct hash_netiface4_elem {  	__be32 ip;  	u8 physdev; @@ -154,37 +137,6 @@ struct hash_netiface4_elem {  	const char *iface;  }; -struct hash_netiface4t_elem { -	__be32 ip; -	u8 physdev; -	u8 cidr; -	u8 nomatch; -	u8 elem; -	const char *iface; -	unsigned long timeout; -}; - -struct hash_netiface4c_elem { -	__be32 ip; -	u8 physdev; -	u8 cidr; -	u8 nomatch; -	u8 elem; -	const char *iface; -	struct ip_set_counter counter; -}; - -struct hash_netiface4ct_elem { -	__be32 ip; -	u8 physdev; -	u8 cidr; -	u8 nomatch; -	u8 elem; -	const char *iface; -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  /* Common functions */  static inline bool @@ -265,10 +217,10 @@ 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); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	int ret;  	if (e.cidr == 0) @@ -319,8 +271,8 @@ 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 ip_set_ext ext = IP_SET_INIT_UEXT(h); -	u32 ip = 0, ip_to, last; +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +	u32 ip = 0, ip_to = 0, last;  	char iface[IFNAMSIZ];  	int ret; @@ -399,7 +351,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],  	return ret;  } -/* IPv6 variants */ +/* IPv6 variant */  struct hash_netiface6_elem_hashed {  	union nf_inet_addr ip; @@ -418,37 +370,6 @@ struct hash_netiface6_elem {  	const char *iface;  }; -struct hash_netiface6t_elem { -	union nf_inet_addr ip; -	u8 physdev; -	u8 cidr; -	u8 nomatch; -	u8 elem; -	const char *iface; -	unsigned long timeout; -}; - -struct hash_netiface6c_elem { -	union nf_inet_addr ip; -	u8 physdev; -	u8 cidr; -	u8 nomatch; -	u8 elem; -	const char *iface; -	struct ip_set_counter counter; -}; - -struct hash_netiface6ct_elem { -	union nf_inet_addr ip; -	u8 physdev; -	u8 cidr; -	u8 nomatch; -	u8 elem; -	const char *iface; -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  /* Common functions */  static inline bool @@ -534,10 +455,10 @@ 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); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	int ret;  	if (e.cidr == 0) @@ -584,7 +505,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 ip_set_ext ext = IP_SET_INIT_UEXT(h); +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);  	char iface[IFNAMSIZ];  	int ret; @@ -645,8 +566,8 @@ static struct ip_set_type hash_netiface_type __read_mostly = {  			  IPSET_TYPE_NOMATCH,  	.dimension	= IPSET_DIM_TWO,  	.family		= NFPROTO_UNSPEC, -	.revision_min	= REVISION_MIN, -	.revision_max	= REVISION_MAX, +	.revision_min	= IPSET_TYPE_REV_MIN, +	.revision_max	= IPSET_TYPE_REV_MAX,  	.create		= hash_netiface_create,  	.create_policy	= {  		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 }, @@ -668,6 +589,7 @@ static struct ip_set_type hash_netiface_type __read_mostly = {  		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },  		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },  		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 }, +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING },  	},  	.me		= THIS_MODULE,  }; diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c new file mode 100644 index 00000000000..3e99987e4bf --- /dev/null +++ b/net/netfilter/ipset/ip_set_hash_netnet.c @@ -0,0 +1,481 @@ +/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> + * Copyright (C) 2013 Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* Kernel module implementing an IP set type: the hash:net type */ + +#include <linux/jhash.h> +#include <linux/module.h> +#include <linux/ip.h> +#include <linux/skbuff.h> +#include <linux/errno.h> +#include <linux/random.h> +#include <net/ip.h> +#include <net/ipv6.h> +#include <net/netlink.h> + +#include <linux/netfilter.h> +#include <linux/netfilter/ipset/pfxlen.h> +#include <linux/netfilter/ipset/ip_set.h> +#include <linux/netfilter/ipset/ip_set_hash.h> + +#define IPSET_TYPE_REV_MIN	0 +#define IPSET_TYPE_REV_MAX	1	/* Forceadd support added */ + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>"); +IP_SET_MODULE_DESC("hash:net,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); +MODULE_ALIAS("ip_set_hash:net,net"); + +/* Type specific function prefix */ +#define HTYPE		hash_netnet +#define IP_SET_HASH_WITH_NETS +#define IPSET_NET_COUNT 2 + +/* IPv4 variants */ + +/* Member elements  */ +struct hash_netnet4_elem { +	union { +		__be32 ip[2]; +		__be64 ipcmp; +	}; +	u8 nomatch; +	union { +		u8 cidr[2]; +		u16 ccmp; +	}; +}; + +/* Common functions */ + +static inline bool +hash_netnet4_data_equal(const struct hash_netnet4_elem *ip1, +		     const struct hash_netnet4_elem *ip2, +		     u32 *multi) +{ +	return ip1->ipcmp == ip2->ipcmp && +	       ip1->ccmp == ip2->ccmp; +} + +static inline int +hash_netnet4_do_data_match(const struct hash_netnet4_elem *elem) +{ +	return elem->nomatch ? -ENOTEMPTY : 1; +} + +static inline void +hash_netnet4_data_set_flags(struct hash_netnet4_elem *elem, u32 flags) +{ +	elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH; +} + +static inline void +hash_netnet4_data_reset_flags(struct hash_netnet4_elem *elem, u8 *flags) +{ +	swap(*flags, elem->nomatch); +} + +static inline void +hash_netnet4_data_reset_elem(struct hash_netnet4_elem *elem, +			  struct hash_netnet4_elem *orig) +{ +	elem->ip[1] = orig->ip[1]; +} + +static inline void +hash_netnet4_data_netmask(struct hash_netnet4_elem *elem, u8 cidr, bool inner) +{ +	if (inner) { +		elem->ip[1] &= ip_set_netmask(cidr); +		elem->cidr[1] = cidr; +	} else { +		elem->ip[0] &= ip_set_netmask(cidr); +		elem->cidr[0] = cidr; +	} +} + +static bool +hash_netnet4_data_list(struct sk_buff *skb, +		    const struct hash_netnet4_elem *data) +{ +	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; + +	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) || +	    nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip[1]) || +	    nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) || +	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) || +	    (flags && +	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)))) +		goto nla_put_failure; +	return false; + +nla_put_failure: +	return true; +} + +static inline void +hash_netnet4_data_next(struct hash_netnet4_elem *next, +		    const struct hash_netnet4_elem *d) +{ +	next->ipcmp = d->ipcmp; +} + +#define MTYPE		hash_netnet4 +#define PF		4 +#define HOST_MASK	32 +#include "ip_set_hash_gen.h" + +static int +hash_netnet4_kadt(struct ip_set *set, const struct sk_buff *skb, +	       const struct xt_action_param *par, +	       enum ipset_adt adt, struct ip_set_adt_opt *opt) +{ +	const struct hash_netnet *h = set->data; +	ipset_adtfn adtfn = set->variant->adt[adt]; +	struct hash_netnet4_elem e = { }; +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +	e.cidr[0] = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK); +	e.cidr[1] = IP_SET_INIT_CIDR(h->nets[0].cidr[1], HOST_MASK); +	if (adt == IPSET_TEST) +		e.ccmp = (HOST_MASK << (sizeof(e.cidr[0]) * 8)) | HOST_MASK; + +	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]); +	ip4addrptr(skb, opt->flags & IPSET_DIM_TWO_SRC, &e.ip[1]); +	e.ip[0] &= ip_set_netmask(e.cidr[0]); +	e.ip[1] &= ip_set_netmask(e.cidr[1]); + +	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); +} + +static int +hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], +	       enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) +{ +	const struct hash_netnet *h = set->data; +	ipset_adtfn adtfn = set->variant->adt[adt]; +	struct hash_netnet4_elem e = { }; +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +	u32 ip = 0, ip_to = 0, last; +	u32 ip2 = 0, ip2_from = 0, ip2_to = 0, last2; +	u8 cidr, cidr2; +	int ret; + +	e.cidr[0] = e.cidr[1] = HOST_MASK; +	if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) +		return -IPSET_ERR_PROTOCOL; + +	if (tb[IPSET_ATTR_LINENO]) +		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); + +	ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) || +	      ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from) || +	      ip_set_get_extensions(set, tb, &ext); +	if (ret) +		return ret; + +	if (tb[IPSET_ATTR_CIDR]) { +		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); +		if (!cidr || cidr > HOST_MASK) +			return -IPSET_ERR_INVALID_CIDR; +		e.cidr[0] = cidr; +	} + +	if (tb[IPSET_ATTR_CIDR2]) { +		cidr2 = nla_get_u8(tb[IPSET_ATTR_CIDR2]); +		if (!cidr2 || cidr2 > HOST_MASK) +			return -IPSET_ERR_INVALID_CIDR; +		e.cidr[1] = cidr2; +	} + +	if (tb[IPSET_ATTR_CADT_FLAGS]) { +		u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); +		if (cadt_flags & IPSET_FLAG_NOMATCH) +			flags |= (IPSET_FLAG_NOMATCH << 16); +	} + +	if (adt == IPSET_TEST || !(tb[IPSET_ATTR_IP_TO] && +				   tb[IPSET_ATTR_IP2_TO])) { +		e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0])); +		e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[1])); +		ret = adtfn(set, &e, &ext, &ext, flags); +		return ip_set_enomatch(ret, flags, adt, set) ? -ret : +		       ip_set_eexist(ret, flags) ? 0 : ret; +	} + +	ip_to = ip; +	if (tb[IPSET_ATTR_IP_TO]) { +		ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); +		if (ret) +			return ret; +		if (ip_to < ip) +			swap(ip, ip_to); +		if (ip + UINT_MAX == ip_to) +			return -IPSET_ERR_HASH_RANGE; +	} + +	ip2_to = ip2_from; +	if (tb[IPSET_ATTR_IP2_TO]) { +		ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to); +		if (ret) +			return ret; +		if (ip2_to < ip2_from) +			swap(ip2_from, ip2_to); +		if (ip2_from + UINT_MAX == ip2_to) +			return -IPSET_ERR_HASH_RANGE; + +	} + +	if (retried) +		ip = ntohl(h->next.ip[0]); + +	while (!after(ip, ip_to)) { +		e.ip[0] = htonl(ip); +		last = ip_set_range_to_cidr(ip, ip_to, &cidr); +		e.cidr[0] = cidr; +		ip2 = (retried && +		       ip == ntohl(h->next.ip[0])) ? ntohl(h->next.ip[1]) +						   : ip2_from; +		while (!after(ip2, ip2_to)) { +			e.ip[1] = htonl(ip2); +			last2 = ip_set_range_to_cidr(ip2, ip2_to, &cidr2); +			e.cidr[1] = cidr2; +			ret = adtfn(set, &e, &ext, &ext, flags); +			if (ret && !ip_set_eexist(ret, flags)) +				return ret; +			else +				ret = 0; +			ip2 = last2 + 1; +		} +		ip = last + 1; +	} +	return ret; +} + +/* IPv6 variants */ + +struct hash_netnet6_elem { +	union nf_inet_addr ip[2]; +	u8 nomatch; +	union { +		u8 cidr[2]; +		u16 ccmp; +	}; +}; + +/* Common functions */ + +static inline bool +hash_netnet6_data_equal(const struct hash_netnet6_elem *ip1, +		     const struct hash_netnet6_elem *ip2, +		     u32 *multi) +{ +	return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) && +	       ipv6_addr_equal(&ip1->ip[1].in6, &ip2->ip[1].in6) && +	       ip1->ccmp == ip2->ccmp; +} + +static inline int +hash_netnet6_do_data_match(const struct hash_netnet6_elem *elem) +{ +	return elem->nomatch ? -ENOTEMPTY : 1; +} + +static inline void +hash_netnet6_data_set_flags(struct hash_netnet6_elem *elem, u32 flags) +{ +	elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH; +} + +static inline void +hash_netnet6_data_reset_flags(struct hash_netnet6_elem *elem, u8 *flags) +{ +	swap(*flags, elem->nomatch); +} + +static inline void +hash_netnet6_data_reset_elem(struct hash_netnet6_elem *elem, +			  struct hash_netnet6_elem *orig) +{ +	elem->ip[1] = orig->ip[1]; +} + +static inline void +hash_netnet6_data_netmask(struct hash_netnet6_elem *elem, u8 cidr, bool inner) +{ +	if (inner) { +		ip6_netmask(&elem->ip[1], cidr); +		elem->cidr[1] = cidr; +	} else { +		ip6_netmask(&elem->ip[0], cidr); +		elem->cidr[0] = cidr; +	} +} + +static bool +hash_netnet6_data_list(struct sk_buff *skb, +		    const struct hash_netnet6_elem *data) +{ +	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; + +	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_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) || +	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) || +	    (flags && +	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)))) +		goto nla_put_failure; +	return false; + +nla_put_failure: +	return true; +} + +static inline void +hash_netnet6_data_next(struct hash_netnet4_elem *next, +		    const struct hash_netnet6_elem *d) +{ +} + +#undef MTYPE +#undef PF +#undef HOST_MASK + +#define MTYPE		hash_netnet6 +#define PF		6 +#define HOST_MASK	128 +#define IP_SET_EMIT_CREATE +#include "ip_set_hash_gen.h" + +static int +hash_netnet6_kadt(struct ip_set *set, const struct sk_buff *skb, +	       const struct xt_action_param *par, +	       enum ipset_adt adt, struct ip_set_adt_opt *opt) +{ +	const struct hash_netnet *h = set->data; +	ipset_adtfn adtfn = set->variant->adt[adt]; +	struct hash_netnet6_elem e = { }; +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +	e.cidr[0] = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK); +	e.cidr[1] = IP_SET_INIT_CIDR(h->nets[0].cidr[1], HOST_MASK); +	if (adt == IPSET_TEST) +		e.ccmp = (HOST_MASK << (sizeof(u8)*8)) | HOST_MASK; + +	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6); +	ip6addrptr(skb, opt->flags & IPSET_DIM_TWO_SRC, &e.ip[1].in6); +	ip6_netmask(&e.ip[0], e.cidr[0]); +	ip6_netmask(&e.ip[1], e.cidr[1]); + +	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); +} + +static int +hash_netnet6_uadt(struct ip_set *set, struct nlattr *tb[], +	       enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) +{ +	ipset_adtfn adtfn = set->variant->adt[adt]; +	struct hash_netnet6_elem e = { }; +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +	int ret; + +	e.cidr[0] = e.cidr[1] = HOST_MASK; +	if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) +		return -IPSET_ERR_PROTOCOL; +	if (unlikely(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_IP2_TO])) +		return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; + +	if (tb[IPSET_ATTR_LINENO]) +		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); + +	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) || +	      ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip[1]) || +	      ip_set_get_extensions(set, tb, &ext); +	if (ret) +		return ret; + +	if (tb[IPSET_ATTR_CIDR]) +		e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]); + +	if (tb[IPSET_ATTR_CIDR2]) +		e.cidr[1] = nla_get_u8(tb[IPSET_ATTR_CIDR2]); + +	if (!e.cidr[0] || e.cidr[0] > HOST_MASK || !e.cidr[1] || +	    e.cidr[1] > HOST_MASK) +		return -IPSET_ERR_INVALID_CIDR; + +	ip6_netmask(&e.ip[0], e.cidr[0]); +	ip6_netmask(&e.ip[1], e.cidr[1]); + +	if (tb[IPSET_ATTR_CADT_FLAGS]) { +		u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); +		if (cadt_flags & IPSET_FLAG_NOMATCH) +			flags |= (IPSET_FLAG_NOMATCH << 16); +	} + +	ret = adtfn(set, &e, &ext, &ext, flags); + +	return ip_set_enomatch(ret, flags, adt, set) ? -ret : +	       ip_set_eexist(ret, flags) ? 0 : ret; +} + +static struct ip_set_type hash_netnet_type __read_mostly = { +	.name		= "hash:net,net", +	.protocol	= IPSET_PROTOCOL, +	.features	= IPSET_TYPE_IP | IPSET_TYPE_IP2 | IPSET_TYPE_NOMATCH, +	.dimension	= IPSET_DIM_TWO, +	.family		= NFPROTO_UNSPEC, +	.revision_min	= IPSET_TYPE_REV_MIN, +	.revision_max	= IPSET_TYPE_REV_MAX, +	.create		= hash_netnet_create, +	.create_policy	= { +		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 }, +		[IPSET_ATTR_MAXELEM]	= { .type = NLA_U32 }, +		[IPSET_ATTR_PROBES]	= { .type = NLA_U8 }, +		[IPSET_ATTR_RESIZE]	= { .type = NLA_U8  }, +		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 }, +		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 }, +	}, +	.adt_policy	= { +		[IPSET_ATTR_IP]		= { .type = NLA_NESTED }, +		[IPSET_ATTR_IP_TO]	= { .type = NLA_NESTED }, +		[IPSET_ATTR_IP2]	= { .type = NLA_NESTED }, +		[IPSET_ATTR_IP2_TO]	= { .type = NLA_NESTED }, +		[IPSET_ATTR_CIDR]	= { .type = NLA_U8 }, +		[IPSET_ATTR_CIDR2]	= { .type = NLA_U8 }, +		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 }, +		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 }, +		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 }, +		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 }, +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING }, +	}, +	.me		= THIS_MODULE, +}; + +static int __init +hash_netnet_init(void) +{ +	return ip_set_type_register(&hash_netnet_type); +} + +static void __exit +hash_netnet_fini(void) +{ +	ip_set_type_unregister(&hash_netnet_type); +} + +module_init(hash_netnet_init); +module_exit(hash_netnet_fini); diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c index 09d6690bee6..1c645fbd09c 100644 --- a/net/netfilter/ipset/ip_set_hash_netport.c +++ b/net/netfilter/ipset/ip_set_hash_netport.c @@ -23,15 +23,17 @@  #include <linux/netfilter/ipset/ip_set_getport.h>  #include <linux/netfilter/ipset/ip_set_hash.h> -#define REVISION_MIN	0 -/*			1    SCTP and UDPLITE support added */ -/*			2    Range as input support for IPv4 added */ -/*			3    nomatch flag support added */ -#define REVISION_MAX	4 /* Counters support added */ +#define IPSET_TYPE_REV_MIN	0 +/*				1    SCTP and UDPLITE support added */ +/*				2    Range as input support for IPv4 added */ +/*				3    nomatch flag support added */ +/*				4    Counters support added */ +/*				5    Comments support added */ +#define IPSET_TYPE_REV_MAX	6 /* Forceadd support added */  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -IP_SET_MODULE_DESC("hash:net,port", REVISION_MIN, REVISION_MAX); +IP_SET_MODULE_DESC("hash:net,port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);  MODULE_ALIAS("ip_set_hash:net,port");  /* Type specific function prefix */ @@ -45,7 +47,7 @@ MODULE_ALIAS("ip_set_hash:net,port");   */  #define IP_SET_HASH_WITH_NETS_PACKED -/* IPv4 variants */ +/* IPv4 variant */  /* Member elements */  struct hash_netport4_elem { @@ -56,34 +58,6 @@ struct hash_netport4_elem {  	u8 nomatch:1;  }; -struct hash_netport4t_elem { -	__be32 ip; -	__be16 port; -	u8 proto; -	u8 cidr:7; -	u8 nomatch:1; -	unsigned long timeout; -}; - -struct hash_netport4c_elem { -	__be32 ip; -	__be16 port; -	u8 proto; -	u8 cidr:7; -	u8 nomatch:1; -	struct ip_set_counter counter; -}; - -struct hash_netport4ct_elem { -	__be32 ip; -	__be16 port; -	u8 proto; -	u8 cidr:7; -	u8 nomatch:1; -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  /* Common functions */  static inline bool @@ -162,9 +136,9 @@ 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); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	if (adt == IPSET_TEST)  		e.cidr = HOST_MASK - 1; @@ -186,8 +160,8 @@ 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 ip_set_ext ext = IP_SET_INIT_UEXT(h); -	u32 port, port_to, p = 0, ip = 0, ip_to, last; +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +	u32 port, port_to, p = 0, ip = 0, ip_to = 0, last;  	bool with_ports = false;  	u8 cidr;  	int ret; @@ -287,7 +261,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],  	return ret;  } -/* IPv6 variants */ +/* IPv6 variant */  struct hash_netport6_elem {  	union nf_inet_addr ip; @@ -297,34 +271,6 @@ struct hash_netport6_elem {  	u8 nomatch:1;  }; -struct hash_netport6t_elem { -	union nf_inet_addr ip; -	__be16 port; -	u8 proto; -	u8 cidr:7; -	u8 nomatch:1; -	unsigned long timeout; -}; - -struct hash_netport6c_elem { -	union nf_inet_addr ip; -	__be16 port; -	u8 proto; -	u8 cidr:7; -	u8 nomatch:1; -	struct ip_set_counter counter; -}; - -struct hash_netport6ct_elem { -	union nf_inet_addr ip; -	__be16 port; -	u8 proto; -	u8 cidr:7; -	u8 nomatch:1; -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  /* Common functions */  static inline bool @@ -407,9 +353,9 @@ 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); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	if (adt == IPSET_TEST)  		e.cidr = HOST_MASK - 1; @@ -431,7 +377,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 ip_set_ext ext = IP_SET_INIT_UEXT(h); +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);  	u32 port, port_to;  	bool with_ports = false;  	u8 cidr; @@ -518,8 +464,8 @@ static struct ip_set_type hash_netport_type __read_mostly = {  	.features	= IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_NOMATCH,  	.dimension	= IPSET_DIM_TWO,  	.family		= NFPROTO_UNSPEC, -	.revision_min	= REVISION_MIN, -	.revision_max	= REVISION_MAX, +	.revision_min	= IPSET_TYPE_REV_MIN, +	.revision_max	= IPSET_TYPE_REV_MAX,  	.create		= hash_netport_create,  	.create_policy	= {  		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 }, @@ -542,6 +488,7 @@ static struct ip_set_type hash_netport_type __read_mostly = {  		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },  		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },  		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 }, +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING },  	},  	.me		= THIS_MODULE,  }; diff --git a/net/netfilter/ipset/ip_set_hash_netportnet.c b/net/netfilter/ipset/ip_set_hash_netportnet.c new file mode 100644 index 00000000000..c0d2ba73f8b --- /dev/null +++ b/net/netfilter/ipset/ip_set_hash_netportnet.c @@ -0,0 +1,587 @@ +/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* Kernel module implementing an IP set type: the hash:ip,port,net type */ + +#include <linux/jhash.h> +#include <linux/module.h> +#include <linux/ip.h> +#include <linux/skbuff.h> +#include <linux/errno.h> +#include <linux/random.h> +#include <net/ip.h> +#include <net/ipv6.h> +#include <net/netlink.h> +#include <net/tcp.h> + +#include <linux/netfilter.h> +#include <linux/netfilter/ipset/pfxlen.h> +#include <linux/netfilter/ipset/ip_set.h> +#include <linux/netfilter/ipset/ip_set_getport.h> +#include <linux/netfilter/ipset/ip_set_hash.h> + +#define IPSET_TYPE_REV_MIN	0 +/*				0    Comments support added */ +#define IPSET_TYPE_REV_MAX	1 /* Forceadd support added */ + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>"); +IP_SET_MODULE_DESC("hash:net,port,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); +MODULE_ALIAS("ip_set_hash:net,port,net"); + +/* Type specific function prefix */ +#define HTYPE		hash_netportnet +#define IP_SET_HASH_WITH_PROTO +#define IP_SET_HASH_WITH_NETS +#define IPSET_NET_COUNT 2 + +/* IPv4 variant */ + +/* Member elements */ +struct hash_netportnet4_elem { +	union { +		__be32 ip[2]; +		__be64 ipcmp; +	}; +	__be16 port; +	union { +		u8 cidr[2]; +		u16 ccmp; +	}; +	u8 nomatch:1; +	u8 proto; +}; + +/* Common functions */ + +static inline bool +hash_netportnet4_data_equal(const struct hash_netportnet4_elem *ip1, +			   const struct hash_netportnet4_elem *ip2, +			   u32 *multi) +{ +	return ip1->ipcmp == ip2->ipcmp && +	       ip1->ccmp == ip2->ccmp && +	       ip1->port == ip2->port && +	       ip1->proto == ip2->proto; +} + +static inline int +hash_netportnet4_do_data_match(const struct hash_netportnet4_elem *elem) +{ +	return elem->nomatch ? -ENOTEMPTY : 1; +} + +static inline void +hash_netportnet4_data_set_flags(struct hash_netportnet4_elem *elem, u32 flags) +{ +	elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH); +} + +static inline void +hash_netportnet4_data_reset_flags(struct hash_netportnet4_elem *elem, u8 *flags) +{ +	swap(*flags, elem->nomatch); +} + +static inline void +hash_netportnet4_data_reset_elem(struct hash_netportnet4_elem *elem, +				struct hash_netportnet4_elem *orig) +{ +	elem->ip[1] = orig->ip[1]; +} + +static inline void +hash_netportnet4_data_netmask(struct hash_netportnet4_elem *elem, +			      u8 cidr, bool inner) +{ +	if (inner) { +		elem->ip[1] &= ip_set_netmask(cidr); +		elem->cidr[1] = cidr; +	} else { +		elem->ip[0] &= ip_set_netmask(cidr); +		elem->cidr[0] = cidr; +	} +} + +static bool +hash_netportnet4_data_list(struct sk_buff *skb, +			  const struct hash_netportnet4_elem *data) +{ +	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; + +	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_CIDR, data->cidr[0]) || +	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) || +	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) || +	    (flags && +	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)))) +		goto nla_put_failure; +	return 0; + +nla_put_failure: +	return 1; +} + +static inline void +hash_netportnet4_data_next(struct hash_netportnet4_elem *next, +			  const struct hash_netportnet4_elem *d) +{ +	next->ipcmp = d->ipcmp; +	next->port = d->port; +} + +#define MTYPE		hash_netportnet4 +#define PF		4 +#define HOST_MASK	32 +#include "ip_set_hash_gen.h" + +static int +hash_netportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, +		     const struct xt_action_param *par, +		     enum ipset_adt adt, struct ip_set_adt_opt *opt) +{ +	const struct hash_netportnet *h = set->data; +	ipset_adtfn adtfn = set->variant->adt[adt]; +	struct hash_netportnet4_elem e = { }; +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +	e.cidr[0] = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK); +	e.cidr[1] = IP_SET_INIT_CIDR(h->nets[0].cidr[1], HOST_MASK); +	if (adt == IPSET_TEST) +		e.ccmp = (HOST_MASK << (sizeof(e.cidr[0]) * 8)) | HOST_MASK; + +	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[0]); +	ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip[1]); +	e.ip[0] &= ip_set_netmask(e.cidr[0]); +	e.ip[1] &= ip_set_netmask(e.cidr[1]); + +	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); +} + +static int +hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], +		     enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) +{ +	const struct hash_netportnet *h = set->data; +	ipset_adtfn adtfn = set->variant->adt[adt]; +	struct hash_netportnet4_elem e = { }; +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +	u32 ip = 0, ip_to = 0, ip_last, p = 0, port, port_to; +	u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2; +	bool with_ports = false; +	u8 cidr, cidr2; +	int ret; + +	e.cidr[0] = e.cidr[1] = HOST_MASK; +	if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || +		     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) +		return -IPSET_ERR_PROTOCOL; + +	if (tb[IPSET_ATTR_LINENO]) +		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); + +	ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) || +	      ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from) || +	      ip_set_get_extensions(set, tb, &ext); +	if (ret) +		return ret; + +	if (tb[IPSET_ATTR_CIDR]) { +		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); +		if (!cidr || cidr > HOST_MASK) +			return -IPSET_ERR_INVALID_CIDR; +		e.cidr[0] = cidr; +	} + +	if (tb[IPSET_ATTR_CIDR2]) { +		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); +		if (!cidr || cidr > HOST_MASK) +			return -IPSET_ERR_INVALID_CIDR; +		e.cidr[1] = cidr; +	} + +	if (tb[IPSET_ATTR_PORT]) +		e.port = nla_get_be16(tb[IPSET_ATTR_PORT]); +	else +		return -IPSET_ERR_PROTOCOL; + +	if (tb[IPSET_ATTR_PROTO]) { +		e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); +		with_ports = ip_set_proto_with_ports(e.proto); + +		if (e.proto == 0) +			return -IPSET_ERR_INVALID_PROTO; +	} else +		return -IPSET_ERR_MISSING_PROTO; + +	if (!(with_ports || e.proto == IPPROTO_ICMP)) +		e.port = 0; + +	if (tb[IPSET_ATTR_CADT_FLAGS]) { +		u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); +		if (cadt_flags & IPSET_FLAG_NOMATCH) +			flags |= (IPSET_FLAG_NOMATCH << 16); +	} + +	with_ports = with_ports && tb[IPSET_ATTR_PORT_TO]; +	if (adt == IPSET_TEST || +	    !(tb[IPSET_ATTR_IP_TO] || with_ports || tb[IPSET_ATTR_IP2_TO])) { +		e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0])); +		e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[1])); +		ret = adtfn(set, &e, &ext, &ext, flags); +		return ip_set_enomatch(ret, flags, adt, set) ? -ret : +		       ip_set_eexist(ret, flags) ? 0 : ret; +	} + +	ip_to = ip; +	if (tb[IPSET_ATTR_IP_TO]) { +		ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); +		if (ret) +			return ret; +		if (ip > ip_to) +			swap(ip, ip_to); +		if (unlikely(ip + UINT_MAX == ip_to)) +			return -IPSET_ERR_HASH_RANGE; +	} + +	port_to = port = ntohs(e.port); +	if (tb[IPSET_ATTR_PORT_TO]) { +		port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); +		if (port > port_to) +			swap(port, port_to); +	} + +	ip2_to = ip2_from; +	if (tb[IPSET_ATTR_IP2_TO]) { +		ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to); +		if (ret) +			return ret; +		if (ip2_from > ip2_to) +			swap(ip2_from, ip2_to); +		if (unlikely(ip2_from + UINT_MAX == ip2_to)) +			return -IPSET_ERR_HASH_RANGE; +	} + +	if (retried) +		ip = ntohl(h->next.ip[0]); + +	while (!after(ip, ip_to)) { +		e.ip[0] = htonl(ip); +		ip_last = ip_set_range_to_cidr(ip, ip_to, &cidr); +		e.cidr[0] = cidr; +		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[0]) && +			       p == ntohs(h->next.port)) ? ntohl(h->next.ip[1]) +							 : ip2_from; +			while (!after(ip2, ip2_to)) { +				e.ip[1] = htonl(ip2); +				ip2_last = ip_set_range_to_cidr(ip2, ip2_to, +								&cidr2); +				e.cidr[1] = cidr2; +				ret = adtfn(set, &e, &ext, &ext, flags); +				if (ret && !ip_set_eexist(ret, flags)) +					return ret; +				else +					ret = 0; +				ip2 = ip2_last + 1; +			} +		} +		ip = ip_last + 1; +	} +	return ret; +} + +/* IPv6 variant */ + +struct hash_netportnet6_elem { +	union nf_inet_addr ip[2]; +	__be16 port; +	union { +		u8 cidr[2]; +		u16 ccmp; +	}; +	u8 nomatch:1; +	u8 proto; +}; + +/* Common functions */ + +static inline bool +hash_netportnet6_data_equal(const struct hash_netportnet6_elem *ip1, +			   const struct hash_netportnet6_elem *ip2, +			   u32 *multi) +{ +	return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) && +	       ipv6_addr_equal(&ip1->ip[1].in6, &ip2->ip[1].in6) && +	       ip1->ccmp == ip2->ccmp && +	       ip1->port == ip2->port && +	       ip1->proto == ip2->proto; +} + +static inline int +hash_netportnet6_do_data_match(const struct hash_netportnet6_elem *elem) +{ +	return elem->nomatch ? -ENOTEMPTY : 1; +} + +static inline void +hash_netportnet6_data_set_flags(struct hash_netportnet6_elem *elem, u32 flags) +{ +	elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH); +} + +static inline void +hash_netportnet6_data_reset_flags(struct hash_netportnet6_elem *elem, u8 *flags) +{ +	swap(*flags, elem->nomatch); +} + +static inline void +hash_netportnet6_data_reset_elem(struct hash_netportnet6_elem *elem, +				struct hash_netportnet6_elem *orig) +{ +	elem->ip[1] = orig->ip[1]; +} + +static inline void +hash_netportnet6_data_netmask(struct hash_netportnet6_elem *elem, +			      u8 cidr, bool inner) +{ +	if (inner) { +		ip6_netmask(&elem->ip[1], cidr); +		elem->cidr[1] = cidr; +	} else { +		ip6_netmask(&elem->ip[0], cidr); +		elem->cidr[0] = cidr; +	} +} + +static bool +hash_netportnet6_data_list(struct sk_buff *skb, +			  const struct hash_netportnet6_elem *data) +{ +	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; + +	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_CIDR, data->cidr[0]) || +	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) || +	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) || +	    (flags && +	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)))) +		goto nla_put_failure; +	return 0; + +nla_put_failure: +	return 1; +} + +static inline void +hash_netportnet6_data_next(struct hash_netportnet4_elem *next, +			  const struct hash_netportnet6_elem *d) +{ +	next->port = d->port; +} + +#undef MTYPE +#undef PF +#undef HOST_MASK + +#define MTYPE		hash_netportnet6 +#define PF		6 +#define HOST_MASK	128 +#define IP_SET_EMIT_CREATE +#include "ip_set_hash_gen.h" + +static int +hash_netportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, +		     const struct xt_action_param *par, +		     enum ipset_adt adt, struct ip_set_adt_opt *opt) +{ +	const struct hash_netportnet *h = set->data; +	ipset_adtfn adtfn = set->variant->adt[adt]; +	struct hash_netportnet6_elem e = { }; +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); + +	e.cidr[0] = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK); +	e.cidr[1] = IP_SET_INIT_CIDR(h->nets[0].cidr[1], HOST_MASK); +	if (adt == IPSET_TEST) +		e.ccmp = (HOST_MASK << (sizeof(u8) * 8)) | HOST_MASK; + +	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[0].in6); +	ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip[1].in6); +	ip6_netmask(&e.ip[0], e.cidr[0]); +	ip6_netmask(&e.ip[1], e.cidr[1]); + +	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); +} + +static int +hash_netportnet6_uadt(struct ip_set *set, struct nlattr *tb[], +		     enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) +{ +	const struct hash_netportnet *h = set->data; +	ipset_adtfn adtfn = set->variant->adt[adt]; +	struct hash_netportnet6_elem e = { }; +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +	u32 port, port_to; +	bool with_ports = false; +	int ret; + +	e.cidr[0] = e.cidr[1] = HOST_MASK; +	if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || +		     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || +		     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) +		return -IPSET_ERR_PROTOCOL; +	if (unlikely(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_IP2_TO])) +		return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; + +	if (tb[IPSET_ATTR_LINENO]) +		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); + +	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) || +	      ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip[1]) || +	      ip_set_get_extensions(set, tb, &ext); +	if (ret) +		return ret; + +	if (tb[IPSET_ATTR_CIDR]) +		e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]); + +	if (tb[IPSET_ATTR_CIDR2]) +		e.cidr[1] = nla_get_u8(tb[IPSET_ATTR_CIDR2]); + +	if (unlikely(!e.cidr[0] || e.cidr[0] > HOST_MASK || !e.cidr[1] || +		     e.cidr[1] > HOST_MASK)) +		return -IPSET_ERR_INVALID_CIDR; + +	ip6_netmask(&e.ip[0], e.cidr[0]); +	ip6_netmask(&e.ip[1], e.cidr[1]); + +	if (tb[IPSET_ATTR_PORT]) +		e.port = nla_get_be16(tb[IPSET_ATTR_PORT]); +	else +		return -IPSET_ERR_PROTOCOL; + +	if (tb[IPSET_ATTR_PROTO]) { +		e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); +		with_ports = ip_set_proto_with_ports(e.proto); + +		if (e.proto == 0) +			return -IPSET_ERR_INVALID_PROTO; +	} else +		return -IPSET_ERR_MISSING_PROTO; + +	if (!(with_ports || e.proto == IPPROTO_ICMPV6)) +		e.port = 0; + +	if (tb[IPSET_ATTR_CADT_FLAGS]) { +		u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); +		if (cadt_flags & IPSET_FLAG_NOMATCH) +			flags |= (IPSET_FLAG_NOMATCH << 16); +	} + +	if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { +		ret = adtfn(set, &e, &ext, &ext, flags); +		return ip_set_enomatch(ret, flags, adt, set) ? -ret : +		       ip_set_eexist(ret, flags) ? 0 : ret; +	} + +	port = ntohs(e.port); +	port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); +	if (port > port_to) +		swap(port, port_to); + +	if (retried) +		port = ntohs(h->next.port); +	for (; port <= port_to; port++) { +		e.port = htons(port); +		ret = adtfn(set, &e, &ext, &ext, flags); + +		if (ret && !ip_set_eexist(ret, flags)) +			return ret; +		else +			ret = 0; +	} +	return ret; +} + +static struct ip_set_type hash_netportnet_type __read_mostly = { +	.name		= "hash:net,port,net", +	.protocol	= IPSET_PROTOCOL, +	.features	= IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2 | +			  IPSET_TYPE_NOMATCH, +	.dimension	= IPSET_DIM_THREE, +	.family		= NFPROTO_UNSPEC, +	.revision_min	= IPSET_TYPE_REV_MIN, +	.revision_max	= IPSET_TYPE_REV_MAX, +	.create		= hash_netportnet_create, +	.create_policy	= { +		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 }, +		[IPSET_ATTR_MAXELEM]	= { .type = NLA_U32 }, +		[IPSET_ATTR_PROBES]	= { .type = NLA_U8 }, +		[IPSET_ATTR_RESIZE]	= { .type = NLA_U8  }, +		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 }, +		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 }, +	}, +	.adt_policy	= { +		[IPSET_ATTR_IP]		= { .type = NLA_NESTED }, +		[IPSET_ATTR_IP_TO]	= { .type = NLA_NESTED }, +		[IPSET_ATTR_IP2]	= { .type = NLA_NESTED }, +		[IPSET_ATTR_IP2_TO]	= { .type = NLA_NESTED }, +		[IPSET_ATTR_PORT]	= { .type = NLA_U16 }, +		[IPSET_ATTR_PORT_TO]	= { .type = NLA_U16 }, +		[IPSET_ATTR_CIDR]	= { .type = NLA_U8 }, +		[IPSET_ATTR_CIDR2]	= { .type = NLA_U8 }, +		[IPSET_ATTR_PROTO]	= { .type = NLA_U8 }, +		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 }, +		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 }, +		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 }, +		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 }, +		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 }, +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING }, +	}, +	.me		= THIS_MODULE, +}; + +static int __init +hash_netportnet_init(void) +{ +	return ip_set_type_register(&hash_netportnet_type); +} + +static void __exit +hash_netportnet_fini(void) +{ +	ip_set_type_unregister(&hash_netportnet_type); +} + +module_init(hash_netportnet_init); +module_exit(hash_netportnet_fini); diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c index 979b8c90e42..3e2317f3cf6 100644 --- a/net/netfilter/ipset/ip_set_list_set.c +++ b/net/netfilter/ipset/ip_set_list_set.c @@ -15,12 +15,13 @@  #include <linux/netfilter/ipset/ip_set.h>  #include <linux/netfilter/ipset/ip_set_list.h> -#define REVISION_MIN	0 -#define REVISION_MAX	1 /* Counters support added */ +#define IPSET_TYPE_REV_MIN	0 +/*				1    Counters support added */ +#define IPSET_TYPE_REV_MAX	2 /* Comments support added */  MODULE_LICENSE("GPL");  MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -IP_SET_MODULE_DESC("list:set", REVISION_MIN, REVISION_MAX); +IP_SET_MODULE_DESC("list:set", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);  MODULE_ALIAS("ip_set_list:set");  /* Member elements  */ @@ -28,28 +29,6 @@ struct set_elem {  	ip_set_id_t id;  }; -struct sett_elem { -	struct { -		ip_set_id_t id; -	} __attribute__ ((aligned)); -	unsigned long timeout; -}; - -struct setc_elem { -	struct { -		ip_set_id_t id; -	} __attribute__ ((aligned)); -	struct ip_set_counter counter; -}; - -struct setct_elem { -	struct { -		ip_set_id_t id; -	} __attribute__ ((aligned)); -	struct ip_set_counter counter; -	unsigned long timeout; -}; -  struct set_adt_elem {  	ip_set_id_t id;  	ip_set_id_t refid; @@ -58,24 +37,14 @@ struct set_adt_elem {  /* Type structure */  struct list_set { -	size_t dsize;		/* element size */ -	size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */  	u32 size;		/* size of set list array */ -	u32 timeout;		/* timeout value */  	struct timer_list gc;	/* garbage collection */ +	struct net *net;	/* namespace */  	struct set_elem members[0]; /* the set members */  }; -static inline struct set_elem * -list_set_elem(const struct list_set *map, u32 id) -{ -	return (struct set_elem *)((void *)map->members + id * map->dsize); -} - -#define ext_timeout(e, m)	\ -(unsigned long *)((void *)(e) + (m)->offset[IPSET_OFFSET_TIMEOUT]) -#define ext_counter(e, m)	\ -(struct ip_set_counter *)((void *)(e) + (m)->offset[IPSET_OFFSET_COUNTER]) +#define list_set_elem(set, map, id)	\ +	(struct set_elem *)((void *)(map)->members + (id) * (set)->dsize)  static int  list_set_ktest(struct ip_set *set, const struct sk_buff *skb, @@ -92,16 +61,16 @@ list_set_ktest(struct ip_set *set, const struct sk_buff *skb,  	if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)  		opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE;  	for (i = 0; i < map->size; i++) { -		e = list_set_elem(map, i); +		e = list_set_elem(set, map, i);  		if (e->id == IPSET_INVALID_ID)  			return 0;  		if (SET_WITH_TIMEOUT(set) && -		    ip_set_timeout_expired(ext_timeout(e, map))) +		    ip_set_timeout_expired(ext_timeout(e, set)))  			continue;  		ret = ip_set_test(e->id, skb, par, opt);  		if (ret > 0) {  			if (SET_WITH_COUNTER(set)) -				ip_set_update_counter(ext_counter(e, map), +				ip_set_update_counter(ext_counter(e, set),  						      ext, &opt->ext,  						      cmdflags);  			return ret; @@ -121,11 +90,11 @@ list_set_kadd(struct ip_set *set, const struct sk_buff *skb,  	int ret;  	for (i = 0; i < map->size; i++) { -		e = list_set_elem(map, i); +		e = list_set_elem(set, map, i);  		if (e->id == IPSET_INVALID_ID)  			return 0;  		if (SET_WITH_TIMEOUT(set) && -		    ip_set_timeout_expired(ext_timeout(e, map))) +		    ip_set_timeout_expired(ext_timeout(e, set)))  			continue;  		ret = ip_set_add(e->id, skb, par, opt);  		if (ret == 0) @@ -145,11 +114,11 @@ list_set_kdel(struct ip_set *set, const struct sk_buff *skb,  	int ret;  	for (i = 0; i < map->size; i++) { -		e = list_set_elem(map, i); +		e = list_set_elem(set, map, i);  		if (e->id == IPSET_INVALID_ID)  			return 0;  		if (SET_WITH_TIMEOUT(set) && -		    ip_set_timeout_expired(ext_timeout(e, map))) +		    ip_set_timeout_expired(ext_timeout(e, set)))  			continue;  		ret = ip_set_del(e->id, skb, par, opt);  		if (ret == 0) @@ -163,8 +132,7 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,  	      const struct xt_action_param *par,  	      enum ipset_adt adt, struct ip_set_adt_opt *opt)  { -	struct list_set *map = set->data; -	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map); +	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);  	switch (adt) {  	case IPSET_TEST: @@ -188,10 +156,10 @@ id_eq(const struct ip_set *set, u32 i, ip_set_id_t id)  	if (i >= map->size)  		return 0; -	e = list_set_elem(map, i); +	e = list_set_elem(set, map, i);  	return !!(e->id == id &&  		 !(SET_WITH_TIMEOUT(set) && -		   ip_set_timeout_expired(ext_timeout(e, map)))); +		   ip_set_timeout_expired(ext_timeout(e, set))));  }  static int @@ -199,28 +167,36 @@ list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d,  	     const struct ip_set_ext *ext)  {  	struct list_set *map = set->data; -	struct set_elem *e = list_set_elem(map, i); +	struct set_elem *e = list_set_elem(set, map, i);  	if (e->id != IPSET_INVALID_ID) { -		if (i == map->size - 1) +		if (i == map->size - 1) {  			/* Last element replaced: e.g. add new,before,last */ -			ip_set_put_byindex(e->id); -		else { -			struct set_elem *x = list_set_elem(map, map->size - 1); +			ip_set_put_byindex(map->net, e->id); +			ip_set_ext_destroy(set, e); +		} else { +			struct set_elem *x = list_set_elem(set, map, +							   map->size - 1);  			/* Last element pushed off */ -			if (x->id != IPSET_INVALID_ID) -				ip_set_put_byindex(x->id); -			memmove(list_set_elem(map, i + 1), e, -				map->dsize * (map->size - (i + 1))); +			if (x->id != IPSET_INVALID_ID) { +				ip_set_put_byindex(map->net, x->id); +				ip_set_ext_destroy(set, x); +			} +			memmove(list_set_elem(set, map, i + 1), e, +				set->dsize * (map->size - (i + 1))); +			/* Extensions must be initialized to zero */ +			memset(e, 0, set->dsize);  		}  	}  	e->id = d->id;  	if (SET_WITH_TIMEOUT(set)) -		ip_set_timeout_set(ext_timeout(e, map), ext->timeout); +		ip_set_timeout_set(ext_timeout(e, set), ext->timeout);  	if (SET_WITH_COUNTER(set)) -		ip_set_init_counter(ext_counter(e, map), ext); +		ip_set_init_counter(ext_counter(e, set), ext); +	if (SET_WITH_COMMENT(set)) +		ip_set_init_comment(ext_comment(e, set), ext);  	return 0;  } @@ -228,16 +204,17 @@ static int  list_set_del(struct ip_set *set, u32 i)  {  	struct list_set *map = set->data; -	struct set_elem *e = list_set_elem(map, i); +	struct set_elem *e = list_set_elem(set, map, i); -	ip_set_put_byindex(e->id); +	ip_set_put_byindex(map->net, e->id); +	ip_set_ext_destroy(set, e);  	if (i < map->size - 1) -		memmove(e, list_set_elem(map, i + 1), -			map->dsize * (map->size - (i + 1))); +		memmove(e, list_set_elem(set, map, i + 1), +			set->dsize * (map->size - (i + 1)));  	/* Last element */ -	e = list_set_elem(map, map->size - 1); +	e = list_set_elem(set, map, map->size - 1);  	e->id = IPSET_INVALID_ID;  	return 0;  } @@ -247,13 +224,16 @@ set_cleanup_entries(struct ip_set *set)  {  	struct list_set *map = set->data;  	struct set_elem *e; -	u32 i; +	u32 i = 0; -	for (i = 0; i < map->size; i++) { -		e = list_set_elem(map, i); +	while (i < map->size) { +		e = list_set_elem(set, map, i);  		if (e->id != IPSET_INVALID_ID && -		    ip_set_timeout_expired(ext_timeout(e, map))) +		    ip_set_timeout_expired(ext_timeout(e, set)))  			list_set_del(set, i); +			/* Check element moved to position i in next loop */ +		else +			i++;  	}  } @@ -268,11 +248,11 @@ list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,  	int ret;  	for (i = 0; i < map->size; i++) { -		e = list_set_elem(map, i); +		e = list_set_elem(set, map, i);  		if (e->id == IPSET_INVALID_ID)  			return 0;  		else if (SET_WITH_TIMEOUT(set) && -			 ip_set_timeout_expired(ext_timeout(e, map))) +			 ip_set_timeout_expired(ext_timeout(e, set)))  			continue;  		else if (e->id != d->id)  			continue; @@ -299,14 +279,14 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,  	bool flag_exist = flags & IPSET_FLAG_EXIST;  	u32 i, ret = 0; +	if (SET_WITH_TIMEOUT(set)) +		set_cleanup_entries(set); +  	/* Check already added element */  	for (i = 0; i < map->size; i++) { -		e = list_set_elem(map, i); +		e = list_set_elem(set, map, i);  		if (e->id == IPSET_INVALID_ID)  			goto insert; -		else if (SET_WITH_TIMEOUT(set) && -			 ip_set_timeout_expired(ext_timeout(e, map))) -			continue;  		else if (e->id != d->id)  			continue; @@ -319,18 +299,22 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,  			/* Can't re-add */  			return -IPSET_ERR_EXIST;  		/* Update extensions */ +		ip_set_ext_destroy(set, e); +  		if (SET_WITH_TIMEOUT(set)) -			ip_set_timeout_set(ext_timeout(e, map), ext->timeout); +			ip_set_timeout_set(ext_timeout(e, set), ext->timeout);  		if (SET_WITH_COUNTER(set)) -			ip_set_init_counter(ext_counter(e, map), ext); +			ip_set_init_counter(ext_counter(e, set), ext); +		if (SET_WITH_COMMENT(set)) +			ip_set_init_comment(ext_comment(e, set), ext);  		/* Set is already added to the list */ -		ip_set_put_byindex(d->id); +		ip_set_put_byindex(map->net, d->id);  		return 0;  	}  insert:  	ret = -IPSET_ERR_LIST_FULL;  	for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) { -		e = list_set_elem(map, i); +		e = list_set_elem(set, map, i);  		if (e->id == IPSET_INVALID_ID)  			ret = d->before != 0 ? -IPSET_ERR_REF_EXIST  				: list_set_add(set, i, d, ext); @@ -355,12 +339,12 @@ list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext,  	u32 i;  	for (i = 0; i < map->size; i++) { -		e = list_set_elem(map, i); +		e = list_set_elem(set, map, i);  		if (e->id == IPSET_INVALID_ID)  			return d->before != 0 ? -IPSET_ERR_REF_EXIST  					      : -IPSET_ERR_EXIST;  		else if (SET_WITH_TIMEOUT(set) && -			 ip_set_timeout_expired(ext_timeout(e, map))) +			 ip_set_timeout_expired(ext_timeout(e, set)))  			continue;  		else if (e->id != d->id)  			continue; @@ -386,7 +370,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],  	struct list_set *map = set->data;  	ipset_adtfn adtfn = set->variant->adt[adt];  	struct set_adt_elem e = { .refid = IPSET_INVALID_ID }; -	struct ip_set_ext ext = IP_SET_INIT_UEXT(map); +	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);  	struct ip_set *s;  	int ret = 0; @@ -403,7 +387,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],  	ret = ip_set_get_extensions(set, tb, &ext);  	if (ret)  		return ret; -	e.id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s); +	e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);  	if (e.id == IPSET_INVALID_ID)  		return -IPSET_ERR_NAME;  	/* "Loop detection" */ @@ -423,7 +407,8 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],  	}  	if (tb[IPSET_ATTR_NAMEREF]) { -		e.refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]), +		e.refid = ip_set_get_byname(map->net, +					    nla_data(tb[IPSET_ATTR_NAMEREF]),  					    &s);  		if (e.refid == IPSET_INVALID_ID) {  			ret = -IPSET_ERR_NAMEREF; @@ -439,9 +424,9 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],  finish:  	if (e.refid != IPSET_INVALID_ID) -		ip_set_put_byindex(e.refid); +		ip_set_put_byindex(map->net, e.refid);  	if (adt != IPSET_ADD || ret) -		ip_set_put_byindex(e.id); +		ip_set_put_byindex(map->net, e.id);  	return ip_set_eexist(ret, flags) ? 0 : ret;  } @@ -454,9 +439,10 @@ list_set_flush(struct ip_set *set)  	u32 i;  	for (i = 0; i < map->size; i++) { -		e = list_set_elem(map, i); +		e = list_set_elem(set, map, i);  		if (e->id != IPSET_INVALID_ID) { -			ip_set_put_byindex(e->id); +			ip_set_put_byindex(map->net, e->id); +			ip_set_ext_destroy(set, e);  			e->id = IPSET_INVALID_ID;  		}  	} @@ -485,14 +471,11 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)  	if (!nested)  		goto nla_put_failure;  	if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) || -	    (SET_WITH_TIMEOUT(set) && -	     nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) || -	    (SET_WITH_COUNTER(set) && -	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, -			   htonl(IPSET_FLAG_WITH_COUNTERS))) ||  	    nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||  	    nla_put_net32(skb, IPSET_ATTR_MEMSIZE, -			  htonl(sizeof(*map) + map->size * map->dsize))) +			  htonl(sizeof(*map) + map->size * set->dsize))) +		goto nla_put_failure; +	if (unlikely(ip_set_put_flags(skb, set)))  		goto nla_put_failure;  	ipset_nest_end(skb, nested); @@ -507,19 +490,20 @@ list_set_list(const struct ip_set *set,  {  	const struct list_set *map = set->data;  	struct nlattr *atd, *nested; -	u32 i, first = cb->args[2]; +	u32 i, first = cb->args[IPSET_CB_ARG0];  	const struct set_elem *e;  	atd = ipset_nest_start(skb, IPSET_ATTR_ADT);  	if (!atd)  		return -EMSGSIZE; -	for (; cb->args[2] < map->size; cb->args[2]++) { -		i = cb->args[2]; -		e = list_set_elem(map, i); +	for (; cb->args[IPSET_CB_ARG0] < map->size; +	     cb->args[IPSET_CB_ARG0]++) { +		i = cb->args[IPSET_CB_ARG0]; +		e = list_set_elem(set, map, i);  		if (e->id == IPSET_INVALID_ID)  			goto finish;  		if (SET_WITH_TIMEOUT(set) && -		    ip_set_timeout_expired(ext_timeout(e, map))) +		    ip_set_timeout_expired(ext_timeout(e, set)))  			continue;  		nested = ipset_nest_start(skb, IPSET_ATTR_DATA);  		if (!nested) { @@ -530,31 +514,25 @@ list_set_list(const struct ip_set *set,  				goto nla_put_failure;  		}  		if (nla_put_string(skb, IPSET_ATTR_NAME, -				   ip_set_name_byindex(e->id))) -			goto nla_put_failure; -		if (SET_WITH_TIMEOUT(set) && -		    nla_put_net32(skb, IPSET_ATTR_TIMEOUT, -				  htonl(ip_set_timeout_get( -						ext_timeout(e, map))))) +				   ip_set_name_byindex(map->net, e->id)))  			goto nla_put_failure; -		if (SET_WITH_COUNTER(set) && -		    ip_set_put_counter(skb, ext_counter(e, map))) +		if (ip_set_put_extensions(skb, set, e, true))  			goto nla_put_failure;  		ipset_nest_end(skb, nested);  	}  finish:  	ipset_nest_end(skb, atd);  	/* Set listing finished */ -	cb->args[2] = 0; +	cb->args[IPSET_CB_ARG0] = 0;  	return 0;  nla_put_failure:  	nla_nest_cancel(skb, nested); -	ipset_nest_end(skb, atd);  	if (unlikely(i == first)) { -		cb->args[2] = 0; +		cb->args[IPSET_CB_ARG0] = 0;  		return -EMSGSIZE;  	} +	ipset_nest_end(skb, atd);  	return 0;  } @@ -565,7 +543,7 @@ list_set_same_set(const struct ip_set *a, const struct ip_set *b)  	const struct list_set *y = b->data;  	return x->size == y->size && -	       x->timeout == y->timeout && +	       a->timeout == b->timeout &&  	       a->extensions == b->extensions;  } @@ -594,7 +572,7 @@ list_set_gc(unsigned long ul_set)  	set_cleanup_entries(set);  	write_unlock_bh(&set->lock); -	map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; +	map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;  	add_timer(&map->gc);  } @@ -606,43 +584,40 @@ list_set_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))  	init_timer(&map->gc);  	map->gc.data = (unsigned long) set;  	map->gc.function = gc; -	map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; +	map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;  	add_timer(&map->gc);  }  /* Create list:set type of sets */ -static struct list_set * -init_list_set(struct ip_set *set, u32 size, size_t dsize, -	      unsigned long timeout) +static bool +init_list_set(struct net *net, struct ip_set *set, u32 size)  {  	struct list_set *map;  	struct set_elem *e;  	u32 i; -	map = kzalloc(sizeof(*map) + size * dsize, GFP_KERNEL); +	map = kzalloc(sizeof(*map) + size * set->dsize, GFP_KERNEL);  	if (!map) -		return NULL; +		return false;  	map->size = size; -	map->dsize = dsize; -	map->timeout = timeout; +	map->net = net;  	set->data = map;  	for (i = 0; i < size; i++) { -		e = list_set_elem(map, i); +		e = list_set_elem(set, map, i);  		e->id = IPSET_INVALID_ID;  	} -	return map; +	return true;  }  static int -list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags) +list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[], +		u32 flags)  { -	struct list_set *map; -	u32 size = IP_SET_LIST_DEFAULT_SIZE, cadt_flags = 0; -	unsigned long timeout = 0; +	u32 size = IP_SET_LIST_DEFAULT_SIZE;  	if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||  		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || @@ -654,45 +629,13 @@ list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)  	if (size < IP_SET_LIST_MIN_SIZE)  		size = IP_SET_LIST_MIN_SIZE; -	if (tb[IPSET_ATTR_CADT_FLAGS]) -		cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); -	if (tb[IPSET_ATTR_TIMEOUT]) -		timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);  	set->variant = &set_variant; -	if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) { -		set->extensions |= IPSET_EXT_COUNTER; -		if (tb[IPSET_ATTR_TIMEOUT]) { -			map = init_list_set(set, size, -					sizeof(struct setct_elem), timeout); -			if (!map) -				return -ENOMEM; -			set->extensions |= IPSET_EXT_TIMEOUT; -			map->offset[IPSET_OFFSET_TIMEOUT] = -				offsetof(struct setct_elem, timeout); -			map->offset[IPSET_OFFSET_COUNTER] = -				offsetof(struct setct_elem, counter); -			list_set_gc_init(set, list_set_gc); -		} else { -			map = init_list_set(set, size, -					    sizeof(struct setc_elem), 0); -			if (!map) -				return -ENOMEM; -			map->offset[IPSET_OFFSET_COUNTER] = -				offsetof(struct setc_elem, counter); -		} -	} else if (tb[IPSET_ATTR_TIMEOUT]) { -		map = init_list_set(set, size, -				    sizeof(struct sett_elem), timeout); -		if (!map) -			return -ENOMEM; -		set->extensions |= IPSET_EXT_TIMEOUT; -		map->offset[IPSET_OFFSET_TIMEOUT] = -			offsetof(struct sett_elem, timeout); +	set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem)); +	if (!init_list_set(net, set, size)) +		return -ENOMEM; +	if (tb[IPSET_ATTR_TIMEOUT]) { +		set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);  		list_set_gc_init(set, list_set_gc); -	} else { -		map = init_list_set(set, size, sizeof(struct set_elem), 0); -		if (!map) -			return -ENOMEM;  	}  	return 0;  } @@ -703,8 +646,8 @@ static struct ip_set_type list_set_type __read_mostly = {  	.features	= IPSET_TYPE_NAME | IPSET_DUMP_LAST,  	.dimension	= IPSET_DIM_ONE,  	.family		= NFPROTO_UNSPEC, -	.revision_min	= REVISION_MIN, -	.revision_max	= REVISION_MAX, +	.revision_min	= IPSET_TYPE_REV_MIN, +	.revision_max	= IPSET_TYPE_REV_MAX,  	.create		= list_set_create,  	.create_policy	= {  		[IPSET_ATTR_SIZE]	= { .type = NLA_U32 }, @@ -721,6 +664,7 @@ static struct ip_set_type list_set_type __read_mostly = {  		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },  		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },  		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 }, +		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING },  	},  	.me		= THIS_MODULE,  }; diff --git a/net/netfilter/ipset/pfxlen.c b/net/netfilter/ipset/pfxlen.c index 4f29fa97044..04d15fdc99e 100644 --- a/net/netfilter/ipset/pfxlen.c +++ b/net/netfilter/ipset/pfxlen.c @@ -7,8 +7,8 @@  #define E(a, b, c, d) \  	{.ip6 = { \ -		__constant_htonl(a), __constant_htonl(b), \ -		__constant_htonl(c), __constant_htonl(d), \ +		htonl(a), htonl(b), \ +		htonl(c), htonl(d), \  	} }  /*  | 
