linux/net/netfilter/ipset/ip_set_hash_netiface.c
<<
>>
Prefs
   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
  31MODULE_LICENSE("GPL");
  32MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
  33IP_SET_MODULE_DESC("hash:net,iface", REVISION_MIN, REVISION_MAX);
  34MODULE_ALIAS("ip_set_hash:net,iface");
  35
  36/* Interface name rbtree */
  37
  38struct 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
  45static void
  46rbtree_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
  75static int
  76iface_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
  96static int
  97iface_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
 139struct 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 */
 148struct hash_netiface4_elem {
 149        __be32 ip;
 150        u8 physdev;
 151        u8 cidr;
 152        u8 nomatch;
 153        u8 elem;
 154        const char *iface;
 155};
 156
 157struct 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
 167struct 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
 177struct 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
 190static inline bool
 191hash_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
 202static inline int
 203hash_netiface4_do_data_match(const struct hash_netiface4_elem *elem)
 204{
 205        return elem->nomatch ? -ENOTEMPTY : 1;
 206}
 207
 208static inline void
 209hash_netiface4_data_set_flags(struct hash_netiface4_elem *elem, u32 flags)
 210{
 211        elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
 212}
 213
 214static inline void
 215hash_netiface4_data_reset_flags(struct hash_netiface4_elem *elem, u8 *flags)
 216{
 217        swap(*flags, elem->nomatch);
 218}
 219
 220static inline void
 221hash_netiface4_data_netmask(struct hash_netiface4_elem *elem, u8 cidr)
 222{
 223        elem->ip &= ip_set_netmask(cidr);
 224        elem->cidr = cidr;
 225}
 226
 227static bool
 228hash_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
 243nla_put_failure:
 244        return 1;
 245}
 246
 247static inline void
 248hash_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
 260static int
 261hash_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
 315static int
 316hash_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) ? 1 :
 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
 404struct hash_netiface6_elem_hashed {
 405        union nf_inet_addr ip;
 406        u8 physdev;
 407        u8 cidr;
 408        u8 nomatch;
 409        u8 elem;
 410};
 411
 412struct 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
 421struct 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
 431struct 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
 441struct 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
 454static inline bool
 455hash_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
 466static inline int
 467hash_netiface6_do_data_match(const struct hash_netiface6_elem *elem)
 468{
 469        return elem->nomatch ? -ENOTEMPTY : 1;
 470}
 471
 472static inline void
 473hash_netiface6_data_set_flags(struct hash_netiface6_elem *elem, u32 flags)
 474{
 475        elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
 476}
 477
 478static inline void
 479hash_netiface6_data_reset_flags(struct hash_netiface6_elem *elem, u8 *flags)
 480{
 481        swap(*flags, elem->nomatch);
 482}
 483
 484static inline void
 485hash_netiface6_data_netmask(struct hash_netiface6_elem *elem, u8 cidr)
 486{
 487        ip6_netmask(&elem->ip, cidr);
 488        elem->cidr = cidr;
 489}
 490
 491static bool
 492hash_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
 507nla_put_failure:
 508        return 1;
 509}
 510
 511static inline void
 512hash_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
 529static int
 530hash_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
 580static int
 581hash_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) ? 1 :
 638               ip_set_eexist(ret, flags) ? 0 : ret;
 639}
 640
 641static 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
 675static int __init
 676hash_netiface_init(void)
 677{
 678        return ip_set_type_register(&hash_netiface_type);
 679}
 680
 681static void __exit
 682hash_netiface_fini(void)
 683{
 684        ip_set_type_unregister(&hash_netiface_type);
 685}
 686
 687module_init(hash_netiface_init);
 688module_exit(hash_netiface_fini);
 689