summaryrefslogtreecommitdiffstats
path: root/kernel/ip_set_iphash.c
diff options
context:
space:
mode:
author/C=EU/ST=EU/CN=Jozsef Kadlecsik/emailAddress=kadlec@blackhole.kfki.hu </C=EU/ST=EU/CN=Jozsef Kadlecsik/emailAddress=kadlec@blackhole.kfki.hu>2008-10-20 10:00:26 +0000
committer/C=EU/ST=EU/CN=Jozsef Kadlecsik/emailAddress=kadlec@blackhole.kfki.hu </C=EU/ST=EU/CN=Jozsef Kadlecsik/emailAddress=kadlec@blackhole.kfki.hu>2008-10-20 10:00:26 +0000
commita96e4fca10506462df4ee4035f0f86f09bd9dc34 (patch)
tree103bed0a7ae3608675f371d2ac91f3fa7f3a58cc /kernel/ip_set_iphash.c
parentbc2ddd2d8da1252e78a1f25bd91c1e3cd8016ead (diff)
ipset 2.4 release
userspace changes: - Added KBUILD_OUTPUT support (Sven Wegener) - Fix memory leak in ipset_iptreemap (Sven Wegener) - Fix multiple compiler warnings (Sven Wegener) - ipportiphash, ipportnethash and setlist types added - binding marked as deprecated functionality - element separator token changed to ',' in anticipating IPv6 addresses, old separator tokens are still supported - unnecessary includes removed - ipset does not try to resolve IP addresses when listing the content of sets (default changed) - manpage updated - ChangeLog forked for kernel part kernel part changes: - ipportiphash, ipportnethash and setlist types added - set type modules reworked to avoid code duplication as much as possible, code unification macros - expand_macros Makefile target added to help debugging code unification macros - ip_set_addip_kernel and ip_set_delip_kernel changed from void to int, __ip_set_get_byname and __ip_set_put_byid added for the sake of setlist type - unnecessary includes removed - compatibility fix for kernels >= 2.6.27: semaphore.h was moved from asm/ to linux/ (James King) - ChangeLog forked for kernel part
Diffstat (limited to 'kernel/ip_set_iphash.c')
-rw-r--r--kernel/ip_set_iphash.c339
1 files changed, 47 insertions, 292 deletions
diff --git a/kernel/ip_set_iphash.c b/kernel/ip_set_iphash.c
index 2ac6066..38b83ed 100644
--- a/kernel/ip_set_iphash.c
+++ b/kernel/ip_set_iphash.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2008 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
@@ -11,32 +11,23 @@
#include <linux/moduleparam.h>
#include <linux/ip.h>
#include <linux/skbuff.h>
-#include <linux/version.h>
#include <linux/jhash.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_set.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/spinlock.h>
-#include <linux/vmalloc.h>
#include <linux/random.h>
#include <net/ip.h>
-#include <linux/netfilter_ipv4/ip_set_malloc.h>
+#include <linux/netfilter_ipv4/ip_set.h>
+#include <linux/netfilter_ipv4/ip_set_hashes.h>
#include <linux/netfilter_ipv4/ip_set_iphash.h>
static int limit = MAX_RANGE;
static inline __u32
-jhash_ip(const struct ip_set_iphash *map, uint16_t i, ip_set_ip_t ip)
-{
- return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
-}
-
-static inline __u32
-hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+iphash_id(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
struct ip_set_iphash *map = set->data;
__u32 id;
@@ -60,59 +51,30 @@ hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
}
static inline int
-__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+iphash_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
- return (ip && hash_id(set, ip, hash_ip) != UINT_MAX);
+ return (ip && iphash_id(set, hash_ip, ip) != UINT_MAX);
}
-static int
-testip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_iphash *req = data;
+#define KADT_CONDITION
- if (size != sizeof(struct ip_set_req_iphash)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_iphash),
- size);
- return -EINVAL;
- }
- return __testip(set, req->ip, hash_ip);
-}
-
-static int
-testip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- return __testip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
-}
+UADT(iphash, test)
+KADT(iphash, test, ipaddr)
static inline int
-__addip(struct ip_set_iphash *map, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+__iphash_add(struct ip_set_iphash *map, ip_set_ip_t *ip)
{
__u32 probe;
u_int16_t i;
ip_set_ip_t *elem;
- if (!ip || map->elements >= limit)
- return -ERANGE;
-
- *hash_ip = ip & map->netmask;
-
for (i = 0; i < map->probes; i++) {
- probe = jhash_ip(map, i, *hash_ip) % map->hashsize;
+ probe = jhash_ip(map, i, *ip) % map->hashsize;
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
- if (*elem == *hash_ip)
+ if (*elem == *ip)
return -EEXIST;
if (!*elem) {
- *elem = *hash_ip;
+ *elem = *ip;
map->elements++;
return 0;
}
@@ -121,110 +83,32 @@ __addip(struct ip_set_iphash *map, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return -EAGAIN;
}
-static int
-addip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_iphash *req = data;
-
- if (size != sizeof(struct ip_set_req_iphash)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_iphash),
- size);
- return -EINVAL;
- }
- return __addip(set->data, req->ip, hash_ip);
-}
-
-static int
-addip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- return __addip((struct ip_set_iphash *) set->data,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
-}
-
-static int retry(struct ip_set *set)
+static inline int
+iphash_add(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
struct ip_set_iphash *map = set->data;
- ip_set_ip_t hash_ip, *elem;
- void *members;
- u_int32_t i, hashsize = map->hashsize;
- int res;
- struct ip_set_iphash *tmp;
- if (map->resize == 0)
+ if (!ip || map->elements >= limit)
return -ERANGE;
- again:
- res = 0;
-
- /* Calculate new hash size */
- hashsize += (hashsize * map->resize)/100;
- if (hashsize == map->hashsize)
- hashsize++;
-
- ip_set_printk("rehashing of set %s triggered: "
- "hashsize grows from %u to %u",
- set->name, map->hashsize, hashsize);
-
- tmp = kmalloc(sizeof(struct ip_set_iphash)
- + map->probes * sizeof(uint32_t), GFP_ATOMIC);
- if (!tmp) {
- DP("out of memory for %d bytes",
- sizeof(struct ip_set_iphash)
- + map->probes * sizeof(uint32_t));
- return -ENOMEM;
- }
- tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
- if (!tmp->members) {
- DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
- kfree(tmp);
- return -ENOMEM;
- }
- tmp->hashsize = hashsize;
- tmp->elements = 0;
- tmp->probes = map->probes;
- tmp->resize = map->resize;
- tmp->netmask = map->netmask;
- memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
-
- write_lock_bh(&set->lock);
- map = set->data; /* Play safe */
- for (i = 0; i < map->hashsize && res == 0; i++) {
- elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
- if (*elem)
- res = __addip(tmp, *elem, &hash_ip);
- }
- if (res) {
- /* Failure, try again */
- write_unlock_bh(&set->lock);
- harray_free(tmp->members);
- kfree(tmp);
- goto again;
- }
+ *hash_ip = ip & map->netmask;
- /* Success at resizing! */
- members = map->members;
-
- map->hashsize = tmp->hashsize;
- map->members = tmp->members;
- write_unlock_bh(&set->lock);
+ return __iphash_add(map, hash_ip);
+}
- harray_free(members);
- kfree(tmp);
+UADT(iphash, add)
+KADT(iphash, add, ipaddr)
- return 0;
+static inline void
+__iphash_retry(struct ip_set_iphash *tmp, struct ip_set_iphash *map)
+{
+ tmp->netmask = map->netmask;
}
+HASH_RETRY(iphash, ip_set_ip_t)
+
static inline int
-__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
+iphash_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
struct ip_set_iphash *map = set->data;
ip_set_ip_t id, *elem;
@@ -232,7 +116,7 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
if (!ip)
return -ERANGE;
- id = hash_id(set, ip, hash_ip);
+ id = iphash_id(set, hash_ip, ip);
if (id == UINT_MAX)
return -EEXIST;
@@ -243,151 +127,35 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return 0;
}
-static int
-delip(struct ip_set *set, const void *data, size_t size,
- ip_set_ip_t *hash_ip)
-{
- const struct ip_set_req_iphash *req = data;
+UADT(iphash, del)
+KADT(iphash, del, ipaddr)
- if (size != sizeof(struct ip_set_req_iphash)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_iphash),
- size);
- return -EINVAL;
- }
- return __delip(set, req->ip, hash_ip);
-}
-
-static int
-delip_kernel(struct ip_set *set,
- const struct sk_buff *skb,
- ip_set_ip_t *hash_ip,
- const u_int32_t *flags,
- unsigned char index)
-{
- return __delip(set,
- ntohl(flags[index] & IPSET_SRC
- ? ip_hdr(skb)->saddr
- : ip_hdr(skb)->daddr),
- hash_ip);
-}
-
-static int create(struct ip_set *set, const void *data, size_t size)
+static inline int
+__iphash_create(const struct ip_set_req_iphash_create *req,
+ struct ip_set_iphash *map)
{
- const struct ip_set_req_iphash_create *req = data;
- struct ip_set_iphash *map;
- uint16_t i;
-
- if (size != sizeof(struct ip_set_req_iphash_create)) {
- ip_set_printk("data length wrong (want %zu, have %zu)",
- sizeof(struct ip_set_req_iphash_create),
- size);
- return -EINVAL;
- }
-
- if (req->hashsize < 1) {
- ip_set_printk("hashsize too small");
- return -ENOEXEC;
- }
-
- if (req->probes < 1) {
- ip_set_printk("probes too small");
- return -ENOEXEC;
- }
-
- map = kmalloc(sizeof(struct ip_set_iphash)
- + req->probes * sizeof(uint32_t), GFP_KERNEL);
- if (!map) {
- DP("out of memory for %d bytes",
- sizeof(struct ip_set_iphash)
- + req->probes * sizeof(uint32_t));
- return -ENOMEM;
- }
- for (i = 0; i < req->probes; i++)
- get_random_bytes(((uint32_t *) map->initval)+i, 4);
- map->elements = 0;
- map->hashsize = req->hashsize;
- map->probes = req->probes;
- map->resize = req->resize;
map->netmask = req->netmask;
- map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
- if (!map->members) {
- DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
- kfree(map);
- return -ENOMEM;
- }
-
- set->data = map;
+
return 0;
}
-static void destroy(struct ip_set *set)
-{
- struct ip_set_iphash *map = set->data;
+HASH_CREATE(iphash, ip_set_ip_t)
+HASH_DESTROY(iphash)
- harray_free(map->members);
- kfree(map);
-
- set->data = NULL;
-}
+HASH_FLUSH(iphash, ip_set_ip_t)
-static void flush(struct ip_set *set)
-{
- struct ip_set_iphash *map = set->data;
- harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
- map->elements = 0;
-}
-
-static void list_header(const struct ip_set *set, void *data)
-{
- struct ip_set_iphash *map = set->data;
- struct ip_set_req_iphash_create *header = data;
-
- header->hashsize = map->hashsize;
- header->probes = map->probes;
- header->resize = map->resize;
+static inline void
+__iphash_list_header(const struct ip_set_iphash *map,
+ struct ip_set_req_iphash_create *header)
+{
header->netmask = map->netmask;
}
-static int list_members_size(const struct ip_set *set)
-{
- const struct ip_set_iphash *map = set->data;
+HASH_LIST_HEADER(iphash)
+HASH_LIST_MEMBERS_SIZE(iphash, ip_set_ip_t)
+HASH_LIST_MEMBERS(iphash, ip_set_ip_t)
- return (map->hashsize * sizeof(ip_set_ip_t));
-}
-
-static void list_members(const struct ip_set *set, void *data)
-{
- const struct ip_set_iphash *map = set->data;
- ip_set_ip_t i, *elem;
-
- for (i = 0; i < map->hashsize; i++) {
- elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
- ((ip_set_ip_t *)data)[i] = *elem;
- }
-}
-
-static struct ip_set_type ip_set_iphash = {
- .typename = SETTYPE_NAME,
- .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
- .protocol_version = IP_SET_PROTOCOL_VERSION,
- .create = &create,
- .destroy = &destroy,
- .flush = &flush,
- .reqsize = sizeof(struct ip_set_req_iphash),
- .addip = &addip,
- .addip_kernel = &addip_kernel,
- .retry = &retry,
- .delip = &delip,
- .delip_kernel = &delip_kernel,
- .testip = &testip,
- .testip_kernel = &testip_kernel,
- .header_size = sizeof(struct ip_set_req_iphash_create),
- .list_header = &list_header,
- .list_members_size = &list_members_size,
- .list_members = &list_members,
- .me = THIS_MODULE,
-};
+IP_SET_RTYPE(iphash, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -395,17 +163,4 @@ MODULE_DESCRIPTION("iphash type of IP sets");
module_param(limit, int, 0600);
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
-static int __init ip_set_iphash_init(void)
-{
- init_max_page_size();
- return ip_set_register_set_type(&ip_set_iphash);
-}
-
-static void __exit ip_set_iphash_fini(void)
-{
- /* FIXME: possible race with ip_set_create() */
- ip_set_unregister_set_type(&ip_set_iphash);
-}
-
-module_init(ip_set_iphash_init);
-module_exit(ip_set_iphash_fini);
+REGISTER_MODULE(iphash)