From patchwork Sun Mar 17 23:37:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bram Yvakh X-Patchwork-Id: 1057626 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=mail.wizbit.be Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44MwzN2w7Wz9s7T for ; Mon, 18 Mar 2019 10:50:08 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727576AbfCQXpT (ORCPT ); Sun, 17 Mar 2019 19:45:19 -0400 Received: from 87-237-14-1.powered-by.benesol.be ([87.237.14.1]:40849 "EHLO wizbit.localdomain" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727171AbfCQXpS (ORCPT ); Sun, 17 Mar 2019 19:45:18 -0400 Received: from mx.wizbit.be (localhost [127.0.0.1]) by wizbit.localdomain (Postfix) with ESMTP id 45EC96004; Mon, 18 Mar 2019 00:37:57 +0100 (CET) From: Bram Yvahk To: steffen.klassert@secunet.com, herbert@gondor.apana.org.au, davem@davemloft.net Cc: netdev@vger.kernel.org Subject: [PATCH ipsec/vti 1/2] vti: fragment IPv4 packets when DF bit is not set Date: Sun, 17 Mar 2019 23:37:56 +0000 Message-Id: <1552865877-13401-2-git-send-email-bram-yvahk@mail.wizbit.be> X-Mailer: git-send-email 1.8.4 In-Reply-To: <1552865877-13401-1-git-send-email-bram-yvahk@mail.wizbit.be> References: <1552865877-13401-1-git-send-email-bram-yvahk@mail.wizbit.be> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Only send a 'need to frag' ICMP message when the "Don't Fragment" bit is set. If it's not set then the packet can/will be fragmented. This fixes sending an 'need to frag' message on a client that did not set the DF bit, i.e.: $ ping -s 1300 -M dont -c5 192.168.235.2 PING 192.168.235.3 (192.168.235.3) 1300(1328) bytes of data. From 192.168.236.254 icmp_seq=1 Frag needed and DF set (mtu = 1214) Signed-off-by: Bram Yvahk --- net/ipv4/ip_vti.c | 43 +++++++++++++++++++++++++++-------------- net/ipv6/ip6_vti.c | 56 +++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 70 insertions(+), 29 deletions(-) diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 68a21bf..5738e44 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -196,6 +196,34 @@ static bool vti_state_check(const struct xfrm_state *x, __be32 dst, __be32 src) return true; } +static bool vti_tunnel_check_size(struct sk_buff *skb) +{ + int mtu; + + if (skb->protocol == htons(ETH_P_IP)) { + if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->ignore_df) + return true; + } + + mtu = dst_mtu(skb_dst(skb)); + if (skb->len > mtu) { + skb_dst_update_pmtu(skb, mtu); + if (skb->protocol == htons(ETH_P_IP)) { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(mtu)); + } else { + if (mtu < IPV6_MIN_MTU) + mtu = IPV6_MIN_MTU; + + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); + } + + return false; + } + + return true; +} + static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl) { @@ -205,7 +233,6 @@ static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev, struct net_device *tdev; /* Device to other host */ int pkt_len = skb->len; int err; - int mtu; if (!dst) { dev->stats.tx_carrier_errors++; @@ -233,19 +260,7 @@ static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev, goto tx_error; } - mtu = dst_mtu(dst); - if (skb->len > mtu) { - skb_dst_update_pmtu(skb, mtu); - if (skb->protocol == htons(ETH_P_IP)) { - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, - htonl(mtu)); - } else { - if (mtu < IPV6_MIN_MTU) - mtu = IPV6_MIN_MTU; - - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); - } - + if (!vti_tunnel_check_size(skb)) { dst_release(dst); goto tx_error; } diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 8b6eeff..47f178c 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -436,6 +436,46 @@ static bool vti6_state_check(const struct xfrm_state *x, } /** + * vti6_tunnel_check_size - check size of packet + * @skb: the outgoing socket buffer + * + * Description: + * Check if packet is too large (> pmtu) + * + * Return: + * true if size of packet is ok + * false if packet is too large + **/ +static bool vti6_tunnel_check_size(struct sk_buff *skb) +{ + int mtu; + + if (skb->protocol == htons(ETH_P_IP)) { + if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->ignore_df) + return true; + } + + mtu = dst_mtu(skb_dst(skb)); + if (skb->len > mtu) { + skb_dst_update_pmtu(skb, mtu); + + if (skb->protocol == htons(ETH_P_IPV6)) { + if (mtu < IPV6_MIN_MTU) + mtu = IPV6_MIN_MTU; + + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); + } else { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(mtu)); + } + + return false; + } + + return true; +} + +/** * vti6_xmit - send a packet * @skb: the outgoing socket buffer * @dev: the outgoing tunnel device @@ -451,7 +491,6 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl) struct xfrm_state *x; int pkt_len = skb->len; int err = -1; - int mtu; if (!dst) goto tx_err_link_failure; @@ -481,20 +520,7 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl) goto tx_err_dst_release; } - mtu = dst_mtu(dst); - if (skb->len > mtu) { - skb_dst_update_pmtu(skb, mtu); - - if (skb->protocol == htons(ETH_P_IPV6)) { - if (mtu < IPV6_MIN_MTU) - mtu = IPV6_MIN_MTU; - - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); - } else { - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, - htonl(mtu)); - } - + if (!vti6_tunnel_check_size(skb)) { err = -EMSGSIZE; goto tx_err_dst_release; }