Skip to content

Commit 94d166c

Browse files
Jiri Bencdavem330
authored andcommitted
vxlan: calculate correct header length for GPE
VXLAN-GPE does not add an extra inner Ethernet header. Take that into account when calculating header length. This causes problems in skb_tunnel_check_pmtu, where incorrect PMTU is cached. In the collect_md mode (which is the only mode that VXLAN-GPE supports), there's no magic auto-setting of the tunnel interface MTU. It can't be, since the destination and thus the underlying interface may be different for each packet. So, the administrator is responsible for setting the correct tunnel interface MTU. Apparently, the administrators are capable enough to calculate that the maximum MTU for VXLAN-GPE is (their_lower_MTU - 36). They set the tunnel interface MTU to 1464. If you run a TCP stream over such interface, it's then segmented according to the MTU 1464, i.e. producing 1514 bytes frames. Which is okay, this still fits the lower MTU. However, skb_tunnel_check_pmtu (called from vxlan_xmit_one) uses 50 as the header size and thus incorrectly calculates the frame size to be 1528. This leads to ICMP too big message being generated (locally), PMTU of 1450 to be cached and the TCP stream to be resegmented. The fix is to use the correct actual header size, especially for skb_tunnel_check_pmtu calculation. Fixes: e1e5314 ("vxlan: implement GPE") Signed-off-by: Jiri Benc <jbenc@redhat.com> Reviewed-by: Simon Horman <simon.horman@corigine.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent a071c6a commit 94d166c

File tree

3 files changed

+20
-18
lines changed

3 files changed

+20
-18
lines changed

drivers/net/ethernet/intel/ixgbe/ixgbe_main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8479,7 +8479,7 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
84798479
struct ixgbe_adapter *adapter = q_vector->adapter;
84808480

84818481
if (unlikely(skb_tail_pointer(skb) < hdr.network +
8482-
VXLAN_HEADROOM))
8482+
vxlan_headroom(0)))
84838483
return;
84848484

84858485
/* verify the port is recognized as VXLAN */

drivers/net/vxlan/vxlan_core.c

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2516,7 +2516,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
25162516
}
25172517

25182518
ndst = &rt->dst;
2519-
err = skb_tunnel_check_pmtu(skb, ndst, VXLAN_HEADROOM,
2519+
err = skb_tunnel_check_pmtu(skb, ndst, vxlan_headroom(flags & VXLAN_F_GPE),
25202520
netif_is_any_bridge_port(dev));
25212521
if (err < 0) {
25222522
goto tx_error;
@@ -2577,7 +2577,8 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
25772577
goto out_unlock;
25782578
}
25792579

2580-
err = skb_tunnel_check_pmtu(skb, ndst, VXLAN6_HEADROOM,
2580+
err = skb_tunnel_check_pmtu(skb, ndst,
2581+
vxlan_headroom((flags & VXLAN_F_GPE) | VXLAN_F_IPV6),
25812582
netif_is_any_bridge_port(dev));
25822583
if (err < 0) {
25832584
goto tx_error;
@@ -2989,14 +2990,12 @@ static int vxlan_change_mtu(struct net_device *dev, int new_mtu)
29892990
struct vxlan_rdst *dst = &vxlan->default_dst;
29902991
struct net_device *lowerdev = __dev_get_by_index(vxlan->net,
29912992
dst->remote_ifindex);
2992-
bool use_ipv6 = !!(vxlan->cfg.flags & VXLAN_F_IPV6);
29932993

29942994
/* This check is different than dev->max_mtu, because it looks at
29952995
* the lowerdev->mtu, rather than the static dev->max_mtu
29962996
*/
29972997
if (lowerdev) {
2998-
int max_mtu = lowerdev->mtu -
2999-
(use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM);
2998+
int max_mtu = lowerdev->mtu - vxlan_headroom(vxlan->cfg.flags);
30002999
if (new_mtu > max_mtu)
30013000
return -EINVAL;
30023001
}
@@ -3644,11 +3643,11 @@ static void vxlan_config_apply(struct net_device *dev,
36443643
struct vxlan_dev *vxlan = netdev_priv(dev);
36453644
struct vxlan_rdst *dst = &vxlan->default_dst;
36463645
unsigned short needed_headroom = ETH_HLEN;
3647-
bool use_ipv6 = !!(conf->flags & VXLAN_F_IPV6);
36483646
int max_mtu = ETH_MAX_MTU;
3647+
u32 flags = conf->flags;
36493648

36503649
if (!changelink) {
3651-
if (conf->flags & VXLAN_F_GPE)
3650+
if (flags & VXLAN_F_GPE)
36523651
vxlan_raw_setup(dev);
36533652
else
36543653
vxlan_ether_setup(dev);
@@ -3673,8 +3672,7 @@ static void vxlan_config_apply(struct net_device *dev,
36733672

36743673
dev->needed_tailroom = lowerdev->needed_tailroom;
36753674

3676-
max_mtu = lowerdev->mtu - (use_ipv6 ? VXLAN6_HEADROOM :
3677-
VXLAN_HEADROOM);
3675+
max_mtu = lowerdev->mtu - vxlan_headroom(flags);
36783676
if (max_mtu < ETH_MIN_MTU)
36793677
max_mtu = ETH_MIN_MTU;
36803678

@@ -3685,10 +3683,9 @@ static void vxlan_config_apply(struct net_device *dev,
36853683
if (dev->mtu > max_mtu)
36863684
dev->mtu = max_mtu;
36873685

3688-
if (use_ipv6 || conf->flags & VXLAN_F_COLLECT_METADATA)
3689-
needed_headroom += VXLAN6_HEADROOM;
3690-
else
3691-
needed_headroom += VXLAN_HEADROOM;
3686+
if (flags & VXLAN_F_COLLECT_METADATA)
3687+
flags |= VXLAN_F_IPV6;
3688+
needed_headroom += vxlan_headroom(flags);
36923689
dev->needed_headroom = needed_headroom;
36933690

36943691
memcpy(&vxlan->cfg, conf, sizeof(*conf));

include/net/vxlan.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -386,10 +386,15 @@ static inline netdev_features_t vxlan_features_check(struct sk_buff *skb,
386386
return features;
387387
}
388388

389-
/* IP header + UDP + VXLAN + Ethernet header */
390-
#define VXLAN_HEADROOM (20 + 8 + 8 + 14)
391-
/* IPv6 header + UDP + VXLAN + Ethernet header */
392-
#define VXLAN6_HEADROOM (40 + 8 + 8 + 14)
389+
static inline int vxlan_headroom(u32 flags)
390+
{
391+
/* VXLAN: IP4/6 header + UDP + VXLAN + Ethernet header */
392+
/* VXLAN-GPE: IP4/6 header + UDP + VXLAN */
393+
return (flags & VXLAN_F_IPV6 ? sizeof(struct ipv6hdr) :
394+
sizeof(struct iphdr)) +
395+
sizeof(struct udphdr) + sizeof(struct vxlanhdr) +
396+
(flags & VXLAN_F_GPE ? 0 : ETH_HLEN);
397+
}
393398

394399
static inline struct vxlanhdr *vxlan_hdr(struct sk_buff *skb)
395400
{

0 commit comments

Comments
 (0)