Commit e75cb467 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

Merge branch 'master' of git://blackhole.kfki.hu/nf

Jozsef Kadlecsik says:
====================
Please apply the next bugfixes against the nf tree.

- Fix extensions alignment in ipset: Gerhard Wiesinger reported
  that the missing data aligments lead to crash on non-intel
  architecture. The patch was tested on armv7h by Gerhard Wiesinger
  and on x86_64 and sparc64 by me.
- An incorrect index at the hash:* types could lead to
  falsely early expired entries and memory leak when the comment
  extension was used too.
- Release empty hash bucket block when all entries are expired or
  all slots are empty instead of shrinkig the data part to zero.
====================
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parents b4865988 0aae24eb
...@@ -421,7 +421,7 @@ extern void ip_set_free(void *members); ...@@ -421,7 +421,7 @@ extern void ip_set_free(void *members);
extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr); 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 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[], extern size_t ip_set_elem_len(struct ip_set *set, struct nlattr *tb[],
size_t len); size_t len, size_t align);
extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[], extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
struct ip_set_ext *ext); struct ip_set_ext *ext);
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#define mtype_gc IPSET_TOKEN(MTYPE, _gc) #define mtype_gc IPSET_TOKEN(MTYPE, _gc)
#define mtype MTYPE #define mtype MTYPE
#define get_ext(set, map, id) ((map)->extensions + (set)->dsize * (id)) #define get_ext(set, map, id) ((map)->extensions + ((set)->dsize * (id)))
static void static void
mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set)) mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
...@@ -67,12 +67,9 @@ mtype_destroy(struct ip_set *set) ...@@ -67,12 +67,9 @@ mtype_destroy(struct ip_set *set)
del_timer_sync(&map->gc); del_timer_sync(&map->gc);
ip_set_free(map->members); ip_set_free(map->members);
if (set->dsize) { if (set->dsize && set->extensions & IPSET_EXT_DESTROY)
if (set->extensions & IPSET_EXT_DESTROY) mtype_ext_cleanup(set);
mtype_ext_cleanup(set); ip_set_free(map);
ip_set_free(map->extensions);
}
kfree(map);
set->data = NULL; set->data = NULL;
} }
...@@ -92,16 +89,14 @@ mtype_head(struct ip_set *set, struct sk_buff *skb) ...@@ -92,16 +89,14 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
{ {
const struct mtype *map = set->data; const struct mtype *map = set->data;
struct nlattr *nested; struct nlattr *nested;
size_t memsize = sizeof(*map) + map->memsize;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA); nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) if (!nested)
goto nla_put_failure; goto nla_put_failure;
if (mtype_do_head(skb, map) || if (mtype_do_head(skb, map) ||
nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) || nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
nla_put_net32(skb, IPSET_ATTR_MEMSIZE, nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)))
htonl(sizeof(*map) +
map->memsize +
set->dsize * map->elements)))
goto nla_put_failure; goto nla_put_failure;
if (unlikely(ip_set_put_flags(skb, set))) if (unlikely(ip_set_put_flags(skb, set)))
goto nla_put_failure; goto nla_put_failure;
......
...@@ -41,7 +41,6 @@ MODULE_ALIAS("ip_set_bitmap:ip"); ...@@ -41,7 +41,6 @@ MODULE_ALIAS("ip_set_bitmap:ip");
/* Type structure */ /* Type structure */
struct bitmap_ip { struct bitmap_ip {
void *members; /* the set members */ void *members; /* the set members */
void *extensions; /* data extensions */
u32 first_ip; /* host byte order, included in range */ u32 first_ip; /* host byte order, included in range */
u32 last_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 elements; /* number of max elements in the set */
...@@ -49,6 +48,8 @@ struct bitmap_ip { ...@@ -49,6 +48,8 @@ struct bitmap_ip {
size_t memsize; /* members size */ size_t memsize; /* members size */
u8 netmask; /* subnet netmask */ u8 netmask; /* subnet netmask */
struct timer_list gc; /* garbage collection */ struct timer_list gc; /* garbage collection */
unsigned char extensions[0] /* data extensions */
__aligned(__alignof__(u64));
}; };
/* ADT structure for generic function args */ /* ADT structure for generic function args */
...@@ -224,13 +225,6 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map, ...@@ -224,13 +225,6 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
map->members = ip_set_alloc(map->memsize); map->members = ip_set_alloc(map->memsize);
if (!map->members) if (!map->members)
return false; return false;
if (set->dsize) {
map->extensions = ip_set_alloc(set->dsize * elements);
if (!map->extensions) {
kfree(map->members);
return false;
}
}
map->first_ip = first_ip; map->first_ip = first_ip;
map->last_ip = last_ip; map->last_ip = last_ip;
map->elements = elements; map->elements = elements;
...@@ -316,13 +310,13 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[], ...@@ -316,13 +310,13 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
pr_debug("hosts %u, elements %llu\n", pr_debug("hosts %u, elements %llu\n",
hosts, (unsigned long long)elements); hosts, (unsigned long long)elements);
map = kzalloc(sizeof(*map), GFP_KERNEL); set->dsize = ip_set_elem_len(set, tb, 0, 0);
map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
if (!map) if (!map)
return -ENOMEM; return -ENOMEM;
map->memsize = bitmap_bytes(0, elements - 1); map->memsize = bitmap_bytes(0, elements - 1);
set->variant = &bitmap_ip; set->variant = &bitmap_ip;
set->dsize = ip_set_elem_len(set, tb, 0);
if (!init_map_ip(set, map, first_ip, last_ip, if (!init_map_ip(set, map, first_ip, last_ip,
elements, hosts, netmask)) { elements, hosts, netmask)) {
kfree(map); kfree(map);
......
...@@ -47,24 +47,26 @@ enum { ...@@ -47,24 +47,26 @@ enum {
/* Type structure */ /* Type structure */
struct bitmap_ipmac { struct bitmap_ipmac {
void *members; /* the set members */ void *members; /* the set members */
void *extensions; /* MAC + data extensions */
u32 first_ip; /* host byte order, included in range */ u32 first_ip; /* host byte order, included in range */
u32 last_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 elements; /* number of max elements in the set */
size_t memsize; /* members size */ size_t memsize; /* members size */
struct timer_list gc; /* garbage collector */ struct timer_list gc; /* garbage collector */
unsigned char extensions[0] /* MAC + data extensions */
__aligned(__alignof__(u64));
}; };
/* ADT structure for generic function args */ /* ADT structure for generic function args */
struct bitmap_ipmac_adt_elem { struct bitmap_ipmac_adt_elem {
unsigned char ether[ETH_ALEN] __aligned(2);
u16 id; u16 id;
unsigned char *ether; u16 add_mac;
}; };
struct bitmap_ipmac_elem { struct bitmap_ipmac_elem {
unsigned char ether[ETH_ALEN]; unsigned char ether[ETH_ALEN];
unsigned char filled; unsigned char filled;
} __attribute__ ((aligned)); } __aligned(__alignof__(u64));
static inline u32 static inline u32
ip_to_id(const struct bitmap_ipmac *m, u32 ip) ip_to_id(const struct bitmap_ipmac *m, u32 ip)
...@@ -72,11 +74,11 @@ ip_to_id(const struct bitmap_ipmac *m, u32 ip) ...@@ -72,11 +74,11 @@ ip_to_id(const struct bitmap_ipmac *m, u32 ip)
return ip - m->first_ip; return ip - m->first_ip;
} }
static inline struct bitmap_ipmac_elem * #define get_elem(extensions, id, dsize) \
get_elem(void *extensions, u16 id, size_t dsize) (struct bitmap_ipmac_elem *)(extensions + (id) * (dsize))
{
return (struct bitmap_ipmac_elem *)(extensions + id * dsize); #define get_const_elem(extensions, id, dsize) \
} (const struct bitmap_ipmac_elem *)(extensions + (id) * (dsize))
/* Common functions */ /* Common functions */
...@@ -88,10 +90,9 @@ bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e, ...@@ -88,10 +90,9 @@ bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,
if (!test_bit(e->id, map->members)) if (!test_bit(e->id, map->members))
return 0; return 0;
elem = get_elem(map->extensions, e->id, dsize); elem = get_const_elem(map->extensions, e->id, dsize);
if (elem->filled == MAC_FILLED) if (e->add_mac && elem->filled == MAC_FILLED)
return !e->ether || return ether_addr_equal(e->ether, elem->ether);
ether_addr_equal(e->ether, elem->ether);
/* Trigger kernel to fill out the ethernet address */ /* Trigger kernel to fill out the ethernet address */
return -EAGAIN; return -EAGAIN;
} }
...@@ -103,7 +104,7 @@ bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize) ...@@ -103,7 +104,7 @@ bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize)
if (!test_bit(id, map->members)) if (!test_bit(id, map->members))
return 0; return 0;
elem = get_elem(map->extensions, id, dsize); elem = get_const_elem(map->extensions, id, dsize);
/* Timer not started for the incomplete elements */ /* Timer not started for the incomplete elements */
return elem->filled == MAC_FILLED; return elem->filled == MAC_FILLED;
} }
...@@ -133,7 +134,7 @@ bitmap_ipmac_add_timeout(unsigned long *timeout, ...@@ -133,7 +134,7 @@ bitmap_ipmac_add_timeout(unsigned long *timeout,
* and we can reuse it later when MAC is filled out, * and we can reuse it later when MAC is filled out,
* possibly by the kernel * possibly by the kernel
*/ */
if (e->ether) if (e->add_mac)
ip_set_timeout_set(timeout, t); ip_set_timeout_set(timeout, t);
else else
*timeout = t; *timeout = t;
...@@ -150,7 +151,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e, ...@@ -150,7 +151,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
elem = get_elem(map->extensions, e->id, dsize); elem = get_elem(map->extensions, e->id, dsize);
if (test_bit(e->id, map->members)) { if (test_bit(e->id, map->members)) {
if (elem->filled == MAC_FILLED) { if (elem->filled == MAC_FILLED) {
if (e->ether && if (e->add_mac &&
(flags & IPSET_FLAG_EXIST) && (flags & IPSET_FLAG_EXIST) &&
!ether_addr_equal(e->ether, elem->ether)) { !ether_addr_equal(e->ether, elem->ether)) {
/* memcpy isn't atomic */ /* memcpy isn't atomic */
...@@ -159,7 +160,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e, ...@@ -159,7 +160,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
ether_addr_copy(elem->ether, e->ether); ether_addr_copy(elem->ether, e->ether);
} }
return IPSET_ADD_FAILED; return IPSET_ADD_FAILED;
} else if (!e->ether) } else if (!e->add_mac)
/* Already added without ethernet address */ /* Already added without ethernet address */
return IPSET_ADD_FAILED; return IPSET_ADD_FAILED;
/* Fill the MAC address and trigger the timer activation */ /* Fill the MAC address and trigger the timer activation */
...@@ -168,7 +169,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e, ...@@ -168,7 +169,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
ether_addr_copy(elem->ether, e->ether); ether_addr_copy(elem->ether, e->ether);
elem->filled = MAC_FILLED; elem->filled = MAC_FILLED;
return IPSET_ADD_START_STORED_TIMEOUT; return IPSET_ADD_START_STORED_TIMEOUT;
} else if (e->ether) { } else if (e->add_mac) {
/* We can store MAC too */ /* We can store MAC too */
ether_addr_copy(elem->ether, e->ether); ether_addr_copy(elem->ether, e->ether);
elem->filled = MAC_FILLED; elem->filled = MAC_FILLED;
...@@ -191,7 +192,7 @@ bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map, ...@@ -191,7 +192,7 @@ bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map,
u32 id, size_t dsize) u32 id, size_t dsize)
{ {
const struct bitmap_ipmac_elem *elem = const struct bitmap_ipmac_elem *elem =
get_elem(map->extensions, id, dsize); get_const_elem(map->extensions, id, dsize);
return nla_put_ipaddr4(skb, IPSET_ATTR_IP, return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
htonl(map->first_ip + id)) || htonl(map->first_ip + id)) ||
...@@ -213,7 +214,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, ...@@ -213,7 +214,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
{ {
struct bitmap_ipmac *map = set->data; struct bitmap_ipmac *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct bitmap_ipmac_adt_elem e = { .id = 0 }; struct bitmap_ipmac_adt_elem e = { .id = 0, .add_mac = 1 };
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
u32 ip; u32 ip;
...@@ -231,7 +232,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, ...@@ -231,7 +232,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
return -EINVAL; return -EINVAL;
e.id = ip_to_id(map, ip); e.id = ip_to_id(map, ip);
e.ether = eth_hdr(skb)->h_source; memcpy(e.ether, eth_hdr(skb)->h_source, ETH_ALEN);
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
} }
...@@ -265,11 +266,10 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -265,11 +266,10 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
return -IPSET_ERR_BITMAP_RANGE; return -IPSET_ERR_BITMAP_RANGE;
e.id = ip_to_id(map, ip); e.id = ip_to_id(map, ip);
if (tb[IPSET_ATTR_ETHER]) if (tb[IPSET_ATTR_ETHER]) {
e.ether = nla_data(tb[IPSET_ATTR_ETHER]); memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN);
else e.add_mac = 1;
e.ether = NULL; }
ret = adtfn(set, &e, &ext, &ext, flags); ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
...@@ -300,13 +300,6 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, ...@@ -300,13 +300,6 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
map->members = ip_set_alloc(map->memsize); map->members = ip_set_alloc(map->memsize);
if (!map->members) if (!map->members)
return false; return false;
if (set->dsize) {
map->extensions = ip_set_alloc(set->dsize * elements);
if (!map->extensions) {
kfree(map->members);
return false;
}
}
map->first_ip = first_ip; map->first_ip = first_ip;
map->last_ip = last_ip; map->last_ip = last_ip;
map->elements = elements; map->elements = elements;
...@@ -361,14 +354,15 @@ bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[], ...@@ -361,14 +354,15 @@ bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
if (elements > IPSET_BITMAP_MAX_RANGE + 1) if (elements > IPSET_BITMAP_MAX_RANGE + 1)
return -IPSET_ERR_BITMAP_RANGE_SIZE; return -IPSET_ERR_BITMAP_RANGE_SIZE;
map = kzalloc(sizeof(*map), GFP_KERNEL); set->dsize = ip_set_elem_len(set, tb,
sizeof(struct bitmap_ipmac_elem),
__alignof__(struct bitmap_ipmac_elem));
map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
if (!map) if (!map)
return -ENOMEM; return -ENOMEM;
map->memsize = bitmap_bytes(0, elements - 1); map->memsize = bitmap_bytes(0, elements - 1);
set->variant = &bitmap_ipmac; set->variant = &bitmap_ipmac;
set->dsize = ip_set_elem_len(set, tb,
sizeof(struct bitmap_ipmac_elem));
if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) { if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
kfree(map); kfree(map);
return -ENOMEM; return -ENOMEM;
......
...@@ -35,12 +35,13 @@ MODULE_ALIAS("ip_set_bitmap:port"); ...@@ -35,12 +35,13 @@ MODULE_ALIAS("ip_set_bitmap:port");
/* Type structure */ /* Type structure */
struct bitmap_port { struct bitmap_port {
void *members; /* the set members */ void *members; /* the set members */
void *extensions; /* data extensions */
u16 first_port; /* host byte order, included in range */ u16 first_port; /* host byte order, included in range */
u16 last_port; /* host byte order, included in range */ u16 last_port; /* host byte order, included in range */
u32 elements; /* number of max elements in the set */ u32 elements; /* number of max elements in the set */
size_t memsize; /* members size */ size_t memsize; /* members size */
struct timer_list gc; /* garbage collection */ struct timer_list gc; /* garbage collection */
unsigned char extensions[0] /* data extensions */
__aligned(__alignof__(u64));
}; };
/* ADT structure for generic function args */ /* ADT structure for generic function args */
...@@ -209,13 +210,6 @@ init_map_port(struct ip_set *set, struct bitmap_port *map, ...@@ -209,13 +210,6 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
map->members = ip_set_alloc(map->memsize); map->members = ip_set_alloc(map->memsize);
if (!map->members) if (!map->members)
return false; return false;
if (set->dsize) {
map->extensions = ip_set_alloc(set->dsize * map->elements);
if (!map->extensions) {
kfree(map->members);
return false;
}
}
map->first_port = first_port; map->first_port = first_port;
map->last_port = last_port; map->last_port = last_port;
set->timeout = IPSET_NO_TIMEOUT; set->timeout = IPSET_NO_TIMEOUT;
...@@ -232,6 +226,7 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[], ...@@ -232,6 +226,7 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
{ {
struct bitmap_port *map; struct bitmap_port *map;
u16 first_port, last_port; u16 first_port, last_port;
u32 elements;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) ||
...@@ -248,14 +243,15 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[], ...@@ -248,14 +243,15 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
last_port = tmp; last_port = tmp;
} }
map = kzalloc(sizeof(*map), GFP_KERNEL); elements = last_port - first_port + 1;
set->dsize = ip_set_elem_len(set, tb, 0, 0);
map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
if (!map) if (!map)
return -ENOMEM; return -ENOMEM;
map->elements = last_port - first_port + 1; map->elements = elements;
map->memsize = bitmap_bytes(0, map->elements); map->memsize = bitmap_bytes(0, map->elements);
set->variant = &bitmap_port; set->variant = &bitmap_port;
set->dsize = ip_set_elem_len(set, tb, 0);
if (!init_map_port(set, map, first_port, last_port)) { if (!init_map_port(set, map, first_port, last_port)) {
kfree(map); kfree(map);
return -ENOMEM; return -ENOMEM;
......
...@@ -364,25 +364,27 @@ add_extension(enum ip_set_ext_id id, u32 flags, struct nlattr *tb[]) ...@@ -364,25 +364,27 @@ add_extension(enum ip_set_ext_id id, u32 flags, struct nlattr *tb[])
} }
size_t size_t
ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len) ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len,
size_t align)
{ {
enum ip_set_ext_id id; enum ip_set_ext_id id;
size_t offset = len;
u32 cadt_flags = 0; u32 cadt_flags = 0;
if (tb[IPSET_ATTR_CADT_FLAGS]) if (tb[IPSET_ATTR_CADT_FLAGS])
cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_WITH_FORCEADD) if (cadt_flags & IPSET_FLAG_WITH_FORCEADD)
set->flags |= IPSET_CREATE_FLAG_FORCEADD; set->flags |= IPSET_CREATE_FLAG_FORCEADD;
if (!align)
align = 1;
for (id = 0; id < IPSET_EXT_ID_MAX; id++) { for (id = 0; id < IPSET_EXT_ID_MAX; id++) {
if (!add_extension(id, cadt_flags, tb)) if (!add_extension(id, cadt_flags, tb))
continue; continue;
offset = ALIGN(offset, ip_set_extensions[id].align); len = ALIGN(len, ip_set_extensions[id].align);
set->offset[id] = offset; set->offset[id] = len;
set->extensions |= ip_set_extensions[id].type; set->extensions |= ip_set_extensions[id].type;
offset += ip_set_extensions[id].len; len += ip_set_extensions[id].len;
} }
return offset; return ALIGN(len, align);
} }
EXPORT_SYMBOL_GPL(ip_set_elem_len); EXPORT_SYMBOL_GPL(ip_set_elem_len);
......
...@@ -72,8 +72,9 @@ struct hbucket { ...@@ -72,8 +72,9 @@ struct hbucket {
DECLARE_BITMAP(used, AHASH_MAX_TUNED); DECLARE_BITMAP(used, AHASH_MAX_TUNED);
u8 size; /* size of the array */ u8 size; /* size of the array */
u8 pos; /* position of the first free entry */ u8 pos; /* position of the first free entry */
unsigned char value[0]; /* the array of the values */ unsigned char value[0] /* the array of the values */
} __attribute__ ((aligned)); __aligned(__alignof__(u64));
};
/* The hash table: the table size stored here in order to make resizing easy */ /* The hash table: the table size stored here in order to make resizing easy */
struct htable { struct htable {
...@@ -475,7 +476,7 @@ static void ...@@ -475,7 +476,7 @@ static void
mtype_expire(struct ip_set *set, 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; struct htable *t;
struct hbucket *n; struct hbucket *n, *tmp;
struct mtype_elem *data; struct mtype_elem *data;
u32 i, j, d; u32 i, j, d;
#ifdef IP_SET_HASH_WITH_NETS #ifdef IP_SET_HASH_WITH_NETS
...@@ -510,9 +511,14 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize) ...@@ -510,9 +511,14 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
} }
} }
if (d >= AHASH_INIT_SIZE) { if (d >= AHASH_INIT_SIZE) {
struct hbucket *tmp = kzalloc(sizeof(*tmp) + if (d >= n->size) {
(n->size - AHASH_INIT_SIZE) * dsize, rcu_assign_pointer(hbucket(t, i), NULL);
GFP_ATOMIC); kfree_rcu(n, rcu);
continue;
}
tmp = kzalloc(sizeof(*tmp) +
(n->size - AHASH_INIT_SIZE) * dsize,
GFP_ATOMIC);
if (!tmp) if (!tmp)
/* Still try to delete expired elements */ /* Still try to delete expired elements */
continue; continue;
...@@ -522,7 +528,7 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize) ...@@ -522,7 +528,7 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
continue; continue;
data = ahash_data(n, j, dsize); data = ahash_data(n, j, dsize);
memcpy(tmp->value + d * dsize, data, dsize); memcpy(tmp->value + d * dsize, data, dsize);
set_bit(j, tmp->used); set_bit(d, tmp->used);
d++; d++;
} }
tmp->pos = d; tmp->pos = d;
...@@ -1323,12 +1329,14 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, ...@@ -1323,12 +1329,14 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
#endif #endif
set->variant = &IPSET_TOKEN(HTYPE, 4_variant); set->variant = &IPSET_TOKEN(HTYPE, 4_variant);
set->dsize = ip_set_elem_len(set, tb, set->dsize = ip_set_elem_len(set, tb,
sizeof(struct IPSET_TOKEN(HTYPE, 4_elem))); sizeof(struct IPSET_TOKEN(HTYPE, 4_elem)),
__alignof__(struct IPSET_TOKEN(HTYPE, 4_elem)));
#ifndef IP_SET_PROTO_UNDEF #ifndef IP_SET_PROTO_UNDEF
} else { } else {
set->variant = &IPSET_TOKEN(HTYPE, 6_variant); set->variant = &IPSET_TOKEN(HTYPE, 6_variant);
set->dsize = ip_set_elem_len(set, tb, set->dsize = ip_set_elem_len(set, tb,
sizeof(struct IPSET_TOKEN(HTYPE, 6_elem))); sizeof(struct IPSET_TOKEN(HTYPE, 6_elem)),
__alignof__(struct IPSET_TOKEN(HTYPE, 6_elem)));
} }
#endif #endif
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
......
...@@ -31,7 +31,7 @@ struct set_elem { ...@@ -31,7 +31,7 @@ struct set_elem {
struct rcu_head rcu; struct rcu_head rcu;
struct list_head list; struct list_head list;
ip_set_id_t id; ip_set_id_t id;
}; } __aligned(__alignof__(u64));
struct set_adt_elem { struct set_adt_elem {
ip_set_id_t id; ip_set_id_t id;
...@@ -618,7 +618,8 @@ list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[], ...@@ -618,7 +618,8 @@ list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
size = IP_SET_LIST_MIN_SIZE; size = IP_SET_LIST_MIN_SIZE;
set->variant = &set_variant; set->variant = &set_variant;
set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem)); set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem),
__alignof__(struct set_elem));
if (!init_list_set(net, set, size)) if (!init_list_set(net, set, size))
return -ENOMEM; return -ENOMEM;
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment