These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / netfilter / ipset / ip_set_hash_netiface.c
index 380ef51..43d8c98 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/skbuff.h>
 #include <linux/errno.h>
 #include <linux/random.h>
-#include <linux/rbtree.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
 #include <net/netlink.h>
@@ -37,88 +36,13 @@ MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
 IP_SET_MODULE_DESC("hash:net,iface", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 MODULE_ALIAS("ip_set_hash:net,iface");
 
-/* Interface name rbtree */
-
-struct iface_node {
-       struct rb_node node;
-       char iface[IFNAMSIZ];
-};
-
-#define iface_data(n)  (rb_entry(n, struct iface_node, node)->iface)
-
-static void
-rbtree_destroy(struct rb_root *root)
-{
-       struct iface_node *node, *next;
-
-       rbtree_postorder_for_each_entry_safe(node, next, root, node)
-               kfree(node);
-
-       *root = RB_ROOT;
-}
-
-static int
-iface_test(struct rb_root *root, const char **iface)
-{
-       struct rb_node *n = root->rb_node;
-
-       while (n) {
-               const char *d = iface_data(n);
-               int res = strcmp(*iface, d);
-
-               if (res < 0)
-                       n = n->rb_left;
-               else if (res > 0)
-                       n = n->rb_right;
-               else {
-                       *iface = d;
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-static int
-iface_add(struct rb_root *root, const char **iface)
-{
-       struct rb_node **n = &(root->rb_node), *p = NULL;
-       struct iface_node *d;
-
-       while (*n) {
-               char *ifname = iface_data(*n);
-               int res = strcmp(*iface, ifname);
-
-               p = *n;
-               if (res < 0)
-                       n = &((*n)->rb_left);
-               else if (res > 0)
-                       n = &((*n)->rb_right);
-               else {
-                       *iface = ifname;
-                       return 0;
-               }
-       }
-
-       d = kzalloc(sizeof(*d), GFP_ATOMIC);
-       if (!d)
-               return -ENOMEM;
-       strcpy(d->iface, *iface);
-
-       rb_link_node(&d->node, p, n);
-       rb_insert_color(&d->node, root);
-
-       *iface = d->iface;
-       return 0;
-}
-
 /* Type specific function prefix */
 #define HTYPE          hash_netiface
 #define IP_SET_HASH_WITH_NETS
-#define IP_SET_HASH_WITH_RBTREE
 #define IP_SET_HASH_WITH_MULTI
 #define IP_SET_HASH_WITH_NET0
 
-#define STREQ(a, b)    (strcmp(a, b) == 0)
+#define STRLCPY(a, b)  strlcpy(a, b, IFNAMSIZ)
 
 /* IPv4 variant */
 
@@ -137,7 +61,7 @@ struct hash_netiface4_elem {
        u8 cidr;
        u8 nomatch;
        u8 elem;
-       const char *iface;
+       char iface[IFNAMSIZ];
 };
 
 /* Common functions */
@@ -151,7 +75,7 @@ hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1,
               ip1->cidr == ip2->cidr &&
               (++*multi) &&
               ip1->physdev == ip2->physdev &&
-              ip1->iface == ip2->iface;
+              strcmp(ip1->iface, ip2->iface) == 0;
 }
 
 static inline int
@@ -193,10 +117,10 @@ hash_netiface4_data_list(struct sk_buff *skb,
            (flags &&
             nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
                goto nla_put_failure;
-       return 0;
+       return false;
 
 nla_put_failure:
-       return 1;
+       return true;
 }
 
 static inline void
@@ -207,7 +131,6 @@ hash_netiface4_data_next(struct hash_netiface4_elem *next,
 }
 
 #define MTYPE          hash_netiface4
-#define PF             4
 #define HOST_MASK      32
 #define HKEY_DATALEN   sizeof(struct hash_netiface4_elem_hashed)
 #include "ip_set_hash_gen.h"
@@ -220,7 +143,7 @@ static const char *get_physindev_name(const struct sk_buff *skb)
        return dev ? dev->name : NULL;
 }
 
-static const char *get_phyoutdev_name(const struct sk_buff *skb)
+static const char *get_physoutdev_name(const struct sk_buff *skb)
 {
        struct net_device *dev = nf_bridge_get_physoutdev(skb);
 
@@ -236,11 +159,10 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
        struct hash_netiface *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netiface4_elem e = {
-               .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
+               .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
                .elem = 1,
        };
        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
-       int ret;
 
        if (e.cidr == 0)
                return -EINVAL;
@@ -250,35 +172,25 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
        ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
        e.ip &= ip_set_netmask(e.cidr);
 
-#define IFACE(dir)     (par->dir ? par->dir->name : NULL)
+#define IFACE(dir)     (par->dir ? par->dir->name : "")
 #define SRCDIR         (opt->flags & IPSET_DIM_TWO_SRC)
 
        if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
-               e.iface = SRCDIR ? get_physindev_name(skb) :
-                                  get_phyoutdev_name(skb);
+               const char *eiface = SRCDIR ? get_physindev_name(skb) :
+                                             get_physoutdev_name(skb);
 
-               if (!e.iface)
+               if (!eiface)
                        return -EINVAL;
+               STRLCPY(e.iface, eiface);
                e.physdev = 1;
-#else
-               e.iface = NULL;
 #endif
-       } else
-               e.iface = SRCDIR ? IFACE(in) : IFACE(out);
+       } else {
+               STRLCPY(e.iface, SRCDIR ? IFACE(in) : IFACE(out));
+       }
 
-       if (!e.iface)
+       if (strlen(e.iface) == 0)
                return -EINVAL;
-       ret = iface_test(&h->rbtree, &e.iface);
-       if (adt == IPSET_ADD) {
-               if (!ret) {
-                       ret = iface_add(&h->rbtree, &e.iface);
-                       if (ret)
-                               return ret;
-               }
-       } else if (!ret)
-               return ret;
-
        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 }
 
@@ -291,25 +203,21 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
        struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
        struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
        u32 ip = 0, ip_to = 0, last;
-       char iface[IFNAMSIZ];
        int ret;
 
+       if (tb[IPSET_ATTR_LINENO])
+               *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !tb[IPSET_ATTR_IFACE] ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE)))
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
                return -IPSET_ERR_PROTOCOL;
 
