inet6_hashtables is build into vmlinux in case ipv6 gets build as a module. As the inet6_hashtables functions depend on ipv6_get_ifaddr via ipv6_get_ifaddr_afnetns_rcu, we need to make the lookup function always available.
Signed-off-by: Hannes Frederic Sowa <han...@stressinduktion.org> --- include/net/addrconf.h | 6 ++++++ net/ipv6/addrconf.c | 35 +---------------------------------- net/ipv6/inet6_hashtables.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 644fa68bb4ddef..dcb17f88fd2875 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -78,6 +78,7 @@ bool ipv6_chk_custom_prefix(const struct in6_addr *addr, int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev); +extern struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE]; struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *addr, struct net_device *dev, int strict); @@ -416,6 +417,11 @@ static inline bool ipv6_addr_is_solict_mult(const struct in6_addr *addr) #endif } +static inline u32 inet6_addr_hash(const struct in6_addr *addr) +{ + return hash_32(ipv6_addr_hash(addr), IN6_ADDR_HSIZE_SHIFT); +} + #ifdef CONFIG_PROC_FS int if6_proc_init(void); void if6_proc_exit(void); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 2e546584695118..319f83a7d29dd5 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -160,7 +160,6 @@ static int ipv6_generate_stable_address(struct in6_addr *addr, /* * Configured unicast address hash table */ -static struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE]; static DEFINE_SPINLOCK(addrconf_hash_lock); static void addrconf_verify(void); @@ -936,11 +935,6 @@ ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) list_add_tail(&ifp->if_list, p); } -static u32 inet6_addr_hash(const struct in6_addr *addr) -{ - return hash_32(ipv6_addr_hash(addr), IN6_ADDR_HSIZE_SHIFT); -} - /* On success it returns ifp with increased reference count */ static struct inet6_ifaddr * @@ -1888,30 +1882,6 @@ int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev) } EXPORT_SYMBOL(ipv6_chk_prefix); -struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *addr, - struct net_device *dev, int strict) -{ - struct inet6_ifaddr *ifp, *result = NULL; - unsigned int hash = inet6_addr_hash(addr); - - rcu_read_lock_bh(); - hlist_for_each_entry_rcu_bh(ifp, &inet6_addr_lst[hash], addr_lst) { - if (!net_eq(dev_net(ifp->idev->dev), net)) - continue; - if (ipv6_addr_equal(&ifp->addr, addr)) { - if (!dev || ifp->idev->dev == dev || - !(ifp->scope&(IFA_LINK|IFA_HOST) || strict)) { - result = ifp; - in6_ifa_hold(ifp); - break; - } - } - } - rcu_read_unlock_bh(); - - return result; -} - /* Gets referenced address, destroys ifaddr */ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed) @@ -6518,7 +6488,7 @@ static struct rtnl_af_ops inet6_ops __read_mostly = { int __init addrconf_init(void) { struct inet6_dev *idev; - int i, err; + int err; err = ipv6_addr_label_init(); if (err < 0) { @@ -6563,9 +6533,6 @@ int __init addrconf_init(void) goto errlo; } - for (i = 0; i < IN6_ADDR_HSIZE; i++) - INIT_HLIST_HEAD(&inet6_addr_lst[i]); - register_netdevice_notifier(&ipv6_dev_notf); addrconf_verify(); diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index d0900918a19e5e..8570e0e3016b65 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -25,6 +25,9 @@ #include <net/ip.h> #include <net/sock_reuseport.h> +struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE]; +EXPORT_SYMBOL(inet6_addr_lst); + u32 inet6_ehashfn(const struct net *net, const struct in6_addr *laddr, const u16 lport, const struct in6_addr *faddr, const __be16 fport) @@ -44,6 +47,32 @@ u32 inet6_ehashfn(const struct net *net, inet6_ehash_secret + net_hash_mix(net)); } +struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, + const struct in6_addr *addr, + struct net_device *dev, int strict) +{ + struct inet6_ifaddr *ifp, *result = NULL; + unsigned int hash = inet6_addr_hash(addr); + + rcu_read_lock_bh(); + hlist_for_each_entry_rcu_bh(ifp, &inet6_addr_lst[hash], addr_lst) { + if (!net_eq(dev_net(ifp->idev->dev), net)) + continue; + if (ipv6_addr_equal(&ifp->addr, addr)) { + if (!dev || ifp->idev->dev == dev || + !(ifp->scope & (IFA_LINK | IFA_HOST) || strict)) { + result = ifp; + in6_ifa_hold(ifp); + break; + } + } + } + rcu_read_unlock_bh(); + + return result; +} +EXPORT_SYMBOL(ipv6_get_ifaddr); + /* * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM @@ -275,3 +304,13 @@ int inet6_hash(struct sock *sk) return err; } EXPORT_SYMBOL_GPL(inet6_hash); + +int __init inet6_hashtables_init(void) +{ + int i; + + for (i = 0; i < IN6_ADDR_HSIZE; i++) + INIT_HLIST_HEAD(&inet6_addr_lst[i]); + return 0; +} +early_initcall(inet6_hashtables_init); -- 2.9.3