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

Commit 03c8b234 authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik
Browse files

netfilter: ipset: Generalize extensions support



Get rid of the structure based extensions and introduce a blob for
the extensions. Thus we can support more extension types easily.

Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
parent ca134ce8
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -66,6 +66,17 @@ enum ip_set_ext_id {
	IPSET_EXT_ID_MAX,
};

/* Extension type */
struct ip_set_ext_type {
	enum ip_set_extension type;
	enum ipset_cadt_flags flag;
	/* Size and minimal alignment */
	u8 len;
	u8 align;
};

extern const struct ip_set_ext_type ip_set_extensions[];

struct ip_set_ext {
	u64 packets;
	u64 bytes;
@@ -283,6 +294,8 @@ extern void *ip_set_alloc(size_t size);
extern void ip_set_free(void *members);
extern int ip_set_get_ipaddr4(struct nlattr *nla,  __be32 *ipaddr);
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
extern size_t ip_set_elem_len(struct ip_set *set, struct nlattr *tb[],
			      size_t len);
extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
				 struct ip_set_ext *ext);

+8 −73
Original line number Diff line number Diff line
@@ -208,25 +208,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 */
@@ -263,7 +244,7 @@ static int
bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
{
	struct bitmap_ip *map;
	u32 first_ip = 0, last_ip = 0, hosts, cadt_flags = 0;
	u32 first_ip = 0, last_ip = 0, hosts;
	u64 elements;
	u8 netmask = 32;
	int ret;
@@ -335,61 +316,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]) {
			set->dsize = sizeof(struct bitmap_ipct_elem);
			set->offset[IPSET_EXT_ID_TIMEOUT] =
				offsetof(struct bitmap_ipct_elem, timeout);
			set->offset[IPSET_EXT_ID_COUNTER] =
				offsetof(struct bitmap_ipct_elem, counter);

	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;
	}

			set->timeout = ip_set_timeout_uget(
				tb[IPSET_ATTR_TIMEOUT]);
			set->extensions |= IPSET_EXT_TIMEOUT;

			bitmap_ip_gc_init(set, bitmap_ip_gc);
		} else {
			set->dsize = sizeof(struct bitmap_ipc_elem);
			set->offset[IPSET_EXT_ID_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]) {
		set->dsize = sizeof(struct bitmap_ipt_elem);
		set->offset[IPSET_EXT_ID_TIMEOUT] =
			offsetof(struct bitmap_ipt_elem, timeout);

		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]);
		set->extensions |= IPSET_EXT_TIMEOUT;

		bitmap_ip_gc_init(set, bitmap_ip_gc);
	} else {
		set->dsize = 0;
		if (!init_map_ip(set, map, first_ip, last_ip,
				 elements, hosts, netmask)) {
			kfree(map);
			return -ENOMEM;
		}
	}
	return 0;
}
+9 −82
Original line number Diff line number Diff line
@@ -289,37 +289,6 @@ bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b)

/* 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 */
@@ -328,7 +297,7 @@ 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) * set->dsize);
	map->members = ip_set_alloc(map->memsize);
	if (!map->members)
		return false;
	if (set->dsize) {
@@ -353,7 +322,7 @@ static int
bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
		    u32 flags)
{
	u32 first_ip = 0, last_ip = 0, cadt_flags = 0;
	u32 first_ip = 0, last_ip = 0;
	u64 elements;
	struct bitmap_ipmac *map;
	int ret;
@@ -397,57 +366,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]) {
			set->dsize = sizeof(struct bitmap_ipmacct_elem);
			set->offset[IPSET_EXT_ID_TIMEOUT] =
				offsetof(struct bitmap_ipmacct_elem, timeout);
			set->offset[IPSET_EXT_ID_COUNTER] =
				offsetof(struct bitmap_ipmacct_elem, counter);

			if (!init_map_ipmac(set, map, first_ip, last_ip,
					    elements)) {
				kfree(map);
				return -ENOMEM;
			}
			set->timeout = ip_set_timeout_uget(
				tb[IPSET_ATTR_TIMEOUT]);
			set->extensions |= IPSET_EXT_TIMEOUT;
			bitmap_ipmac_gc_init(set, bitmap_ipmac_gc);
		} else {
			set->dsize = sizeof(struct bitmap_ipmacc_elem);
			set->offset[IPSET_EXT_ID_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]) {
		set->dsize = sizeof(struct bitmap_ipmact_elem);
		set->offset[IPSET_EXT_ID_TIMEOUT] =
			offsetof(struct bitmap_ipmact_elem, 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]);
		set->extensions |= IPSET_EXT_TIMEOUT;
		bitmap_ipmac_gc_init(set, bitmap_ipmac_gc);
	} else {
		set->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;
}
+6 −65
Original line number Diff line number Diff line
@@ -198,25 +198,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 */
@@ -250,7 +231,6 @@ bitmap_port_create(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,53 +254,14 @@ bitmap_port_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
	map->elements = last_port - first_port + 1;
	map->memsize = map->elements * sizeof(unsigned long);
	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]) {
			set->dsize = sizeof(struct bitmap_portct_elem);
			set->offset[IPSET_EXT_ID_TIMEOUT] =
				offsetof(struct bitmap_portct_elem, timeout);
			set->offset[IPSET_EXT_ID_COUNTER] =
				offsetof(struct bitmap_portct_elem, counter);
			if (!init_map_port(set, map, first_port, last_port)) {
				kfree(map);
				return -ENOMEM;
			}

			set->timeout =
				ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
			set->extensions |= IPSET_EXT_TIMEOUT;
			bitmap_port_gc_init(set, bitmap_port_gc);
		} else {
			set->dsize = sizeof(struct bitmap_portc_elem);
			set->offset[IPSET_EXT_ID_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]) {
		set->dsize = sizeof(struct bitmap_portt_elem);
		set->offset[IPSET_EXT_ID_TIMEOUT] =
			offsetof(struct bitmap_portt_elem, 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]);
		set->extensions |= IPSET_EXT_TIMEOUT;
		bitmap_port_gc_init(set, bitmap_port_gc);
	} else {
		set->dsize = 0;
		if (!init_map_port(set, map, first_port, last_port)) {
			kfree(map);
			return -ENOMEM;
		}

	}
	return 0;
}
+46 −0
Original line number Diff line number Diff line
@@ -315,6 +315,52 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr)
}
EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6);

/* 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),
	},
};
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]);
	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)
Loading