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