xtensa: ccount based clockevent implementation
[linux-2.6-block.git] / net / netfilter / ipset / ip_set_bitmap_gen.h
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 ext_counter(e, m)       \
41         (struct ip_set_counter *)((e) + (m)->offset[IPSET_OFFSET_COUNTER])
42 #define get_ext(map, id)        ((map)->extensions + (map)->dsize * (id))
43
44 static void
45 mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
46 {
47         struct mtype *map = set->data;
48
49         init_timer(&map->gc);
50         map->gc.data = (unsigned long) set;
51         map->gc.function = gc;
52         map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
53         add_timer(&map->gc);
54 }
55
56 static void
57 mtype_destroy(struct ip_set *set)
58 {
59         struct mtype *map = set->data;
60
61         if (SET_WITH_TIMEOUT(set))
62                 del_timer_sync(&map->gc);
63
64         ip_set_free(map->members);
65         if (map->dsize)
66                 ip_set_free(map->extensions);
67         kfree(map);
68
69         set->data = NULL;
70 }
71
72 static void
73 mtype_flush(struct ip_set *set)
74 {
75         struct mtype *map = set->data;
76
77         memset(map->members, 0, map->memsize);
78 }
79
80 static int
81 mtype_head(struct ip_set *set, struct sk_buff *skb)
82 {
83         const struct mtype *map = set->data;
84         struct nlattr *nested;
85
86         nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
87         if (!nested)
88                 goto nla_put_failure;
89         if (mtype_do_head(skb, map) ||
90             nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
91             nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
92                           htonl(sizeof(*map) +
93                                 map->memsize +
94                                 map->dsize * map->elements)) ||
95             (SET_WITH_TIMEOUT(set) &&
96              nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) ||
97             (SET_WITH_COUNTER(set) &&
98              nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS,
99                            htonl(IPSET_FLAG_WITH_COUNTERS))))
100                 goto nla_put_failure;
101         ipset_nest_end(skb, nested);
102
103         return 0;
104 nla_put_failure:
105         return -EMSGSIZE;
106 }
107
108 static int
109 mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
110            struct ip_set_ext *mext, u32 flags)
111 {
112         struct mtype *map = set->data;
113         const struct mtype_adt_elem *e = value;
114         void *x = get_ext(map, e->id);
115         int ret = mtype_do_test(e, map);
116
117         if (ret <= 0)
118                 return ret;
119         if (SET_WITH_TIMEOUT(set) &&
120             ip_set_timeout_expired(ext_timeout(x, map)))
121                 return 0;
122         if (SET_WITH_COUNTER(set))
123                 ip_set_update_counter(ext_counter(x, map), ext, mext, flags);
124         return 1;
125 }
126
127 static int
128 mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
129           struct ip_set_ext *mext, u32 flags)
130 {
131         struct mtype *map = set->data;
132         const struct mtype_adt_elem *e = value;
133         void *x = get_ext(map, e->id);
134         int ret = mtype_do_add(e, map, flags);
135
136         if (ret == IPSET_ADD_FAILED) {
137                 if (SET_WITH_TIMEOUT(set) &&
138                     ip_set_timeout_expired(ext_timeout(x, map)))
139                         ret = 0;
140                 else if (!(flags & IPSET_FLAG_EXIST))
141                         return -IPSET_ERR_EXIST;
142         }
143
144         if (SET_WITH_TIMEOUT(set))
145 #ifdef IP_SET_BITMAP_STORED_TIMEOUT
146                 mtype_add_timeout(ext_timeout(x, map), e, ext, map, ret);
147 #else
148                 ip_set_timeout_set(ext_timeout(x, map), ext->timeout);
149 #endif
150
151         if (SET_WITH_COUNTER(set))
152                 ip_set_init_counter(ext_counter(x, map), ext);
153         return 0;
154 }
155
156 static int
157 mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
158           struct ip_set_ext *mext, u32 flags)
159 {
160         struct mtype *map = set->data;
161         const struct mtype_adt_elem *e = value;
162         const void *x = get_ext(map, e->id);
163
164         if (mtype_do_del(e, map) ||
165             (SET_WITH_TIMEOUT(set) &&
166              ip_set_timeout_expired(ext_timeout(x, map))))
167                 return -IPSET_ERR_EXIST;
168
169         return 0;
170 }
171
172 static int
173 mtype_list(const struct ip_set *set,
174            struct sk_buff *skb, struct netlink_callback *cb)
175 {
176         struct mtype *map = set->data;
177         struct nlattr *adt, *nested;
178         void *x;
179         u32 id, first = cb->args[2];
180
181         adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
182         if (!adt)
183                 return -EMSGSIZE;
184         for (; cb->args[2] < map->elements; cb->args[2]++) {
185                 id = cb->args[2];
186                 x = get_ext(map, id);
187                 if (!test_bit(id, map->members) ||
188                     (SET_WITH_TIMEOUT(set) &&
189 #ifdef IP_SET_BITMAP_STORED_TIMEOUT
190                      mtype_is_filled((const struct mtype_elem *) x) &&
191 #endif
192                      ip_set_timeout_expired(ext_timeout(x, map))))
193                         continue;
194                 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
195                 if (!nested) {
196                         if (id == first) {
197                                 nla_nest_cancel(skb, adt);
198                                 return -EMSGSIZE;
199                         } else
200                                 goto nla_put_failure;
201                 }
202                 if (mtype_do_list(skb, map, id))
203                         goto nla_put_failure;
204                 if (SET_WITH_TIMEOUT(set)) {
205 #ifdef IP_SET_BITMAP_STORED_TIMEOUT
206                         if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
207                                           htonl(ip_set_timeout_stored(map, id,
208                                                         ext_timeout(x, map)))))
209                                 goto nla_put_failure;
210 #else
211                         if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
212                                           htonl(ip_set_timeout_get(
213                                                         ext_timeout(x, map)))))
214                                 goto nla_put_failure;
215 #endif
216                 }
217                 if (SET_WITH_COUNTER(set) &&
218                     ip_set_put_counter(skb, ext_counter(x, map)))
219                         goto nla_put_failure;
220                 ipset_nest_end(skb, nested);
221         }
222         ipset_nest_end(skb, adt);
223
224         /* Set listing finished */
225         cb->args[2] = 0;
226
227         return 0;
228
229 nla_put_failure:
230         nla_nest_cancel(skb, nested);
231         ipset_nest_end(skb, adt);
232         if (unlikely(id == first)) {
233                 cb->args[2] = 0;
234                 return -EMSGSIZE;
235         }
236         return 0;
237 }
238
239 static void
240 mtype_gc(unsigned long ul_set)
241 {
242         struct ip_set *set = (struct ip_set *) ul_set;
243         struct mtype *map = set->data;
244         const void *x;
245         u32 id;
246
247         /* We run parallel with other readers (test element)
248          * but adding/deleting new entries is locked out */
249         read_lock_bh(&set->lock);
250         for (id = 0; id < map->elements; id++)
251                 if (mtype_gc_test(id, map)) {
252                         x = get_ext(map, id);
253                         if (ip_set_timeout_expired(ext_timeout(x, map)))
254                                 clear_bit(id, map->members);
255                 }
256         read_unlock_bh(&set->lock);
257
258         map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
259         add_timer(&map->gc);
260 }
261
262 static const struct ip_set_type_variant mtype = {
263         .kadt   = mtype_kadt,
264         .uadt   = mtype_uadt,
265         .adt    = {
266                 [IPSET_ADD] = mtype_add,
267                 [IPSET_DEL] = mtype_del,
268                 [IPSET_TEST] = mtype_test,
269         },
270         .destroy = mtype_destroy,
271         .flush  = mtype_flush,
272         .head   = mtype_head,
273         .list   = mtype_list,
274         .same_set = mtype_same_set,
275 };
276
277 #endif /* __IP_SET_BITMAP_IP_GEN_H */