aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2013-04-08 15:05:44 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2013-04-29 14:08:56 -0400
commit1feab10d7e6ddb5e13d6a4bd93a1b877390262ec (patch)
tree7da5d5aba00e9bd207de7b8c493c589c826f8604 /net
parentb0da3905bb1eb0969470f57b18c978f902475c78 (diff)
netfilter: ipset: Unified hash type generation
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/ipset/ip_set_hash_gen.h1039
1 files changed, 1039 insertions, 0 deletions
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
new file mode 100644
index 000000000000..2ba7d4e76cde
--- /dev/null
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -0,0 +1,1039 @@
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_HASH_GEN_H
9#define _IP_SET_HASH_GEN_H
10
11#include <linux/rcupdate.h>
12#include <linux/jhash.h>
13#include <linux/netfilter/ipset/ip_set_timeout.h>
14#ifndef rcu_dereference_bh
15#define rcu_dereference_bh(p) rcu_dereference(p)
16#endif
17
18#define CONCAT(a, b) a##b
19#define TOKEN(a, b) CONCAT(a, b)
20
21/* Hashing which uses arrays to resolve clashing. The hash table is resized
22 * (doubled) when searching becomes too long.
23 * Internally jhash is used with the assumption that the size of the
24 * stored data is a multiple of sizeof(u32). If storage supports timeout,
25 * the timeout field must be the last one in the data structure - that field
26 * is ignored when computing the hash key.
27 *
28 * Readers and resizing
29 *
30 * Resizing can be triggered by userspace command only, and those
31 * are serialized by the nfnl mutex. During resizing the set is
32 * read-locked, so the only possible concurrent operations are
33 * the kernel side readers. Those must be protected by proper RCU locking.
34 */
35
36/* Number of elements to store in an initial array block */
37#define AHASH_INIT_SIZE 4
38/* Max number of elements to store in an array block */
39#define AHASH_MAX_SIZE (3*AHASH_INIT_SIZE)
40
41/* Max number of elements can be tuned */
42#ifdef IP_SET_HASH_WITH_MULTI
43#define AHASH_MAX(h) ((h)->ahash_max)
44
45static inline u8
46tune_ahash_max(u8 curr, u32 multi)
47{
48 u32 n;
49
50 if (multi < curr)
51 return curr;
52
53 n = curr + AHASH_INIT_SIZE;
54 /* Currently, at listing one hash bucket must fit into a message.
55 * Therefore we have a hard limit here.
56 */
57 return n > curr && n <= 64 ? n : curr;
58}
59#define TUNE_AHASH_MAX(h, multi) \
60 ((h)->ahash_max = tune_ahash_max((h)->ahash_max, multi))
61#else
62#define AHASH_MAX(h) AHASH_MAX_SIZE
63#define TUNE_AHASH_MAX(h, multi)
64#endif
65
66/* A hash bucket */
67struct hbucket {
68 void *value; /* the array of the values */
69 u8 size; /* size of the array */
70 u8 pos; /* position of the first free entry */
71};
72
73/* The hash table: the table size stored here in order to make resizing easy */
74struct htable {
75 u8 htable_bits; /* size of hash table == 2^htable_bits */
76 struct hbucket bucket[0]; /* hashtable buckets */
77};
78
79#define hbucket(h, i) (&((h)->bucket[i]))
80
81/* Book-keeping of the prefixes added to the set */
82struct net_prefixes {
83 u8 cidr; /* the different cidr values in the set */
84 u32 nets; /* number of elements per cidr */
85};
86
87/* Compute the hash table size */
88static size_t
89htable_size(u8 hbits)
90{
91 size_t hsize;
92
93 /* We must fit both into u32 in jhash and size_t */
94 if (hbits > 31)
95 return 0;
96 hsize = jhash_size(hbits);
97 if ((((size_t)-1) - sizeof(struct htable))/sizeof(struct hbucket)
98 < hsize)
99 return 0;
100
101 return hsize * sizeof(struct hbucket) + sizeof(struct htable);
102}
103
104/* Compute htable_bits from the user input parameter hashsize */
105static u8
106htable_bits(u32 hashsize)
107{
108 /* Assume that hashsize == 2^htable_bits */
109 u8 bits = fls(hashsize - 1);
110 if (jhash_size(bits) != hashsize)
111 /* Round up to the first 2^n value */
112 bits = fls(hashsize);
113
114 return bits;
115}
116
117/* Destroy the hashtable part of the set */
118static void
119ahash_destroy(struct htable *t)
120{
121 struct hbucket *n;
122 u32 i;
123
124 for (i = 0; i < jhash_size(t->htable_bits); i++) {
125 n = hbucket(t, i);
126 if (n->size)
127 /* FIXME: use slab cache */
128 kfree(n->value);
129 }
130
131 ip_set_free(t);
132}
133
134static int
135hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
136{
137 if (n->pos >= n->size) {
138 void *tmp;
139
140 if (n->size >= ahash_max)
141 /* Trigger rehashing */
142 return -EAGAIN;
143
144 tmp = kzalloc((n->size + AHASH_INIT_SIZE) * dsize,
145 GFP_ATOMIC);
146 if (!tmp)
147 return -ENOMEM;
148 if (n->size) {
149 memcpy(tmp, n->value, n->size * dsize);
150 kfree(n->value);
151 }
152 n->value = tmp;
153 n->size += AHASH_INIT_SIZE;
154 }
155 return 0;
156}
157
158#ifdef IP_SET_HASH_WITH_NETS
159#ifdef IP_SET_HASH_WITH_NETS_PACKED
160/* When cidr is packed with nomatch, cidr - 1 is stored in the entry */
161#define CIDR(cidr) (cidr + 1)
162#else
163#define CIDR(cidr) (cidr)
164#endif
165
166#define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128)
167
168#ifdef IP_SET_HASH_WITH_MULTI
169#define NETS_LENGTH(family) (SET_HOST_MASK(family) + 1)
170#else
171#define NETS_LENGTH(family) SET_HOST_MASK(family)
172#endif
173
174#else
175#define NETS_LENGTH(family) 0
176#endif /* IP_SET_HASH_WITH_NETS */
177
178#define ext_timeout(e, h) \
179(unsigned long *)(((void *)(e)) + (h)->offset[IPSET_OFFSET_TIMEOUT])
180
181#endif /* _IP_SET_HASH_GEN_H */
182
183/* Family dependent templates */
184
185#undef ahash_data
186#undef mtype_data_equal
187#undef mtype_do_data_match
188#undef mtype_data_set_flags
189#undef mtype_data_reset_flags
190#undef mtype_data_netmask
191#undef mtype_data_list
192#undef mtype_data_next
193#undef mtype_elem
194
195#undef mtype_add_cidr
196#undef mtype_del_cidr
197#undef mtype_ahash_memsize
198#undef mtype_flush
199#undef mtype_destroy
200#undef mtype_gc_init
201#undef mtype_same_set
202#undef mtype_kadt
203#undef mtype_uadt
204#undef mtype
205
206#undef mtype_add
207#undef mtype_del
208#undef mtype_test_cidrs
209#undef mtype_test
210#undef mtype_expire
211#undef mtype_resize
212#undef mtype_head
213#undef mtype_list
214#undef mtype_gc
215#undef mtype_gc_init
216#undef mtype_variant
217#undef mtype_data_match
218
219#undef HKEY
220
221#define mtype_data_equal TOKEN(MTYPE, _data_equal)
222#ifdef IP_SET_HASH_WITH_NETS
223#define mtype_do_data_match TOKEN(MTYPE, _do_data_match)
224#else
225#define mtype_do_data_match(d) 1
226#endif
227#define mtype_data_set_flags TOKEN(MTYPE, _data_set_flags)
228#define mtype_data_reset_flags TOKEN(MTYPE, _data_reset_flags)
229#define mtype_data_netmask TOKEN(MTYPE, _data_netmask)
230#define mtype_data_list TOKEN(MTYPE, _data_list)
231#define mtype_data_next TOKEN(MTYPE, _data_next)
232#define mtype_elem TOKEN(MTYPE, _elem)
233#define mtype_add_cidr TOKEN(MTYPE, _add_cidr)
234#define mtype_del_cidr TOKEN(MTYPE, _del_cidr)
235#define mtype_ahash_memsize TOKEN(MTYPE, _ahash_memsize)
236#define mtype_flush TOKEN(MTYPE, _flush)
237#define mtype_destroy TOKEN(MTYPE, _destroy)
238#define mtype_gc_init TOKEN(MTYPE, _gc_init)
239#define mtype_same_set TOKEN(MTYPE, _same_set)
240#define mtype_kadt TOKEN(MTYPE, _kadt)
241#define mtype_uadt TOKEN(MTYPE, _uadt)
242#define mtype MTYPE
243
244#define mtype_elem TOKEN(MTYPE, _elem)
245#define mtype_add TOKEN(MTYPE, _add)
246#define mtype_del TOKEN(MTYPE, _del)
247#define mtype_test_cidrs TOKEN(MTYPE, _test_cidrs)
248#define mtype_test TOKEN(MTYPE, _test)
249#define mtype_expire TOKEN(MTYPE, _expire)
250#define mtype_resize TOKEN(MTYPE, _resize)
251#define mtype_head TOKEN(MTYPE, _head)
252#define mtype_list TOKEN(MTYPE, _list)
253#define mtype_gc TOKEN(MTYPE, _gc)
254#define mtype_variant TOKEN(MTYPE, _variant)
255#define mtype_data_match TOKEN(MTYPE, _data_match)
256
257#ifndef HKEY_DATALEN
258#define HKEY_DATALEN sizeof(struct mtype_elem)
259#endif
260
261#define HKEY(data, initval, htable_bits) \
262(jhash2((u32 *)(data), HKEY_DATALEN/sizeof(u32), initval) \
263 & jhash_mask(htable_bits))
264
265#ifndef htype
266#define htype HTYPE
267
268/* The generic hash structure */
269struct htype {
270 struct htable *table; /* the hash table */
271 u32 maxelem; /* max elements in the hash */
272 u32 elements; /* current element (vs timeout) */
273 u32 initval; /* random jhash init value */
274 u32 timeout; /* timeout value, if enabled */
275 size_t dsize; /* data struct size */
276 size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
277 struct timer_list gc; /* garbage collection when timeout enabled */
278 struct mtype_elem next; /* temporary storage for uadd */
279#ifdef IP_SET_HASH_WITH_MULTI
280 u8 ahash_max; /* max elements in an array block */
281#endif
282#ifdef IP_SET_HASH_WITH_NETMASK
283 u8 netmask; /* netmask value for subnets to store */
284#endif
285#ifdef IP_SET_HASH_WITH_RBTREE
286 struct rb_root rbtree;
287#endif
288#ifdef IP_SET_HASH_WITH_NETS
289 struct net_prefixes nets[0]; /* book-keeping of prefixes */
290#endif
291};
292#endif
293
294#ifdef IP_SET_HASH_WITH_NETS
295/* Network cidr size book keeping when the hash stores different
296 * sized networks */
297static void
298mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
299{
300 int i, j;
301
302 /* Add in increasing prefix order, so larger cidr first */
303 for (i = 0, j = -1; i < nets_length && h->nets[i].nets; i++) {
304 if (j != -1)
305 continue;
306 else if (h->nets[i].cidr < cidr)
307 j = i;
308 else if (h->nets[i].cidr == cidr) {
309 h->nets[i].nets++;
310 return;
311 }
312 }
313 if (j != -1) {
314 for (; i > j; i--) {
315 h->nets[i].cidr = h->nets[i - 1].cidr;
316 h->nets[i].nets = h->nets[i - 1].nets;
317 }
318 }
319 h->nets[i].cidr = cidr;
320 h->nets[i].nets = 1;
321}
322
323static void
324mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length)
325{
326 u8 i, j;
327
328 for (i = 0; i < nets_length - 1 && h->nets[i].cidr != cidr; i++)
329 ;
330 h->nets[i].nets--;
331
332 if (h->nets[i].nets != 0)
333 return;
334
335 for (j = i; j < nets_length - 1 && h->nets[j].nets; j++) {
336 h->nets[j].cidr = h->nets[j + 1].cidr;
337 h->nets[j].nets = h->nets[j + 1].nets;
338 }
339}
340#endif
341
342/* Calculate the actual memory size of the set data */
343static size_t
344mtype_ahash_memsize(const struct htype *h, u8 nets_length)
345{
346 u32 i;
347 struct htable *t = h->table;
348 size_t memsize = sizeof(*h)
349 + sizeof(*t)
350#ifdef IP_SET_HASH_WITH_NETS
351 + sizeof(struct net_prefixes) * nets_length
352#endif
353 + jhash_size(t->htable_bits) * sizeof(struct hbucket);
354
355 for (i = 0; i < jhash_size(t->htable_bits); i++)
356 memsize += t->bucket[i].size * h->dsize;
357
358 return memsize;
359}
360
361/* Flush a hash type of set: destroy all elements */
362static void
363mtype_flush(struct ip_set *set)
364{
365 struct htype *h = set->data;
366 struct htable *t = h->table;
367 struct hbucket *n;
368 u32 i;
369
370 for (i = 0; i < jhash_size(t->htable_bits); i++) {
371 n = hbucket(t, i);
372 if (n->size) {
373 n->size = n->pos = 0;
374 /* FIXME: use slab cache */
375 kfree(n->value);
376 }
377 }
378#ifdef IP_SET_HASH_WITH_NETS
379 memset(h->nets, 0, sizeof(struct net_prefixes)
380 * NETS_LENGTH(set->family));
381#endif
382 h->elements = 0;
383}
384
385/* Destroy a hash type of set */
386static void
387mtype_destroy(struct ip_set *set)
388{
389 struct htype *h = set->data;
390
391 if (set->extensions & IPSET_EXT_TIMEOUT)
392 del_timer_sync(&h->gc);
393
394 ahash_destroy(h->table);
395#ifdef IP_SET_HASH_WITH_RBTREE
396 rbtree_destroy(&h->rbtree);
397#endif
398 kfree(h);
399
400 set->data = NULL;
401}
402
403static void
404mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
405{
406 struct htype *h = set->data;
407
408 init_timer(&h->gc);
409 h->gc.data = (unsigned long) set;
410 h->gc.function = gc;
411 h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
412 add_timer(&h->gc);
413 pr_debug("gc initialized, run in every %u\n",
414 IPSET_GC_PERIOD(h->timeout));
415}
416
417static bool
418mtype_same_set(const struct ip_set *a, const struct ip_set *b)
419{
420 const struct htype *x = a->data;
421 const struct htype *y = b->data;
422
423 /* Resizing changes htable_bits, so we ignore it */
424 return x->maxelem == y->maxelem &&
425 x->timeout == y->timeout &&
426#ifdef IP_SET_HASH_WITH_NETMASK
427 x->netmask == y->netmask &&
428#endif
429 a->extensions == b->extensions;
430}
431
432/* Get the ith element from the array block n */
433#define ahash_data(n, i, dsize) \
434 ((struct mtype_elem *)((n)->value + ((i) * (dsize))))
435
436/* Delete expired elements from the hashtable */
437static void
438mtype_expire(struct htype *h, u8 nets_length, size_t dsize)
439{
440 struct htable *t = h->table;
441 struct hbucket *n;
442 struct mtype_elem *data;
443 u32 i;
444 int j;
445
446 for (i = 0; i < jhash_size(t->htable_bits); i++) {
447 n = hbucket(t, i);
448 for (j = 0; j < n->pos; j++) {
449 data = ahash_data(n, j, dsize);
450 if (ip_set_timeout_expired(ext_timeout(data, h))) {
451 pr_debug("expired %u/%u\n", i, j);
452#ifdef IP_SET_HASH_WITH_NETS
453 mtype_del_cidr(h, CIDR(data->cidr),
454 nets_length);
455#endif
456 if (j != n->pos - 1)
457 /* Not last one */
458 memcpy(data,
459 ahash_data(n, n->pos - 1, dsize),
460 dsize);
461 n->pos--;
462 h->elements--;
463 }
464 }
465 if (n->pos + AHASH_INIT_SIZE < n->size) {
466 void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
467 * dsize,
468 GFP_ATOMIC);
469 if (!tmp)
470 /* Still try to delete expired elements */
471 continue;
472 n->size -= AHASH_INIT_SIZE;
473 memcpy(tmp, n->value, n->size * dsize);
474 kfree(n->value);
475 n->value = tmp;
476 }
477 }
478}
479
480static void
481mtype_gc(unsigned long ul_set)
482{
483 struct ip_set *set = (struct ip_set *) ul_set;
484 struct htype *h = set->data;
485
486 pr_debug("called\n");
487 write_lock_bh(&set->lock);
488 mtype_expire(h, NETS_LENGTH(set->family), h->dsize);
489 write_unlock_bh(&set->lock);
490
491 h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
492 add_timer(&h->gc);
493}
494
495/* Resize a hash: create a new hash table with doubling the hashsize
496 * and inserting the elements to it. Repeat until we succeed or
497 * fail due to memory pressures. */
498static int
499mtype_resize(struct ip_set *set, bool retried)
500{
501 struct htype *h = set->data;
502 struct htable *t, *orig = h->table;
503 u8 htable_bits = orig->htable_bits;
504#ifdef IP_SET_HASH_WITH_NETS
505 u8 flags;
506#endif
507 struct mtype_elem *data;
508 struct mtype_elem *d;
509 struct hbucket *n, *m;
510 u32 i, j;
511 int ret;
512
513 /* Try to cleanup once */
514 if (SET_WITH_TIMEOUT(set) && !retried) {
515 i = h->elements;
516 write_lock_bh(&set->lock);
517 mtype_expire(set->data, NETS_LENGTH(set->family),
518 h->dsize);
519 write_unlock_bh(&set->lock);
520 if (h->elements < i)
521 return 0;
522 }
523
524retry:
525 ret = 0;
526 htable_bits++;
527 pr_debug("attempt to resize set %s from %u to %u, t %p\n",
528 set->name, orig->htable_bits, htable_bits, orig);
529 if (!htable_bits) {
530 /* In case we have plenty of memory :-) */
531 pr_warning("Cannot increase the hashsize of set %s further\n",
532 set->name);
533 return -IPSET_ERR_HASH_FULL;
534 }
535 t = ip_set_alloc(sizeof(*t)
536 + jhash_size(htable_bits) * sizeof(struct hbucket));
537 if (!t)
538 return -ENOMEM;
539 t->htable_bits = htable_bits;
540
541 read_lock_bh(&set->lock);
542 for (i = 0; i < jhash_size(orig->htable_bits); i++) {
543 n = hbucket(orig, i);
544 for (j = 0; j < n->pos; j++) {
545 data = ahash_data(n, j, h->dsize);
546#ifdef IP_SET_HASH_WITH_NETS
547 flags = 0;
548 mtype_data_reset_flags(data, &flags);
549#endif
550 m = hbucket(t, HKEY(data, h->initval, htable_bits));
551 ret = hbucket_elem_add(m, AHASH_MAX(h), h->dsize);
552 if (ret < 0) {
553#ifdef IP_SET_HASH_WITH_NETS
554 mtype_data_reset_flags(data, &flags);
555#endif
556 read_unlock_bh(&set->lock);
557 ahash_destroy(t);
558 if (ret == -EAGAIN)
559 goto retry;
560 return ret;
561 }
562 d = ahash_data(m, m->pos++, h->dsize);
563 memcpy(d, data, h->dsize);
564#ifdef IP_SET_HASH_WITH_NETS
565 mtype_data_reset_flags(d, &flags);
566#endif
567 }
568 }
569
570 rcu_assign_pointer(h->table, t);
571 read_unlock_bh(&set->lock);
572
573 /* Give time to other readers of the set */
574 synchronize_rcu_bh();
575
576 pr_debug("set %s resized from %u (%p) to %u (%p)\n", set->name,
577 orig->htable_bits, orig, t->htable_bits, t);
578 ahash_destroy(orig);
579
580 return 0;
581}
582
583/* Add an element to a hash and update the internal counters when succeeded,
584 * otherwise report the proper error code. */
585static int
586mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
587 struct ip_set_ext *mext, u32 flags)
588{
589 struct htype *h = set->data;
590 struct htable *t;
591 const struct mtype_elem *d = value;
592 struct mtype_elem *data;
593 struct hbucket *n;
594 int i, ret = 0;
595 int j = AHASH_MAX(h) + 1;
596 bool flag_exist = flags & IPSET_FLAG_EXIST;
597 u32 key, multi = 0;
598
599 if (SET_WITH_TIMEOUT(set) && h->elements >= h->maxelem)
600 /* FIXME: when set is full, we slow down here */
601 mtype_expire(h, NETS_LENGTH(set->family), h->dsize);
602
603 if (h->elements >= h->maxelem) {
604 if (net_ratelimit())
605 pr_warning("Set %s is full, maxelem %u reached\n",
606 set->name, h->maxelem);
607 return -IPSET_ERR_HASH_FULL;
608 }
609
610 rcu_read_lock_bh();
611 t = rcu_dereference_bh(h->table);
612 key = HKEY(value, h->initval, t->htable_bits);
613 n = hbucket(t, key);
614 for (i = 0; i < n->pos; i++) {
615 data = ahash_data(n, i, h->dsize);
616 if (mtype_data_equal(data, d, &multi)) {
617 if (flag_exist ||
618 (SET_WITH_TIMEOUT(set) &&
619 ip_set_timeout_expired(ext_timeout(data, h)))) {
620 /* Just the extensions could be overwritten */
621 j = i;
622 goto reuse_slot;
623 } else {
624 ret = -IPSET_ERR_EXIST;
625 goto out;
626 }
627 }
628 /* Reuse first timed out entry */
629 if (SET_WITH_TIMEOUT(set) &&
630 ip_set_timeout_expired(ext_timeout(data, h)) &&
631 j != AHASH_MAX(h) + 1)
632 j = i;
633 }
634reuse_slot:
635 if (j != AHASH_MAX(h) + 1) {
636 /* Fill out reused slot */
637 data = ahash_data(n, j, h->dsize);
638#ifdef IP_SET_HASH_WITH_NETS
639 mtype_del_cidr(h, CIDR(data->cidr), NETS_LENGTH(set->family));
640 mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
641#endif
642 } else {
643 /* Use/create a new slot */
644 TUNE_AHASH_MAX(h, multi);
645 ret = hbucket_elem_add(n, AHASH_MAX(h), h->dsize);
646 if (ret != 0) {
647 if (ret == -EAGAIN)
648 mtype_data_next(&h->next, d);
649 goto out;
650 }
651 data = ahash_data(n, n->pos++, h->dsize);
652#ifdef IP_SET_HASH_WITH_NETS
653 mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
654#endif
655 h->elements++;
656 }
657 memcpy(data, d, sizeof(struct mtype_elem));
658#ifdef IP_SET_HASH_WITH_NETS
659 mtype_data_set_flags(data, flags);
660#endif
661 if (SET_WITH_TIMEOUT(set))
662 ip_set_timeout_set(ext_timeout(data, h), ext->timeout);
663
664out:
665 rcu_read_unlock_bh();
666 return ret;
667}
668
669/* Delete an element from the hash: swap it with the last element
670 * and free up space if possible.
671 */
672static int
673mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
674 struct ip_set_ext *mext, u32 flags)
675{
676 struct htype *h = set->data;
677 struct htable *t = h->table;
678 const struct mtype_elem *d = value;
679 struct mtype_elem *data;
680 struct hbucket *n;
681 int i;
682 u32 key, multi = 0;
683
684 key = HKEY(value, h->initval, t->htable_bits);
685 n = hbucket(t, key);
686 for (i = 0; i < n->pos; i++) {
687 data = ahash_data(n, i, h->dsize);
688 if (!mtype_data_equal(data, d, &multi))
689 continue;
690 if (SET_WITH_TIMEOUT(set) &&
691 ip_set_timeout_expired(ext_timeout(data, h)))
692 return -IPSET_ERR_EXIST;
693 if (i != n->pos - 1)
694 /* Not last one */
695 memcpy(data, ahash_data(n, n->pos - 1, h->dsize),
696 h->dsize);
697
698 n->pos--;
699 h->elements--;
700#ifdef IP_SET_HASH_WITH_NETS
701 mtype_del_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
702#endif
703 if (n->pos + AHASH_INIT_SIZE < n->size) {
704 void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
705 * h->dsize,
706 GFP_ATOMIC);
707 if (!tmp)
708 return 0;
709 n->size -= AHASH_INIT_SIZE;
710 memcpy(tmp, n->value, n->size * h->dsize);
711 kfree(n->value);
712 n->value = tmp;
713 }
714 return 0;
715 }
716
717 return -IPSET_ERR_EXIST;
718}
719
720static inline int
721mtype_data_match(struct mtype_elem *data, const struct ip_set_ext *ext,
722 struct ip_set_ext *mext, struct ip_set *set, u32 flags)
723{
724 return mtype_do_data_match(data);
725}
726
727#ifdef IP_SET_HASH_WITH_NETS
728/* Special test function which takes into account the different network
729 * sizes added to the set */
730static int
731mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
732 const struct ip_set_ext *ext,
733 struct ip_set_ext *mext, u32 flags)
734{
735 struct htype *h = set->data;
736 struct htable *t = h->table;
737 struct hbucket *n;
738 struct mtype_elem *data;
739 int i, j = 0;
740 u32 key, multi = 0;
741 u8 nets_length = NETS_LENGTH(set->family);
742
743 pr_debug("test by nets\n");
744 for (; j < nets_length && h->nets[j].nets && !multi; j++) {
745 mtype_data_netmask(d, h->nets[j].cidr);
746 key = HKEY(d, h->initval, t->htable_bits);
747 n = hbucket(t, key);
748 for (i = 0; i < n->pos; i++) {
749 data = ahash_data(n, i, h->dsize);
750 if (!mtype_data_equal(data, d, &multi))
751 continue;
752 if (SET_WITH_TIMEOUT(set)) {
753 if (!ip_set_timeout_expired(
754 ext_timeout(data, h)))
755 return mtype_data_match(data, ext,
756 mext, set,
757 flags);
758#ifdef IP_SET_HASH_WITH_MULTI
759 multi = 0;
760#endif
761 } else
762 return mtype_data_match(data, ext,
763 mext, set, flags);
764 }
765 }
766 return 0;
767}
768#endif
769
770/* Test whether the element is added to the set */
771static int
772mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
773 struct ip_set_ext *mext, u32 flags)
774{
775 struct htype *h = set->data;
776 struct htable *t = h->table;
777 struct mtype_elem *d = value;
778 struct hbucket *n;
779 struct mtype_elem *data;
780 int i;
781 u32 key, multi = 0;
782
783#ifdef IP_SET_HASH_WITH_NETS
784 /* If we test an IP address and not a network address,
785 * try all possible network sizes */
786 if (CIDR(d->cidr) == SET_HOST_MASK(set->family))
787 return mtype_test_cidrs(set, d, ext, mext, flags);
788#endif
789
790 key = HKEY(d, h->initval, t->htable_bits);
791 n = hbucket(t, key);
792 for (i = 0; i < n->pos; i++) {
793 data = ahash_data(n, i, h->dsize);
794 if (mtype_data_equal(data, d, &multi) &&
795 !(SET_WITH_TIMEOUT(set) &&
796 ip_set_timeout_expired(ext_timeout(data, h))))
797 return mtype_data_match(data, ext, mext, set, flags);
798 }
799 return 0;
800}
801
802/* Reply a HEADER request: fill out the header part of the set */
803static int
804mtype_head(struct ip_set *set, struct sk_buff *skb)
805{
806 const struct htype *h = set->data;
807 struct nlattr *nested;
808 size_t memsize;
809
810 read_lock_bh(&set->lock);
811 memsize = mtype_ahash_memsize(h, NETS_LENGTH(set->family));
812 read_unlock_bh(&set->lock);
813
814 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
815 if (!nested)
816 goto nla_put_failure;
817 if (nla_put_net32(skb, IPSET_ATTR_HASHSIZE,
818 htonl(jhash_size(h->table->htable_bits))) ||
819 nla_put_net32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem)))
820 goto nla_put_failure;
821#ifdef IP_SET_HASH_WITH_NETMASK
822 if (h->netmask != HOST_MASK &&
823 nla_put_u8(skb, IPSET_ATTR_NETMASK, h->netmask))
824 goto nla_put_failure;
825#endif
826 if (nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
827 nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)) ||
828 ((set->extensions & IPSET_EXT_TIMEOUT) &&
829 nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout))))
830 goto nla_put_failure;
831 ipset_nest_end(skb, nested);
832
833 return 0;
834nla_put_failure:
835 return -EMSGSIZE;
836}
837
838/* Reply a LIST/SAVE request: dump the elements of the specified set */
839static int
840mtype_list(const struct ip_set *set,
841 struct sk_buff *skb, struct netlink_callback *cb)
842{
843 const struct htype *h = set->data;
844 const struct htable *t = h->table;
845 struct nlattr *atd, *nested;
846 const struct hbucket *n;
847 const struct mtype_elem *e;
848 u32 first = cb->args[2];
849 /* We assume that one hash bucket fills into one page */
850 void *incomplete;
851 int i;
852
853 atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
854 if (!atd)
855 return -EMSGSIZE;
856 pr_debug("list hash set %s\n", set->name);
857 for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
858 incomplete = skb_tail_pointer(skb);
859 n = hbucket(t, cb->args[2]);
860 pr_debug("cb->args[2]: %lu, t %p n %p\n", cb->args[2], t, n);
861 for (i = 0; i < n->pos; i++) {
862 e = ahash_data(n, i, h->dsize);
863 if (SET_WITH_TIMEOUT(set) &&
864 ip_set_timeout_expired(ext_timeout(e, h)))
865 continue;
866 pr_debug("list hash %lu hbucket %p i %u, data %p\n",
867 cb->args[2], n, i, e);
868 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
869 if (!nested) {
870 if (cb->args[2] == first) {
871 nla_nest_cancel(skb, atd);
872 return -EMSGSIZE;
873 } else
874 goto nla_put_failure;
875 }
876 if (mtype_data_list(skb, e))
877 goto nla_put_failure;
878 if (SET_WITH_TIMEOUT(set) &&
879 nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
880 htonl(ip_set_timeout_get(
881 ext_timeout(e, h)))))
882 goto nla_put_failure;
883 ipset_nest_end(skb, nested);
884 }
885 }
886 ipset_nest_end(skb, atd);
887 /* Set listing finished */
888 cb->args[2] = 0;
889
890 return 0;
891
892nla_put_failure:
893 nlmsg_trim(skb, incomplete);
894 ipset_nest_end(skb, atd);
895 if (unlikely(first == cb->args[2])) {
896 pr_warning("Can't list set %s: one bucket does not fit into "
897 "a message. Please report it!\n", set->name);
898 cb->args[2] = 0;
899 return -EMSGSIZE;
900 }
901 return 0;
902}
903
904static int
905TOKEN(MTYPE, _kadt)(struct ip_set *set, const struct sk_buff *skb,
906 const struct xt_action_param *par,
907 enum ipset_adt adt, struct ip_set_adt_opt *opt);
908
909static int
910TOKEN(MTYPE, _uadt)(struct ip_set *set, struct nlattr *tb[],
911 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
912
913static const struct ip_set_type_variant mtype_variant = {
914 .kadt = mtype_kadt,
915 .uadt = mtype_uadt,
916 .adt = {
917 [IPSET_ADD] = mtype_add,
918 [IPSET_DEL] = mtype_del,
919 [IPSET_TEST] = mtype_test,
920 },
921 .destroy = mtype_destroy,
922 .flush = mtype_flush,
923 .head = mtype_head,
924 .list = mtype_list,
925 .resize = mtype_resize,
926 .same_set = mtype_same_set,
927};
928
929#ifdef IP_SET_EMIT_CREATE
930static int
931TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags)
932{
933 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
934 u8 hbits;
935#ifdef IP_SET_HASH_WITH_NETMASK
936 u8 netmask;
937#endif
938 size_t hsize;
939 struct HTYPE *h;
940
941 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
942 return -IPSET_ERR_INVALID_FAMILY;
943#ifdef IP_SET_HASH_WITH_NETMASK
944 netmask = set->family == NFPROTO_IPV4 ? 32 : 128;
945 pr_debug("Create set %s with family %s\n",
946 set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6");
947#endif
948
949 if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
950 !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
951 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
952 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
953 return -IPSET_ERR_PROTOCOL;
954
955 if (tb[IPSET_ATTR_HASHSIZE]) {
956 hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
957 if (hashsize < IPSET_MIMINAL_HASHSIZE)
958 hashsize = IPSET_MIMINAL_HASHSIZE;
959 }
960
961 if (tb[IPSET_ATTR_MAXELEM])
962 maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
963
964#ifdef IP_SET_HASH_WITH_NETMASK
965 if (tb[IPSET_ATTR_NETMASK]) {
966 netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
967
968 if ((set->family == NFPROTO_IPV4 && netmask > 32) ||
969 (set->family == NFPROTO_IPV6 && netmask > 128) ||
970 netmask == 0)
971 return -IPSET_ERR_INVALID_NETMASK;
972 }
973#endif
974
975 hsize = sizeof(*h);
976#ifdef IP_SET_HASH_WITH_NETS
977 hsize += sizeof(struct net_prefixes) *
978 (set->family == NFPROTO_IPV4 ? 32 : 128);
979#endif
980 h = kzalloc(hsize, GFP_KERNEL);
981 if (!h)
982 return -ENOMEM;
983
984 h->maxelem = maxelem;
985#ifdef IP_SET_HASH_WITH_NETMASK
986 h->netmask = netmask;
987#endif
988 get_random_bytes(&h->initval, sizeof(h->initval));
989 h->timeout = IPSET_NO_TIMEOUT;
990
991 hbits = htable_bits(hashsize);
992 hsize = htable_size(hbits);
993 if (hsize == 0) {
994 kfree(h);
995 return -ENOMEM;
996 }
997 h->table = ip_set_alloc(hsize);
998 if (!h->table) {
999 kfree(h);
1000 return -ENOMEM;
1001 }
1002 h->table->htable_bits = hbits;
1003
1004 set->data = h;
1005 if (set->family == NFPROTO_IPV4)
1006 set->variant = &TOKEN(HTYPE, 4_variant);
1007 else
1008 set->variant = &TOKEN(HTYPE, 6_variant);
1009
1010 if (tb[IPSET_ATTR_TIMEOUT]) {
1011 h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
1012 set->extensions |= IPSET_EXT_TIMEOUT;
1013 if (set->family == NFPROTO_IPV4) {
1014 h->dsize = sizeof(struct TOKEN(HTYPE, 4t_elem));
1015 h->offset[IPSET_OFFSET_TIMEOUT] =
1016 offsetof(struct TOKEN(HTYPE, 4t_elem),
1017 timeout);
1018 TOKEN(HTYPE, 4_gc_init)(set, TOKEN(HTYPE, 4_gc));
1019 } else {
1020 h->dsize = sizeof(struct TOKEN(HTYPE, 6t_elem));
1021 h->offset[IPSET_OFFSET_TIMEOUT] =
1022 offsetof(struct TOKEN(HTYPE, 6t_elem),
1023 timeout);
1024 TOKEN(HTYPE, 6_gc_init)(set, TOKEN(HTYPE, 6_gc));
1025 }
1026 } else {
1027 if (set->family == NFPROTO_IPV4)
1028 h->dsize = sizeof(struct TOKEN(HTYPE, 4_elem));
1029 else
1030 h->dsize = sizeof(struct TOKEN(HTYPE, 6_elem));
1031 }
1032
1033 pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
1034 set->name, jhash_size(h->table->htable_bits),
1035 h->table->htable_bits, h->maxelem, set->data, h->table);
1036
1037 return 0;
1038}
1039#endif /* IP_SET_EMIT_CREATE */