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+ip 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_ipportiphash.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 ipportiphash_id(struct ip_set
*set
,
35 ip_set_ip_t ip
, ip_set_ip_t port
, ip_set_ip_t ip1
)
37 struct ip_set_ipportiphash
*map
= set
->data
;
40 struct ipportip
*elem
;
42 ip
= pack_ip_port(map
, ip
, port
);
46 for (i
= 0; i
< map
->probes
; i
++) {
47 id
= jhash_ip2(map
, i
, ip
, ip1
) % map
->hashsize
;
48 DP("hash key: %u", id
);
49 elem
= HARRAY_ELEM(map
->members
, struct ipportip
*, id
);
50 if (elem
->ip
== ip
&& elem
->ip1
== ip1
)
52 /* No shortcut - there can be deleted entries. */
58 ipportiphash_test(struct ip_set
*set
,
59 ip_set_ip_t ip
, ip_set_ip_t port
, ip_set_ip_t ip1
)
61 struct ip_set_ipportiphash
*map
= set
->data
;
63 if (ip
< map
->first_ip
|| ip
> map
->last_ip
)
66 return (ipportiphash_id(set
, ip
, port
, ip1
) != UINT_MAX
);
69 #define KADT_CONDITION \
70 ip_set_ip_t port, ip1; \
75 port = get_port(skb, ++flags); \
76 ip1 = ipaddr(skb, ++flags); \
78 if (port == INVALID_PORT) \
81 UADT(ipportiphash
, test
, req
->port
, req
->ip1
)
82 KADT(ipportiphash
, test
, ipaddr
, port
, ip1
)
85 __ipportip_add(struct ip_set_ipportiphash
*map
,
86 ip_set_ip_t ip
, ip_set_ip_t ip1
)
90 struct ipportip
*elem
, *slot
= NULL
;
92 for (i
= 0; i
< map
->probes
; i
++) {
93 probe
= jhash_ip2(map
, i
, ip
, ip1
) % map
->hashsize
;
94 elem
= HARRAY_ELEM(map
->members
, struct ipportip
*, probe
);
95 if (elem
->ip
== ip
&& elem
->ip1
== ip1
)
97 if (!(slot
|| elem
->ip
|| elem
->ip1
))
99 /* There can be deleted entries, must check all slots */
107 /* Trigger rehashing */
112 __ipportiphash_add(struct ip_set_ipportiphash
*map
,
113 struct ipportip
*elem
)
115 return __ipportip_add(map
, elem
->ip
, elem
->ip1
);
119 ipportiphash_add(struct ip_set
*set
,
120 ip_set_ip_t ip
, ip_set_ip_t port
, ip_set_ip_t ip1
)
122 struct ip_set_ipportiphash
*map
= set
->data
;
124 if (map
->elements
> limit
)
126 if (ip
< map
->first_ip
|| ip
> map
->last_ip
)
129 ip
= pack_ip_port(map
, ip
, port
);
133 return __ipportip_add(map
, ip
, ip1
);
136 UADT(ipportiphash
, add
, req
->port
, req
->ip1
)
137 KADT(ipportiphash
, add
, ipaddr
, port
, ip1
)
140 __ipportiphash_retry(struct ip_set_ipportiphash
*tmp
,
141 struct ip_set_ipportiphash
*map
)
143 tmp
->first_ip
= map
->first_ip
;
144 tmp
->last_ip
= map
->last_ip
;
147 HASH_RETRY2(ipportiphash
, struct ipportip
)
150 ipportiphash_del(struct ip_set
*set
,
151 ip_set_ip_t ip
, ip_set_ip_t port
, ip_set_ip_t ip1
)
153 struct ip_set_ipportiphash
*map
= set
->data
;
155 struct ipportip
*elem
;
157 if (ip
< map
->first_ip
|| ip
> map
->last_ip
)
160 id
= ipportiphash_id(set
, ip
, port
, ip1
);
165 elem
= HARRAY_ELEM(map
->members
, struct ipportip
*, id
);
166 elem
->ip
= elem
->ip1
= 0;
172 UADT(ipportiphash
, del
, req
->port
, req
->ip1
)
173 KADT(ipportiphash
, del
, ipaddr
, port
, ip1
)
176 __ipportiphash_create(const struct ip_set_req_ipportiphash_create
*req
,
177 struct ip_set_ipportiphash
*map
)
179 if (req
->to
- req
->from
> MAX_RANGE
) {
180 ip_set_printk("range too big, %d elements (max %d)",
181 req
->to
- req
->from
+ 1, MAX_RANGE
+1);
184 map
->first_ip
= req
->from
;
185 map
->last_ip
= req
->to
;
189 HASH_CREATE(ipportiphash
, struct ipportip
)
190 HASH_DESTROY(ipportiphash
)
191 HASH_FLUSH(ipportiphash
, struct ipportip
)
194 __ipportiphash_list_header(const struct ip_set_ipportiphash
*map
,
195 struct ip_set_req_ipportiphash_create
*header
)
197 header
->from
= map
->first_ip
;
198 header
->to
= map
->last_ip
;
201 HASH_LIST_HEADER(ipportiphash
)
202 HASH_LIST_MEMBERS_SIZE(ipportiphash
, struct ipportip
)
203 HASH_LIST_MEMBERS_MEMCPY(ipportiphash
, struct ipportip
,
204 (elem
->ip
|| elem
->ip1
))
206 IP_SET_RTYPE(ipportiphash
, IPSET_TYPE_IP
| IPSET_TYPE_PORT
207 | IPSET_TYPE_IP1
| IPSET_DATA_TRIPLE
)
209 MODULE_LICENSE("GPL");
210 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
211 MODULE_DESCRIPTION("ipportiphash type of IP sets");
212 module_param(limit
, int, 0600);
213 MODULE_PARM_DESC(limit
, "maximal number of elements stored in the sets");
215 REGISTER_MODULE(ipportiphash
)