-       if (tb[IPSET_ATTR_LINENO])
-               *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+       ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
+       if (ret)
+               return ret;
 
-       ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
-             ip_set_get_extensions(set, tb, &ext);
+       ret = ip_set_get_extensions(set, tb, &ext);
        if (ret)
                return ret;
 
@@ -318,21 +226,11 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
                if (e.cidr > HOST_MASK)
                        return -IPSET_ERR_INVALID_CIDR;
        }
-
-       strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
-       e.iface = iface;
-       ret = iface_test(&h->rbtree, &e.iface);
-       if (adt == IPSET_ADD) {
-               if (!ret) {
-                       ret = iface_add(&h->rbtree, &e.iface);
-                       if (ret)
-                               return ret;
-               }
-       } else if (!ret)
-               return ret;
+       nla_strlcpy(e.iface, tb[IPSET_ATTR_IFACE], IFNAMSIZ);
 
        if (tb[IPSET_ATTR_CADT_FLAGS]) {
                u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+
                if (cadt_flags & IPSET_FLAG_PHYSDEV)
                        e.physdev = 1;
                if (cadt_flags & IPSET_FLAG_NOMATCH)
@@ -353,8 +251,9 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
                        swap(ip, ip_to);
                if (ip + UINT_MAX == ip_to)
                        return -IPSET_ERR_HASH_RANGE;
-       } else
+       } else {
                ip_set_mask_from_to(ip, ip_to, e.cidr);
+       }
 
        if (retried)
                ip = ntohl(h->next.ip);
@@ -365,8 +264,8 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
 
                if (ret && !ip_set_eexist(ret, flags))
                        return ret;
-               else
-                       ret = 0;
+
+               ret = 0;
                ip = last + 1;
        }
        return ret;
@@ -388,7 +287,7 @@ struct hash_netiface6_elem {
        u8 cidr;
        u8 nomatch;
        u8 elem;
-       const char *iface;
+       char iface[IFNAMSIZ];
 };
 
 /* Common functions */
@@ -402,7 +301,7 @@ hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1,
               ip1->cidr == ip2->cidr &&
               (++*multi) &&
               ip1->physdev == ip2->physdev &&
-              ip1->iface == ip2->iface;
+              strcmp(ip1->iface, ip2->iface) == 0;
 }
 
 static inline int
