Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 40cd63b

Browse files
author
Jozsef Kadlecsik
committed
netfilter: ipset: Support extensions which need a per data destroy function
Signed-off-by: Jozsef Kadlecsik <[email protected]>
1 parent 03c8b23 commit 40cd63b

File tree

4 files changed

+107
-43
lines changed

4 files changed

+107
-43
lines changed

include/linux/netfilter/ipset/ip_set.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,13 @@ enum ip_set_feature {
4949

5050
/* Set extensions */
5151
enum ip_set_extension {
52-
IPSET_EXT_NONE = 0,
53-
IPSET_EXT_BIT_TIMEOUT = 1,
52+
IPSET_EXT_BIT_TIMEOUT = 0,
5453
IPSET_EXT_TIMEOUT = (1 << IPSET_EXT_BIT_TIMEOUT),
55-
IPSET_EXT_BIT_COUNTER = 2,
54+
IPSET_EXT_BIT_COUNTER = 1,
5655
IPSET_EXT_COUNTER = (1 << IPSET_EXT_BIT_COUNTER),
56+
/* Mark set with an extension which needs to call destroy */
57+
IPSET_EXT_BIT_DESTROY = 7,
58+
IPSET_EXT_DESTROY = (1 << IPSET_EXT_BIT_DESTROY),
5759
};
5860

5961
#define SET_WITH_TIMEOUT(s) ((s)->extensions & IPSET_EXT_TIMEOUT)
@@ -68,6 +70,8 @@ enum ip_set_ext_id {
6870

6971
/* Extension type */
7072
struct ip_set_ext_type {
73+
/* Destroy extension private data (can be NULL) */
74+
void (*destroy)(void *ext);
7175
enum ip_set_extension type;
7276
enum ipset_cadt_flags flag;
7377
/* Size and minimal alignment */
@@ -88,13 +92,21 @@ struct ip_set_counter {
8892
atomic64_t packets;
8993
};
9094

95+
struct ip_set;
96+
97+
static inline void
98+
ip_set_ext_destroy(struct ip_set *set, void *data)
99+
{
100+
/* Check that the extension is enabled for the set and
101+
* call it's destroy function for its extension part in data.
102+
*/
103+
}
104+
91105
#define ext_timeout(e, s) \
92106
(unsigned long *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_TIMEOUT])
93107
#define ext_counter(e, s) \
94108
(struct ip_set_counter *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COUNTER])
95109

96-
struct ip_set;
97-
98110
typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
99111
const struct ip_set_ext *ext,
100112
struct ip_set_ext *mext, u32 cmdflags);

net/netfilter/ipset/ip_set_bitmap_gen.h

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#define mtype_gc_test IPSET_TOKEN(MTYPE, _gc_test)
1313
#define mtype_is_filled IPSET_TOKEN(MTYPE, _is_filled)
1414
#define mtype_do_add IPSET_TOKEN(MTYPE, _do_add)
15+
#define mtype_ext_cleanup IPSET_TOKEN(MTYPE, _ext_cleanup)
1516
#define mtype_do_del IPSET_TOKEN(MTYPE, _do_del)
1617
#define mtype_do_list IPSET_TOKEN(MTYPE, _do_list)
1718
#define mtype_do_head IPSET_TOKEN(MTYPE, _do_head)
@@ -46,6 +47,17 @@ mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
4647
add_timer(&map->gc);
4748
}
4849

50+
static void
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+
4961
static void
5062
mtype_destroy(struct ip_set *set)
5163
{
@@ -55,8 +67,11 @@ mtype_destroy(struct ip_set *set)
5567
del_timer_sync(&map->gc);
5668

5769
ip_set_free(map->members);
58-
if (set->dsize)
70+
if (set->dsize) {
71+
if (set->extensions & IPSET_EXT_DESTROY)
72+
mtype_ext_cleanup(set);
5973
ip_set_free(map->extensions);
74+
}
6075
kfree(map);
6176

6277
set->data = NULL;
@@ -67,6 +82,8 @@ mtype_flush(struct ip_set *set)
6782
{
6883
struct mtype *map = set->data;
6984

85+
if (set->extensions & IPSET_EXT_DESTROY)
86+
mtype_ext_cleanup(set);
7087
memset(map->members, 0, map->memsize);
7188
}
7289

@@ -132,6 +149,8 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
132149
ret = 0;
133150
else if (!(flags & IPSET_FLAG_EXIST))
134151
return -IPSET_ERR_EXIST;
152+
/* Element is re-added, cleanup extensions */
153+
ip_set_ext_destroy(set, x);
135154
}
136155

