diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 781ca8c07a0da3..6506ade70f3f9e 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -67,6 +67,7 @@ struct ip6gre_net { struct ip6_tnl __rcu *collect_md_tun; struct ip6_tnl __rcu *collect_md_tun_erspan; + struct ip6_tnl __rcu *fb_tun; struct net_device *fb_tunnel_dev; }; @@ -238,9 +239,9 @@ static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev, if (t && t->dev->flags & IFF_UP) return t; - dev = ign->fb_tunnel_dev; - if (dev && dev->flags & IFF_UP) - return netdev_priv(dev); + t = rcu_dereference(ign->fb_tun); + if (t && t->dev->flags & IFF_UP) + return t; return NULL; } @@ -411,8 +412,12 @@ static void ip6gre_tunnel_uninit(struct net_device *dev) struct ip6_tnl *t = netdev_priv(dev); struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id); - ip6gre_tunnel_unlink_md(ign, t); - ip6gre_tunnel_unlink(ign, t); + if (dev == ign->fb_tunnel_dev) { + RCU_INIT_POINTER(ign->fb_tun, NULL); + } else { + ip6gre_tunnel_unlink_md(ign, t); + ip6gre_tunnel_unlink(ign, t); + } dst_cache_reset(&t->dst_cache); dev_put(dev); } @@ -1584,7 +1589,7 @@ static int __net_init ip6gre_init_net(struct net *net) if (err) goto err_reg_dev; - rcu_assign_pointer(ign->tunnels_wc[0], + rcu_assign_pointer(ign->fb_tun, netdev_priv(ign->fb_tunnel_dev)); return 0;