Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp3014910imu; Sun, 9 Dec 2018 15:09:24 -0800 (PST) X-Google-Smtp-Source: AFSGD/XSBfX8C4oGcZ3MLtEuAXC01u5CUGdYToIS4U2m9EBtmy8HzIZCYCqVgtgjJbVypfJsX6bA X-Received: by 2002:a17:902:9a4c:: with SMTP id x12mr9741974plv.94.1544396964344; Sun, 09 Dec 2018 15:09:24 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1544396964; cv=none; d=google.com; s=arc-20160816; b=luwvSD4YSG9gZbuJdOFpxYgZkN9aTZNfWUwu/Uzab6MTwk8BLjr46zZGMyyV90VUyK rrmAx6h2bIpmMUvu8dpH2FB8sbCWn6OKDzjJUIpT2Ws8G5ADKgVPagl9Cht3Cuel1ZUx 9Z9UlfmehKKqAdoCFJfARF2qcsFE0gKwW0+vj9t8XwUUN12VD5d7hNbcHWOxIXijcFIh IGlhwxtqE1rjkWnUhrCU1y+FY7RFU3wjKI5/rmKnztS5Ffr0h4iUrOqHySueEhTTYbUj anw0fPOv3HutQjjj0EgsBbdZQHX5Bbmn7AZRyV3Rs/f8wP/PaMIRbGmx83xlKbBxAzqQ whYQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:in-reply-to:subject:message-id:date:cc:to :from:mime-version:content-transfer-encoding:content-disposition; bh=wOj/4JxgIzdO/rB3dvIJEkoRs5UYB9lfhaFEn7N1FLE=; b=NZ0Zo8dV7oOyeI6UFrx5mAhDUWHhcvgJPZmqKUENjNs4mbvJNfZYn0iDhiQ9egmvPc XYNf1qkT4slDElpwXP4dJ35z+9qEDi591gR4ER1SRX0JeRckSsHc7BpxJZlKubHc4pws nglQ7m7lXskGmqI6zfXlO1pmZH/uw0IjAzm6NTIrMHMjZQm5U8NznTvwM21Fj//gmwoL pmGLNWzrfrSkV8wQIMVgukMfrBcLW8cvyIWtHbfOcL5qhlPrvSI5LiX52QqD581th4W9 oWOvu1bGE6M/5RVrmtuJgsJP6DRXp4z0r7AXqWxMQ7+etjtJVYnDoKjXWC+uZSBC+aeD mbNA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y18si8175147plp.269.2018.12.09.15.09.08; Sun, 09 Dec 2018 15:09:24 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728406AbeLIWT6 (ORCPT + 99 others); Sun, 9 Dec 2018 17:19:58 -0500 Received: from shadbolt.e.decadent.org.uk ([88.96.1.126]:35436 "EHLO shadbolt.e.decadent.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726555AbeLIVzZ (ORCPT ); Sun, 9 Dec 2018 16:55:25 -0500 Received: from pub.yeoldevic.com ([81.174.156.145] helo=deadeye) by shadbolt.decadent.org.uk with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1gW72o-0002iZ-6W; Sun, 09 Dec 2018 21:55:22 +0000 Received: from ben by deadeye with local (Exim 4.91) (envelope-from ) id 1gW72l-0003gU-7a; Sun, 09 Dec 2018 21:55:19 +0000 Content-Type: text/plain; charset="UTF-8" Content-Disposition: inline Content-Transfer-Encoding: 8bit MIME-Version: 1.0 From: Ben Hutchings To: linux-kernel@vger.kernel.org, stable@vger.kernel.org CC: akpm@linux-foundation.org, "Sabrina Dubroca" , "David S. Miller" , "Stefano Brivio" , "David Ahern" Date: Sun, 09 Dec 2018 21:50:33 +0000 Message-ID: X-Mailer: LinuxStableQueue (scripts by bwh) X-Patchwork-Hint: ignore Subject: [PATCH 3.16 310/328] net: ipv4: update fnhe_pmtu when first hop's MTU changes In-Reply-To: X-SA-Exim-Connect-IP: 81.174.156.145 X-SA-Exim-Mail-From: ben@decadent.org.uk X-SA-Exim-Scanned: No (on shadbolt.decadent.org.uk); SAEximRunCond expanded to false Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 3.16.62-rc1 review patch. If anyone has any objections, please let me know. ------------------ From: Sabrina Dubroca commit af7d6cce53694a88d6a1bb60c9a239a6a5144459 upstream. Since commit 5aad1de5ea2c ("ipv4: use separate genid for next hop exceptions"), exceptions get deprecated separately from cached routes. In particular, administrative changes don't clear PMTU anymore. As Stefano described in commit e9fa1495d738 ("ipv6: Reflect MTU changes on PMTU of exceptions for MTU-less routes"), the PMTU discovered before the local MTU change can become stale: - if the local MTU is now lower than the PMTU, that PMTU is now incorrect - if the local MTU was the lowest value in the path, and is increased, we might discover a higher PMTU Similarly to what commit e9fa1495d738 did for IPv6, update PMTU in those cases. If the exception was locked, the discovered PMTU was smaller than the minimal accepted PMTU. In that case, if the new local MTU is smaller than the current PMTU, let PMTU discovery figure out if locking of the exception is still needed. To do this, we need to know the old link MTU in the NETDEV_CHANGEMTU notifier. By the time the notifier is called, dev->mtu has been changed. This patch adds the old MTU as additional information in the notifier structure, and a new call_netdevice_notifiers_u32() function. Fixes: 5aad1de5ea2c ("ipv4: use separate genid for next hop exceptions") Signed-off-by: Sabrina Dubroca Reviewed-by: Stefano Brivio Reviewed-by: David Ahern Signed-off-by: David S. Miller [bwh: Backported to 3.16: - Pass net_device argument to call_netdevice_notifiers_info() - Adjust context] Signed-off-by: Ben Hutchings --- --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1867,6 +1867,13 @@ struct netdev_notifier_info { struct net_device *dev; }; +struct netdev_notifier_info_ext { + struct netdev_notifier_info info; /* must be first */ + union { + u32 mtu; + } ext; +}; + struct netdev_notifier_change_info { struct netdev_notifier_info info; /* must be first */ unsigned int flags_changed; --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -293,6 +293,7 @@ int ip_fib_check_default(__be32 gw, stru int fib_sync_down_dev(struct net_device *dev, int force); int fib_sync_down_addr(struct net *net, __be32 local); int fib_sync_up(struct net_device *dev); +void fib_sync_mtu(struct net_device *dev, u32 orig_mtu); void fib_select_multipath(struct fib_result *res); /* Exported by fib_trie.c */ --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1598,6 +1598,28 @@ int call_netdevice_notifiers(unsigned lo } EXPORT_SYMBOL(call_netdevice_notifiers); +/** + * call_netdevice_notifiers_mtu - call all network notifier blocks + * @val: value passed unmodified to notifier function + * @dev: net_device pointer passed unmodified to notifier function + * @arg: additional u32 argument passed to the notifier function + * + * Call all network notifier blocks. Parameters and return value + * are as for raw_notifier_call_chain(). + */ +static int call_netdevice_notifiers_mtu(unsigned long val, + struct net_device *dev, u32 arg) +{ + struct netdev_notifier_info_ext info = { + .info.dev = dev, + .ext.mtu = arg, + }; + + BUILD_BUG_ON(offsetof(struct netdev_notifier_info_ext, info) != 0); + + return call_netdevice_notifiers_info(val, dev, &info.info); +} + static struct static_key netstamp_needed __read_mostly; #ifdef HAVE_JUMP_LABEL static atomic_t netstamp_needed_deferred; @@ -5688,14 +5710,16 @@ int dev_set_mtu(struct net_device *dev, err = __dev_set_mtu(dev, new_mtu); if (!err) { - err = call_netdevice_notifiers(NETDEV_CHANGEMTU, dev); + err = call_netdevice_notifiers_mtu(NETDEV_CHANGEMTU, dev, + orig_mtu); err = notifier_to_errno(err); if (err) { /* setting mtu back and notifying everyone again, * so that they have a chance to revert changes. */ __dev_set_mtu(dev, orig_mtu); - call_netdevice_notifiers(NETDEV_CHANGEMTU, dev); + call_netdevice_notifiers_mtu(NETDEV_CHANGEMTU, dev, + new_mtu); } } return err; --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -1046,6 +1046,7 @@ static int fib_inetaddr_event(struct not static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct netdev_notifier_info_ext *info_ext = ptr; struct in_device *in_dev; struct net *net = dev_net(dev); @@ -1074,6 +1075,9 @@ static int fib_netdev_event(struct notif fib_disable_ip(dev, 0); break; case NETDEV_CHANGEMTU: + fib_sync_mtu(dev, info_ext->ext.mtu); + rt_cache_flush(net); + break; case NETDEV_CHANGE: rt_cache_flush(net); break; --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -1122,6 +1122,56 @@ int fib_sync_down_addr(struct net *net, return ret; } +/* Update the PMTU of exceptions when: + * - the new MTU of the first hop becomes smaller than the PMTU + * - the old MTU was the same as the PMTU, and it limited discovery of + * larger MTUs on the path. With that limit raised, we can now + * discover larger MTUs + * A special case is locked exceptions, for which the PMTU is smaller + * than the minimal accepted PMTU: + * - if the new MTU is greater than the PMTU, don't make any change + * - otherwise, unlock and set PMTU + */ +static void nh_update_mtu(struct fib_nh *nh, u32 new, u32 orig) +{ + struct fnhe_hash_bucket *bucket; + int i; + + bucket = rcu_dereference_protected(nh->nh_exceptions, 1); + if (!bucket) + return; + + for (i = 0; i < FNHE_HASH_SIZE; i++) { + struct fib_nh_exception *fnhe; + + for (fnhe = rcu_dereference_protected(bucket[i].chain, 1); + fnhe; + fnhe = rcu_dereference_protected(fnhe->fnhe_next, 1)) { + if (fnhe->fnhe_mtu_locked) { + if (new <= fnhe->fnhe_pmtu) { + fnhe->fnhe_pmtu = new; + fnhe->fnhe_mtu_locked = false; + } + } else if (new < fnhe->fnhe_pmtu || + orig == fnhe->fnhe_pmtu) { + fnhe->fnhe_pmtu = new; + } + } + } +} + +void fib_sync_mtu(struct net_device *dev, u32 orig_mtu) +{ + unsigned int hash = fib_devindex_hashfn(dev->ifindex); + struct hlist_head *head = &fib_info_devhash[hash]; + struct fib_nh *nh; + + hlist_for_each_entry(nh, head, nh_hash) { + if (nh->nh_dev == dev) + nh_update_mtu(nh, dev->mtu, orig_mtu); + } +} + int fib_sync_down_dev(struct net_device *dev, int force) { int ret = 0;