]> Git Repo - linux.git/blobdiff - drivers/net/vxlan/vxlan_core.c
net: bgmac: Fix return value check for fixed_phy_register()
[linux.git] / drivers / net / vxlan / vxlan_core.c
index 78744549c1b30d4c18fed0c5188cfef4bb292df4..c9a9373733c0159103dd33200f0d2b64f63a77db 100644 (file)
@@ -623,6 +623,32 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,
        return 1;
 }
 
+static bool vxlan_parse_gpe_proto(struct vxlanhdr *hdr, __be16 *protocol)
+{
+       struct vxlanhdr_gpe *gpe = (struct vxlanhdr_gpe *)hdr;
+
+       /* Need to have Next Protocol set for interfaces in GPE mode. */
+       if (!gpe->np_applied)
+               return false;
+       /* "The initial version is 0. If a receiver does not support the
+        * version indicated it MUST drop the packet.
+        */
+       if (gpe->version != 0)
+               return false;
+       /* "When the O bit is set to 1, the packet is an OAM packet and OAM
+        * processing MUST occur." However, we don't implement OAM
+        * processing, thus drop the packet.
+        */
+       if (gpe->oam_flag)
+               return false;
+
+       *protocol = tun_p_to_eth_p(gpe->next_protocol);
+       if (!*protocol)
+               return false;
+
+       return true;
+}
+
 static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,
                                          unsigned int off,
                                          struct vxlanhdr *vh, size_t hdrlen,
@@ -649,26 +675,24 @@ static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,
        return vh;
 }
 
-static struct sk_buff *vxlan_gro_receive(struct sock *sk,
-                                        struct list_head *head,
-                                        struct sk_buff *skb)
+static struct vxlanhdr *vxlan_gro_prepare_receive(struct sock *sk,
+                                                 struct list_head *head,
+                                                 struct sk_buff *skb,
+                                                 struct gro_remcsum *grc)
 {
-       struct sk_buff *pp = NULL;
        struct sk_buff *p;
        struct vxlanhdr *vh, *vh2;
        unsigned int hlen, off_vx;
-       int flush = 1;
        struct vxlan_sock *vs = rcu_dereference_sk_user_data(sk);
        __be32 flags;
-       struct gro_remcsum grc;
 
-       skb_gro_remcsum_init(&grc);
+       skb_gro_remcsum_init(grc);
 
        off_vx = skb_gro_offset(skb);
        hlen = off_vx + sizeof(*vh);
        vh = skb_gro_header(skb, hlen, off_vx);
        if (unlikely(!vh))
-               goto out;
+               return NULL;
 
        skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr));
 
@@ -676,12 +700,12 @@ static struct sk_buff *vxlan_gro_receive(struct sock *sk,
 
        if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) {
                vh = vxlan_gro_remcsum(skb, off_vx, vh, sizeof(struct vxlanhdr),
-                                      vh->vx_vni, &grc,
+                                      vh->vx_vni, grc,
                                       !!(vs->flags &
                                          VXLAN_F_REMCSUM_NOPARTIAL));
 
                if (!vh)
-                       goto out;
+                       return NULL;
        }
 
        skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */
@@ -698,12 +722,48 @@ static struct sk_buff *vxlan_gro_receive(struct sock *sk,
                }
        }
 
-       pp = call_gro_receive(eth_gro_receive, head, skb);
-       flush = 0;
+       return vh;
+}
 
