1 /* Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation.
8 /* Kernel module implementing an ip+port hash set */
10 #include <linux/module.h>
11 #include <linux/moduleparam.h>
13 #include <linux/tcp.h>
14 #include <linux/udp.h>
15 #include <linux/skbuff.h>
16 #include <linux/netfilter_ipv4/ip_set_jhash.h>
17 #include <linux/errno.h>
18 #include <asm/uaccess.h>
19 #include <asm/bitops.h>
20 #include <linux/spinlock.h>
21 #include <linux/random.h>
25 #include <linux/netfilter_ipv4/ip_set_ipporthash.h>
26 #include <linux/netfilter_ipv4/ip_set_getport.h>
28 static int limit
= MAX_RANGE
;
31 ipporthash_id(struct ip_set
*set
, ip_set_ip_t ip
, ip_set_ip_t port
)
33 struct ip_set_ipporthash
*map
= set
->data
;
38 ip
= pack_ip_port(map
, ip
, port
);
43 for (i
= 0; i
< map
->probes
; i
++) {
44 id
= jhash_ip(map
, i
, ip
) % map
->hashsize
;
45 DP("hash key: %u", id
);
46 elem
= HARRAY_ELEM(map
->members
, ip_set_ip_t
*, id
);
49 /* No shortcut - there can be deleted entries. */
55 ipporthash_test(struct ip_set
*set
, ip_set_ip_t ip
, ip_set_ip_t port
)
57 struct ip_set_ipporthash
*map
= set
->data
;
59 if (ip
< map
->first_ip
|| ip
> map
->last_ip
)
62 return (ipporthash_id(set
, ip
, port
) != UINT_MAX
);
65 #define KADT_CONDITION \
71 port = get_port(skb, ++flags); \
73 if (port == INVALID_PORT) \
76 UADT(ipporthash
, test
, req
->port
)
77 KADT(ipporthash
, test
, ipaddr
, port
)
80 __ipporthash_add(struct ip_set_ipporthash
*map
, ip_set_ip_t
*ip
)
84 ip_set_ip_t
*elem
, *slot
= NULL
;
86 for (i
= 0; i
< map
->probes
; i
++) {
87 probe
= jhash_ip(map
, i
, *ip
) % map
->hashsize
;
88 elem
= HARRAY_ELEM(map
->members
, ip_set_ip_t
*, probe
);
93 /* There can be deleted entries, must check all slots */
100 /* Trigger rehashing */
105 ipporthash_add(struct ip_set
*set
, ip_set_ip_t ip
, ip_set_ip_t port
)
107 struct ip_set_ipporthash
*map
= set
->data
;
108 if (map
->elements
> limit
)
110 if (ip
< map
->first_ip
|| ip
> map
->last_ip
)
113 ip
= pack_ip_port(map
, ip
, port
);
118 return __ipporthash_add(map
, &ip
);
121 UADT(ipporthash
, add
, req
->port
)
122 KADT(ipporthash
, add
, ipaddr
, port
)
125 __ipporthash_retry(struct ip_set_ipporthash
*tmp
,
126 struct ip_set_ipporthash
*map
)
128 tmp
->first_ip
= map
->first_ip
;
129 tmp
->last_ip
= map
->last_ip
;
132 HASH_RETRY(ipporthash
, ip_set_ip_t
)
135 ipporthash_del(struct ip_set
*set
, ip_set_ip_t ip
, ip_set_ip_t port
)
137 struct ip_set_ipporthash
*map
= set
->data
;
141 if (ip
< map
->first_ip
|| ip
> map
->last_ip
)
144 id
= ipporthash_id(set
, ip
, port
);
149 elem
= HARRAY_ELEM(map
->members
, ip_set_ip_t
*, id
);
156 UADT(ipporthash
, del
, req
->port
)
157 KADT(ipporthash
, del
, ipaddr
, port
)
160 __ipporthash_create(const struct ip_set_req_ipporthash_create
*req
,
161 struct ip_set_ipporthash
*map
)
163 if (req
->to
- req
->from
> MAX_RANGE
) {
164 ip_set_printk("range too big, %d elements (max %d)",
165 req
->to
- req
->from
+ 1, MAX_RANGE
+1);
168 map
->first_ip
= req
->from
;
169 map
->last_ip
= req
->to
;
173 HASH_CREATE(ipporthash
, ip_set_ip_t
)
174 HASH_DESTROY(ipporthash
)
175 HASH_FLUSH(ipporthash
, ip_set_ip_t
)
178 __ipporthash_list_header(const struct ip_set_ipporthash
*map
,
179 struct ip_set_req_ipporthash_create
*header
)
181 header
->from
= map
->first_ip
;
182 header
->to
= map
->last_ip
;
185 HASH_LIST_HEADER(ipporthash
)
186 HASH_LIST_MEMBERS_SIZE(ipporthash
, ip_set_ip_t
)
187 HASH_LIST_MEMBERS(ipporthash
, ip_set_ip_t
)
189 IP_SET_RTYPE(ipporthash
, IPSET_TYPE_IP
| IPSET_TYPE_PORT
| IPSET_DATA_DOUBLE
)
191 MODULE_LICENSE("GPL");
192 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
193 MODULE_DESCRIPTION("ipporthash type of IP sets");
194 module_param(limit
, int, 0600);
195 MODULE_PARM_DESC(limit
, "maximal number of elements stored in the sets");
197 REGISTER_MODULE(ipporthash
)