From patchwork Mon Jul 1 06:30:32 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Pravin B Shelar X-Patchwork-Id: 256017 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id D3CEC2C009F for ; Mon, 1 Jul 2013 16:30:41 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752472Ab3GAGai (ORCPT ); Mon, 1 Jul 2013 02:30:38 -0400 Received: from na3sys009aog124.obsmtp.com ([74.125.149.151]:48311 "HELO na3sys009aog124.obsmtp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1750987Ab3GAGah (ORCPT ); Mon, 1 Jul 2013 02:30:37 -0400 Received: from mail-pb0-f47.google.com ([209.85.160.47]) (using TLSv1) by na3sys009aob124.postini.com ([74.125.148.12]) with SMTP ID DSNKUdEiDB9tk8J5X3l8Hmkm7Upcb6FZS0E4@postini.com; Sun, 30 Jun 2013 23:30:37 PDT Received: by mail-pb0-f47.google.com with SMTP id rr13so4451958pbb.34 for ; Sun, 30 Jun 2013 23:30:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:x-gm-message-state; bh=6XppC9432y/jwGQ5IzJrWO/5yew6CUJrPJOQmBV6FCA=; b=UcALk/Ip8t372J3uSvhHFh7hUICbDDHC2SjJf1qJrgXb7hxhJmttw+hgEZQXOkqk5j 8gbjeVAtj4e0d2P5v4Jv9321E+NcndEL+NhkxxzBea828s3z2Yjha8EbhOrbt+PY12uc M2/qQ7Z5s2LWvZgBLnAMMAy1lSkycWd1dnZsles1kjGbzaVLCVlCxDn010BOP0IXXT1A x+l3mpo1wa3BOukbRjQ961bYqO6E2M5KKiP+FZHEsg/cFAwf0YhpyXyGJUhJP2iCjHtD wmOfqIMmISq11UHrNTfQE0bzgBnVcKJ9k0DhQ/q10+TF9FgRPO0jE0ImQYI31kSZV5ee woOA== X-Received: by 10.68.241.193 with SMTP id wk1mr22522991pbc.5.1372660236790; Sun, 30 Jun 2013 23:30:36 -0700 (PDT) X-Received: by 10.68.241.193 with SMTP id wk1mr22522985pbc.5.1372660236719; Sun, 30 Jun 2013 23:30:36 -0700 (PDT) Received: from localhost ([75.98.92.113]) by mx.google.com with ESMTPSA id aj3sm22235078pad.8.2013.06.30.23.30.34 for (version=TLSv1.1 cipher=RC4-SHA bits=128/128); Sun, 30 Jun 2013 23:30:35 -0700 (PDT) From: Pravin B Shelar To: netdev@vger.kernel.org Cc: timo.teras@iki.fi, Pravin B Shelar Subject: [PATCH net v2] ip_tunnels: Use skb-len to PMTU check. Date: Sun, 30 Jun 2013 23:30:32 -0700 Message-Id: <1372660232-12174-1-git-send-email-pshelar@nicira.com> X-Mailer: git-send-email 1.8.2.135.g7b592fa X-Gm-Message-State: ALoCoQkiLwxEA1jTr1ZgkDYZQAbolYzcdL/a/PhbIdWISt8VWkOBHvBdn1nZ6wtsismwq9qLGOuf78nRBkAtvBDsj4YK5fhMmwprjh8CUu/ytwXOKuy10NrP0dpjXiJmqzxnQy0e4fcMM+4qENrOWMWsRW8C8cxBhYY+1lQyluieGqR7/cfL1C4= Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org In path mtu check, ip header total length works for gre device but not for gre-tap device. Use skb len which is consistent for all tunneling types. This is old bug in gre. This also fixes mtu calculation bug introduced by commit c54419321455631079c7d (GRE: Refactor GRE tunneling code). Reported-by: Timo Teras Signed-off-by: Pravin B Shelar Acked-by: Timo Teräs --- v1-v2: - Fix pmtu set. - This patch also restructures code which help couple of improvements I have. --- net/ipv4/ip_tunnel.c | 98 +++++++++++++++++++++++++++---------------------- 1 files changed, 54 insertions(+), 44 deletions(-) diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 7fa8f08..ae5b78c 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -486,6 +486,53 @@ drop: } EXPORT_SYMBOL_GPL(ip_tunnel_rcv); +static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb, + struct rtable *rt, __be16 df) +{ + struct ip_tunnel *tunnel = netdev_priv(dev); + int pkt_size = skb->len - tunnel->hlen; + int mtu; + + if (df) + mtu = dst_mtu(&rt->dst) - dev->hard_header_len + - sizeof(struct iphdr) - tunnel->hlen; + else + mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; + + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); + + if (skb->protocol == htons(ETH_P_IP)) { + if (!skb_is_gso(skb) && + (df & htons(IP_DF)) && mtu < pkt_size) { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); + return -E2BIG; + } + } +#if IS_ENABLED(CONFIG_IPV6) + else if (skb->protocol == htons(ETH_P_IPV6)) { + struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb); + + if (rt6 && mtu < dst_mtu(skb_dst(skb)) && + mtu >= IPV6_MIN_MTU) { + if ((tunnel->parms.iph.daddr && + !ipv4_is_multicast(tunnel->parms.iph.daddr)) || + rt6->rt6i_dst.plen == 128) { + rt6->rt6i_flags |= RTF_MODIFIED; + dst_metric_set(skb_dst(skb), RTAX_MTU, mtu); + } + } + + if (!skb_is_gso(skb) && mtu >= IPV6_MIN_MTU && + mtu < pkt_size) { + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); + return -E2BIG; + } + } +#endif + return 0; +} + void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, const struct iphdr *tnl_params) { @@ -499,7 +546,6 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, struct net_device *tdev; /* Device to other host */ unsigned int max_headroom; /* The extra header space needed */ __be32 dst; - int mtu; inner_iph = (const struct iphdr *)skb_inner_network_header(skb); @@ -579,50 +625,10 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, goto tx_error; } - df = tnl_params->frag_off; - - if (df) - mtu = dst_mtu(&rt->dst) - dev->hard_header_len - - sizeof(struct iphdr); - else - mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; - - if (skb_dst(skb)) - skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); - - if (skb->protocol == htons(ETH_P_IP)) { - df |= (inner_iph->frag_off&htons(IP_DF)); - - if (!skb_is_gso(skb) && - (inner_iph->frag_off&htons(IP_DF)) && - mtu < ntohs(inner_iph->tot_len)) { - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); - ip_rt_put(rt); - goto tx_error; - } - } -#if IS_ENABLED(CONFIG_IPV6) - else if (skb->protocol == htons(ETH_P_IPV6)) { - struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb); - - if (rt6 && mtu < dst_mtu(skb_dst(skb)) && - mtu >= IPV6_MIN_MTU) { - if ((tunnel->parms.iph.daddr && - !ipv4_is_multicast(tunnel->parms.iph.daddr)) || - rt6->rt6i_dst.plen == 128) { - rt6->rt6i_flags |= RTF_MODIFIED; - dst_metric_set(skb_dst(skb), RTAX_MTU, mtu); - } - } - - if (!skb_is_gso(skb) && mtu >= IPV6_MIN_MTU && - mtu < skb->len) { - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); - ip_rt_put(rt); - goto tx_error; - } + if (tnl_update_pmtu(dev, skb, rt, tnl_params->frag_off)) { + ip_rt_put(rt); + goto tx_error; } -#endif if (tunnel->err_count > 0) { if (time_before(jiffies, @@ -667,6 +673,10 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, iph = ip_hdr(skb); inner_iph = (const struct iphdr *)skb_inner_network_header(skb); + df = tnl_params->frag_off; + if (skb->protocol == htons(ETH_P_IP)) + df |= (inner_iph->frag_off&htons(IP_DF)); + iph->version = 4; iph->ihl = sizeof(struct iphdr) >> 2; iph->frag_off = df;