-out:
+static struct sk_buff *vxlan_gro_receive(struct sock *sk,
+                                        struct list_head *head,
+                                        struct sk_buff *skb)
+{
+       struct sk_buff *pp = NULL;
+       struct gro_remcsum grc;
+       int flush = 1;
+
+       if (vxlan_gro_prepare_receive(sk, head, skb, &grc)) {
+               pp = call_gro_receive(eth_gro_receive, head, skb);
+               flush = 0;
+       }
        skb_gro_flush_final_remcsum(skb, pp, flush, &grc);
+       return pp;
+}
+
+static struct sk_buff *vxlan_gpe_gro_receive(struct sock *sk,
+                                            struct list_head *head,
+                                            struct sk_buff *skb)
+{
+       const struct packet_offload *ptype;
+       struct sk_buff *pp = NULL;
+       struct gro_remcsum grc;
+       struct vxlanhdr *vh;
+       __be16 protocol;
+       int flush = 1;
 
+       vh = vxlan_gro_prepare_receive(sk, head, skb, &grc);
+       if (vh) {
+               if (!vxlan_parse_gpe_proto(vh, &protocol))
+                       goto out;
+               ptype = gro_find_receive_by_type(protocol);
+               if (!ptype)
+                       goto out;
+               pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+               flush = 0;
+       }
+out:
+       skb_gro_flush_final_remcsum(skb, pp, flush, &grc);
        return pp;
 }
 
@@ -715,6 +775,21 @@ static int vxlan_gro_complete(struct sock *sk, struct sk_buff *skb, int nhoff)
        return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr));
 }
 
+static int vxlan_gpe_gro_complete(struct sock *sk, struct sk_buff *skb, int nhoff)
+{
+       struct vxlanhdr *vh = (struct vxlanhdr *)(skb->data + nhoff);
+       const struct packet_offload *ptype;
+       int err = -ENOSYS;
+       __be16 protocol;
+
+       if (!vxlan_parse_gpe_proto(vh, &protocol))
+               return err;
+       ptype = gro_find_complete_by_type(protocol);
+       if (ptype)
+               err = ptype->callbacks.gro_complete(skb, nhoff + sizeof(struct vxlanhdr));
+       return err;
+}
+
 static struct vxlan_fdb *vxlan_fdb_alloc(struct vxlan_dev *vxlan, const u8 *mac,
                                         __u16 state, __be32 src_vni,
                                         __u16 ndm_flags)
@@ -1525,35 +1600,6 @@ out:
        unparsed->vx_flags &= ~VXLAN_GBP_USED_BITS;
 }
 
-static bool vxlan_parse_gpe_hdr(struct vxlanhdr *unparsed,
-                               __be16 *protocol,
-                               struct sk_buff *skb, u32 vxflags)
-{
-       struct vxlanhdr_gpe *gpe = (struct vxlanhdr_gpe *)unparsed;
-
-       /* Need to have Next Protocol set for interfaces in GPE mode. */
-       if (!gpe->np_applied)
-               return false;
-       /* "The initial version is 0. If a receiver does not support the
-        * version indicated it MUST drop the packet.
-        */
-       if (gpe->version != 0)
-               return false;
-       /* "When the O bit is set to 1, the packet is an OAM packet and OAM
-        * processing MUST occur." However, we don't implement OAM
-        * processing, thus drop the packet.
-        */
-       if (gpe->oam_flag)
-               return false;
-
-       *protocol = tun_p_to_eth_p(gpe->next_protocol);
-       if (!*protocol)
-               return false;
-
-       unparsed->vx_flags &= ~VXLAN_GPE_USED_BITS;
-       return true;
-}
-
 static bool vxlan_set_mac(struct vxlan_dev *vxlan,
                          struct vxlan_sock *vs,
                          struct sk_buff *skb, __be32 vni)
@@ -1655,8 +1701,9 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
         * used by VXLAN extensions if explicitly requested.
         */
        if (vs->flags & VXLAN_F_GPE) {
-               if (!vxlan_parse_gpe_hdr(&unparsed, &protocol, skb, vs->flags))
+               if (!vxlan_parse_gpe_proto(&unparsed, &protocol))
                        goto drop;
+               unparsed.vx_flags &= ~VXLAN_GPE_USED_BITS;
                raw_proto = true;
        }
 
@@ -2516,7 +2563,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                }
 
                ndst = &rt->dst;
