igb: convert to CYCLECOUNTER_MASK macro.
[cascardo/linux.git] / drivers / net / vxlan.c
index be4649a..2ab0922 100644 (file)
@@ -549,10 +549,7 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff
 {
        struct sk_buff *p, **pp = NULL;
        struct vxlanhdr *vh, *vh2;
-       struct ethhdr *eh, *eh2;
-       unsigned int hlen, off_vx, off_eth;
-       const struct packet_offload *ptype;
-       __be16 type;
+       unsigned int hlen, off_vx;
        int flush = 1;
 
        off_vx = skb_gro_offset(skb);
@@ -563,17 +560,6 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff
                if (unlikely(!vh))
                        goto out;
        }
-       skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */
-       skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr));
-
-       off_eth = skb_gro_offset(skb);
-       hlen = off_eth + sizeof(*eh);
-       eh   = skb_gro_header_fast(skb, off_eth);
-       if (skb_gro_header_hard(skb, hlen)) {
-               eh = skb_gro_header_slow(skb, hlen, off_eth);
-               if (unlikely(!eh))
-                       goto out;
-       }
 
        flush = 0;
 
@@ -582,28 +568,16 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff
                        continue;
 
                vh2 = (struct vxlanhdr *)(p->data + off_vx);
-               eh2 = (struct ethhdr   *)(p->data + off_eth);
-               if (vh->vx_vni != vh2->vx_vni || compare_ether_header(eh, eh2)) {
+               if (vh->vx_vni != vh2->vx_vni) {
                        NAPI_GRO_CB(p)->same_flow = 0;
                        continue;
                }
        }
 
-       type = eh->h_proto;
-
-       rcu_read_lock();
-       ptype = gro_find_receive_by_type(type);
-       if (ptype == NULL) {
-               flush = 1;
-               goto out_unlock;
-       }
-
-       skb_gro_pull(skb, sizeof(*eh)); /* pull inner eth header */
-       skb_gro_postpull_rcsum(skb, eh, sizeof(*eh));
-       pp = ptype->callbacks.gro_receive(head, skb);
+       skb_gro_pull(skb, sizeof(struct vxlanhdr));
+       skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr));
+       pp = eth_gro_receive(head, skb);
 
-out_unlock:
-       rcu_read_unlock();
 out:
        NAPI_GRO_CB(skb)->flush |= flush;
 
@@ -612,24 +586,9 @@ out:
 
 static int vxlan_gro_complete(struct sk_buff *skb, int nhoff)
 {
-       struct ethhdr *eh;
-       struct packet_offload *ptype;
-       __be16 type;
-       int vxlan_len  = sizeof(struct vxlanhdr) + sizeof(struct ethhdr);
-       int err = -ENOSYS;
-
        udp_tunnel_gro_complete(skb, nhoff);
 
-       eh = (struct ethhdr *)(skb->data + nhoff + sizeof(struct vxlanhdr));
-       type = eh->h_proto;
-
-       rcu_read_lock();
-       ptype = gro_find_complete_by_type(type);
-       if (ptype != NULL)
-               err = ptype->callbacks.gro_complete(skb, nhoff + vxlan_len);
-
-       rcu_read_unlock();
-       return err;
+       return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr));
 }
 
 /* Notify netdevs that UDP port started listening */
@@ -849,7 +808,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan,
 /* Add static entry (via netlink) */
 static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
                         struct net_device *dev,
