ip_set_bitmap_gen.h 7.69 KB
Newer Older
1
/* SPDX-License-Identifier: GPL-2.0-only */
2
/* Copyright (C) 2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
3
4
5
6

#ifndef __IP_SET_BITMAP_IP_GEN_H
#define __IP_SET_BITMAP_IP_GEN_H

7
8
9
10
#define mtype_do_test		IPSET_TOKEN(MTYPE, _do_test)
#define mtype_gc_test		IPSET_TOKEN(MTYPE, _gc_test)
#define mtype_is_filled		IPSET_TOKEN(MTYPE, _is_filled)
#define mtype_do_add		IPSET_TOKEN(MTYPE, _do_add)
11
#define mtype_ext_cleanup	IPSET_TOKEN(MTYPE, _ext_cleanup)
12
13
14
15
16
17
18
19
20
#define mtype_do_del		IPSET_TOKEN(MTYPE, _do_del)
#define mtype_do_list		IPSET_TOKEN(MTYPE, _do_list)
#define mtype_do_head		IPSET_TOKEN(MTYPE, _do_head)
#define mtype_adt_elem		IPSET_TOKEN(MTYPE, _adt_elem)
#define mtype_add_timeout	IPSET_TOKEN(MTYPE, _add_timeout)
#define mtype_gc_init		IPSET_TOKEN(MTYPE, _gc_init)
#define mtype_kadt		IPSET_TOKEN(MTYPE, _kadt)
#define mtype_uadt		IPSET_TOKEN(MTYPE, _uadt)
#define mtype_destroy		IPSET_TOKEN(MTYPE, _destroy)
21
#define mtype_memsize		IPSET_TOKEN(MTYPE, _memsize)
22
23
24
25
26
27
28
29
30
#define mtype_flush		IPSET_TOKEN(MTYPE, _flush)
#define mtype_head		IPSET_TOKEN(MTYPE, _head)
#define mtype_same_set		IPSET_TOKEN(MTYPE, _same_set)
#define mtype_elem		IPSET_TOKEN(MTYPE, _elem)
#define mtype_test		IPSET_TOKEN(MTYPE, _test)
#define mtype_add		IPSET_TOKEN(MTYPE, _add)
#define mtype_del		IPSET_TOKEN(MTYPE, _del)
#define mtype_list		IPSET_TOKEN(MTYPE, _list)
#define mtype_gc		IPSET_TOKEN(MTYPE, _gc)
31
32
#define mtype			MTYPE

33
#define get_ext(set, map, id)	((map)->extensions + ((set)->dsize * (id)))
34
35

static void
36
mtype_gc_init(struct ip_set *set, void (*gc)(struct timer_list *t))
37
38
39
{
	struct mtype *map = set->data;

40
	timer_setup(&map->gc, gc, 0);
41
	mod_timer(&map->gc, jiffies + IPSET_GC_PERIOD(set->timeout) * HZ);
42
43
}

44
45
46
47
48
49
50
51
52
53
54
static void
mtype_ext_cleanup(struct ip_set *set)
{
	struct mtype *map = set->data;
	u32 id;

	for (id = 0; id < map->elements; id++)
		if (test_bit(id, map->members))
			ip_set_ext_destroy(set, get_ext(set, map, id));
}

55
56
57
58
59
60
61
62
static void
mtype_destroy(struct ip_set *set)
{
	struct mtype *map = set->data;

	if (SET_WITH_TIMEOUT(set))
		del_timer_sync(&map->gc);

63
64
	if (set->dsize && set->extensions & IPSET_EXT_DESTROY)
		mtype_ext_cleanup(set);
65
	ip_set_free(map->members);
66
	ip_set_free(map);
67
68
69
70
71
72
73
74
75

	set->data = NULL;
}

static void
mtype_flush(struct ip_set *set)
{
	struct mtype *map = set->data;

76
77
	if (set->extensions & IPSET_EXT_DESTROY)
		mtype_ext_cleanup(set);
78
	bitmap_zero(map->members, map->elements);
79
	set->elements = 0;
80
	set->ext_size = 0;
81
82
}

83
84
85
86
87
88
89
90
/* Calculate the actual memory size of the set data */
static size_t
mtype_memsize(const struct mtype *map, size_t dsize)
{
	return sizeof(*map) + map->memsize +
	       map->elements * dsize;
}

91
92
93
94
95
static int
mtype_head(struct ip_set *set, struct sk_buff *skb)
{
	const struct mtype *map = set->data;
	struct nlattr *nested;
96
	size_t memsize = mtype_memsize(map, set->dsize) + set->ext_size;
97

98
	nested = nla_nest_start(skb, IPSET_ATTR_DATA);
99
100
101
	if (!nested)
		goto nla_put_failure;
	if (mtype_do_head(skb, map) ||
102
	    nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref)) ||
103
104
	    nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)) ||
	    nla_put_net32(skb, IPSET_ATTR_ELEMENTS, htonl(set->elements)))
105
106
		goto nla_put_failure;
	if (unlikely(ip_set_put_flags(skb, set)))
107
		goto nla_put_failure;
108
	nla_nest_end(skb, nested);
109
110
111
112
113
114
115
116
117
118
119
120

	return 0;
nla_put_failure:
	return -EMSGSIZE;
}

static int
mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
	   struct ip_set_ext *mext, u32 flags)
{
	struct mtype *map = set->data;
	const struct mtype_adt_elem *e = value;
121
122
	void *x = get_ext(set, map, e->id);
	int ret = mtype_do_test(e, map, set->dsize);
123
124
125

	if (ret <= 0)
		return ret;
126
	return ip_set_match_extensions(set, ext, mext, flags, x);
127
128
129
130
131
132
133
134
}