-               err = skb_tunnel_check_pmtu(skb, ndst, VXLAN_HEADROOM,
+               err = skb_tunnel_check_pmtu(skb, ndst, vxlan_headroom(flags & VXLAN_F_GPE),
                                            netif_is_any_bridge_port(dev));
                if (err < 0) {
                        goto tx_error;
@@ -2577,7 +2624,8 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                                goto out_unlock;
                }
 
-               err = skb_tunnel_check_pmtu(skb, ndst, VXLAN6_HEADROOM,
+               err = skb_tunnel_check_pmtu(skb, ndst,
+                                           vxlan_headroom((flags & VXLAN_F_GPE) | VXLAN_F_IPV6),
                                            netif_is_any_bridge_port(dev));
                if (err < 0) {
                        goto tx_error;
@@ -2989,14 +3037,12 @@ static int vxlan_change_mtu(struct net_device *dev, int new_mtu)
        struct vxlan_rdst *dst = &vxlan->default_dst;
        struct net_device *lowerdev = __dev_get_by_index(vxlan->net,
                                                         dst->remote_ifindex);
-       bool use_ipv6 = !!(vxlan->cfg.flags & VXLAN_F_IPV6);
 
        /* This check is different than dev->max_mtu, because it looks at
         * the lowerdev->mtu, rather than the static dev->max_mtu
         */
        if (lowerdev) {
-               int max_mtu = lowerdev->mtu -
-                             (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM);
+               int max_mtu = lowerdev->mtu - vxlan_headroom(vxlan->cfg.flags);
                if (new_mtu > max_mtu)
                        return -EINVAL;
        }
@@ -3379,8 +3425,13 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, bool ipv6,
        tunnel_cfg.encap_rcv = vxlan_rcv;
        tunnel_cfg.encap_err_lookup = vxlan_err_lookup;
        tunnel_cfg.encap_destroy = NULL;
-       tunnel_cfg.gro_receive = vxlan_gro_receive;
-       tunnel_cfg.gro_complete = vxlan_gro_complete;
+       if (vs->flags & VXLAN_F_GPE) {
+               tunnel_cfg.gro_receive = vxlan_gpe_gro_receive;
+               tunnel_cfg.gro_complete = vxlan_gpe_gro_complete;
+       } else {
+               tunnel_cfg.gro_receive = vxlan_gro_receive;
+               tunnel_cfg.gro_complete = vxlan_gro_complete;
+       }
 
        setup_udp_tunnel_sock(net, sock, &tunnel_cfg);
 
@@ -3644,11 +3695,11 @@ static void vxlan_config_apply(struct net_device *dev,
        struct vxlan_dev *vxlan = netdev_priv(dev);
        struct vxlan_rdst *dst = &vxlan->default_dst;
        unsigned short needed_headroom = ETH_HLEN;
-       bool use_ipv6 = !!(conf->flags & VXLAN_F_IPV6);
        int max_mtu = ETH_MAX_MTU;
+       u32 flags = conf->flags;
 
        if (!changelink) {
-               if (conf->flags & VXLAN_F_GPE)
+               if (flags & VXLAN_F_GPE)
                        vxlan_raw_setup(dev);
                else
                        vxlan_ether_setup(dev);
@@ -3673,8 +3724,7 @@ static void vxlan_config_apply(struct net_device *dev,
 
                dev->needed_tailroom = lowerdev->needed_tailroom;
 
-               max_mtu = lowerdev->mtu - (use_ipv6 ? VXLAN6_HEADROOM :
-                                          VXLAN_HEADROOM);
+               max_mtu = lowerdev->mtu - vxlan_headroom(flags);
                if (max_mtu < ETH_MIN_MTU)
                        max_mtu = ETH_MIN_MTU;
 
@@ -3685,10 +3735,9 @@ static void vxlan_config_apply(struct net_device *dev,
        if (dev->mtu > max_mtu)
                dev->mtu = max_mtu;
 
-       if (use_ipv6 || conf->flags & VXLAN_F_COLLECT_METADATA)
-               needed_headroom += VXLAN6_HEADROOM;
-       else
-               needed_headroom += VXLAN_HEADROOM;
+       if (flags & VXLAN_F_COLLECT_METADATA)
+               flags |= VXLAN_F_IPV6;
+       needed_headroom += vxlan_headroom(flags);
        dev->needed_headroom = needed_headroom;
 
        memcpy(&vxlan->cfg, conf, sizeof(*conf));
This page took 0.041736 seconds and 4 git commands to generate.