• Florian Westphal's avatar
    net: ip, ipv6: handle gso skbs in forwarding path · 29a3cd46
    Florian Westphal authored
    commit fe6cc55f upstream.
    
    [ use zero netdev_feature mask to avoid backport of
      netif_skb_dev_features function ]
    
    Marcelo Ricardo Leitner reported problems when the forwarding link path
    has a lower mtu than the incoming one if the inbound interface supports GRO.
    
    Given:
    Host <mtu1500> R1 <mtu1200> R2
    
    Host sends tcp stream which is routed via R1 and R2.  R1 performs GRO.
    
    In this case, the kernel will fail to send ICMP fragmentation needed
    messages (or pkt too big for ipv6), as GSO packets currently bypass dstmtu
    checks in forward path. Instead, Linux tries to send out packets exceeding
    the mtu.
    
    When locking route MTU on Host (i.e., no ipv4 DF bit set), R1 does
    not fragment the packets when forwarding, and again tries to send out
    packets exceeding R1-R2 link mtu.
    
    This alters the forwarding dstmtu checks to take the individual gso
    segment lengths into account.
    
    For ipv6, we send out pkt too big error for gso if the individual
    segments are too big.
    
    For ipv4, we either send icmp fragmentation needed, or, if the DF bit
    is not set, perform software segmentation and let the output path
    create fragments when the packet is leaving the machine.
    It is not 100% correct as the error message will contain the headers of
    the GRO skb instead of the original/segmented one, but it seems to
    work fine in my (limited) tests.
    
    Eric Dumazet suggested to simply shrink mss via ->gso_size to avoid
    sofware segmentation.
    
    However it turns out that skb_segment() assumes skb nr_frags is related
    to mss size so we would BUG there.  I don't want to mess with it considering
    Herbert and Eric disagree on what the correct behavior should be.
    
    Hannes Frederic Sowa notes that when we would shrink gso_size
    skb_segment would then also need to deal with the case where
    SKB_MAX_FRAGS would be exceeded.
    
    This uses sofware segmentation in the forward path when we hit ipv4
    non-DF packets and the outgoing link mtu is too small.  Its not perfect,
    but given the lack of bug reports wrt. GRO fwd being broken this is a
    rare case anyway.  Also its not like this could not be improved later
    once the dust settles.
    Acked-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
    Reported-by: default avatarMarcelo Ricardo Leitner <mleitner@redhat.com>
    Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    29a3cd46
ip6_output.c 42.1 KB