-                        const unsigned char *addr, u16 flags)
+                        const unsigned char *addr, u16 vid, u16 flags)
 {
        struct vxlan_dev *vxlan = netdev_priv(dev);
        /* struct net *net = dev_net(vxlan->dev); */
@@ -885,7 +844,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 /* Delete entry (via netlink) */
 static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
                            struct net_device *dev,
-                           const unsigned char *addr)
+                           const unsigned char *addr, u16 vid)
 {
        struct vxlan_dev *vxlan = netdev_priv(dev);
        struct vxlan_fdb *f;
@@ -1579,8 +1538,10 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
        bool udp_sum = !udp_get_no_check6_tx(vs->sock->sk);
 
        skb = udp_tunnel_handle_offloads(skb, udp_sum);
-       if (IS_ERR(skb))
-               return -EINVAL;
+       if (IS_ERR(skb)) {
+               err = -EINVAL;
+               goto err;
+       }
 
        skb_scrub_packet(skb, xnet);
 
@@ -1590,16 +1551,15 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
 
        /* Need space for new headers (invalidates iph ptr) */
        err = skb_cow_head(skb, min_headroom);
-       if (unlikely(err))
-               return err;
-
-       if (vlan_tx_tag_present(skb)) {
-               if (WARN_ON(!__vlan_put_tag(skb,
-                                           skb->vlan_proto,
-                                           vlan_tx_tag_get(skb))))
-                       return -ENOMEM;
+       if (unlikely(err)) {
+               kfree_skb(skb);
+               goto err;
+       }
 
-               skb->vlan_tci = 0;
+       skb = vlan_hwaccel_push_inside(skb);
+       if (WARN_ON(!skb)) {
+               err = -ENOMEM;
+               goto err;
        }
 
        vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
@@ -1611,6 +1571,9 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
        udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio,
                             ttl, src_port, dst_port);
        return 0;
+err:
+       dst_release(dst);
+       return err;
 }
 #endif
 
@@ -1626,7 +1589,7 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
 
        skb = udp_tunnel_handle_offloads(skb, udp_sum);
        if (IS_ERR(skb))
-               return -EINVAL;
+               return PTR_ERR(skb);
 
        min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
                        + VXLAN_HLEN + sizeof(struct iphdr)
@@ -1634,18 +1597,15 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
 
        /* Need space for new headers (invalidates iph ptr) */
        err = skb_cow_head(skb, min_headroom);
-       if (unlikely(err))
+       if (unlikely(err)) {
+               kfree_skb(skb);
                return err;
-
-       if (vlan_tx_tag_present(skb)) {
-               if (WARN_ON(!__vlan_put_tag(skb,
-                                           skb->vlan_proto,
-                                           vlan_tx_tag_get(skb))))
-                       return -ENOMEM;
-
-               skb->vlan_tci = 0;
        }
 
+       skb = vlan_hwaccel_push_inside(skb);
+       if (WARN_ON(!skb))
+               return -ENOMEM;
+
        vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
        vxh->vx_flags = htonl(VXLAN_FLAGS);
        vxh->vx_vni = vni;
@@ -1786,9 +1746,12 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                                     tos, ttl, df, src_port, dst_port,
                                     htonl(vni << 8),
                                     !net_eq(vxlan->net, dev_net(vxlan->dev)));
-
-               if (err < 0)
+               if (err < 0) {
+                       /* skb is already freed. */
+                       skb = NULL;
                        goto rt_tx_error;
+               }
+
                iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
 #if IS_ENABLED(CONFIG_IPV6)
        } else {
@@ -1995,9 +1958,8 @@ static int vxlan_init(struct net_device *dev)
        spin_lock(&vn->sock_lock);
        vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET,
                             vxlan->dst_port);
-       if (vs) {
+       if (vs && atomic_add_unless(&vs->refcnt, 1, 0)) {
                /* If we have a socket with same port already, reuse it */
-               atomic_inc(&vs->refcnt);
                vxlan_vs_add_dev(vs, vxlan);
        } else {
                /* otherwise make new socket outside of RTNL */
@@ -2236,6 +2198,9 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = {
        [IFLA_VXLAN_L2MISS]     = { .type = NLA_U8 },
        [IFLA_VXLAN_L3MISS]     = { .type = NLA_U8 },
        [IFLA_VXLAN_PORT]       = { .type = NLA_U16 },
+       [IFLA_VXLAN_UDP_CSUM]   = { .type = NLA_U8 },
+       [IFLA_VXLAN_UDP_ZERO_CSUM6_TX]  = { .type = NLA_U8 },
+       [IFLA_VXLAN_UDP_ZERO_CSUM6_RX]  = { .type = NLA_U8 },
 };
 
 static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
@@ -2396,12 +2361,9 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
 
        spin_lock(&vn->sock_lock);
        vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port);
-       if (vs) {
-               if (vs->rcv == rcv)
-                       atomic_inc(&vs->refcnt);
-               else
+       if (vs && ((vs->rcv != rcv) ||
+                  !atomic_add_unless(&vs->refcnt, 1, 0)))
                        vs = ERR_PTR(-EBUSY);
-       }
        spin_unlock(&vn->sock_lock);
 
        if (!vs)