@@ -444,10 +343,10 @@ hash_netiface6_data_list(struct sk_buff *skb,
            (flags &&
             nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
                goto nla_put_failure;
-       return 0;
+       return false;
 
 nla_put_failure:
-       return 1;
+       return true;
 }
 
 static inline void
@@ -457,12 +356,9 @@ hash_netiface6_data_next(struct hash_netiface4_elem *next,
 }
 
 #undef MTYPE
-#undef PF
 #undef HOST_MASK
-#undef HKEY_DATALEN
 
 #define MTYPE          hash_netiface6
-#define PF             6
 #define HOST_MASK      128
 #define HKEY_DATALEN   sizeof(struct hash_netiface6_elem_hashed)
 #define IP_SET_EMIT_CREATE
@@ -476,11 +372,10 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
        struct hash_netiface *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netiface6_elem e = {
-               .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
+               .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
                .elem = 1,
        };
        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
-       int ret;
 
        if (e.cidr == 0)
                return -EINVAL;
@@ -492,85 +387,64 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
 
        if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
-               e.iface = SRCDIR ? get_physindev_name(skb) :
-                                  get_phyoutdev_name(skb);
-               if (!e.iface)
-                       return -EINVAL;
+               const char *eiface = SRCDIR ? get_physindev_name(skb) :
+                                             get_physoutdev_name(skb);
 
+               if (!eiface)
+                       return -EINVAL;
+               STRLCPY(e.iface, eiface);
                e.physdev = 1;
-#else
-               e.iface = NULL;
 #endif
-       } else
-               e.iface = SRCDIR ? IFACE(in) : IFACE(out);
+       } else {
+               STRLCPY(e.iface, SRCDIR ? IFACE(in) : IFACE(out));
+       }
 
-       if (!e.iface)
+       if (strlen(e.iface) == 0)
                return -EINVAL;
-       ret = iface_test(&h->rbtree, &e.iface);
-       if (adt == IPSET_ADD) {
-               if (!ret) {
-                       ret = iface_add(&h->rbtree, &e.iface);
-                       if (ret)
-                               return ret;
-               }
-       } else if (!ret)
-               return ret;
 
        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 }
 
 static int
 hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
-                  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
+                   enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
-       struct hash_netiface *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netiface6_elem e = { .cidr = HOST_MASK, .elem = 1 };
        struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
-       char iface[IFNAMSIZ];
        int ret;
 
+       if (tb[IPSET_ATTR_LINENO])
+               *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !tb[IPSET_ATTR_IFACE] ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) ||
-                    !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE)))
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
                return -IPSET_ERR_PROTOCOL;
        if (unlikely(tb[IPSET_ATTR_IP_TO]))
                return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
 
-       if (tb[IPSET_ATTR_LINENO])
-               *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+       ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip);
+       if (ret)
+               return ret;
 
-       ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
-             ip_set_get_extensions(set, tb, &ext);
+       ret = ip_set_get_extensions(set, tb, &ext);
        if (ret)
                return ret;
 
-       if (tb[IPSET_ATTR_CIDR])
+       if (tb[IPSET_ATTR_CIDR]) {
                e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-       if (e.cidr > HOST_MASK)
-               return -IPSET_ERR_INVALID_CIDR;
+               if (e.cidr > HOST_MASK)
+                       return -IPSET_ERR_INVALID_CIDR;
+       }
+
        ip6_netmask(&e.ip, e.cidr);
 
-       strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
-       e.iface = iface;
-       ret = iface_test(&h->rbtree, &e.iface);
-       if (adt == IPSET_ADD) {
-               if (!ret) {
-                       ret = iface_add(&h->rbtree, &e.iface);
-                       if (ret)
-                               return ret;
-               }
-       } else if (!ret)
-               return ret;
+       nla_strlcpy(e.iface, tb[IPSET_ATTR_IFACE], IFNAMSIZ);
 
        if (tb[IPSET_ATTR_CADT_FLAGS]) {
                u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+
                if (cadt_flags & IPSET_FLAG_PHYSDEV)
                        e.physdev = 1;
                if (cadt_flags & IPSET_FLAG_NOMATCH)
@@ -613,7 +487,8 @@ static struct ip_set_type hash_netiface_type __read_mostly = {
                [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
                [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
                [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
-               [IPSET_ATTR_COMMENT]    = { .type = NLA_NUL_STRING },
+               [IPSET_ATTR_COMMENT]    = { .type = NLA_NUL_STRING,
+                                           .len  = IPSET_MAX_COMMENT_SIZE },
                [IPSET_ATTR_SKBMARK]    = { .type = NLA_U64 },
                [IPSET_ATTR_SKBPRIO]    = { .type = NLA_U32 },
                [IPSET_ATTR_SKBQUEUE]   = { .type = NLA_U16 },
@@ -630,6 +505,7 @@ hash_netiface_init(void)
 static void __exit
 hash_netiface_fini(void)
 {
+       rcu_barrier();
        ip_set_type_unregister(&hash_netiface_type);
 }