Re: [PATCH RFC net-next 18/20] net/ipv6: separate handling of FIB entries from dst based routes
On 2/28/18 11:44 AM, Martin KaFai Lau wrote: > On Sun, Feb 25, 2018 at 11:47:28AM -0800, David Ahern wrote: >> Signed-off-by: David Ahern>> --- >> include/net/ip6_fib.h | 4 +- >> include/net/ip6_route.h | 3 +- >> net/ipv6/addrconf.c | 31 ++--- >> net/ipv6/anycast.c | 7 +- >> net/ipv6/ip6_fib.c | 50 +-- >> net/ipv6/ip6_output.c | 3 +- >> net/ipv6/ndisc.c| 6 +- >> net/ipv6/route.c| 167 >> +--- >> 8 files changed, 121 insertions(+), 150 deletions(-) >> >> diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h >> index 70978deac538..ff16e3d571a2 100644 >> --- a/include/net/ip6_fib.h >> +++ b/include/net/ip6_fib.h >> @@ -315,9 +315,7 @@ static inline u32 rt6_get_cookie(const struct rt6_info >> *rt) >> >> if (rt->rt6i_flags & RTF_PCPU || >> (unlikely(!list_empty(>rt6i_uncached)) && rt->from)) >> -rt = rt->from; >> - >> -rt6_get_cookie_safe(rt, ); >> +rt6_get_cookie_safe(rt->from, ); >> >> return cookie; >> } >> diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h >> index 24c78fb6ac36..fcda09a58193 100644 >> --- a/include/net/ip6_route.h >> +++ b/include/net/ip6_route.h >> @@ -113,8 +113,7 @@ static inline int ip6_route_get_saddr(struct net *net, >> struct rt6_info *rt, >>unsigned int prefs, >>struct in6_addr *saddr) >> { >> -struct inet6_dev *idev = >> -rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL; >> +struct inet6_dev *idev = rt ? rt->rt6i_idev : NULL; >> int err = 0; >> >> if (rt && rt->rt6i_prefsrc.plen) >> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c >> index 2a032b932922..4dd7b4e9de4c 100644 >> --- a/net/ipv6/addrconf.c >> +++ b/net/ipv6/addrconf.c >> @@ -927,7 +927,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) >> pr_warn("Freeing alive inet6 address %p\n", ifp); >> return; >> } >> -ip6_rt_put(ifp->rt); >> +fib6_info_release(ifp->rt); >> >> kfree_rcu(ifp, rcu); >> } >> @@ -1080,6 +1080,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct >> in6_addr *addr, >> ifa->cstamp = ifa->tstamp = jiffies; >> ifa->tokenized = false; >> >> +fib6_info_hold(rt); > Did fib6_info_alloc() already bump the refcnt? Why > another fib6_info_hold() is needed? Comment would be > useful here. The alloc does set it to 1; the extra bump here is because of the ifa->rt assignment. Without the additional reference, deleting the route would cause rt to be freed, yet ifa has a reference to it. I did not want to wade into changes to the accounting for this set, though I do think it needs to be revisited. I'll take another look at whether this is really needed. > >> ifa->rt = rt; >> >> ifa->idev = idev; >> @@ -1114,8 +1115,12 @@ ipv6_add_addr(struct inet6_dev *idev, const struct >> in6_addr *addr, >> inet6addr_notifier_call_chain(NETDEV_UP, ifa); >> out: >> if (unlikely(err < 0)) { >> -if (rt) >> -ip6_rt_put(rt); >> +/* one release for the hold taken when rt is set in ifa >> + * and a second release for the hold taken on rt create >> + */ >> +fib6_info_release(rt); >> +fib6_info_release(rt); > The extra release corresponds to the above fib6_info_hold()? yes.
Re: [PATCH RFC net-next 18/20] net/ipv6: separate handling of FIB entries from dst based routes
On Sun, Feb 25, 2018 at 11:47:28AM -0800, David Ahern wrote: > Signed-off-by: David Ahern> --- > include/net/ip6_fib.h | 4 +- > include/net/ip6_route.h | 3 +- > net/ipv6/addrconf.c | 31 ++--- > net/ipv6/anycast.c | 7 +- > net/ipv6/ip6_fib.c | 50 +-- > net/ipv6/ip6_output.c | 3 +- > net/ipv6/ndisc.c| 6 +- > net/ipv6/route.c| 167 > +--- > 8 files changed, 121 insertions(+), 150 deletions(-) > > diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h > index 70978deac538..ff16e3d571a2 100644 > --- a/include/net/ip6_fib.h > +++ b/include/net/ip6_fib.h > @@ -315,9 +315,7 @@ static inline u32 rt6_get_cookie(const struct rt6_info > *rt) > > if (rt->rt6i_flags & RTF_PCPU || > (unlikely(!list_empty(>rt6i_uncached)) && rt->from)) > - rt = rt->from; > - > - rt6_get_cookie_safe(rt, ); > + rt6_get_cookie_safe(rt->from, ); > > return cookie; > } > diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h > index 24c78fb6ac36..fcda09a58193 100644 > --- a/include/net/ip6_route.h > +++ b/include/net/ip6_route.h > @@ -113,8 +113,7 @@ static inline int ip6_route_get_saddr(struct net *net, > struct rt6_info *rt, > unsigned int prefs, > struct in6_addr *saddr) > { > - struct inet6_dev *idev = > - rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL; > + struct inet6_dev *idev = rt ? rt->rt6i_idev : NULL; > int err = 0; > > if (rt && rt->rt6i_prefsrc.plen) > diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c > index 2a032b932922..4dd7b4e9de4c 100644 > --- a/net/ipv6/addrconf.c > +++ b/net/ipv6/addrconf.c > @@ -927,7 +927,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) > pr_warn("Freeing alive inet6 address %p\n", ifp); > return; > } > - ip6_rt_put(ifp->rt); > + fib6_info_release(ifp->rt); > > kfree_rcu(ifp, rcu); > } > @@ -1080,6 +1080,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct > in6_addr *addr, > ifa->cstamp = ifa->tstamp = jiffies; > ifa->tokenized = false; > > + fib6_info_hold(rt); Did fib6_info_alloc() already bump the refcnt? Why another fib6_info_hold() is needed? Comment would be useful here. > ifa->rt = rt; > > ifa->idev = idev; > @@ -1114,8 +1115,12 @@ ipv6_add_addr(struct inet6_dev *idev, const struct > in6_addr *addr, > inet6addr_notifier_call_chain(NETDEV_UP, ifa); > out: > if (unlikely(err < 0)) { > - if (rt) > - ip6_rt_put(rt); > + /* one release for the hold taken when rt is set in ifa > + * and a second release for the hold taken on rt create > + */ > + fib6_info_release(rt); > + fib6_info_release(rt); The extra release corresponds to the above fib6_info_hold()? > + > if (ifa) { > if (ifa->idev) > in6_dev_put(ifa->idev); > @@ -1203,7 +1208,7 @@ cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned > long expires, bool del_r > else { > if (!(rt->rt6i_flags & RTF_EXPIRES)) > fib6_set_expires(rt, expires); > - ip6_rt_put(rt); > + fib6_info_release(rt); > } > } > } > @@ -2350,8 +2355,7 @@ static struct rt6_info *addrconf_get_prefix_route(const > struct in6_addr *pfx, > continue; > if ((rt->rt6i_flags & noflags) != 0) > continue; > - if (!dst_hold_safe(>dst)) > - rt = NULL; > + fib6_info_hold(rt); > break; > } > out: > @@ -2663,7 +2667,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 > *opt, int len, bool sllao) > addrconf_prefix_route(>prefix, pinfo->prefix_len, > dev, expires, flags, GFP_ATOMIC); > } > - ip6_rt_put(rt); > + fib6_info_release(rt); > } > > /* Try to figure out our local address for this prefix */ > @@ -3330,9 +3334,14 @@ static int fixup_permanent_addr(struct net *net, > spin_lock(>lock); > prev = ifp->rt; > ifp->rt = rt; > + fib6_info_hold(rt); > spin_unlock(>lock); > > - ip6_rt_put(prev); > + /* one release for the hold taken when rt is set in ifa > + * and a second release for the hold taken on rt create > + */ > + fib6_info_release(prev); > + fib6_info_release(prev); > } > > if (!(ifp->flags & IFA_F_NOPREFIXROUTE)) { > @@ -3706,6 +3715,7 @@ static int
[PATCH RFC net-next 18/20] net/ipv6: separate handling of FIB entries from dst based routes
Signed-off-by: David Ahern--- include/net/ip6_fib.h | 4 +- include/net/ip6_route.h | 3 +- net/ipv6/addrconf.c | 31 ++--- net/ipv6/anycast.c | 7 +- net/ipv6/ip6_fib.c | 50 +-- net/ipv6/ip6_output.c | 3 +- net/ipv6/ndisc.c| 6 +- net/ipv6/route.c| 167 +--- 8 files changed, 121 insertions(+), 150 deletions(-) diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 70978deac538..ff16e3d571a2 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -315,9 +315,7 @@ static inline u32 rt6_get_cookie(const struct rt6_info *rt) if (rt->rt6i_flags & RTF_PCPU || (unlikely(!list_empty(>rt6i_uncached)) && rt->from)) - rt = rt->from; - - rt6_get_cookie_safe(rt, ); + rt6_get_cookie_safe(rt->from, ); return cookie; } diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 24c78fb6ac36..fcda09a58193 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -113,8 +113,7 @@ static inline int ip6_route_get_saddr(struct net *net, struct rt6_info *rt, unsigned int prefs, struct in6_addr *saddr) { - struct inet6_dev *idev = - rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL; + struct inet6_dev *idev = rt ? rt->rt6i_idev : NULL; int err = 0; if (rt && rt->rt6i_prefsrc.plen) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 2a032b932922..4dd7b4e9de4c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -927,7 +927,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) pr_warn("Freeing alive inet6 address %p\n", ifp); return; } - ip6_rt_put(ifp->rt); + fib6_info_release(ifp->rt); kfree_rcu(ifp, rcu); } @@ -1080,6 +1080,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, ifa->cstamp = ifa->tstamp = jiffies; ifa->tokenized = false; + fib6_info_hold(rt); ifa->rt = rt; ifa->idev = idev; @@ -1114,8 +1115,12 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, inet6addr_notifier_call_chain(NETDEV_UP, ifa); out: if (unlikely(err < 0)) { - if (rt) - ip6_rt_put(rt); + /* one release for the hold taken when rt is set in ifa +* and a second release for the hold taken on rt create +*/ + fib6_info_release(rt); + fib6_info_release(rt); + if (ifa) { if (ifa->idev) in6_dev_put(ifa->idev); @@ -1203,7 +1208,7 @@ cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_r else { if (!(rt->rt6i_flags & RTF_EXPIRES)) fib6_set_expires(rt, expires); - ip6_rt_put(rt); + fib6_info_release(rt); } } } @@ -2350,8 +2355,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, continue; if ((rt->rt6i_flags & noflags) != 0) continue; - if (!dst_hold_safe(>dst)) - rt = NULL; + fib6_info_hold(rt); break; } out: @@ -2663,7 +2667,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) addrconf_prefix_route(>prefix, pinfo->prefix_len, dev, expires, flags, GFP_ATOMIC); } - ip6_rt_put(rt); + fib6_info_release(rt); } /* Try to figure out our local address for this prefix */ @@ -3330,9 +3334,14 @@ static int fixup_permanent_addr(struct net *net, spin_lock(>lock); prev = ifp->rt; ifp->rt = rt; + fib6_info_hold(rt); spin_unlock(>lock); - ip6_rt_put(prev); + /* one release for the hold taken when rt is set in ifa +* and a second release for the hold taken on rt create +*/ + fib6_info_release(prev); + fib6_info_release(prev); } if (!(ifp->flags & IFA_F_NOPREFIXROUTE)) { @@ -3706,6 +3715,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) rt = ifa->rt; ifa->rt = NULL; + fib6_info_release(rt); } else { state = ifa->state; ifa->state = INET6_IFADDR_STATE_DEAD; @@ -5600,8 +5610,9 @@ static void __ipv6_ifa_notify(int event, struct