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