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 44static void 45mtype_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 56static void 57mtype_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 72static void 73mtype_flush(struct ip_set *set) 74{ 75 struct mtype *map = set->data; 76 77 memset(map->members, 0, map->memsize); 78} 79 80static int 81mtype_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; 104nla_put_failure: 105 return -EMSGSIZE; 106} 107 108static int 109mtype_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 127static int 128mtype_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 156static int 157mtype_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 172static int 173mtype_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 229nla_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 239static void 240mtype_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 262static 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 */ 278