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 	struct list_set *map = set->data;
160 
161 	ip_set_put_byindex(map->net, e->id);
162 	ip_set_ext_destroy(set, e);
163 	kfree(e);
164 }
165 
166 static inline void
167 list_set_del(struct ip_set *set, struct set_elem *e)
168 {
169 	list_del_rcu(&e->list);
170 	call_rcu(&e->rcu, __list_set_del_rcu);
171 }
172 
173 static inline void
174 list_set_replace(struct set_elem *e, struct set_elem *old)
175 {
176 	list_replace_rcu(&old->list, &e->list);
177 	call_rcu(&old->rcu, __list_set_del_rcu);
178 }
179 
180 static void
181 set_cleanup_entries(struct ip_set *set)
182 {
183 	struct list_set *map = set->data;
184 	struct set_elem *e, *n;
185 
186 	list_for_each_entry_safe(e, n, &map->members, list)
187 		if (ip_set_timeout_expired(ext_timeout(e, set)))
188 			list_set_del(set, e);
189 }
190 
191 static int
192 list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,
193 	       struct ip_set_ext *mext, u32 flags)
194 {
195 	struct list_set *map = set->data;
196 	struct set_adt_elem *d = value;
197 	struct set_elem *e, *next, *prev = NULL;
198 	int ret;
199 
200 	list_for_each_entry(e, &map->members, list) {
201 		if (SET_WITH_TIMEOUT(set) &&
202 		    ip_set_timeout_expired(ext_timeout(e, set)))
203 			continue;
204 		else if (e->id != d->id) {
205 			prev = e;
206 			continue;
207 		}
208 
209 		if (d->before == 0) {
210 			ret = 1;
211 		} else if (d->before > 0) {
212 			next = list_next_entry(e, list);
213 			ret = !list_is_last(&e->list, &map->members) &&
214 			      next->id == d->refid;
215 		} else {
216 			ret = prev && prev->id == d->refid;
217 		}
218 		return ret;
219 	}
220 	return 0;
221 }
222 
223 static void
224 list_set_init_extensions(struct ip_set *set, const struct ip_set_ext *ext,
225 			 struct set_elem *e)
226 {
227 	if (SET_WITH_COUNTER(set))
228 		ip_set_init_counter(ext_counter(e, set), ext);
229 	if (SET_WITH_COMMENT(set))
230 		ip_set_init_comment(ext_comment(e, set), ext);
231 	if (SET_WITH_SKBINFO(set))
232 		ip_set_init_skbinfo(ext_skbinfo(e, set), ext);
233 	/* Update timeout last */
234 	if (SET_WITH_TIMEOUT(set))
235 		ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
236 }
237 
238 static int
239 list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
240 	      struct ip_set_ext *mext, u32 flags)
241 {
242 	struct list_set *map = set->data;
243 	struct set_adt_elem *d = value;
244 	struct set_elem *e, *n, *prev, *next;
245 	bool flag_exist = flags & IPSET_FLAG_EXIST;
246 
247 	/* Find where to add the new entry */
248 	n = prev = next = NULL;
249 	list_for_each_entry(e, &map->members, list) {
250 		if (SET_WITH_TIMEOUT(set) &&
251 		    ip_set_timeout_expired(ext_timeout(e, set)))
252 			continue;
253 		else if (d->id == e->id)
254 			n = e;
255 		else if (d->before == 0 || e->id != d->refid)
256 			continue;
257 		else if (d->before > 0)
258 			next = e;
259 		else
260 			prev = e;
261 	}
262 	/* Re-add already existing element */
263 	if (n) {
264 		if ((d->before > 0 && !next) ||
265 		    (d->before < 0 && !prev))
266 			return -IPSET_ERR_REF_EXIST;
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(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 
313 	return 0;
314 }
315 
316 static int
317 list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext,
318 	      struct ip_set_ext *mext, u32 flags)
319 {
320 	struct list_set *map = set->data;
321 	struct set_adt_elem *d = value;
322 	struct set_elem *e, *next, *prev = NULL;
323 
324 	list_for_each_entry(e, &map->members, list) {
325 		if (SET_WITH_TIMEOUT(set) &&
326 		    ip_set_timeout_expired(ext_timeout(e, set)))
327 			continue;
328 		else if (e->id != d->id) {
329 			prev = e;
330 			continue;
331 		}
332 
333 		if (d->before > 0) {
334 			next = list_next_entry(e, list);
335 			if (list_is_last(&e->list, &map->members) ||
336 			    next->id != d->refid)
337 				return -IPSET_ERR_REF_EXIST;
338 		} else if (d->before < 0) {
339 			if (!prev || prev->id != d->refid)
340 				return -IPSET_ERR_REF_EXIST;
341 		}
342 		list_set_del(set, e);
343 		return 0;
344 	}
345 	return d->before != 0 ? -IPSET_ERR_REF_EXIST : -IPSET_ERR_EXIST;
346 }
347 
348 static int
349 list_set_uadt(struct ip_set *set, struct nlattr *tb[],
350 	      enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
351 {
352 	struct list_set *map = set->data;
353 	ipset_adtfn adtfn = set->variant->adt[adt];
354 	struct set_adt_elem e = { .refid = IPSET_INVALID_ID };
355 	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
356 	struct ip_set *s;
357 	int ret = 0;
358 
359 	if (tb[IPSET_ATTR_LINENO])
360 		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
361 
362 	if (unlikely(!tb[IPSET_ATTR_NAME] ||
363 		     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
364 		return -IPSET_ERR_PROTOCOL;
365 
366 	ret = ip_set_get_extensions(set, tb, &ext);
367 	if (ret)
368 		return ret;
369 	e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
370 	if (e.id == IPSET_INVALID_ID)
371 		return -IPSET_ERR_NAME;
372 	/* "Loop detection" */
373 	if (s->type->features & IPSET_TYPE_NAME) {
374 		ret = -IPSET_ERR_LOOP;
375 		goto finish;
376 	}
377 
378 	if (tb[IPSET_ATTR_CADT_FLAGS]) {
379 		u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
380 
381 		e.before = f & IPSET_FLAG_BEFORE;
382 	}
383 
384 	if (e.before && !tb[IPSET_ATTR_NAMEREF]) {
385 		ret = -IPSET_ERR_BEFORE;
386 		goto finish;
387 	}
388 
389 	if (tb[IPSET_ATTR_NAMEREF]) {
390 		e.refid = ip_set_get_byname(map->net,
391 					    nla_data(tb[IPSET_ATTR_NAMEREF]),
392 					    &s);
393 		if (e.refid == IPSET_INVALID_ID) {
394 			ret = -IPSET_ERR_NAMEREF;
395 			goto finish;
396 		}
397 		if (!e.before)
398 			e.before = -1;
399 	}
400 	if (adt != IPSET_TEST && SET_WITH_TIMEOUT(set))
401 		set_cleanup_entries(set);
402 
403 	ret = adtfn(set, &e, &ext, &ext, flags);
404 
405 finish:
406 	if (e.refid != IPSET_INVALID_ID)
407 		ip_set_put_byindex(map->net, e.refid);
408 	if (adt != IPSET_ADD || ret)
409 		ip_set_put_byindex(map->net, e.id);
410 
411 	return ip_set_eexist(ret, flags) ? 0 : ret;
412 }
413 
414 static void
415 list_set_flush(struct ip_set *set)
416 {
417 	struct list_set *map = set->data;
418 	struct set_elem *e, *n;
419 
420 	list_for_each_entry_safe(e, n, &map->members, list)
421 		list_set_del(set, e);
422 }
423 
424 static void
425 list_set_destroy(struct ip_set *set)
426 {
427 	struct list_set *map = set->data;
428 	struct set_elem *e, *n;
429 
430 	if (SET_WITH_TIMEOUT(set))
431 		del_timer_sync(&map->gc);
432 
433 	list_for_each_entry_safe(e, n, &map->members, list) {
434 		list_del(&e->list);
435 		ip_set_put_byindex(map->net, e->id);
436 		ip_set_ext_destroy(set, e);
437 		kfree(e);
438 	}
439 	kfree(map);
440 
441 	set->data = NULL;
442 }
443 
444 static int
445 list_set_head(struct ip_set *set, struct sk_buff *skb)
446 {
447 	const struct list_set *map = set->data;
448 	struct nlattr *nested;
449 	struct set_elem *e;
450 	u32 n = 0;
451 
452 	rcu_read_lock();
453 	list_for_each_entry_rcu(e, &map->members, list)
454 		n++;
455 	rcu_read_unlock();
456 
457 	nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
458 	if (!nested)
459 		goto nla_put_failure;
460 	if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) ||
461 	    nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref)) ||
462 	    nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
463 			  htonl(sizeof(*map) + n * set->dsize)))
464 		goto nla_put_failure;
465 	if (unlikely(ip_set_put_flags(skb, set)))
466 		goto nla_put_failure;
467 	ipset_nest_end(skb, nested);
468 
469 	return 0;
470 nla_put_failure:
471 	return -EMSGSIZE;
472 }
473 
474 static int
475 list_set_list(const struct ip_set *set,
476 	      struct sk_buff *skb, struct netlink_callback *cb)
477 {
478 	const struct list_set *map = set->data;
479 	struct nlattr *atd, *nested;
480 	u32 i = 0, first = cb->args[IPSET_CB_ARG0];
481 	struct set_elem *e;
482 	int ret = 0;
483 
484 	atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
485 	if (!atd)
486 		return -EMSGSIZE;
487 
488 	rcu_read_lock();
489 	list_for_each_entry_rcu(e, &map->members, list) {
490 		if (i < first ||
491 		    (SET_WITH_TIMEOUT(set) &&
492 		     ip_set_timeout_expired(ext_timeout(e, set)))) {
493 			i++;
494 			continue;
495 		}
496 		nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
497 		if (!nested)
498 			goto nla_put_failure;
499 		if (nla_put_string(skb, IPSET_ATTR_NAME,
500 				   ip_set_name_byindex(map->net, e->id)))
501 			goto nla_put_failure;
502 		if (ip_set_put_extensions(skb, set, e, true))
503 			goto nla_put_failure;
504 		ipset_nest_end(skb, nested);
505 		i++;
506 	}
507 
508 	ipset_nest_end(skb, atd);
509 	/* Set listing finished */
510 	cb->args[IPSET_CB_ARG0] = 0;
511 	goto out;
512 
513 nla_put_failure:
514 	nla_nest_cancel(skb, nested);
515 	if (unlikely(i == first)) {
516 		nla_nest_cancel(skb, atd);
517 		cb->args[IPSET_CB_ARG0] = 0;
518 		ret = -EMSGSIZE;
519 	} else {
520 		cb->args[IPSET_CB_ARG0] = i;
521 	}
522 	ipset_nest_end(skb, atd);
523 out:
524 	rcu_read_unlock();
525 	return ret;
526 }
527 
528 static bool
529 list_set_same_set(const struct ip_set *a, const struct ip_set *b)
530 {
531 	const struct list_set *x = a->data;
532 	const struct list_set *y = b->data;
533 
534 	return x->size == y->size &&
535 	       a->timeout == b->timeout &&
536 	       a->extensions == b->extensions;
537 }
538 
539 static const struct ip_set_type_variant set_variant = {
540 	.kadt	= list_set_kadt,
541 	.uadt	= list_set_uadt,
542 	.adt	= {
543 		[IPSET_ADD] = list_set_uadd,
544 		[IPSET_DEL] = list_set_udel,
545 		[IPSET_TEST] = list_set_utest,
546 	},
547 	.destroy = list_set_destroy,
548 	.flush	= list_set_flush,
549 	.head	= list_set_head,
550 	.list	= list_set_list,
551 	.same_set = list_set_same_set,
552 };
553 
554 static void
555 list_set_gc(unsigned long ul_set)
556 {
557 	struct ip_set *set = (struct ip_set *)ul_set;
558 	struct list_set *map = set->data;
559 
560 	spin_lock_bh(&set->lock);
561 	set_cleanup_entries(set);
562 	spin_unlock_bh(&set->lock);
563 
564 	map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
565 	add_timer(&map->gc);
566 }
567 
568 static void
569 list_set_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
570 {
571 	struct list_set *map = set->data;
572 
573 	init_timer(&map->gc);
574 	map->gc.data = (unsigned long)set;
575 	map->gc.function = gc;
576 	map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
577 	add_timer(&map->gc);
578 }
579 
580 /* Create list:set type of sets */
581 
582 static bool
583 init_list_set(struct net *net, struct ip_set *set, u32 size)
584 {
585 	struct list_set *map;
586 
587 	map = kzalloc(sizeof(*map), GFP_KERNEL);
588 	if (!map)
589 		return false;
590 
591 	map->size = size;
592 	map->net = net;
593 	INIT_LIST_HEAD(&map->members);
594 	set->data = map;
595 
596 	return true;
597 }
598 
599 static int
600 list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
601 		u32 flags)
602 {
603 	u32 size = IP_SET_LIST_DEFAULT_SIZE;
604 
605 	if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
606 		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
607 		     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
608 		return -IPSET_ERR_PROTOCOL;
609 
610 	if (tb[IPSET_ATTR_SIZE])
611 		size = ip_set_get_h32(tb[IPSET_ATTR_SIZE]);
612 	if (size < IP_SET_LIST_MIN_SIZE)
613 		size = IP_SET_LIST_MIN_SIZE;
614 
615 	set->variant = &set_variant;
616 	set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem),
617 				     __alignof__(struct set_elem));
618 	if (!init_list_set(net, set, size))
619 		return -ENOMEM;
620 	if (tb[IPSET_ATTR_TIMEOUT]) {
621 		set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
622 		list_set_gc_init(set, list_set_gc);
623 	}
624 	return 0;
625 }
626 
627 static struct ip_set_type list_set_type __read_mostly = {
628 	.name		= "list:set",
629 	.protocol	= IPSET_PROTOCOL,
630 	.features	= IPSET_TYPE_NAME | IPSET_DUMP_LAST,
631 	.dimension	= IPSET_DIM_ONE,
632 	.family		= NFPROTO_UNSPEC,
633 	.revision_min	= IPSET_TYPE_REV_MIN,
634 	.revision_max	= IPSET_TYPE_REV_MAX,
635 	.create		= list_set_create,
636 	.create_policy	= {
637 		[IPSET_ATTR_SIZE]	= { .type = NLA_U32 },
638 		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
639 		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },
640 	},
641 	.adt_policy	= {
642 		[IPSET_ATTR_NAME]	= { .type = NLA_STRING,
643 					    .len = IPSET_MAXNAMELEN },
644 		[IPSET_ATTR_NAMEREF]	= { .type = NLA_STRING,
645 					    .len = IPSET_MAXNAMELEN },
646 		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
647 		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },
648 		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },
649 		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },
650 		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 },
651 		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING,
652 					    .len  = IPSET_MAX_COMMENT_SIZE },
653 		[IPSET_ATTR_SKBMARK]	= { .type = NLA_U64 },
654 		[IPSET_ATTR_SKBPRIO]	= { .type = NLA_U32 },
655 		[IPSET_ATTR_SKBQUEUE]	= { .type = NLA_U16 },
656 	},
657 	.me		= THIS_MODULE,
658 };
659 
660 static int __init
661 list_set_init(void)
662 {
663 	return ip_set_type_register(&list_set_type);
664 }
665 
666 static void __exit
667 list_set_fini(void)
668 {
669 	rcu_barrier();
670 	ip_set_type_unregister(&list_set_type);
671 }
672 
673 module_init(list_set_init);
674 module_exit(list_set_fini);
675