diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2013-04-08 15:00:52 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-04-29 14:08:54 -0400 |
commit | 4d73de38c256623b324474098f7d2bb4e97f7cf0 (patch) | |
tree | 8c44627b11540b6d821a726b9693b89f297f9610 | |
parent | 075e64c041b5d3c29651965608e1e76505e01d54 (diff) |
netfilter: ipset: Unified bitmap type generation
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | include/linux/netfilter/ipset/ip_set_bitmap.h | 6 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_bitmap_gen.h | 265 |
2 files changed, 271 insertions, 0 deletions
diff --git a/include/linux/netfilter/ipset/ip_set_bitmap.h b/include/linux/netfilter/ipset/ip_set_bitmap.h index 1a30646d5be8..5e4662a71e01 100644 --- a/include/linux/netfilter/ipset/ip_set_bitmap.h +++ b/include/linux/netfilter/ipset/ip_set_bitmap.h | |||
@@ -5,6 +5,12 @@ | |||
5 | 5 | ||
6 | #define IPSET_BITMAP_MAX_RANGE 0x0000FFFF | 6 | #define IPSET_BITMAP_MAX_RANGE 0x0000FFFF |
7 | 7 | ||
8 | enum { | ||
9 | IPSET_ADD_FAILED = 1, | ||
10 | IPSET_ADD_STORE_PLAIN_TIMEOUT, | ||
11 | IPSET_ADD_START_STORED_TIMEOUT, | ||
12 | }; | ||
13 | |||
8 | /* Common functions */ | 14 | /* Common functions */ |
9 | 15 | ||
10 | static inline u32 | 16 | static inline u32 |
diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h new file mode 100644 index 000000000000..b9931591cbe9 --- /dev/null +++ b/net/netfilter/ipset/ip_set_bitmap_gen.h | |||
@@ -0,0 +1,265 @@ | |||
1 | /* Copyright (C) 2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | ||
2 | * | ||
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. | ||
6 | */ | ||
7 | |||
8 | #ifndef __IP_SET_BITMAP_IP_GEN_H | ||
9 | #define __IP_SET_BITMAP_IP_GEN_H | ||
10 | |||
11 | #define CONCAT(a, b) a##b | ||
12 | #define TOKEN(a,b) CONCAT(a, b) | ||
13 | |||
14 | #define mtype_do_test TOKEN(MTYPE, _do_test) | ||
15 | #define mtype_gc_test TOKEN(MTYPE, _gc_test) | ||
16 | #define mtype_is_filled TOKEN(MTYPE, _is_filled) | ||
17 | #define mtype_do_add TOKEN(MTYPE, _do_add) | ||
18 | #define mtype_do_del TOKEN(MTYPE, _do_del) | ||
19 | #define mtype_do_list TOKEN(MTYPE, _do_list) | ||
20 | #define mtype_do_head TOKEN(MTYPE, _do_head) | ||
21 | #define mtype_adt_elem TOKEN(MTYPE, _adt_elem) | ||
22 | #define mtype_add_timeout TOKEN(MTYPE, _add_timeout) | ||
23 | #define mtype_gc_init TOKEN(MTYPE, _gc_init) | ||
24 | #define mtype_kadt TOKEN(MTYPE, _kadt) | ||
25 | #define mtype_uadt TOKEN(MTYPE, _uadt) | ||
26 | #define mtype_destroy TOKEN(MTYPE, _destroy) | ||
27 | #define mtype_flush TOKEN(MTYPE, _flush) | ||
28 | #define mtype_head TOKEN(MTYPE, _head) | ||
29 | #define mtype_same_set TOKEN(MTYPE, _same_set) | ||
30 | #define mtype_elem TOKEN(MTYPE, _elem) | ||
31 | #define mtype_test TOKEN(MTYPE, _test) | ||
32 | #define mtype_add TOKEN(MTYPE, _add) | ||
33 | #define mtype_del TOKEN(MTYPE, _del) | ||
34 | #define mtype_list TOKEN(MTYPE, _list) | ||
35 | #define mtype_gc TOKEN(MTYPE, _gc) | ||
36 | #define mtype MTYPE | ||
37 | |||
38 | #define ext_timeout(e, m) \ | ||
39 | (unsigned long *)((e) + (m)->offset[IPSET_OFFSET_TIMEOUT]) | ||
40 | #define get_ext(map, id) ((map)->extensions + (map)->dsize * (id)) | ||
41 | |||
42 | static void | ||
43 | mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set)) | ||
44 | { | ||
45 | struct mtype *map = set->data; | ||
46 | |||
47 | init_timer(&map->gc); | ||
48 | map->gc.data = (unsigned long) set; | ||
49 | map->gc.function = gc; | ||
50 | map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; | ||
51 | add_timer(&map->gc); | ||
52 | } | ||
53 | |||
54 | static void | ||
55 | mtype_destroy(struct ip_set *set) | ||
56 | { | ||
57 | struct mtype *map = set->data; | ||
58 | |||
59 | if (SET_WITH_TIMEOUT(set)) | ||
60 | del_timer_sync(&map->gc); | ||
61 | |||
62 | ip_set_free(map->members); | ||
63 | if (map->dsize) | ||
64 | ip_set_free(map->extensions); | ||
65 | kfree(map); | ||
66 | |||
67 | set->data = NULL; | ||
68 | } | ||
69 | |||
70 | static void | ||
71 | mtype_flush(struct ip_set *set) | ||
72 | { | ||
73 | struct mtype *map = set->data; | ||
74 | |||
75 | memset(map->members, 0, map->memsize); | ||
76 | } | ||
77 | |||
78 | static int | ||
79 | mtype_head(struct ip_set *set, struct sk_buff *skb) | ||
80 | { | ||
81 | const struct mtype *map = set->data; | ||
82 | struct nlattr *nested; | ||
83 | |||
84 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | ||
85 | if (!nested) | ||
86 | goto nla_put_failure; | ||
87 | if (mtype_do_head(skb, map) || | ||
88 | nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) || | ||
89 | nla_put_net32(skb, IPSET_ATTR_MEMSIZE, | ||
90 | htonl(sizeof(*map) + | ||
91 | map->memsize + | ||
92 | map->dsize * map->elements)) || | ||
93 | (SET_WITH_TIMEOUT(set) && | ||
94 | nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout)))) | ||
95 | goto nla_put_failure; | ||
96 | ipset_nest_end(skb, nested); | ||
97 | |||
98 | return 0; | ||
99 | nla_put_failure: | ||
100 | return -EMSGSIZE; | ||
101 | } | ||
102 | |||
103 | static int | ||
104 | mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext, | ||
105 | struct ip_set_ext *mext, u32 flags) | ||
106 | { | ||
107 | struct mtype *map = set->data; | ||
108 | const struct mtype_adt_elem *e = value; | ||
109 | void *x = get_ext(map, e->id); | ||
110 | int ret = mtype_do_test(e, map); | ||
111 | |||
112 | if (ret <= 0) | ||
113 | return ret; | ||
114 | if (SET_WITH_TIMEOUT(set) && | ||
115 | ip_set_timeout_expired(ext_timeout(x, map))) | ||
116 | return 0; | ||
117 | return 1; | ||
118 | } | ||
119 | |||
120 | static int | ||
121 | mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, | ||
122 | struct ip_set_ext *mext, u32 flags) | ||
123 | { | ||
124 | struct mtype *map = set->data; | ||
125 | const struct mtype_adt_elem *e = value; | ||
126 | void *x = get_ext(map, e->id); | ||
127 | int ret = mtype_do_add(e, map, flags); | ||
128 | |||
129 | if (ret == IPSET_ADD_FAILED) { | ||
130 | if (SET_WITH_TIMEOUT(set) && | ||
131 | ip_set_timeout_expired(ext_timeout(x, map))) | ||
132 | ret = 0; | ||
133 | else if (!(flags & IPSET_FLAG_EXIST)) | ||
134 | return -IPSET_ERR_EXIST; | ||
135 | } | ||
136 | |||
137 | if (SET_WITH_TIMEOUT(set)) | ||
138 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT | ||
139 | mtype_add_timeout(ext_timeout(x, map), e, ext, map, ret); | ||
140 | #else | ||
141 | ip_set_timeout_set(ext_timeout(x, map), ext->timeout); | ||
142 | #endif | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | static int | ||
148 | mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, | ||
149 | struct ip_set_ext *mext, u32 flags) | ||
150 | { | ||
151 | struct mtype *map = set->data; | ||
152 | const struct mtype_adt_elem *e = value; | ||
153 | const void *x = get_ext(map, e->id); | ||
154 | |||
155 | if (mtype_do_del(e, map) || | ||
156 | (SET_WITH_TIMEOUT(set) && | ||
157 | ip_set_timeout_expired(ext_timeout(x, map)))) | ||
158 | return -IPSET_ERR_EXIST; | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int | ||
164 | mtype_list(const struct ip_set *set, | ||
165 | struct sk_buff *skb, struct netlink_callback *cb) | ||
166 | { | ||
167 | struct mtype *map = set->data; | ||
168 | struct nlattr *adt, *nested; | ||
169 | void *x; | ||
170 | u32 id, first = cb->args[2]; | ||
171 | |||
172 | adt = ipset_nest_start(skb, IPSET_ATTR_ADT); | ||
173 | if (!adt) | ||
174 | return -EMSGSIZE; | ||
175 | for (; cb->args[2] < map->elements; cb->args[2]++) { | ||
176 | id = cb->args[2]; | ||
177 | x = get_ext(map, id); | ||
178 | if (!test_bit(id, map->members) || | ||
179 | (SET_WITH_TIMEOUT(set) && | ||
180 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT | ||
181 | mtype_is_filled((const struct mtype_elem *) x) && | ||
182 | #endif | ||
183 | ip_set_timeout_expired(ext_timeout(x, map)))) | ||
184 | continue; | ||
185 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | ||
186 | if (!nested) { | ||
187 | if (id == first) { | ||
188 | nla_nest_cancel(skb, adt); | ||
189 | return -EMSGSIZE; | ||
190 | } else | ||
191 | goto nla_put_failure; | ||
192 | } | ||
193 | if (mtype_do_list(skb, map, id)) | ||
194 | goto nla_put_failure; | ||
195 | if (SET_WITH_TIMEOUT(set)) { | ||
196 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT | ||
197 | if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, | ||
198 | htonl(ip_set_timeout_stored(map, id, | ||
199 | ext_timeout(x, map))))) | ||
200 | goto nla_put_failure; | ||
201 | #else | ||
202 | if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, | ||
203 | htonl(ip_set_timeout_get( | ||
204 | ext_timeout(x, map))))) | ||
205 | goto nla_put_failure; | ||
206 | #endif | ||
207 | } | ||
208 | ipset_nest_end(skb, nested); | ||
209 | } | ||
210 | ipset_nest_end(skb, adt); | ||
211 | |||
212 | /* Set listing finished */ | ||
213 | cb->args[2] = 0; | ||
214 | |||
215 | return 0; | ||
216 | |||
217 | nla_put_failure: | ||
218 | nla_nest_cancel(skb, nested); | ||
219 | ipset_nest_end(skb, adt); | ||
220 | if (unlikely(id == first)) { | ||
221 | cb->args[2] = 0; | ||
222 | return -EMSGSIZE; | ||
223 | } | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static void | ||
228 | mtype_gc(unsigned long ul_set) | ||
229 | { | ||
230 | struct ip_set *set = (struct ip_set *) ul_set; | ||
231 | struct mtype *map = set->data; | ||
232 | const void *x; | ||
233 | u32 id; | ||
234 | |||
235 | /* We run parallel with other readers (test element) | ||
236 | * but adding/deleting new entries is locked out */ | ||
237 | read_lock_bh(&set->lock); | ||
238 | for (id = 0; id < map->elements; id++) | ||
239 | if (mtype_gc_test(id, map)) { | ||
240 | x = get_ext(map, id); | ||
241 | if (ip_set_timeout_expired(ext_timeout(x, map))) | ||
242 | clear_bit(id, map->members); | ||
243 | } | ||
244 | read_unlock_bh(&set->lock); | ||
245 | |||
246 | map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; | ||
247 | add_timer(&map->gc); | ||
248 | } | ||
249 | |||
250 | static const struct ip_set_type_variant mtype = { | ||
251 | .kadt = mtype_kadt, | ||
252 | .uadt = mtype_uadt, | ||
253 | .adt = { | ||
254 | [IPSET_ADD] = mtype_add, | ||
255 | [IPSET_DEL] = mtype_del, | ||
256 | [IPSET_TEST] = mtype_test, | ||
257 | }, | ||
258 | .destroy = mtype_destroy, | ||
259 | .flush = mtype_flush, | ||
260 | .head = mtype_head, | ||
261 | .list = mtype_list, | ||
262 | .same_set = mtype_same_set, | ||
263 | }; | ||
264 | |||
265 | #endif /* __IP_SET_BITMAP_IP_GEN_H */ | ||