static int
mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
	  struct ip_set_ext *mext, u32 flags)
{
	struct mtype *map = set->data;
	const struct mtype_adt_elem *e = value;
135
136
	void *x = get_ext(set, map, e->id);
	int ret = mtype_do_add(e, map, flags, set->dsize);
137
138
139

	if (ret == IPSET_ADD_FAILED) {
		if (SET_WITH_TIMEOUT(set) &&
140
		    ip_set_timeout_expired(ext_timeout(x, set))) {
141
			set->elements--;
142
			ret = 0;
143
144
		} else if (!(flags & IPSET_FLAG_EXIST)) {
			set_bit(e->id, map->members);
145
			return -IPSET_ERR_EXIST;
146
		}
147
148
		/* Element is re-added, cleanup extensions */
		ip_set_ext_destroy(set, x);
149
	}
150
151
	if (ret > 0)
		set->elements--;
152
153
154

	if (SET_WITH_TIMEOUT(set))
#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), ext->timeout);
158
159
#endif

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
165
	if (SET_WITH_SKBINFO(set))
		ip_set_init_skbinfo(ext_skbinfo(x, set), ext);
166
167
168

	/* Activate element */
	set_bit(e->id, map->members);
169
	set->elements++;
170

171
172
173
174
175
176
177
178
179
	return 0;
}

static int
mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
	  struct ip_set_ext *mext, u32 flags)
{
	struct mtype *map = set->data;
	const struct mtype_adt_elem *e = value;
180
	void *x = get_ext(set, map, e->id);
181

182
183
184
185
	if (mtype_do_del(e, map))
		return -IPSET_ERR_EXIST;

	ip_set_ext_destroy(set, x);
186
	set->elements--;
187
188
	if (SET_WITH_TIMEOUT(set) &&
	    ip_set_timeout_expired(ext_timeout(x, set)))
189
190
191
192
193
		return -IPSET_ERR_EXIST;

	return 0;
}

194
#ifndef IP_SET_BITMAP_STORED_TIMEOUT
195
static bool
196
197
198
199
200
201
mtype_is_filled(const struct mtype_elem *x)
{
	return true;
}
#endif

202
203
204
205
206
207
208
static int
mtype_list(const struct ip_set *set,
	   struct sk_buff *skb, struct netlink_callback *cb)
{
	struct mtype *map = set->data;
	struct nlattr *adt, *nested;
	void *x;
209
	u32 id, first = cb->args[IPSET_CB_ARG0];
210
	int ret = 0;
211

212
	adt = nla_nest_start(skb, IPSET_ATTR_ADT);
213
214
	if (!adt)
		return -EMSGSIZE;
215
216
	/* Extensions may be replaced */
	rcu_read_lock();
217
218
	for (; cb->args[IPSET_CB_ARG0] < map->elements;
	     cb->args[IPSET_CB_ARG0]++) {
219
		cond_resched_rcu();
220
		id = cb->args[IPSET_CB_ARG0];
221
		x = get_ext(set, map, id);
222
223
224
		if (!test_bit(id, map->members) ||
		    (SET_WITH_TIMEOUT(set) &&
#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, IPSET_ATTR_DATA);
230
231
232
		if (!nested) {
			if (id == first) {
				nla_nest_cancel(skb, adt);
233
234
235
236
237
				ret = -EMSGSIZE;
				goto out;
			}

			goto nla_put_failure;
238
		}
239
		if (mtype_do_list(skb, map, id, set->dsize))
240
			goto nla_put_failure;
241
		if (ip_set_put_extensions(skb, set, x, mtype_is_filled(x)))
242
			goto nla_put_failure;
243
		nla_nest_end(skb, nested);
244
	}
245
	nla_nest_end(skb, adt);
246
247

	/* Set listing finished */
248
	cb->args[IPSET_CB_ARG0] = 0;
249

250
	goto out;
251
252
253
254

nla_put_failure:
	nla_nest_cancel(skb, nested);
	if (unlikely(id == first)) {
255
		cb->args[IPSET_CB_ARG0] = 0;
256
		ret = -EMSGSIZE;
257
	}
258
	nla_nest_end(skb, adt);
259
260
261
out:
	rcu_read_unlock();
	return ret;
262
263
264
}

static void
265
mtype_gc(struct timer_list *t)
266
{
267
268
	struct mtype *map = from_timer(map, t, gc);
	struct ip_set *set = map->set;
269
	void *x;
270
271
272
	u32 id;

	/* We run parallel with other readers (test element)
273
274
	 * but adding/deleting new entries is locked out
	 */
275
	spin_lock_bh(&set->lock);
276
	for (id = 0; id < map->elements; id++)
277
278
		if (mtype_gc_test(id, map, set->dsize)) {
			x = get_ext(set, map, id);
279
			if (ip_set_timeout_expired(ext_timeout(x, set))) {
280
				clear_bit(id, map->members);
281
				ip_set_ext_destroy(set, x);
282
				set->elements--;
283
			}
284
		}
285
	spin_unlock_bh(&set->lock);
286

287
	map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
	add_timer(&map->gc);
}

static const struct ip_set_type_variant mtype = {
	.kadt	= mtype_kadt,
	.uadt	= mtype_uadt,
	.adt	= {
		[IPSET_ADD] = mtype_add,
		[IPSET_DEL] = mtype_del,
		[IPSET_TEST] = mtype_test,
	},
	.destroy = mtype_destroy,
	.flush	= mtype_flush,
	.head	= mtype_head,
	.list	= mtype_list,
	.same_set = mtype_same_set,
};

#endif /* __IP_SET_BITMAP_IP_GEN_H */