]>
Commit | Line | Data |
---|---|---|
4d73de38 JK |
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 | ||
35b8dcf8 JK |
11 | #define mtype_do_test IPSET_TOKEN(MTYPE, _do_test) |
12 | #define mtype_gc_test IPSET_TOKEN(MTYPE, _gc_test) | |
13 | #define mtype_is_filled IPSET_TOKEN(MTYPE, _is_filled) | |
14 | #define mtype_do_add IPSET_TOKEN(MTYPE, _do_add) | |
40cd63bf | 15 | #define mtype_ext_cleanup IPSET_TOKEN(MTYPE, _ext_cleanup) |
35b8dcf8 JK |
16 | #define mtype_do_del IPSET_TOKEN(MTYPE, _do_del) |
17 | #define mtype_do_list IPSET_TOKEN(MTYPE, _do_list) | |
18 | #define mtype_do_head IPSET_TOKEN(MTYPE, _do_head) | |
19 | #define mtype_adt_elem IPSET_TOKEN(MTYPE, _adt_elem) | |
20 | #define mtype_add_timeout IPSET_TOKEN(MTYPE, _add_timeout) | |
21 | #define mtype_gc_init IPSET_TOKEN(MTYPE, _gc_init) | |
22 | #define mtype_kadt IPSET_TOKEN(MTYPE, _kadt) | |
23 | #define mtype_uadt IPSET_TOKEN(MTYPE, _uadt) | |
24 | #define mtype_destroy IPSET_TOKEN(MTYPE, _destroy) | |
25 | #define mtype_flush IPSET_TOKEN(MTYPE, _flush) | |
26 | #define mtype_head IPSET_TOKEN(MTYPE, _head) | |
27 | #define mtype_same_set IPSET_TOKEN(MTYPE, _same_set) | |
28 | #define mtype_elem IPSET_TOKEN(MTYPE, _elem) | |
29 | #define mtype_test IPSET_TOKEN(MTYPE, _test) | |
30 | #define mtype_add IPSET_TOKEN(MTYPE, _add) | |
31 | #define mtype_del IPSET_TOKEN(MTYPE, _del) | |
32 | #define mtype_list IPSET_TOKEN(MTYPE, _list) | |
33 | #define mtype_gc IPSET_TOKEN(MTYPE, _gc) | |
4d73de38 JK |
34 | #define mtype MTYPE |
35 | ||
ca134ce8 | 36 | #define get_ext(set, map, id) ((map)->extensions + (set)->dsize * (id)) |
4d73de38 JK |
37 | |
38 | static void | |
39 | mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set)) | |
40 | { | |
41 | struct mtype *map = set->data; | |
42 | ||
43 | init_timer(&map->gc); | |
44 | map->gc.data = (unsigned long) set; | |
45 | map->gc.function = gc; | |
ca134ce8 | 46 | map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ; |
4d73de38 JK |
47 | add_timer(&map->gc); |
48 | } | |
49 | ||
40cd63bf JK |
50 | static void |
51 | mtype_ext_cleanup(struct ip_set *set) | |
52 | { | |
53 | struct mtype *map = set->data; | |
54 | u32 id; | |
55 | ||
56 | for (id = 0; id < map->elements; id++) | |
57 | if (test_bit(id, map->members)) | |
58 | ip_set_ext_destroy(set, get_ext(set, map, id)); | |
59 | } | |
60 | ||
4d73de38 JK |
61 | static void |
62 | mtype_destroy(struct ip_set *set) | |
63 | { | |
64 | struct mtype *map = set->data; | |
65 | ||
66 | if (SET_WITH_TIMEOUT(set)) | |
67 | del_timer_sync(&map->gc); | |
68 | ||
69 | ip_set_free(map->members); | |
40cd63bf JK |
70 | if (set->dsize) { |
71 | if (set->extensions & IPSET_EXT_DESTROY) | |
72 | mtype_ext_cleanup(set); | |
4d73de38 | 73 | ip_set_free(map->extensions); |
40cd63bf | 74 | } |
4d73de38 JK |
75 | kfree(map); |
76 | ||
77 | set->data = NULL; | |
78 | } | |
79 | ||
80 | static void | |
81 | mtype_flush(struct ip_set *set) | |
82 | { | |
83 | struct mtype *map = set->data; | |
84 | ||
40cd63bf JK |
85 | if (set->extensions & IPSET_EXT_DESTROY) |
86 | mtype_ext_cleanup(set); | |
4d73de38 JK |
87 | memset(map->members, 0, map->memsize); |
88 | } | |
89 | ||
90 | static int | |
91 | mtype_head(struct ip_set *set, struct sk_buff *skb) | |
92 | { | |
93 | const struct mtype *map = set->data; | |
94 | struct nlattr *nested; | |
95 | ||
96 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | |
97 | if (!nested) | |
98 | goto nla_put_failure; | |
99 | if (mtype_do_head(skb, map) || | |
100 | nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) || | |
101 | nla_put_net32(skb, IPSET_ATTR_MEMSIZE, | |
102 | htonl(sizeof(*map) + | |
103 | map->memsize + | |
b90cb8ba OS |
104 | set->dsize * map->elements))) |
105 | goto nla_put_failure; | |
106 | if (unlikely(ip_set_put_flags(skb, set))) | |
4d73de38 JK |
107 | goto nla_put_failure; |
108 | ipset_nest_end(skb, nested); | |
109 | ||
110 | return 0; | |
111 | nla_put_failure: | |
112 | return -EMSGSIZE; | |
113 | } | |
114 | ||
115 | static int | |
116 | mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |
117 | struct ip_set_ext *mext, u32 flags) | |
118 | { | |
119 | struct mtype *map = set->data; | |
120 | const struct mtype_adt_elem *e = value; | |
ca134ce8 JK |
121 | void *x = get_ext(set, map, e->id); |
122 | int ret = mtype_do_test(e, map, set->dsize); | |
4d73de38 JK |
123 | |
124 | if (ret <= 0) | |
125 | return ret; | |
126 | if (SET_WITH_TIMEOUT(set) && | |
ca134ce8 | 127 | ip_set_timeout_expired(ext_timeout(x, set))) |
4d73de38 | 128 | return 0; |
f48d19db | 129 | if (SET_WITH_COUNTER(set)) |
ca134ce8 | 130 | ip_set_update_counter(ext_counter(x, set), ext, mext, flags); |
4d73de38 JK |
131 | return 1; |
132 | } | |
133 | ||
134 | static int | |
135 | mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |
136 | struct ip_set_ext *mext, u32 flags) | |
137 | { | |
138 | struct mtype *map = set->data; | |
139 | const struct mtype_adt_elem *e = value; | |
ca134ce8 JK |
140 | void *x = get_ext(set, map, e->id); |
141 | int ret = mtype_do_add(e, map, flags, set->dsize); | |
4d73de38 JK |
142 | |
143 | if (ret == IPSET_ADD_FAILED) { | |
144 | if (SET_WITH_TIMEOUT(set) && | |
ca134ce8 | 145 | ip_set_timeout_expired(ext_timeout(x, set))) |
4d73de38 JK |
146 | ret = 0; |
147 | else if (!(flags & IPSET_FLAG_EXIST)) | |
148 | return -IPSET_ERR_EXIST; | |
40cd63bf JK |
149 | /* Element is re-added, cleanup extensions */ |
150 | ip_set_ext_destroy(set, x); | |
4d73de38 JK |
151 | } |
152 | ||
153 | if (SET_WITH_TIMEOUT(set)) | |
154 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT | |
ca134ce8 | 155 | mtype_add_timeout(ext_timeout(x, set), e, ext, set, map, ret); |
4d73de38 | 156 | #else |
ca134ce8 | 157 | ip_set_timeout_set(ext_timeout(x, set), ext->timeout); |
4d73de38 JK |
158 | #endif |
159 | ||
f48d19db | 160 | if (SET_WITH_COUNTER(set)) |
ca134ce8 | 161 | ip_set_init_counter(ext_counter(x, set), ext); |
b90cb8ba OS |
162 | if (SET_WITH_COMMENT(set)) |
163 | ip_set_init_comment(ext_comment(x, set), ext); | |
4d73de38 JK |
164 | return 0; |
165 | } | |
166 | ||
167 | static int | |
168 | mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |
169 | struct ip_set_ext *mext, u32 flags) | |
170 | { | |
171 | struct mtype *map = set->data; | |
172 | const struct mtype_adt_elem *e = value; | |
40cd63bf | 173 | void *x = get_ext(set, map, e->id); |
4d73de38 | 174 | |
40cd63bf JK |
175 | if (mtype_do_del(e, map)) |
176 | return -IPSET_ERR_EXIST; | |
177 | ||
178 | ip_set_ext_destroy(set, x); | |
179 | if (SET_WITH_TIMEOUT(set) && | |
180 | ip_set_timeout_expired(ext_timeout(x, set))) | |
4d73de38 JK |
181 | return -IPSET_ERR_EXIST; |
182 | ||
183 | return 0; | |
184 | } | |
185 | ||
3fd986b3 JK |
186 | #ifndef IP_SET_BITMAP_STORED_TIMEOUT |
187 | static inline bool | |
188 | mtype_is_filled(const struct mtype_elem *x) | |
189 | { | |
190 | return true; | |
191 | } | |
192 | #endif | |
193 | ||
4d73de38 JK |
194 | static int |
195 | mtype_list(const struct ip_set *set, | |
196 | struct sk_buff *skb, struct netlink_callback *cb) | |
197 | { | |
198 | struct mtype *map = set->data; | |
199 | struct nlattr *adt, *nested; | |
200 | void *x; | |
93302880 | 201 | u32 id, first = cb->args[IPSET_CB_ARG0]; |
4d73de38 JK |
202 | |
203 | adt = ipset_nest_start(skb, IPSET_ATTR_ADT); | |
204 | if (!adt) | |
205 | return -EMSGSIZE; | |
93302880 JK |
206 | for (; cb->args[IPSET_CB_ARG0] < map->elements; |
207 | cb->args[IPSET_CB_ARG0]++) { | |
208 | id = cb->args[IPSET_CB_ARG0]; | |
ca134ce8 | 209 | x = get_ext(set, map, id); |
4d73de38 JK |
210 | if (!test_bit(id, map->members) || |
211 | (SET_WITH_TIMEOUT(set) && | |
212 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT | |
213 | mtype_is_filled((const struct mtype_elem *) x) && | |
214 | #endif | |
ca134ce8 | 215 | ip_set_timeout_expired(ext_timeout(x, set)))) |
4d73de38 JK |
216 | continue; |
217 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | |
218 | if (!nested) { | |
219 | if (id == first) { | |
220 | nla_nest_cancel(skb, adt); | |
221 | return -EMSGSIZE; | |
222 | } else | |
223 | goto nla_put_failure; | |
224 | } | |
ca134ce8 | 225 | if (mtype_do_list(skb, map, id, set->dsize)) |
4d73de38 | 226 | goto nla_put_failure; |
3fd986b3 JK |
227 | if (ip_set_put_extensions(skb, set, x, |
228 | mtype_is_filled((const struct mtype_elem *) x))) | |
b90cb8ba | 229 | goto nla_put_failure; |
4d73de38 JK |
230 | ipset_nest_end(skb, nested); |
231 | } | |
232 | ipset_nest_end(skb, adt); | |
233 | ||
234 | /* Set listing finished */ | |
93302880 | 235 | cb->args[IPSET_CB_ARG0] = 0; |
4d73de38 JK |
236 | |
237 | return 0; | |
238 | ||
239 | nla_put_failure: | |
240 | nla_nest_cancel(skb, nested); | |
4d73de38 | 241 | if (unlikely(id == first)) { |
93302880 | 242 | cb->args[IPSET_CB_ARG0] = 0; |
4d73de38 JK |
243 | return -EMSGSIZE; |
244 | } | |
122ebbf2 | 245 | ipset_nest_end(skb, adt); |
4d73de38 JK |
246 | return 0; |
247 | } | |
248 | ||
249 | static void | |
250 | mtype_gc(unsigned long ul_set) | |
251 | { | |
252 | struct ip_set *set = (struct ip_set *) ul_set; | |
253 | struct mtype *map = set->data; | |
40cd63bf | 254 | void *x; |
4d73de38 JK |
255 | u32 id; |
256 | ||
257 | /* We run parallel with other readers (test element) | |
258 | * but adding/deleting new entries is locked out */ | |
259 | read_lock_bh(&set->lock); | |
260 | for (id = 0; id < map->elements; id++) | |
ca134ce8 JK |
261 | if (mtype_gc_test(id, map, set->dsize)) { |
262 | x = get_ext(set, map, id); | |
40cd63bf | 263 | if (ip_set_timeout_expired(ext_timeout(x, set))) { |
4d73de38 | 264 | clear_bit(id, map->members); |
40cd63bf JK |
265 | ip_set_ext_destroy(set, x); |
266 | } | |
4d73de38 JK |
267 | } |
268 | read_unlock_bh(&set->lock); | |
269 | ||
ca134ce8 | 270 | map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ; |
4d73de38 JK |
271 | add_timer(&map->gc); |
272 | } | |
273 | ||
274 | static const struct ip_set_type_variant mtype = { | |
275 | .kadt = mtype_kadt, | |
276 | .uadt = mtype_uadt, | |
277 | .adt = { | |
278 | [IPSET_ADD] = mtype_add, | |
279 | [IPSET_DEL] = mtype_del, | |
280 | [IPSET_TEST] = mtype_test, | |
281 | }, | |
282 | .destroy = mtype_destroy, | |
283 | .flush = mtype_flush, | |
284 | .head = mtype_head, | |
285 | .list = mtype_list, | |
286 | .same_set = mtype_same_set, | |
287 | }; | |
288 | ||
289 | #endif /* __IP_SET_BITMAP_IP_GEN_H */ |