1 /* Copyright (C) 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+net 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_ipportnethash.h>
26 #include <linux/netfilter_ipv4/ip_set_getport.h>
28 static int limit
= MAX_RANGE
;
30 #define jhash_ip2(map, i, ipport, ip1) \
31 jhash_2words(ipport, ip1, *(map->initval + i))
34 ipportnethash_id_cidr(struct ip_set
*set
,
35 ip_set_ip_t ip
, ip_set_ip_t port
,
36 ip_set_ip_t ip1
, uint8_t cidr
)
38 struct ip_set_ipportnethash
*map
= set
->data
;
41 struct ipportip
*elem
;
43 ip
= pack_ip_port(map
, ip
, port
);
44 ip1
= pack_ip_cidr(ip1
, cidr
);
48 for (i
= 0; i
< map
->probes
; i
++) {
49 id
= jhash_ip2(map
, i
, ip
, ip1
) % map
->hashsize
;
50 DP("hash key: %u", id
);
51 elem
= HARRAY_ELEM(map
->members
, struct ipportip
*, id
);
52 if (elem
->ip
== ip
&& elem
->ip1
== ip1
)
54 /* No shortcut - there can be deleted entries. */
60 ipportnethash_id(struct ip_set
*set
,
61 ip_set_ip_t ip
, ip_set_ip_t port
, ip_set_ip_t ip1
)
63 struct ip_set_ipportnethash
*map
= set
->data
;
67 for (i
= 0; i
< 30 && map
->cidr
[i
]; i
++) {
68 id
= ipportnethash_id_cidr(set
, ip
, port
, ip1
, map
->cidr
[i
]);
76 ipportnethash_test_cidr(struct ip_set
*set
,
77 ip_set_ip_t ip
, ip_set_ip_t port
,
78 ip_set_ip_t ip1
, uint8_t cidr
)
80 struct ip_set_ipportnethash
*map
= set
->data
;
82 if (ip
< map
->first_ip
|| ip
> map
->last_ip
)
85 return (ipportnethash_id_cidr(set
, ip
, port
, ip1
, cidr
) != UINT_MAX
);
89 ipportnethash_test(struct ip_set
*set
,
90 ip_set_ip_t ip
, ip_set_ip_t port
, ip_set_ip_t ip1
)
92 struct ip_set_ipportnethash
*map
= set
->data
;
94 if (ip
< map
->first_ip
|| ip
> map
->last_ip
)
97 return (ipportnethash_id(set
, ip
, port
, ip1
) != UINT_MAX
);
101 ipportnethash_utest(struct ip_set
*set
, const void *data
, u_int32_t size
)
103 const struct ip_set_req_ipportnethash
*req
= data
;
105 if (req
->cidr
<= 0 || req
->cidr
> 32)
107 return (req
->cidr
== 32
108 ? ipportnethash_test(set
, req
->ip
, req
->port
, req
->ip1
)
109 : ipportnethash_test_cidr(set
, req
->ip
, req
->port
,
110 req
->ip1
, req
->cidr
));
113 #define KADT_CONDITION \
114 ip_set_ip_t port, ip1; \
119 port = get_port(skb, ++flags); \
120 ip1 = ipaddr(skb, ++flags); \
122 if (port == INVALID_PORT) \
125 KADT(ipportnethash
, test
, ipaddr
, port
, ip1
)
128 __ipportnet_add(struct ip_set_ipportnethash
*map
,
129 ip_set_ip_t ip
, ip_set_ip_t ip1
)
133 struct ipportip
*elem
, *slot
= NULL
;
135 for (i
= 0; i
< map
->probes
; i
++) {
136 probe
= jhash_ip2(map
, i
, ip
, ip1
) % map
->hashsize
;
137 elem
= HARRAY_ELEM(map
->members
, struct ipportip
*, probe
);
138 if (elem
->ip
== ip
&& elem
->ip1
== ip1
)
140 if (!(slot
|| elem
->ip
|| elem
->ip1
))
142 /* There can be deleted entries, must check all slots */
150 /* Trigger rehashing */
155 __ipportnethash_add(struct ip_set_ipportnethash
*map
,
156 struct ipportip
*elem
)
158 return __ipportnet_add(map
, elem
->ip
, elem
->ip1
);
162 ipportnethash_add(struct ip_set
*set
,
163 ip_set_ip_t ip
, ip_set_ip_t port
,
164 ip_set_ip_t ip1
, uint8_t cidr
)
166 struct ip_set_ipportnethash
*map
= set
->data
;
170 if (map
->elements
> limit
)
172 if (ip
< map
->first_ip
|| ip
> map
->last_ip
)
174 if (cidr
<= 0 || cidr
>= 32)
176 if (map
->nets
[cidr
-1] == UINT16_MAX
)
179 ip
= pack_ip_port(map
, ip
, port
);
180 ip1
= pack_ip_cidr(ip1
, cidr
);
184 ret
=__ipportnet_add(map
, ip
, ip1
);
186 if (!map
->nets
[cidr
-1]++)
187 add_cidr_size(map
->cidr
, cidr
);
192 #undef KADT_CONDITION
193 #define KADT_CONDITION \
194 struct ip_set_ipportnethash *map = set->data; \
195 uint8_t cidr = map->cidr[0] ? map->cidr[0] : 31; \
196 ip_set_ip_t port, ip1; \
201 port = get_port(skb, flags++); \
202 ip1 = ipaddr(skb, flags++); \
204 if (port == INVALID_PORT) \
207 UADT(ipportnethash
, add
, req
->port
, req
->ip1
, req
->cidr
)
208 KADT(ipportnethash
, add
, ipaddr
, port
, ip1
, cidr
)
211 __ipportnethash_retry(struct ip_set_ipportnethash
*tmp
,
212 struct ip_set_ipportnethash
*map
)
214 tmp
->first_ip
= map
->first_ip
;
215 tmp
->last_ip
= map
->last_ip
;
216 memcpy(tmp
->cidr
, map
->cidr
, sizeof(tmp
->cidr
));
217 memcpy(tmp
->nets
, map
->nets
, sizeof(tmp
->nets
));
220 HASH_RETRY2(ipportnethash
, struct ipportip
)
223 ipportnethash_del(struct ip_set
*set
,
224 ip_set_ip_t ip
, ip_set_ip_t port
,
225 ip_set_ip_t ip1
, uint8_t cidr
)
227 struct ip_set_ipportnethash
*map
= set
->data
;
229 struct ipportip
*elem
;
231 if (ip
< map
->first_ip
|| ip
> map
->last_ip
)
235 if (cidr
<= 0 || cidr
>= 32)
238 id
= ipportnethash_id_cidr(set
, ip
, port
, ip1
, cidr
);
243 elem
= HARRAY_ELEM(map
->members
, struct ipportip
*, id
);
244 elem
->ip
= elem
->ip1
= 0;
246 if (!map
->nets
[cidr
-1]--)
247 del_cidr_size(map
->cidr
, cidr
);
252 UADT(ipportnethash
, del
, req
->port
, req
->ip1
, req
->cidr
)
253 KADT(ipportnethash
, del
, ipaddr
, port
, ip1
, cidr
)
256 __ipportnethash_create(const struct ip_set_req_ipportnethash_create
*req
,
257 struct ip_set_ipportnethash
*map
)
259 if (req
->to
- req
->from
> MAX_RANGE
) {
260 ip_set_printk("range too big, %d elements (max %d)",
261 req
->to
- req
->from
+ 1, MAX_RANGE
+1);
264 map
->first_ip
= req
->from
;
265 map
->last_ip
= req
->to
;
266 memset(map
->cidr
, 0, sizeof(map
->cidr
));
267 memset(map
->nets
, 0, sizeof(map
->nets
));
271 HASH_CREATE(ipportnethash
, struct ipportip
)
272 HASH_DESTROY(ipportnethash
)
273 HASH_FLUSH_CIDR(ipportnethash
, struct ipportip
);
276 __ipportnethash_list_header(const struct ip_set_ipportnethash
*map
,
277 struct ip_set_req_ipportnethash_create
*header
)
279 header
->from
= map
->first_ip
;
280 header
->to
= map
->last_ip
;
283 HASH_LIST_HEADER(ipportnethash
)
285 HASH_LIST_MEMBERS_SIZE(ipportnethash
, struct ipportip
)
286 HASH_LIST_MEMBERS_MEMCPY(ipportnethash
, struct ipportip
,
287 (elem
->ip
|| elem
->ip1
))
289 IP_SET_RTYPE(ipportnethash
, IPSET_TYPE_IP
| IPSET_TYPE_PORT
290 | IPSET_TYPE_IP1
| IPSET_DATA_TRIPLE
)
292 MODULE_LICENSE("GPL");
293 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
294 MODULE_DESCRIPTION("ipportnethash type of IP sets");
295 module_param(limit
, int, 0600);
296 MODULE_PARM_DESC(limit
, "maximal number of elements stored in the sets");
298 REGISTER_MODULE(ipportnethash
)