]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/netfilter/ipset/ip_set_hash_netiface.c
Merge tag 'jfs-3.12' of git://github.com/kleikamp/linux-shaggy
[karo-tx-linux.git] / net / netfilter / ipset / ip_set_hash_netiface.c
1 /* Copyright (C) 2011-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 hash:net,iface type */
9
10 #include <linux/jhash.h>
11 #include <linux/module.h>
12 #include <linux/ip.h>
13 #include <linux/skbuff.h>
14 #include <linux/errno.h>
15 #include <linux/random.h>
16 #include <linux/rbtree.h>
17 #include <net/ip.h>
18 #include <net/ipv6.h>
19 #include <net/netlink.h>
20
21 #include <linux/netfilter.h>
22 #include <linux/netfilter/ipset/pfxlen.h>
23 #include <linux/netfilter/ipset/ip_set.h>
24 #include <linux/netfilter/ipset/ip_set_hash.h>
25
26 #define REVISION_MIN    0
27 /*                      1    nomatch flag support added */
28 /*                      2    /0 support added */
29 #define REVISION_MAX    3 /* Counters support added */
30
31 MODULE_LICENSE("GPL");
32 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
33 IP_SET_MODULE_DESC("hash:net,iface", REVISION_MIN, REVISION_MAX);
34 MODULE_ALIAS("ip_set_hash:net,iface");
35
36 /* Interface name rbtree */
37
38 struct iface_node {
39         struct rb_node node;
40         char iface[IFNAMSIZ];
41 };
42
43 #define iface_data(n)   (rb_entry(n, struct iface_node, node)->iface)
44
45 static void
46 rbtree_destroy(struct rb_root *root)
47 {
48         struct rb_node *p, *n = root->rb_node;
49         struct iface_node *node;
50
51         /* Non-recursive destroy, like in ext3 */
52         while (n) {
53                 if (n->rb_left) {
54                         n = n->rb_left;
55                         continue;
56                 }
57                 if (n->rb_right) {
58                         n = n->rb_right;
59                         continue;
60                 }
61                 p = rb_parent(n);
62                 node = rb_entry(n, struct iface_node, node);
63                 if (!p)
64                         *root = RB_ROOT;
65                 else if (p->rb_left == n)
66                         p->rb_left = NULL;
67                 else if (p->rb_right == n)
68                         p->rb_right = NULL;
69
70                 kfree(node);
71                 n = p;
72         }
73 }
74
75 static int
76 iface_test(struct rb_root *root, const char **iface)
77 {
78         struct rb_node *n = root->rb_node;
79
80         while (n) {
81                 const char *d = iface_data(n);
82                 int res = strcmp(*iface, d);
83
84                 if (res < 0)
85                         n = n->rb_left;
86                 else if (res > 0)
87                         n = n->rb_right;
88                 else {
89                         *iface = d;
90                         return 1;
91                 }
92         }
93         return 0;
94 }
95
96 static int
97 iface_add(struct rb_root *root, const char **iface)
98 {
99         struct rb_node **n = &(root->rb_node), *p = NULL;
100         struct iface_node *d;
101
102         while (*n) {
103                 char *ifname = iface_data(*n);
104                 int res = strcmp(*iface, ifname);
105
106                 p = *n;
107                 if (res < 0)
108                         n = &((*n)->rb_left);
109                 else if (res > 0)
110                         n = &((*n)->rb_right);
111                 else {
112                         *iface = ifname;
113                         return 0;
114                 }
115         }
116
117         d = kzalloc(sizeof(*d), GFP_ATOMIC);
118         if (!d)
119                 return -ENOMEM;
120         strcpy(d->iface, *iface);
121
122         rb_link_node(&d->node, p, n);
123         rb_insert_color(&d->node, root);
124
125         *iface = d->iface;
126         return 0;
127 }
128
129 /* Type specific function prefix */
130 #define HTYPE           hash_netiface
131 #define IP_SET_HASH_WITH_NETS
132 #define IP_SET_HASH_WITH_RBTREE
133 #define IP_SET_HASH_WITH_MULTI
134
135 #define STREQ(a, b)     (strcmp(a, b) == 0)
136
137 /* IPv4 variants */
138
139 struct hash_netiface4_elem_hashed {
140         __be32 ip;
141         u8 physdev;
142         u8 cidr;
143         u8 nomatch;
144         u8 elem;
145 };
146
147 /* Member elements without timeout */
148 struct hash_netiface4_elem {
149         __be32 ip;
150         u8 physdev;
151         u8 cidr;
152         u8 nomatch;
153         u8 elem;
154         const char *iface;
155 };
156
157 struct hash_netiface4t_elem {
158         __be32 ip;
159         u8 physdev;
160         u8 cidr;
161         u8 nomatch;
162         u8 elem;
163         const char *iface;
164         unsigned long timeout;
165 };
166
167 struct hash_netiface4c_elem {
168         __be32 ip;
169         u8 physdev;
170         u8 cidr;
171         u8 nomatch;
172         u8 elem;
173         const char *iface;
174         struct ip_set_counter counter;
175 };
176
177 struct hash_netiface4ct_elem {
178         __be32 ip;
179         u8 physdev;
180         u8 cidr;
181         u8 nomatch;
182         u8 elem;
183         const char *iface;
184         struct ip_set_counter counter;
185         unsigned long timeout;
186 };
187
188 /* Common functions */
189
190 static inline bool
191 hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1,
192                           const struct hash_netiface4_elem *ip2,
193                           u32 *multi)
194 {
195         return ip1->ip == ip2->ip &&
196                ip1->cidr == ip2->cidr &&
197                (++*multi) &&
198                ip1->physdev == ip2->physdev &&
199                ip1->iface == ip2->iface;
200 }
201
202 static inline int
203 hash_netiface4_do_data_match(const struct hash_netiface4_elem *elem)
204 {
205         return elem->nomatch ? -ENOTEMPTY : 1;
206 }
207
208 static inline void
209 hash_netiface4_data_set_flags(struct hash_netiface4_elem *elem, u32 flags)
210 {
211         elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
212 }
213
214 static inline void
215 hash_netiface4_data_reset_flags(struct hash_netiface4_elem *elem, u8 *flags)
216 {
217         swap(*flags, elem->nomatch);
218 }
219
220 static inline void
221 hash_netiface4_data_netmask(struct hash_netiface4_elem *elem, u8 cidr)
222 {
223         elem->ip &= ip_set_netmask(cidr);
224         elem->cidr = cidr;
225 }
226
227 static bool
228 hash_netiface4_data_list(struct sk_buff *skb,
229                          const struct hash_netiface4_elem *data)
230 {
231         u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
232
233         if (data->nomatch)
234                 flags |= IPSET_FLAG_NOMATCH;
235         if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
236             nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
237             nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
238             (flags &&
239              nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
240                 goto nla_put_failure;
241         return 0;
242
243 nla_put_failure:
244         return 1;
245 }
246
247 static inline void
248 hash_netiface4_data_next(struct hash_netiface4_elem *next,
249                          const struct hash_netiface4_elem *d)
250 {
251         next->ip = d->ip;
252 }
253
254 #define MTYPE           hash_netiface4
255 #define PF              4
256 #define HOST_MASK       32
257 #define HKEY_DATALEN    sizeof(struct hash_netiface4_elem_hashed)
258 #include "ip_set_hash_gen.h"
259
260 static int
261 hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
262                     const struct xt_action_param *par,
263                     enum ipset_adt adt, struct ip_set_adt_opt *opt)
264 {
265         struct hash_netiface *h = set->data;
266         ipset_adtfn adtfn = set->variant->adt[adt];
267         struct hash_netiface4_elem e = {
268                 .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
269                 .elem = 1,
270         };
271         struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
272         int ret;
273
274         if (e.cidr == 0)
275                 return -EINVAL;
276         if (adt == IPSET_TEST)
277                 e.cidr = HOST_MASK;
278
279         ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
280         e.ip &= ip_set_netmask(e.cidr);
281
282 #define IFACE(dir)      (par->dir ? par->dir->name : NULL)
283 #define PHYSDEV(dir)    (nf_bridge->dir ? nf_bridge->dir->name : NULL)
284 #define SRCDIR          (opt->flags & IPSET_DIM_TWO_SRC)
285
286         if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
287 #ifdef CONFIG_BRIDGE_NETFILTER
288                 const struct nf_bridge_info *nf_bridge = skb->nf_bridge;
289
290                 if (!nf_bridge)
291                         return -EINVAL;
292                 e.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
293                 e.physdev = 1;
294 #else
295                 e.iface = NULL;
296 #endif
297         } else
298                 e.iface = SRCDIR ? IFACE(in) : IFACE(out);
299
300         if (!e.iface)
301                 return -EINVAL;
302         ret = iface_test(&h->rbtree, &e.iface);
303         if (adt == IPSET_ADD) {
304                 if (!ret) {
305                         ret = iface_add(&h->rbtree, &e.iface);
306                         if (ret)
307                                 return ret;
308                 }
309         } else if (!ret)
310                 return ret;
311
312         return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
313 }
314
315 static int
316 hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
317                     enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
318 {
319         struct hash_netiface *h = set->data;
320         ipset_adtfn adtfn = set->variant->adt[adt];
321         struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
322         struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
323         u32 ip = 0, ip_to, last;
324         char iface[IFNAMSIZ];
325         int ret;
326
327         if (unlikely(!tb[IPSET_ATTR_IP] ||
328                      !tb[IPSET_ATTR_IFACE] ||
329                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
330                      !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
331                      !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
332                      !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
333                 return -IPSET_ERR_PROTOCOL;
334
335         if (tb[IPSET_ATTR_LINENO])
336                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
337
338         ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
339               ip_set_get_extensions(set, tb, &ext);
340         if (ret)
341                 return ret;
342
343         if (tb[IPSET_ATTR_CIDR]) {
344                 e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
345                 if (e.cidr > HOST_MASK)
346                         return -IPSET_ERR_INVALID_CIDR;
347         }
348
349         strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
350         e.iface = iface;
351         ret = iface_test(&h->rbtree, &e.iface);
352         if (adt == IPSET_ADD) {
353                 if (!ret) {
354                         ret = iface_add(&h->rbtree, &e.iface);
355                         if (ret)
356                                 return ret;
357                 }
358         } else if (!ret)
359                 return ret;
360
361         if (tb[IPSET_ATTR_CADT_FLAGS]) {
362                 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
363                 if (cadt_flags & IPSET_FLAG_PHYSDEV)
364                         e.physdev = 1;
365                 if (cadt_flags & IPSET_FLAG_NOMATCH)
366                         flags |= (IPSET_FLAG_NOMATCH << 16);
367         }
368         if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
369                 e.ip = htonl(ip & ip_set_hostmask(e.cidr));
370                 ret = adtfn(set, &e, &ext, &ext, flags);
371                 return ip_set_enomatch(ret, flags, adt, set) ? -ret :
372                        ip_set_eexist(ret, flags) ? 0 : ret;
373         }
374
375         if (tb[IPSET_ATTR_IP_TO]) {
376                 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
377                 if (ret)
378                         return ret;
379                 if (ip_to < ip)
380                         swap(ip, ip_to);
381                 if (ip + UINT_MAX == ip_to)
382                         return -IPSET_ERR_HASH_RANGE;
383         } else
384                 ip_set_mask_from_to(ip, ip_to, e.cidr);
385
386         if (retried)
387                 ip = ntohl(h->next.ip);
388         while (!after(ip, ip_to)) {
389                 e.ip = htonl(ip);
390                 last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
391                 ret = adtfn(set, &e, &ext, &ext, flags);
392
393                 if (ret && !ip_set_eexist(ret, flags))
394                         return ret;
395                 else
396                         ret = 0;
397                 ip = last + 1;
398         }
399         return ret;
400 }
401
402 /* IPv6 variants */
403
404 struct hash_netiface6_elem_hashed {
405         union nf_inet_addr ip;
406         u8 physdev;
407         u8 cidr;
408         u8 nomatch;
409         u8 elem;
410 };
411
412 struct hash_netiface6_elem {
413         union nf_inet_addr ip;
414         u8 physdev;
415         u8 cidr;
416         u8 nomatch;
417         u8 elem;
418         const char *iface;
419 };
420
421 struct hash_netiface6t_elem {
422         union nf_inet_addr ip;
423         u8 physdev;
424         u8 cidr;
425         u8 nomatch;
426         u8 elem;
427         const char *iface;
428         unsigned long timeout;
429 };
430
431 struct hash_netiface6c_elem {
432         union nf_inet_addr ip;
433         u8 physdev;
434         u8 cidr;
435         u8 nomatch;
436         u8 elem;
437         const char *iface;
438         struct ip_set_counter counter;
439 };
440
441 struct hash_netiface6ct_elem {
442         union nf_inet_addr ip;
443         u8 physdev;
444         u8 cidr;
445         u8 nomatch;
446         u8 elem;
447         const char *iface;
448         struct ip_set_counter counter;
449         unsigned long timeout;
450 };
451
452 /* Common functions */
453
454 static inline bool
455 hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1,
456                           const struct hash_netiface6_elem *ip2,
457                           u32 *multi)
458 {
459         return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
460                ip1->cidr == ip2->cidr &&
461                (++*multi) &&
462                ip1->physdev == ip2->physdev &&
463                ip1->iface == ip2->iface;
464 }
465
466 static inline int
467 hash_netiface6_do_data_match(const struct hash_netiface6_elem *elem)
468 {
469         return elem->nomatch ? -ENOTEMPTY : 1;
470 }
471
472 static inline void
473 hash_netiface6_data_set_flags(struct hash_netiface6_elem *elem, u32 flags)
474 {
475         elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
476 }
477
478 static inline void
479 hash_netiface6_data_reset_flags(struct hash_netiface6_elem *elem, u8 *flags)
480 {
481         swap(*flags, elem->nomatch);
482 }
483
484 static inline void
485 hash_netiface6_data_netmask(struct hash_netiface6_elem *elem, u8 cidr)
486 {
487         ip6_netmask(&elem->ip, cidr);
488         elem->cidr = cidr;
489 }
490
491 static bool
492 hash_netiface6_data_list(struct sk_buff *skb,
493                          const struct hash_netiface6_elem *data)
494 {
495         u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
496
497         if (data->nomatch)
498                 flags |= IPSET_FLAG_NOMATCH;
499         if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
500             nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
501             nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
502             (flags &&
503              nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
504                 goto nla_put_failure;
505         return 0;
506
507 nla_put_failure:
508         return 1;
509 }
510
511 static inline void
512 hash_netiface6_data_next(struct hash_netiface4_elem *next,
513                          const struct hash_netiface6_elem *d)
514 {
515 }
516
517 #undef MTYPE
518 #undef PF
519 #undef HOST_MASK
520 #undef HKEY_DATALEN
521
522 #define MTYPE           hash_netiface6
523 #define PF              6
524 #define HOST_MASK       128
525 #define HKEY_DATALEN    sizeof(struct hash_netiface6_elem_hashed)
526 #define IP_SET_EMIT_CREATE
527 #include "ip_set_hash_gen.h"
528
529 static int
530 hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
531                     const struct xt_action_param *par,
532                     enum ipset_adt adt, struct ip_set_adt_opt *opt)
533 {
534         struct hash_netiface *h = set->data;
535         ipset_adtfn adtfn = set->variant->adt[adt];
536         struct hash_netiface6_elem e = {
537                 .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
538                 .elem = 1,
539         };
540         struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
541         int ret;
542
543         if (e.cidr == 0)
544                 return -EINVAL;
545         if (adt == IPSET_TEST)
546                 e.cidr = HOST_MASK;
547
548         ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
549         ip6_netmask(&e.ip, e.cidr);
550
551         if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
552 #ifdef CONFIG_BRIDGE_NETFILTER
553                 const struct nf_bridge_info *nf_bridge = skb->nf_bridge;
554
555                 if (!nf_bridge)
556                         return -EINVAL;
557                 e.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
558                 e.physdev = 1;
559 #else
560                 e.iface = NULL;
561 #endif
562         } else
563                 e.iface = SRCDIR ? IFACE(in) : IFACE(out);
564
565         if (!e.iface)
566                 return -EINVAL;
567         ret = iface_test(&h->rbtree, &e.iface);
568         if (adt == IPSET_ADD) {
569                 if (!ret) {
570                         ret = iface_add(&h->rbtree, &e.iface);
571                         if (ret)
572                                 return ret;
573                 }
574         } else if (!ret)
575                 return ret;
576
577         return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
578 }
579
580 static int
581 hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
582                    enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
583 {
584         struct hash_netiface *h = set->data;
585         ipset_adtfn adtfn = set->variant->adt[adt];
586         struct hash_netiface6_elem e = { .cidr = HOST_MASK, .elem = 1 };
587         struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
588         char iface[IFNAMSIZ];
589         int ret;
590
591         if (unlikely(!tb[IPSET_ATTR_IP] ||
592                      !tb[IPSET_ATTR_IFACE] ||
593                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
594                      !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
595                      !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
596                      !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
597                 return -IPSET_ERR_PROTOCOL;
598         if (unlikely(tb[IPSET_ATTR_IP_TO]))
599                 return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
600
601         if (tb[IPSET_ATTR_LINENO])
602                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
603
604         ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
605               ip_set_get_extensions(set, tb, &ext);
606         if (ret)
607                 return ret;
608
609         if (tb[IPSET_ATTR_CIDR])
610                 e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
611         if (e.cidr > HOST_MASK)
612                 return -IPSET_ERR_INVALID_CIDR;
613         ip6_netmask(&e.ip, e.cidr);
614
615         strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
616         e.iface = iface;
617         ret = iface_test(&h->rbtree, &e.iface);
618         if (adt == IPSET_ADD) {
619                 if (!ret) {
620                         ret = iface_add(&h->rbtree, &e.iface);
621                         if (ret)
622                                 return ret;
623                 }
624         } else if (!ret)
625                 return ret;
626
627         if (tb[IPSET_ATTR_CADT_FLAGS]) {
628                 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
629                 if (cadt_flags & IPSET_FLAG_PHYSDEV)
630                         e.physdev = 1;
631                 if (cadt_flags & IPSET_FLAG_NOMATCH)
632                         flags |= (IPSET_FLAG_NOMATCH << 16);
633         }
634
635         ret = adtfn(set, &e, &ext, &ext, flags);
636
637         return ip_set_enomatch(ret, flags, adt, set) ? -ret :
638                ip_set_eexist(ret, flags) ? 0 : ret;
639 }
640
641 static struct ip_set_type hash_netiface_type __read_mostly = {
642         .name           = "hash:net,iface",
643         .protocol       = IPSET_PROTOCOL,
644         .features       = IPSET_TYPE_IP | IPSET_TYPE_IFACE |
645                           IPSET_TYPE_NOMATCH,
646         .dimension      = IPSET_DIM_TWO,
647         .family         = NFPROTO_UNSPEC,
648         .revision_min   = REVISION_MIN,
649         .revision_max   = REVISION_MAX,
650         .create         = hash_netiface_create,
651         .create_policy  = {
652                 [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
653                 [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
654                 [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
655                 [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
656                 [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
657                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
658                 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
659         },
660         .adt_policy     = {
661                 [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
662                 [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
663                 [IPSET_ATTR_IFACE]      = { .type = NLA_NUL_STRING,
664                                             .len  = IFNAMSIZ - 1 },
665                 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
666                 [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
667                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
668                 [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
669                 [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
670                 [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
671         },
672         .me             = THIS_MODULE,
673 };
674
675 static int __init
676 hash_netiface_init(void)
677 {
678         return ip_set_type_register(&hash_netiface_type);
679 }
680
681 static void __exit
682 hash_netiface_fini(void)
683 {
684         ip_set_type_unregister(&hash_netiface_type);
685 }
686
687 module_init(hash_netiface_init);
688 module_exit(hash_netiface_fini);