137156
if (SET_WITH_TIMEOUT(set))
@@ -152,11 +171,14 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
152171
{
153172
struct mtype *map = set->data;
154173
const struct mtype_adt_elem *e = value;
155-
const void *x = get_ext(set, map, e->id);
174+
void *x = get_ext(set, map, e->id);
156175

157-
if (mtype_do_del(e, map) ||
158-
(SET_WITH_TIMEOUT(set) &&
159-
ip_set_timeout_expired(ext_timeout(x, set))))
176+
if (mtype_do_del(e, map))
177+
return -IPSET_ERR_EXIST;
178+
179+
ip_set_ext_destroy(set, x);
180+
if (SET_WITH_TIMEOUT(set) &&
181+
ip_set_timeout_expired(ext_timeout(x, set)))
160182
return -IPSET_ERR_EXIST;
161183

162184
return 0;
@@ -235,7 +257,7 @@ mtype_gc(unsigned long ul_set)
235257
{
236258
struct ip_set *set = (struct ip_set *) ul_set;
237259
struct mtype *map = set->data;
238-
const void *x;
260+
void *x;
239261
u32 id;
240262

241263
/* We run parallel with other readers (test element)
@@ -244,8 +266,10 @@ mtype_gc(unsigned long ul_set)
244266
for (id = 0; id < map->elements; id++)
245267
if (mtype_gc_test(id, map, set->dsize)) {
246268
x = get_ext(set, map, id);
247-
if (ip_set_timeout_expired(ext_timeout(x, set)))
269+
if (ip_set_timeout_expired(ext_timeout(x, set))) {
248270
clear_bit(id, map->members);
271+
ip_set_ext_destroy(set, x);
272+
}
249273
}
250274
read_unlock_bh(&set->lock);
251275

net/netfilter/ipset/ip_set_hash_gen.h

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -117,23 +117,6 @@ htable_bits(u32 hashsize)
117117
return bits;
118118
}
119119

120-
/* Destroy the hashtable part of the set */
121-
static void
122-
ahash_destroy(struct htable *t)
123-
{
124-
struct hbucket *n;
125-
u32 i;
126-
127-
for (i = 0; i < jhash_size(t->htable_bits); i++) {
128-
n = hbucket(t, i);
129-
if (n->size)
130-
/* FIXME: use slab cache */
131-
kfree(n->value);
132-
}
133-
134-
ip_set_free(t);
135-
}
136-
137120
static int
138121
hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
139122
{
@@ -192,6 +175,8 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
192175
#undef mtype_data_next
193176
#undef mtype_elem
194177

178+
#undef mtype_ahash_destroy
179+
#undef mtype_ext_cleanup
195180
#undef mtype_add_cidr
196181
#undef mtype_del_cidr
197182
#undef mtype_ahash_memsize
@@ -230,6 +215,8 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
230215
#define mtype_data_list IPSET_TOKEN(MTYPE, _data_list)
231216
#define mtype_data_next IPSET_TOKEN(MTYPE, _data_next)
232217
#define mtype_elem IPSET_TOKEN(MTYPE, _elem)
218+
#define mtype_ahash_destroy IPSET_TOKEN(MTYPE, _ahash_destroy)
219+
#define mtype_ext_cleanup IPSET_TOKEN(MTYPE, _ext_cleanup)
233220
#define mtype_add_cidr IPSET_TOKEN(MTYPE, _add_cidr)
234221
#define mtype_del_cidr IPSET_TOKEN(MTYPE, _del_cidr)
235222
#define mtype_ahash_memsize IPSET_TOKEN(MTYPE, _ahash_memsize)
@@ -359,6 +346,19 @@ mtype_ahash_memsize(const struct htype *h, const struct htable *t,
359346
return memsize;
360347
}
361348

349+
/* Get the ith element from the array block n */
350+
#define ahash_data(n, i, dsize) \
351+
((struct mtype_elem *)((n)->value + ((i) * (dsize))))
352+
353+
static void
354+
mtype_ext_cleanup(struct ip_set *set, struct hbucket *n)
355+
{
356+
int i;
357+
358+
for (i = 0; i < n->pos; i++)
359+
ip_set_ext_destroy(set, ahash_data(n, i, set->dsize));
360+
}
361+
362362
/* Flush a hash type of set: destroy all elements */
363363
static void
364364
mtype_flush(struct ip_set *set)
@@ -372,6 +372,8 @@ mtype_flush(struct ip_set *set)
372372
for (i = 0; i < jhash_size(t->htable_bits); i++) {
373373
n = hbucket(t, i);
374374
if (n->size) {
375+
if (set->extensions & IPSET_EXT_DESTROY)
376+
mtype_ext_cleanup(set, n);
375377
n->size = n->pos = 0;
376378
/* FIXME: use slab cache */
377379
kfree(n->value);
@@ -383,6 +385,26 @@ mtype_flush(struct ip_set *set)
383385
h->elements = 0;
384386
}
385387

388+
/* Destroy the hashtable part of the set */
389+
static void
390+
mtype_ahash_destroy(struct ip_set *set, struct htable *t)
391+
{
392+
struct hbucket *n;
393+
u32 i;
394+
395+
for (i = 0; i < jhash_size(t->htable_bits); i++) {
396+
n = hbucket(t, i);
397+
if (n->size) {
398+
if (set->extensions & IPSET_EXT_DESTROY)
399+
mtype_ext_cleanup(set, n);
400+
/* FIXME: use slab cache */
401+
kfree(n->value);
402+
}
403+
}
404+
405+
ip_set_free(t);
406+
}
407+
386408
/* Destroy a hash type of set */
387409
static void
388410
mtype_destroy(struct ip_set *set)
@@ -392,7 +414,7 @@ mtype_destroy(struct ip_set *set)
392414
if (set->extensions & IPSET_EXT_TIMEOUT)
393415
del_timer_sync(&h->gc);
394416

395-
ahash_destroy(rcu_dereference_bh_nfnl(h->table));
417+
mtype_ahash_destroy(set, rcu_dereference_bh_nfnl(h->table));
396418
#ifdef IP_SET_HASH_WITH_RBTREE
397419
rbtree_destroy(&h->rbtree);
398420
#endif
@@ -430,10 +452,6 @@ mtype_same_set(const struct ip_set *a, const struct ip_set *b)
430452
a->extensions == b->extensions;
431453
}
432454

433-
/* Get the ith element from the array block n */
434-
#define ahash_data(n, i, dsize) \
435-
((struct mtype_elem *)((n)->value + ((i) * (dsize))))
436-
437455
/* Delete expired elements from the hashtable */
438456
static void
439457
mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
@@ -456,6 +474,7 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
456474
mtype_del_cidr(h, CIDR(data->cidr),
457475
nets_length, 0);
458476
#endif
477+
ip_set_ext_destroy(set, data);
459478
if (j != n->pos - 1)
460479
/* Not last one */
461480
memcpy(data,
@@ -557,7 +576,7 @@ mtype_resize(struct ip_set *set, bool retried)
557576
mtype_data_reset_flags(data, &flags);
558577
#endif
559578
read_unlock_bh(&set->lock);
560-
ahash_destroy(t);
579+
mtype_ahash_destroy(set, t);
561580
if (ret == -EAGAIN)
562581
goto retry;
563582
return ret;
@@ -578,7 +597,7 @@ mtype_resize(struct ip_set *set, bool retried)
578597

579598
pr_debug("set %s resized from %u (%p) to %u (%p)\n", set->name,
580599
orig->htable_bits, orig, t->htable_bits, t);
581-
ahash_destroy(orig);
600+
mtype_ahash_destroy(set, orig);
582601

583602
return 0;
584603
}
@@ -642,6 +661,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
642661
mtype_del_cidr(h, CIDR(data->cidr), NLEN(set->family), 0);
643662
mtype_add_cidr(h, CIDR(d->cidr), NLEN(set->family), 0);
644663
#endif
664+
ip_set_ext_destroy(set, data);
645665
} else {
646666
/* Use/create a new slot */
647667
TUNE_AHASH_MAX(h, multi);
@@ -707,6 +727,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
707727
#ifdef IP_SET_HASH_WITH_NETS
708728
mtype_del_cidr(h, CIDR(d->cidr), NLEN(set->family), 0);
709729
#endif
730+
ip_set_ext_destroy(set, data);
710731
if (n->pos + AHASH_INIT_SIZE < n->size) {
711732
void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
712733
* set->dsize,
@@ -1033,7 +1054,7 @@ IPSET_TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags)
10331054
rcu_assign_pointer(h->table, t);
10341055

10351056
set->data = h;
1036-
if (set->family == NFPROTO_IPV4) {
1057+
if (set->family == NFPROTO_IPV4) {
10371058
set->variant = &IPSET_TOKEN(HTYPE, 4_variant);
10381059
set->dsize = ip_set_elem_len(set, tb,
10391060
sizeof(struct IPSET_TOKEN(HTYPE, 4_elem)));

net/netfilter/ipset/ip_set_list_set.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,16 +168,19 @@ list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d,
168168
struct set_elem *e = list_set_elem(set, map, i);
169169

170170
if (e->id != IPSET_INVALID_ID) {
171-
if (i == map->size - 1)
171+
if (i == map->size - 1) {
172172
/* Last element replaced: e.g. add new,before,last */
173173
ip_set_put_byindex(e->id);
174-
else {
174+
ip_set_ext_destroy(set, e);
175+
} else {
175176
struct set_elem *x = list_set_elem(set, map,
176177
map->size - 1);
177178

178179
/* Last element pushed off */
179-
if (x->id != IPSET_INVALID_ID)
180+
if (x->id != IPSET_INVALID_ID) {
180181
ip_set_put_byindex(x->id);
182+
ip_set_ext_destroy(set, x);
183+
}
181184
memmove(list_set_elem(set, map, i + 1), e,
182185
set->dsize * (map->size - (i + 1)));
183186
}
@@ -198,6 +201,7 @@ list_set_del(struct ip_set *set, u32 i)
198201
struct set_elem *e = list_set_elem(set, map, i);
199202

200203
ip_set_put_byindex(e->id);
204+
ip_set_ext_destroy(set, e);
201205

202206
if (i < map->size - 1)
203207
memmove(e, list_set_elem(set, map, i + 1),
@@ -266,14 +270,14 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
266270
bool flag_exist = flags & IPSET_FLAG_EXIST;
267271
u32 i, ret = 0;
268272

273+
if (SET_WITH_TIMEOUT(set))
274+
set_cleanup_entries(set);
275+
269276
/* Check already added element */
270277
for (i = 0; i < map->size; i++) {
271278
e = list_set_elem(set, map, i);
272279
if (e->id == IPSET_INVALID_ID)
273280
goto insert;
274-
else if (SET_WITH_TIMEOUT(set) &&
275-
ip_set_timeout_expired(ext_timeout(e, set)))
276-
continue;
277281
else if (e->id != d->id)
278282
continue;
279283

@@ -286,6 +290,8 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
286290
/* Can't re-add */
287291
return -IPSET_ERR_EXIST;
288292
/* Update extensions */
293+
ip_set_ext_destroy(set, e);
294+
289295
if (SET_WITH_TIMEOUT(set))
290296
ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
291297
if (SET_WITH_COUNTER(set))
@@ -423,6 +429,7 @@ list_set_flush(struct ip_set *set)
423429
e = list_set_elem(set, map, i);
424430
if (e->id != IPSET_INVALID_ID) {
425431
ip_set_put_byindex(e->id);
432+
ip_set_ext_destroy(set, e);
426433
e->id = IPSET_INVALID_ID;
427434
}
428435
}

0 commit comments

Comments
 (0)