]>
Commit | Line | Data |
---|---|---|
6cd9def1 | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
0fdebb3b | 2 | /* Copyright (C) 2013 Jozsef Kadlecsik <kadlec@netfilter.org> |
e2f4b810 JK |
3 | */ |
4 | ||
5 | #ifndef __IP_SET_BITMAP_IP_GEN_H | |
6 | #define __IP_SET_BITMAP_IP_GEN_H | |
7 | ||
76e1fadb JK |
8 | #define mtype_do_test IPSET_TOKEN(MTYPE, _do_test) |
9 | #define mtype_gc_test IPSET_TOKEN(MTYPE, _gc_test) | |
10 | #define mtype_is_filled IPSET_TOKEN(MTYPE, _is_filled) | |
11 | #define mtype_do_add IPSET_TOKEN(MTYPE, _do_add) | |
92f6f53b | 12 | #define mtype_ext_cleanup IPSET_TOKEN(MTYPE, _ext_cleanup) |
76e1fadb JK |
13 | #define mtype_do_del IPSET_TOKEN(MTYPE, _do_del) |
14 | #define mtype_do_list IPSET_TOKEN(MTYPE, _do_list) | |
15 | #define mtype_do_head IPSET_TOKEN(MTYPE, _do_head) | |
16 | #define mtype_adt_elem IPSET_TOKEN(MTYPE, _adt_elem) | |
17 | #define mtype_add_timeout IPSET_TOKEN(MTYPE, _add_timeout) | |
18 | #define mtype_gc_init IPSET_TOKEN(MTYPE, _gc_init) | |
19 | #define mtype_kadt IPSET_TOKEN(MTYPE, _kadt) | |
20 | #define mtype_uadt IPSET_TOKEN(MTYPE, _uadt) | |
21 | #define mtype_destroy IPSET_TOKEN(MTYPE, _destroy) | |
d897885a | 22 | #define mtype_memsize IPSET_TOKEN(MTYPE, _memsize) |
76e1fadb JK |
23 | #define mtype_flush IPSET_TOKEN(MTYPE, _flush) |
24 | #define mtype_head IPSET_TOKEN(MTYPE, _head) | |
25 | #define mtype_same_set IPSET_TOKEN(MTYPE, _same_set) | |
26 | #define mtype_elem IPSET_TOKEN(MTYPE, _elem) | |
27 | #define mtype_test IPSET_TOKEN(MTYPE, _test) | |
28 | #define mtype_add IPSET_TOKEN(MTYPE, _add) | |
29 | #define mtype_del IPSET_TOKEN(MTYPE, _del) | |
30 | #define mtype_list IPSET_TOKEN(MTYPE, _list) | |
31 | #define mtype_gc IPSET_TOKEN(MTYPE, _gc) | |
148fad4d | 32 | #define mtype_cancel_gc IPSET_TOKEN(MTYPE, _cancel_gc) |
e2f4b810 JK |
33 | #define mtype MTYPE |
34 | ||
c7cf6f3b | 35 | #define get_ext(set, map, id) ((map)->extensions + ((set)->dsize * (id))) |
e2f4b810 JK |
36 | |
37 | static void | |
0a81ab50 | 38 | mtype_gc_init(struct ip_set *set, void (*gc)(GC_ARG)) |
e2f4b810 JK |
39 | { |
40 | struct mtype *map = set->data; | |
41 | ||
0a81ab50 | 42 | TIMER_SETUP(&map->gc, gc); |
8f6237f6 | 43 | mod_timer(&map->gc, jiffies + IPSET_GC_PERIOD(set->timeout) * HZ); |
e2f4b810 JK |
44 | } |
45 | ||
92f6f53b JK |
46 | static void |
47 | mtype_ext_cleanup(struct ip_set *set) | |
48 | { | |
49 | struct mtype *map = set->data; | |
50 | u32 id; | |
51 | ||
52 | for (id = 0; id < map->elements; id++) | |
53 | if (test_bit(id, map->members)) | |
54 | ip_set_ext_destroy(set, get_ext(set, map, id)); | |
55 | } | |
56 | ||
e2f4b810 JK |
57 | static void |
58 | mtype_destroy(struct ip_set *set) | |
59 | { | |
60 | struct mtype *map = set->data; | |
61 | ||
c7cf6f3b JK |
62 | if (set->dsize && set->extensions & IPSET_EXT_DESTROY) |
63 | mtype_ext_cleanup(set); | |
d5bfa437 | 64 | ip_set_free(map->members); |
c7cf6f3b | 65 | ip_set_free(map); |
e2f4b810 JK |
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 | ||
92f6f53b JK |
75 | if (set->extensions & IPSET_EXT_DESTROY) |
76 | mtype_ext_cleanup(set); | |
b661f385 | 77 | bitmap_zero(map->members, map->elements); |
0c7e18ed | 78 | set->elements = 0; |
5a568889 | 79 | set->ext_size = 0; |
e2f4b810 JK |
80 | } |
81 | ||
d897885a JK |
82 | /* Calculate the actual memory size of the set data */ |
83 | static size_t | |
b8251a4a | 84 | mtype_memsize(const struct mtype *map, size_t dsize) |
d897885a | 85 | { |
b8251a4a JK |
86 | size_t memsize = sizeof(*map) + |
87 | map->memsize + | |
88 | map->elements * dsize; | |
89 | return memsize; | |
d897885a JK |
90 | } |
91 | ||
e2f4b810 JK |
92 | static int |
93 | mtype_head(struct ip_set *set, struct sk_buff *skb) | |
94 | { | |
95 | const struct mtype *map = set->data; | |
96 | struct nlattr *nested; | |
b8251a4a | 97 | size_t memsize = mtype_memsize(map, set->dsize) + set->ext_size; |
e2f4b810 JK |
98 | |
99 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | |
100 | if (!nested) | |
101 | goto nla_put_failure; | |
102 | if (mtype_do_head(skb, map) || | |
4c70c227 | 103 | nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref)) || |
0c7e18ed JK |
104 | nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)) || |
105 | nla_put_net32(skb, IPSET_ATTR_ELEMENTS, htonl(set->elements))) | |
9af0e20d OS |
106 | goto nla_put_failure; |
107 | if (unlikely(ip_set_put_flags(skb, set))) | |
e2f4b810 JK |
108 | goto nla_put_failure; |
109 | ipset_nest_end(skb, nested); | |
110 | ||
111 | return 0; | |
112 | nla_put_failure: | |
113 | return -EMSGSIZE; | |
114 | } | |
115 | ||
116 | static int | |
117 | mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |
118 | struct ip_set_ext *mext, u32 flags) | |
119 | { | |
120 | struct mtype *map = set->data; | |
121 | const struct mtype_adt_elem *e = value; | |
71b092cb JK |
122 | void *x = get_ext(set, map, e->id); |
123 | int ret = mtype_do_test(e, map, set->dsize); | |
e2f4b810 JK |
124 | |
125 | if (ret <= 0) | |
126 | return ret; | |
ad92ed77 | 127 | return ip_set_match_extensions(set, ext, mext, flags, x); |
e2f4b810 JK |
128 | } |
129 | ||
130 | static int | |
131 | mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |
132 | struct ip_set_ext *mext, u32 flags) | |
133 | { | |
134 | struct mtype *map = set->data; | |
135 | const struct mtype_adt_elem *e = value; | |
71b092cb JK |
136 | void *x = get_ext(set, map, e->id); |
137 | int ret = mtype_do_add(e, map, flags, set->dsize); | |
e2f4b810 JK |
138 | |
139 | if (ret == IPSET_ADD_FAILED) { | |
140 | if (SET_WITH_TIMEOUT(set) && | |
e91b76ec | 141 | ip_set_timeout_expired(ext_timeout(x, set))) { |
0c7e18ed | 142 | set->elements--; |
e2f4b810 | 143 | ret = 0; |
e91b76ec JK |
144 | } else if (!(flags & IPSET_FLAG_EXIST)) { |
145 | set_bit(e->id, map->members); | |
e2f4b810 | 146 | return -IPSET_ERR_EXIST; |
e91b76ec | 147 | } |
92f6f53b JK |
148 | /* Element is re-added, cleanup extensions */ |
149 | ip_set_ext_destroy(set, x); | |
e2f4b810 | 150 | } |
0c7e18ed JK |
151 | if (ret > 0) |
152 | set->elements--; | |
e2f4b810 JK |
153 | |
154 | if (SET_WITH_TIMEOUT(set)) | |
155 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT | |
71b092cb | 156 | mtype_add_timeout(ext_timeout(x, set), e, ext, set, map, ret); |
e2f4b810 | 157 | #else |
71b092cb | 158 | ip_set_timeout_set(ext_timeout(x, set), ext->timeout); |
e2f4b810 JK |
159 | #endif |
160 | ||
9272b57d | 161 | if (SET_WITH_COUNTER(set)) |
71b092cb | 162 | ip_set_init_counter(ext_counter(x, set), ext); |
9af0e20d | 163 | if (SET_WITH_COMMENT(set)) |
5a568889 | 164 | ip_set_init_comment(set, ext_comment(x, set), ext); |
b9653a47 AD |
165 | if (SET_WITH_SKBINFO(set)) |
166 | ip_set_init_skbinfo(ext_skbinfo(x, set), ext); | |
e91b76ec JK |
167 | |
168 | /* Activate element */ | |
169 | set_bit(e->id, map->members); | |
0c7e18ed | 170 | set->elements++; |
e91b76ec | 171 | |
e2f4b810 JK |
172 | return 0; |
173 | } | |
174 | ||
175 | static int | |
176 | mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |
177 | struct ip_set_ext *mext, u32 flags) | |
178 | { | |
179 | struct mtype *map = set->data; | |
180 | const struct mtype_adt_elem *e = value; | |
92f6f53b | 181 | void *x = get_ext(set, map, e->id); |
e2f4b810 | 182 | |
92f6f53b JK |
183 | if (mtype_do_del(e, map)) |
184 | return -IPSET_ERR_EXIST; | |
185 | ||
186 | ip_set_ext_destroy(set, x); | |
0c7e18ed | 187 | set->elements--; |
92f6f53b JK |
188 | if (SET_WITH_TIMEOUT(set) && |
189 | ip_set_timeout_expired(ext_timeout(x, set))) | |
e2f4b810 JK |
190 | return -IPSET_ERR_EXIST; |
191 | ||
192 | return 0; | |
193 | } | |
194 | ||
def57acb | 195 | #ifndef IP_SET_BITMAP_STORED_TIMEOUT |
4392230c | 196 | static bool |
def57acb JK |
197 | mtype_is_filled(const struct mtype_elem *x) |
198 | { | |
199 | return true; | |
200 | } | |
201 | #endif | |
202 | ||
e2f4b810 JK |
203 | static int |
204 | mtype_list(const struct ip_set *set, | |
205 | struct sk_buff *skb, struct netlink_callback *cb) | |
206 | { | |
207 | struct mtype *map = set->data; | |
208 | struct nlattr *adt, *nested; | |
209 | void *x; | |
a61d7ebe | 210 | u32 id, first = cb->args[IPSET_CB_ARG0]; |
aa458c2d | 211 | int ret = 0; |
e2f4b810 JK |
212 | |
213 | adt = ipset_nest_start(skb, IPSET_ATTR_ADT); | |
214 | if (!adt) | |
215 | return -EMSGSIZE; | |
aa458c2d JK |
216 | /* Extensions may be replaced */ |
217 | rcu_read_lock(); | |
a61d7ebe JK |
218 | for (; cb->args[IPSET_CB_ARG0] < map->elements; |
219 | cb->args[IPSET_CB_ARG0]++) { | |
56004fb7 | 220 | cond_resched_rcu(); |
a61d7ebe | 221 | id = cb->args[IPSET_CB_ARG0]; |
71b092cb | 222 | x = get_ext(set, map, id); |
e2f4b810 JK |
223 | if (!test_bit(id, map->members) || |
224 | (SET_WITH_TIMEOUT(set) && | |
225 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT | |
c4c74ae6 | 226 | mtype_is_filled(x) && |
e2f4b810 | 227 | #endif |
68ade830 | 228 | ip_set_timeout_expired(ext_timeout(x, set)))) |
e2f4b810 JK |
229 | continue; |
230 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | |
231 | if (!nested) { | |
232 | if (id == first) { | |
233 | nla_nest_cancel(skb, adt); | |
aa458c2d JK |
234 | ret = -EMSGSIZE; |
235 | goto out; | |
9f497f7e JK |
236 | } |
237 | ||
238 | goto nla_put_failure; | |
e2f4b810 | 239 | } |
71b092cb | 240 | if (mtype_do_list(skb, map, id, set->dsize)) |
e2f4b810 | 241 | goto nla_put_failure; |
cb410bbb | 242 | if (ip_set_put_extensions(skb, set, x, mtype_is_filled(x))) |
9af0e20d | 243 | goto nla_put_failure; |
e2f4b810 JK |
244 | ipset_nest_end(skb, nested); |
245 | } | |
246 | ipset_nest_end(skb, adt); | |
247 | ||
248 | /* Set listing finished */ | |
a61d7ebe | 249 | cb->args[IPSET_CB_ARG0] = 0; |
e2f4b810 | 250 | |
aa458c2d | 251 | goto out; |
e2f4b810 JK |
252 | |
253 | nla_put_failure: | |
254 | nla_nest_cancel(skb, nested); | |
e2f4b810 | 255 | if (unlikely(id == first)) { |
a61d7ebe | 256 | cb->args[IPSET_CB_ARG0] = 0; |
aa458c2d | 257 | ret = -EMSGSIZE; |
e2f4b810 | 258 | } |
5ebed3ba | 259 | ipset_nest_end(skb, adt); |
aa458c2d JK |
260 | out: |
261 | rcu_read_unlock(); | |
262 | return ret; | |
e2f4b810 JK |
263 | } |
264 | ||
265 | static void | |
0a81ab50 | 266 | mtype_gc(GC_ARG) |
e2f4b810 | 267 | { |
0a81ab50 | 268 | INIT_GC_VARS(mtype, map); |
92f6f53b | 269 | void *x; |
e2f4b810 JK |
270 | u32 id; |
271 | ||
272 | /* We run parallel with other readers (test element) | |
9f497f7e JK |
273 | * but adding/deleting new entries is locked out |
274 | */ | |
920ddfa0 | 275 | spin_lock_bh(&set->lock); |
e2f4b810 | 276 | for (id = 0; id < map->elements; id++) |
71b092cb JK |
277 | if (mtype_gc_test(id, map, set->dsize)) { |
278 | x = get_ext(set, map, id); | |
92f6f53b | 279 | if (ip_set_timeout_expired(ext_timeout(x, set))) { |
e2f4b810 | 280 | clear_bit(id, map->members); |
92f6f53b | 281 | ip_set_ext_destroy(set, x); |
0c7e18ed | 282 | set->elements--; |
92f6f53b | 283 | } |
e2f4b810 | 284 | } |
920ddfa0 | 285 | spin_unlock_bh(&set->lock); |
e2f4b810 | 286 | |
71b092cb | 287 | map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ; |
e2f4b810 JK |
288 | add_timer(&map->gc); |
289 | } | |
290 | ||
148fad4d JK |
291 | static void |
292 | mtype_cancel_gc(struct ip_set *set) | |
293 | { | |
294 | struct mtype *map = set->data; | |
295 | ||
296 | if (SET_WITH_TIMEOUT(set)) | |
297 | del_timer_sync(&map->gc); | |
298 | } | |
299 | ||
e2f4b810 JK |
300 | static const struct ip_set_type_variant mtype = { |
301 | .kadt = mtype_kadt, | |
302 | .uadt = mtype_uadt, | |
303 | .adt = { | |
304 | [IPSET_ADD] = mtype_add, | |
305 | [IPSET_DEL] = mtype_del, | |
306 | [IPSET_TEST] = mtype_test, | |
307 | }, | |
308 | .destroy = mtype_destroy, | |
309 | .flush = mtype_flush, | |
310 | .head = mtype_head, | |
311 | .list = mtype_list, | |
312 | .same_set = mtype_same_set, | |
148fad4d | 313 | .cancel_gc = mtype_cancel_gc, |
e2f4b810 JK |
314 | }; |
315 | ||
316 | #endif /* __IP_SET_BITMAP_IP_GEN_H */ |