| From foo@baz Thu Dec 21 09:02:40 CET 2017 |
| From: Mike Manning <mmanning@brocade.com> |
| Date: Mon, 25 Sep 2017 22:01:36 +0100 |
| Subject: net: ipv6: send NS for DAD when link operationally up |
| |
| From: Mike Manning <mmanning@brocade.com> |
| |
| |
| [ Upstream commit 1f372c7bfb23286d2bf4ce0423ab488e86b74bb2 ] |
| |
| The NS for DAD are sent on admin up as long as a valid qdisc is found. |
| A race condition exists by which these packets will not egress the |
| interface if the operational state of the lower device is not yet up. |
| The solution is to delay DAD until the link is operationally up |
| according to RFC2863. Rather than only doing this, follow the existing |
| code checks by deferring IPv6 device initialization altogether. The fix |
| allows DAD on devices like tunnels that are controlled by userspace |
| control plane. The fix has no impact on regular deployments, but means |
| that there is no IPv6 connectivity until the port has been opened in |
| the case of port-based network access control, which should be |
| desirable. |
| |
| Signed-off-by: Mike Manning <mmanning@brocade.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <alexander.levin@verizon.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv6/addrconf.c | 12 ++++++------ |
| 1 file changed, 6 insertions(+), 6 deletions(-) |
| |
| --- a/net/ipv6/addrconf.c |
| +++ b/net/ipv6/addrconf.c |
| @@ -286,10 +286,10 @@ static struct ipv6_devconf ipv6_devconf_ |
| .keep_addr_on_down = 0, |
| }; |
| |
| -/* Check if a valid qdisc is available */ |
| -static inline bool addrconf_qdisc_ok(const struct net_device *dev) |
| +/* Check if link is ready: is it up and is a valid qdisc available */ |
| +static inline bool addrconf_link_ready(const struct net_device *dev) |
| { |
| - return !qdisc_tx_is_noop(dev); |
| + return netif_oper_up(dev) && !qdisc_tx_is_noop(dev); |
| } |
| |
| static void addrconf_del_rs_timer(struct inet6_dev *idev) |
| @@ -434,7 +434,7 @@ static struct inet6_dev *ipv6_add_dev(st |
| |
| ndev->token = in6addr_any; |
| |
| - if (netif_running(dev) && addrconf_qdisc_ok(dev)) |
| + if (netif_running(dev) && addrconf_link_ready(dev)) |
| ndev->if_flags |= IF_READY; |
| |
| ipv6_mc_init_dev(ndev); |
| @@ -3368,7 +3368,7 @@ static int addrconf_notify(struct notifi |
| /* restore routes for permanent addresses */ |
| addrconf_permanent_addr(dev); |
| |
| - if (!addrconf_qdisc_ok(dev)) { |
| + if (!addrconf_link_ready(dev)) { |
| /* device is not ready yet. */ |
| pr_info("ADDRCONF(NETDEV_UP): %s: link is not ready\n", |
| dev->name); |
| @@ -3383,7 +3383,7 @@ static int addrconf_notify(struct notifi |
| run_pending = 1; |
| } |
| } else if (event == NETDEV_CHANGE) { |
| - if (!addrconf_qdisc_ok(dev)) { |
| + if (!addrconf_link_ready(dev)) { |
| /* device is still not ready. */ |
| break; |
| } |