Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 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 | |
Jozsef Kadlecsik | 35b8dcf | 2013-04-30 23:02:43 +0200 | [diff] [blame] | 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) |
Jozsef Kadlecsik | 40cd63b | 2013-09-09 14:44:29 +0200 | [diff] [blame] | 15 | #define mtype_ext_cleanup IPSET_TOKEN(MTYPE, _ext_cleanup) |
Jozsef Kadlecsik | 35b8dcf | 2013-04-30 23:02:43 +0200 | [diff] [blame] | 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) |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 34 | #define mtype MTYPE |
| 35 | |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 36 | #define get_ext(set, map, id) ((map)->extensions + (set)->dsize * (id)) |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 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; |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 46 | map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ; |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 47 | add_timer(&map->gc); |
| 48 | } |
| 49 | |
| 50 | static void |
Jozsef Kadlecsik | 40cd63b | 2013-09-09 14:44:29 +0200 | [diff] [blame] | 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 | |
| 61 | static void |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 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); |
Jozsef Kadlecsik | 40cd63b | 2013-09-09 14:44:29 +0200 | [diff] [blame] | 70 | if (set->dsize) { |
| 71 | if (set->extensions & IPSET_EXT_DESTROY) |
| 72 | mtype_ext_cleanup(set); |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 73 | ip_set_free(map->extensions); |
Jozsef Kadlecsik | 40cd63b | 2013-09-09 14:44:29 +0200 | [diff] [blame] | 74 | } |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 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 | |
Jozsef Kadlecsik | 40cd63b | 2013-09-09 14:44:29 +0200 | [diff] [blame] | 85 | if (set->extensions & IPSET_EXT_DESTROY) |
| 86 | mtype_ext_cleanup(set); |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 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 + |
Oliver Smith | b90cb8b | 2013-09-22 20:56:32 +0200 | [diff] [blame] | 104 | set->dsize * map->elements))) |
| 105 | goto nla_put_failure; |
| 106 | if (unlikely(ip_set_put_flags(skb, set))) |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 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; |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 121 | void *x = get_ext(set, map, e->id); |
| 122 | int ret = mtype_do_test(e, map, set->dsize); |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 123 | |
| 124 | if (ret <= 0) |
| 125 | return ret; |
| 126 | if (SET_WITH_TIMEOUT(set) && |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 127 | ip_set_timeout_expired(ext_timeout(x, set))) |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 128 | return 0; |
Jozsef Kadlecsik | f48d19d | 2013-04-08 23:10:22 +0200 | [diff] [blame] | 129 | if (SET_WITH_COUNTER(set)) |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 130 | ip_set_update_counter(ext_counter(x, set), ext, mext, flags); |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 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; |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 140 | void *x = get_ext(set, map, e->id); |
| 141 | int ret = mtype_do_add(e, map, flags, set->dsize); |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 142 | |
| 143 | if (ret == IPSET_ADD_FAILED) { |
| 144 | if (SET_WITH_TIMEOUT(set) && |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 145 | ip_set_timeout_expired(ext_timeout(x, set))) |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 146 | ret = 0; |
| 147 | else if (!(flags & IPSET_FLAG_EXIST)) |
| 148 | return -IPSET_ERR_EXIST; |
Jozsef Kadlecsik | 40cd63b | 2013-09-09 14:44:29 +0200 | [diff] [blame] | 149 | /* Element is re-added, cleanup extensions */ |
| 150 | ip_set_ext_destroy(set, x); |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 151 | } |
| 152 | |
| 153 | if (SET_WITH_TIMEOUT(set)) |
| 154 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 155 | mtype_add_timeout(ext_timeout(x, set), e, ext, set, map, ret); |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 156 | #else |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 157 | ip_set_timeout_set(ext_timeout(x, set), ext->timeout); |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 158 | #endif |
| 159 | |
Jozsef Kadlecsik | f48d19d | 2013-04-08 23:10:22 +0200 | [diff] [blame] | 160 | if (SET_WITH_COUNTER(set)) |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 161 | ip_set_init_counter(ext_counter(x, set), ext); |
Oliver Smith | b90cb8b | 2013-09-22 20:56:32 +0200 | [diff] [blame] | 162 | if (SET_WITH_COMMENT(set)) |
| 163 | ip_set_init_comment(ext_comment(x, set), ext); |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 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; |
Jozsef Kadlecsik | 40cd63b | 2013-09-09 14:44:29 +0200 | [diff] [blame] | 173 | void *x = get_ext(set, map, e->id); |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 174 | |
Jozsef Kadlecsik | 40cd63b | 2013-09-09 14:44:29 +0200 | [diff] [blame] | 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))) |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 181 | return -IPSET_ERR_EXIST; |
| 182 | |
| 183 | return 0; |
| 184 | } |
| 185 | |
Jozsef Kadlecsik | 3fd986b | 2013-09-25 17:44:35 +0200 | [diff] [blame] | 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 | |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 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; |
Jozsef Kadlecsik | 9330288 | 2013-10-18 11:41:55 +0200 | [diff] [blame] | 201 | u32 id, first = cb->args[IPSET_CB_ARG0]; |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 202 | |
| 203 | adt = ipset_nest_start(skb, IPSET_ATTR_ADT); |
| 204 | if (!adt) |
| 205 | return -EMSGSIZE; |
Jozsef Kadlecsik | 9330288 | 2013-10-18 11:41:55 +0200 | [diff] [blame] | 206 | for (; cb->args[IPSET_CB_ARG0] < map->elements; |
| 207 | cb->args[IPSET_CB_ARG0]++) { |
| 208 | id = cb->args[IPSET_CB_ARG0]; |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 209 | x = get_ext(set, map, id); |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 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 |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 215 | ip_set_timeout_expired(ext_timeout(x, set)))) |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 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 | } |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 225 | if (mtype_do_list(skb, map, id, set->dsize)) |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 226 | goto nla_put_failure; |
Jozsef Kadlecsik | 3fd986b | 2013-09-25 17:44:35 +0200 | [diff] [blame] | 227 | if (ip_set_put_extensions(skb, set, x, |
| 228 | mtype_is_filled((const struct mtype_elem *) x))) |
Oliver Smith | b90cb8b | 2013-09-22 20:56:32 +0200 | [diff] [blame] | 229 | goto nla_put_failure; |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 230 | ipset_nest_end(skb, nested); |
| 231 | } |
| 232 | ipset_nest_end(skb, adt); |
| 233 | |
| 234 | /* Set listing finished */ |
Jozsef Kadlecsik | 9330288 | 2013-10-18 11:41:55 +0200 | [diff] [blame] | 235 | cb->args[IPSET_CB_ARG0] = 0; |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 236 | |
| 237 | return 0; |
| 238 | |
| 239 | nla_put_failure: |
| 240 | nla_nest_cancel(skb, nested); |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 241 | if (unlikely(id == first)) { |
Jozsef Kadlecsik | 9330288 | 2013-10-18 11:41:55 +0200 | [diff] [blame] | 242 | cb->args[IPSET_CB_ARG0] = 0; |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 243 | return -EMSGSIZE; |
| 244 | } |
Jozsef Kadlecsik | 122ebbf | 2013-04-27 21:02:59 +0200 | [diff] [blame] | 245 | ipset_nest_end(skb, adt); |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 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; |
Jozsef Kadlecsik | 40cd63b | 2013-09-09 14:44:29 +0200 | [diff] [blame] | 254 | void *x; |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 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++) |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 261 | if (mtype_gc_test(id, map, set->dsize)) { |
| 262 | x = get_ext(set, map, id); |
Jozsef Kadlecsik | 40cd63b | 2013-09-09 14:44:29 +0200 | [diff] [blame] | 263 | if (ip_set_timeout_expired(ext_timeout(x, set))) { |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 264 | clear_bit(id, map->members); |
Jozsef Kadlecsik | 40cd63b | 2013-09-09 14:44:29 +0200 | [diff] [blame] | 265 | ip_set_ext_destroy(set, x); |
| 266 | } |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 267 | } |
| 268 | read_unlock_bh(&set->lock); |
| 269 | |
Jozsef Kadlecsik | ca134ce | 2013-09-07 00:10:07 +0200 | [diff] [blame] | 270 | map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ; |
Jozsef Kadlecsik | 4d73de3 | 2013-04-08 21:00:52 +0200 | [diff] [blame] | 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 */ |