commit 6825b782796215a4c701c44cdb0253e936cf2957 Author: Cong Wang Date: Tue May 20 15:24:43 2014 -0700 ipv4, tunnel: update tunnel name when netdev name is changed Signed-off-by: Cong Wang diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index a4daf9e..0f6805f 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -130,6 +130,7 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], struct ip_tunnel_parm *p); void ip_tunnel_setup(struct net_device *dev, int net_id); void ip_tunnel_dst_reset_all(struct ip_tunnel *t); +struct ip_tunnel *ip_tunnel_get_by_dev(struct ip_tunnel_net *itn, struct net_device *dev); /* Extract dsfield from inner protocol */ static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph, diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index c5a557a..7255edf 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -778,6 +778,37 @@ static struct pernet_operations ipgre_tap_net_ops = { .size = sizeof(struct ip_tunnel_net), }; +static int ip_gre_event(struct notifier_block *unused, unsigned long event, + void *ptr) +{ + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct net *net = dev_net(dev); + struct ip_tunnel *t; + struct ip_tunnel_net *itn; + + if (event != NETDEV_CHANGENAME) + return NOTIFY_DONE; + + itn = net_generic(net, ipgre_net_id); + t = ip_tunnel_get_by_dev(itn, dev); + if (!t) { + itn = net_generic(net, gre_tap_net_id); + t = ip_tunnel_get_by_dev(itn, dev); + } + + if (!t) + return NOTIFY_DONE; + + if (t->parms.name[0]) + strlcpy(t->parms.name, dev->name, IFNAMSIZ); + + return NOTIFY_DONE; +} + +static struct notifier_block ip_gre_notifier = { + .notifier_call = ip_gre_event +}; + static int __init ipgre_init(void) { int err; @@ -806,8 +837,13 @@ static int __init ipgre_init(void) if (err < 0) goto tap_ops_failed; - return 0; + err = register_netdevice_notifier(&ip_gre_notifier); + if (err < 0) + goto netdev_notify_failed; + return 0; +netdev_notify_failed: + rtnl_link_unregister(&ipgre_tap_ops); tap_ops_failed: rtnl_link_unregister(&ipgre_link_ops); rtnl_link_failed: @@ -821,6 +857,7 @@ pnet_tap_faied: static void __exit ipgre_fini(void) { + unregister_netdevice_notifier(&ip_gre_notifier); rtnl_link_unregister(&ipgre_tap_ops); rtnl_link_unregister(&ipgre_link_ops); gre_cisco_unregister(&ipgre_protocol); diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 289c6ee..a5070ea 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -1053,4 +1053,22 @@ void ip_tunnel_setup(struct net_device *dev, int net_id) } EXPORT_SYMBOL_GPL(ip_tunnel_setup); +struct ip_tunnel *ip_tunnel_get_by_dev(struct ip_tunnel_net *itn, struct net_device *dev) +{ + int h; + + for (h = 0; h < IP_TNL_HASH_SIZE; h++) { + struct hlist_head *thead = &itn->tunnels[h]; + struct ip_tunnel *t; + + hlist_for_each_entry_rcu(t, thead, hash_node) { + if (t->dev == dev) + return t; + } + } + + return NULL; +} +EXPORT_SYMBOL_GPL(ip_tunnel_get_by_dev); + MODULE_LICENSE("GPL"); diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index afcee51..5e0a495 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -523,6 +523,32 @@ static struct rtnl_link_ops vti_link_ops __read_mostly = { .fill_info = vti_fill_info, }; +static int vti_event(struct notifier_block *unused, unsigned long event, + void *ptr) +{ + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct ip_tunnel *t; + struct net *net = dev_net(dev); + struct ip_tunnel_net *itn; + + if (event != NETDEV_CHANGENAME) + return NOTIFY_DONE; + + itn = net_generic(net, vti_net_id); + t = ip_tunnel_get_by_dev(itn, dev); + if (!t) + return NOTIFY_DONE; + + if (t->parms.name[0]) + strlcpy(t->parms.name, dev->name, IFNAMSIZ); + + return NOTIFY_DONE; +} + +static struct notifier_block vti_notifier = { + .notifier_call = vti_event +}; + static int __init vti_init(void) { int err; @@ -562,9 +588,14 @@ static int __init vti_init(void) err = rtnl_link_register(&vti_link_ops); if (err < 0) goto rtnl_link_failed; + err = register_netdevice_notifier(&vti_notifier); + if (err < 0) + goto netdev_notify_failed; return err; +netdev_notify_failed: + rtnl_link_unregister(&vti_link_ops); rtnl_link_failed: xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP); xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH); @@ -575,6 +606,7 @@ rtnl_link_failed: static void __exit vti_fini(void) { + unregister_netdevice_notifier(&vti_notifier); rtnl_link_unregister(&vti_link_ops); if (xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP)) pr_info("vti close: can't deregister tunnel\n"); diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 812b183..ccd2b75fa 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -446,6 +446,32 @@ static struct pernet_operations ipip_net_ops = { .size = sizeof(struct ip_tunnel_net), }; +static int ipip_event(struct notifier_block *unused, unsigned long event, + void *ptr) +{ + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct ip_tunnel *t; + struct net *net = dev_net(dev); + struct ip_tunnel_net *itn; + + if (event != NETDEV_CHANGENAME) + return NOTIFY_DONE; + + itn = net_generic(net, ipip_net_id); + t = ip_tunnel_get_by_dev(itn, dev); + if (!t) + return NOTIFY_DONE; + + if (t->parms.name[0]) + strlcpy(t->parms.name, dev->name, IFNAMSIZ); + + return NOTIFY_DONE; +} + +static struct notifier_block ipip_notifier = { + .notifier_call = ipip_event +}; + static int __init ipip_init(void) { int err; @@ -463,10 +489,15 @@ static int __init ipip_init(void) err = rtnl_link_register(&ipip_link_ops); if (err < 0) goto rtnl_link_failed; + err = register_netdevice_notifier(&ipip_notifier); + if (err < 0) + goto netdev_notify_failed; out: return err; +netdev_notify_failed: + rtnl_link_unregister(&ipip_link_ops); rtnl_link_failed: xfrm4_tunnel_deregister(&ipip_handler, AF_INET); xfrm_tunnel_failed: @@ -476,6 +507,7 @@ xfrm_tunnel_failed: static void __exit ipip_fini(void) { + unregister_netdevice_notifier(&ipip_notifier); rtnl_link_unregister(&ipip_link_ops); if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) pr_info("%s: can't deregister tunnel\n", __func__);