GNU Linux-libre 4.19.286-gnu1
[releases.git] / net / netfilter / ipset / ip_set_list_set.c
1 /* Copyright (C) 2008-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 /* Kernel module implementing an IP set type: the list:set type */
9
10 #include <linux/module.h>
11 #include <linux/ip.h>
12 #include <linux/rculist.h>
13 #include <linux/skbuff.h>
14 #include <linux/errno.h>
15
16 #include <linux/netfilter/ipset/ip_set.h>
17 #include <linux/netfilter/ipset/ip_set_list.h>
18
19 #define IPSET_TYPE_REV_MIN      0
20 /*                              1    Counters support added */
21 /*                              2    Comments support added */
22 #define IPSET_TYPE_REV_MAX      3 /* skbinfo support added */
23
24 MODULE_LICENSE("GPL");
25 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
26 IP_SET_MODULE_DESC("list:set", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
27 MODULE_ALIAS("ip_set_list:set");
28
29 /* Member elements  */
30 struct set_elem {
31         struct rcu_head rcu;
32         struct list_head list;
33         struct ip_set *set;     /* Sigh, in order to cleanup reference */
34         ip_set_id_t id;
35 } __aligned(__alignof__(u64));
36
37 struct set_adt_elem {
38         ip_set_id_t id;
39         ip_set_id_t refid;
40         int before;
41 };
42
43 /* Type structure */
44 struct list_set {
45         u32 size;               /* size of set list array */
46         struct timer_list gc;   /* garbage collection */
47         struct ip_set *set;     /* attached to this ip_set */
48         struct net *net;        /* namespace */
49         struct list_head members; /* the set members */
50 };
51
52 static int
53 list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
54                const struct xt_action_param *par,
55                struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
56 {
57         struct list_set *map = set->data;
58         struct ip_set_ext *mext = &opt->ext;
59         struct set_elem *e;
60         u32 flags = opt->cmdflags;
61         int ret;
62
63         /* Don't lookup sub-counters at all */
64         opt->cmdflags &= ~IPSET_FLAG_MATCH_COUNTERS;
65         if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)
66                 opt->cmdflags |= IPSET_FLAG_SKIP_COUNTER_UPDATE;
67         list_for_each_entry_rcu(e, &map->members, list) {
68                 ret = ip_set_test(e->id, skb, par, opt);
69                 if (ret <= 0)
70                         continue;
71                 if (ip_set_match_extensions(set, ext, mext, flags, e))
72                         return 1;
73         }
74         return 0;
75 }
76
77 static int
78 list_set_kadd(struct ip_set *set, const struct sk_buff *skb,
79               const struct xt_action_param *par,
80               struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
81 {
82         struct list_set *map = set->data;
83         struct set_elem *e;
84         int ret;
85
86         list_for_each_entry(e, &map->members, list) {
87                 if (SET_WITH_TIMEOUT(set) &&
88                     ip_set_timeout_expired(ext_timeout(e, set)))
89                         continue;
90                 ret = ip_set_add(e->id, skb, par, opt);
91                 if (ret == 0)
92                         return ret;
93         }
94         return 0;
95 }
96
97 static int
98 list_set_kdel(struct ip_set *set, const struct sk_buff *skb,
99               const struct xt_action_param *par,
100               struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
101 {
102         struct list_set *map = set->data;
103         struct set_elem *e;
104         int ret;
105
106         list_for_each_entry(e, &map->members, list) {
107                 if (SET_WITH_TIMEOUT(set) &&
108                     ip_set_timeout_expired(ext_timeout(e, set)))
109                         continue;
110                 ret = ip_set_del(e->id, skb, par, opt);
111                 if (ret == 0)
112                         return ret;
113         }
114         return 0;
115 }
116
117 static int
118 list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
119               const struct xt_action_param *par,
120               enum ipset_adt adt, struct ip_set_adt_opt *opt)
121 {
122         struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
123         int ret = -EINVAL;
124
125         rcu_read_lock();
126         switch (adt) {
127         case IPSET_TEST:
128                 ret = list_set_ktest(set, skb, par, opt, &ext);
129                 break;
130         case IPSET_ADD:
131                 ret = list_set_kadd(set, skb, par, opt, &ext);
132                 break;
133         case IPSET_DEL:
134                 ret = list_set_kdel(set, skb, par, opt, &ext);
135                 break;
136         default:
137                 break;
138         }
139         rcu_read_unlock();
140
141         return ret;
142 }
143
144 /* Userspace interfaces: we are protected by the nfnl mutex */
145
146 static void
147 __list_set_del_rcu(struct rcu_head * rcu)
148 {
149         struct set_elem *e = container_of(rcu, struct set_elem, rcu);
150         struct ip_set *set = e->set;
151
152         ip_set_ext_destroy(set, e);
153         kfree(e);
154 }
155
156 static inline void
157 list_set_del(struct ip_set *set, struct set_elem *e)
158 {
159         struct list_set *map = set->data;
160
161         set->elements--;
162         list_del_rcu(&e->list);
163         ip_set_put_byindex(map->net, e->id);
164         call_rcu(&e->rcu, __list_set_del_rcu);
165 }
166
167 static inline void
168 list_set_replace(struct ip_set *set, struct set_elem *e, struct set_elem *old)
169 {
170         struct list_set *map = set->data;
171
172         list_replace_rcu(&old->list, &e->list);
173         ip_set_put_byindex(map->net, old->id);
174         call_rcu(&old->rcu, __list_set_del_rcu);
175 }
176
177 static void
178 set_cleanup_entries(struct ip_set *set)
179 {
180         struct list_set *map = set->data;
181         struct set_elem *e, *n;
182
183         list_for_each_entry_safe(e, n, &map->members, list)
184                 if (ip_set_timeout_expired(ext_timeout(e, set)))
185                         list_set_del(set, e);
186 }
187
188 static int
189 list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,
190                struct ip_set_ext *mext, u32 flags)
191 {
192         struct list_set *map = set->data;
193         struct set_adt_elem *d = value;
194         struct set_elem *e, *next, *prev = NULL;
195         int ret;
196
197         list_for_each_entry(e, &map->members, list) {
198                 if (SET_WITH_TIMEOUT(set) &&
199                     ip_set_timeout_expired(ext_timeout(e, set)))
200                         continue;
201                 else if (e->id != d->id) {
202                         prev = e;
203                         continue;
204                 }
205
206                 if (d->before == 0) {
207                         ret = 1;
208                 } else if (d->before > 0) {
209                         next = list_next_entry(e, list);
210                         ret = !list_is_last(&e->list, &map->members) &&
211                               next->id == d->refid;
212                 } else {
213                         ret = prev && prev->id == d->refid;
214                 }
215                 return ret;
216         }
217         return 0;
218 }
219
220 static void
221 list_set_init_extensions(struct ip_set *set, const struct ip_set_ext *ext,
222                          struct set_elem *e)
223 {
224         if (SET_WITH_COUNTER(set))
225                 ip_set_init_counter(ext_counter(e, set), ext);
226         if (SET_WITH_COMMENT(set))
227                 ip_set_init_comment(set, ext_comment(e, set), ext);
228         if (SET_WITH_SKBINFO(set))
229                 ip_set_init_skbinfo(ext_skbinfo(e, set), ext);
230         /* Update timeout last */
231         if (SET_WITH_TIMEOUT(set))
232                 ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
233 }
234
235 static int
236 list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
237               struct ip_set_ext *mext, u32 flags)
238 {
239         struct list_set *map = set->data;
240         struct set_adt_elem *d = value;
241         struct set_elem *e, *n, *prev, *next;
242         bool flag_exist = flags & IPSET_FLAG_EXIST;
243
244         /* Find where to add the new entry */
245         n = prev = next = NULL;
246         list_for_each_entry(e, &map->members, list) {
247                 if (SET_WITH_TIMEOUT(set) &&
248                     ip_set_timeout_expired(ext_timeout(e, set)))
249                         continue;
250                 else if (d->id == e->id)
251                         n = e;
252                 else if (d->before == 0 || e->id != d->refid)
253                         continue;
254                 else if (d->before > 0)
255                         next = e;
256                 else
257                         prev = e;
258         }
259
260         /* If before/after is used on an empty set */
261         if ((d->before > 0 && !next) ||
262             (d->before < 0 && !prev))
263                 return -IPSET_ERR_REF_EXIST;
264
265         /* Re-add already existing element */
266         if (n) {
267                 if (!flag_exist)
268                         return -IPSET_ERR_EXIST;
269                 /* Update extensions */
270                 ip_set_ext_destroy(set, n);
271                 list_set_init_extensions(set, ext, n);
272
273                 /* Set is already added to the list */
274                 ip_set_put_byindex(map->net, d->id);
275                 return 0;
276         }
277         /* Add new entry */
278         if (d->before == 0) {
279                 /* Append  */
280                 n = list_empty(&map->members) ? NULL :
281                     list_last_entry(&map->members, struct set_elem, list);
282         } else if (d->before > 0) {
283                 /* Insert after next element */
284                 if (!list_is_last(&next->list, &map->members))
285                         n = list_next_entry(next, list);
286         } else {
287                 /* Insert before prev element */
288                 if (prev->list.prev != &map->members)
289                         n = list_prev_entry(prev, list);
290         }
291         /* Can we replace a timed out entry? */
292         if (n &&
293             !(SET_WITH_TIMEOUT(set) &&
294               ip_set_timeout_expired(ext_timeout(n, set))))
295                 n =  NULL;
296
297         e = kzalloc(set->dsize, GFP_ATOMIC);
298         if (!e)
299                 return -ENOMEM;
300         e->id = d->id;
301         e->set = set;
302         INIT_LIST_HEAD(&e->list);
303         list_set_init_extensions(set, ext, e);
304         if (n)
305                 list_set_replace(set, e, n);
306         else if (next)
307                 list_add_tail_rcu(&e->list, &next->list);
308         else if (prev)
309                 list_add_rcu(&e->list, &prev->list);
310         else
311                 list_add_tail_rcu(&e->list, &map->members);
312         set->elements++;
313
314         return 0;
315 }
316
317 static int
318 list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext,
319               struct ip_set_ext *mext, u32 flags)
320 {
321         struct list_set *map = set->data;
322         struct set_adt_elem *d = value;
323         struct set_elem *e, *next, *prev = NULL;
324
325         list_for_each_entry(e, &map->members, list) {
326                 if (SET_WITH_TIMEOUT(set) &&
327                     ip_set_timeout_expired(ext_timeout(e, set)))
328                         continue;
329                 else if (e->id != d->id) {
330                         prev = e;
331                         continue;
332                 }
333
334                 if (d->before > 0) {
335                         next = list_next_entry(e, list);
336                         if (list_is_last(&e->list, &map->members) ||
337                             next->id != d->refid)
338                                 return -IPSET_ERR_REF_EXIST;
339                 } else if (d->before < 0) {
340                         if (!prev || prev->id != d->refid)
341                                 return -IPSET_ERR_REF_EXIST;
342                 }
343                 list_set_del(set, e);
344                 return 0;
345         }
346         return d->before != 0 ? -IPSET_ERR_REF_EXIST : -IPSET_ERR_EXIST;
347 }
348
349 static int
350 list_set_uadt(struct ip_set *set, struct nlattr *tb[],
351               enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
352 {
353         struct list_set *map = set->data;
354         ipset_adtfn adtfn = set->variant->adt[adt];
355         struct set_adt_elem e = { .refid = IPSET_INVALID_ID };
356         struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
357         struct ip_set *s;
358         int ret = 0;
359
360         if (tb[IPSET_ATTR_LINENO])
361                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
362
363         if (unlikely(!tb[IPSET_ATTR_NAME] ||
364                      !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
365                 return -IPSET_ERR_PROTOCOL;
366
367         ret = ip_set_get_extensions(set, tb, &ext);
368         if (ret)
369                 return ret;
370         e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
371         if (e.id == IPSET_INVALID_ID)
372                 return -IPSET_ERR_NAME;
373         /* "Loop detection" */
374         if (s->type->features & IPSET_TYPE_NAME) {
375                 ret = -IPSET_ERR_LOOP;
376                 goto finish;
377         }
378
379         if (tb[IPSET_ATTR_CADT_FLAGS]) {
380                 u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
381
382                 e.before = f & IPSET_FLAG_BEFORE;
383         }
384
385         if (e.before && !tb[IPSET_ATTR_NAMEREF]) {
386                 ret = -IPSET_ERR_BEFORE;
387                 goto finish;
388         }
389
390         if (tb[IPSET_ATTR_NAMEREF]) {
391                 e.refid = ip_set_get_byname(map->net,
392                                             nla_data(tb[IPSET_ATTR_NAMEREF]),
393                                             &s);
394                 if (e.refid == IPSET_INVALID_ID) {
395                         ret = -IPSET_ERR_NAMEREF;
396                         goto finish;
397                 }
398                 if (!e.before)
399                         e.before = -1;
400         }
401         if (adt != IPSET_TEST && SET_WITH_TIMEOUT(set))
402                 set_cleanup_entries(set);
403
404         ret = adtfn(set, &e, &ext, &ext, flags);
405
406 finish:
407         if (e.refid != IPSET_INVALID_ID)
408                 ip_set_put_byindex(map->net, e.refid);
409         if (adt != IPSET_ADD || ret)
410                 ip_set_put_byindex(map->net, e.id);
411
412         return ip_set_eexist(ret, flags) ? 0 : ret;
413 }
414
415 static void
416 list_set_flush(struct ip_set *set)
417 {
418         struct list_set *map = set->data;
419         struct set_elem *e, *n;
420
421         list_for_each_entry_safe(e, n, &map->members, list)
422                 list_set_del(set, e);
423         set->elements = 0;
424         set->ext_size = 0;
425 }
426
427 static void
428 list_set_destroy(struct ip_set *set)
429 {
430         struct list_set *map = set->data;
431         struct set_elem *e, *n;
432
433         if (SET_WITH_TIMEOUT(set))
434                 del_timer_sync(&map->gc);
435
436         list_for_each_entry_safe(e, n, &map->members, list) {
437                 list_del(&e->list);
438                 ip_set_put_byindex(map->net, e->id);
439                 ip_set_ext_destroy(set, e);
440                 kfree(e);
441         }
442         kfree(map);
443
444         set->data = NULL;
445 }
446
447 /* Calculate the actual memory size of the set data */
448 static size_t
449 list_set_memsize(const struct list_set *map, size_t dsize)
450 {
451         struct set_elem *e;
452         u32 n = 0;
453
454         rcu_read_lock();
455         list_for_each_entry_rcu(e, &map->members, list)
456                 n++;
457         rcu_read_unlock();
458
459         return (sizeof(*map) + n * dsize);
460 }
461
462 static int
463 list_set_head(struct ip_set *set, struct sk_buff *skb)
464 {
465         const struct list_set *map = set->data;
466         struct nlattr *nested;
467         size_t memsize = list_set_memsize(map, set->dsize) + set->ext_size;
468
469         nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
470         if (!nested)
471                 goto nla_put_failure;
472         if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) ||
473             nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref)) ||
474             nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)) ||
475             nla_put_net32(skb, IPSET_ATTR_ELEMENTS, htonl(set->elements)))
476                 goto nla_put_failure;
477         if (unlikely(ip_set_put_flags(skb, set)))
478                 goto nla_put_failure;
479         ipset_nest_end(skb, nested);
480
481         return 0;
482 nla_put_failure:
483         return -EMSGSIZE;
484 }
485
486 static int
487 list_set_list(const struct ip_set *set,
488               struct sk_buff *skb, struct netlink_callback *cb)
489 {
490         const struct list_set *map = set->data;
491         struct nlattr *atd, *nested;
492         u32 i = 0, first = cb->args[IPSET_CB_ARG0];
493         char name[IPSET_MAXNAMELEN];
494         struct set_elem *e;
495         int ret = 0;
496
497         atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
498         if (!atd)
499                 return -EMSGSIZE;
500
501         rcu_read_lock();
502         list_for_each_entry_rcu(e, &map->members, list) {
503                 if (i < first ||
504                     (SET_WITH_TIMEOUT(set) &&
505                      ip_set_timeout_expired(ext_timeout(e, set)))) {
506                         i++;
507                         continue;
508                 }
509                 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
510                 if (!nested)
511                         goto nla_put_failure;
512                 ip_set_name_byindex(map->net, e->id, name);
513                 if (nla_put_string(skb, IPSET_ATTR_NAME, name))
514                         goto nla_put_failure;
515                 if (ip_set_put_extensions(skb, set, e, true))
516                         goto nla_put_failure;
517                 ipset_nest_end(skb, nested);
518                 i++;
519         }
520
521         ipset_nest_end(skb, atd);
522         /* Set listing finished */
523         cb->args[IPSET_CB_ARG0] = 0;
524         goto out;
525
526 nla_put_failure:
527         nla_nest_cancel(skb, nested);
528         if (unlikely(i == first)) {
529                 nla_nest_cancel(skb, atd);
530                 cb->args[IPSET_CB_ARG0] = 0;
531                 ret = -EMSGSIZE;
532         } else {
533                 cb->args[IPSET_CB_ARG0] = i;
534                 ipset_nest_end(skb, atd);
535         }
536 out:
537         rcu_read_unlock();
538         return ret;
539 }
540
541 static bool
542 list_set_same_set(const struct ip_set *a, const struct ip_set *b)
543 {
544         const struct list_set *x = a->data;
545         const struct list_set *y = b->data;
546
547         return x->size == y->size &&
548                a->timeout == b->timeout &&
549                a->extensions == b->extensions;
550 }
551
552 static const struct ip_set_type_variant set_variant = {
553         .kadt   = list_set_kadt,
554         .uadt   = list_set_uadt,
555         .adt    = {
556                 [IPSET_ADD] = list_set_uadd,
557                 [IPSET_DEL] = list_set_udel,
558                 [IPSET_TEST] = list_set_utest,
559         },
560         .destroy = list_set_destroy,
561         .flush  = list_set_flush,
562         .head   = list_set_head,
563         .list   = list_set_list,
564         .same_set = list_set_same_set,
565 };
566
567 static void
568 list_set_gc(struct timer_list *t)
569 {
570         struct list_set *map = from_timer(map, t, gc);
571         struct ip_set *set = map->set;
572
573         spin_lock_bh(&set->lock);
574         set_cleanup_entries(set);
575         spin_unlock_bh(&set->lock);
576
577         map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
578         add_timer(&map->gc);
579 }
580
581 static void
582 list_set_gc_init(struct ip_set *set, void (*gc)(struct timer_list *t))
583 {
584         struct list_set *map = set->data;
585
586         timer_setup(&map->gc, gc, 0);
587         mod_timer(&map->gc, jiffies + IPSET_GC_PERIOD(set->timeout) * HZ);
588 }
589
590 /* Create list:set type of sets */
591
592 static bool
593 init_list_set(struct net *net, struct ip_set *set, u32 size)
594 {
595         struct list_set *map;
596
597         map = kzalloc(sizeof(*map), GFP_KERNEL);
598         if (!map)
599                 return false;
600
601         map->size = size;
602         map->net = net;
603         map->set = set;
604         INIT_LIST_HEAD(&map->members);
605         set->data = map;
606
607         return true;
608 }
609
610 static int
611 list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
612                 u32 flags)
613 {
614         u32 size = IP_SET_LIST_DEFAULT_SIZE;
615
616         if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
617                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
618                      !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
619                 return -IPSET_ERR_PROTOCOL;
620
621         if (tb[IPSET_ATTR_SIZE])
622                 size = ip_set_get_h32(tb[IPSET_ATTR_SIZE]);
623         if (size < IP_SET_LIST_MIN_SIZE)
624                 size = IP_SET_LIST_MIN_SIZE;
625
626         set->variant = &set_variant;
627         set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem),
628                                      __alignof__(struct set_elem));
629         if (!init_list_set(net, set, size))
630                 return -ENOMEM;
631         if (tb[IPSET_ATTR_TIMEOUT]) {
632                 set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
633                 list_set_gc_init(set, list_set_gc);
634         }
635         return 0;
636 }
637
638 static struct ip_set_type list_set_type __read_mostly = {
639         .name           = "list:set",
640         .protocol       = IPSET_PROTOCOL,
641         .features       = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
642         .dimension      = IPSET_DIM_ONE,
643         .family         = NFPROTO_UNSPEC,
644         .revision_min   = IPSET_TYPE_REV_MIN,
645         .revision_max   = IPSET_TYPE_REV_MAX,
646         .create         = list_set_create,
647         .create_policy  = {
648                 [IPSET_ATTR_SIZE]       = { .type = NLA_U32 },
649                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
650                 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
651         },
652         .adt_policy     = {
653                 [IPSET_ATTR_NAME]       = { .type = NLA_STRING,
654                                             .len = IPSET_MAXNAMELEN },
655                 [IPSET_ATTR_NAMEREF]    = { .type = NLA_STRING,
656                                             .len = IPSET_MAXNAMELEN },
657                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
658                 [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
659                 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
660                 [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
661                 [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
662                 [IPSET_ATTR_COMMENT]    = { .type = NLA_NUL_STRING,
663                                             .len  = IPSET_MAX_COMMENT_SIZE },
664                 [IPSET_ATTR_SKBMARK]    = { .type = NLA_U64 },
665                 [IPSET_ATTR_SKBPRIO]    = { .type = NLA_U32 },
666                 [IPSET_ATTR_SKBQUEUE]   = { .type = NLA_U16 },
667         },
668         .me             = THIS_MODULE,
669 };
670
671 static int __init
672 list_set_init(void)
673 {
674         return ip_set_type_register(&list_set_type);
675 }
676
677 static void __exit
678 list_set_fini(void)
679 {
680         rcu_barrier();
681         ip_set_type_unregister(&list_set_type);
682 }
683
684 module_init(list_set_init);
685 module_exit(list_set_fini);