Subject: Re: [PATCH net] ipv6: use rt6_info members when dst is set in rt6_fill_node

From: Hangbin Liu <[email-masked]>
Date: Tue, 11 Sep 2018 09:04:49 +0800

On Mon, Sep 10, 2018 at 01:07:11PM -0600, David Ahern wrote:
> On 9/10/18 11:55 AM, Xin Long wrote:
> > On Tue, Sep 11, 2018 at 12:13 AM David Ahern <[email-masked]> wrote:
> >>
> >> On 9/9/18 12:29 AM, Xin Long wrote:
> >>>>> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
> >>>>> index 18e00ce..e554922 100644
> >>>>> --- a/net/ipv6/route.c
> >>>>> +++ b/net/ipv6/route.c
> >>>>> @@ -4670,20 +4670,33 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
> >>>>>                        int iif, int type, u32 portid, u32 seq,
> >>>>>                        unsigned int flags)
> >>>>>  {
> >>>>> -     struct rtmsg *rtm;
> >>>>> +     struct rt6key *fib6_prefsrc, *fib6_dst, *fib6_src;
> >>>>> +     struct rt6_info *rt6 = (struct rt6_info *)dst;
> >>>>> +     u32 *pmetrics, table, fib6_flags;
> >>>>>       struct nlmsghdr *nlh;
> >>>>> +     struct rtmsg *rtm;
> >>>>>       long expires = 0;
> >>>>> -     u32 *pmetrics;
> >>>>> -     u32 table;
> >>>>>
> >>>>>       nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
> >>>>>       if (!nlh)
> >>>>>               return -EMSGSIZE;
> >>>>>
> >>>>> +     if (rt6) {
> >>>>> +             fib6_dst = &rt6->rt6i_dst;
> >>>>> +             fib6_src = &rt6->rt6i_src;
> >>>>> +             fib6_flags = rt6->rt6i_flags;
> >>>>> +             fib6_prefsrc = &rt6->rt6i_prefsrc;
> >>>>> +     } else {
> >>>>> +             fib6_dst = &rt->fib6_dst;
> >>>>> +             fib6_src = &rt->fib6_src;
> >>>>> +             fib6_flags = rt->fib6_flags;
> >>>>> +             fib6_prefsrc = &rt->fib6_prefsrc;
> >>>>> +     }
> >>>>
> >>>> Unless I am missing something at the moment, an rt6_info can only have
> >>>> the same dst, src and prefsrc as the fib6_info on which it is based.
> >>>> Thus, only the flags is needed above. That simplifies this patch a lot.
> >>> If dst, src and prefsrc in rt6_info are always the same as these in fib6_info,
> >>> why do we need them in rt6_info? we could just get it by 'from'.
> >>>
> >>
> >> I just sent a patch removing rt6i_prefsrc. It is set with only 1 reader
> >> that can be converted.
> >>
> >> rt6i_src is checked against the fib6_info to invalidate a dst if the src
> >> has changed, so a valid rt will always have the same rt6i_src as the
> >> rt->from.
> >>
> >> rt6i_dst is set to the dest address / 128 in cases, so it should be used
> >> for rt6_info cases above.
> > So that means, I will use rt6i_dst and rt6i_flags when dst is set?
> > how about I use rt6i_src there as well? just to make it look clear.
> > and plus the gw/nh dump fix in rt6_fill_node():
> > -        if (rt->fib6_nsiblings) {
> > +        if (rt6) {
> > +                if (fib6_flags & RTF_GATEWAY)
> > +                        if (nla_put_in6_addr(skb, RTA_GATEWAY,
> > +                                             &rt6->rt6i_gateway) < 0)
> > +                                goto nla_put_failure;
> > +
> > +                if (dst->dev && nla_put_u32(skb, RTA_OIF, dst->dev->ifindex))
> > +                        goto nla_put_failure;
> > +        } else if (rt->fib6_nsiblings) {
> >                  struct fib6_info *sibling, *next_sibling;
> >                  struct nlattr *mp;
> > 
> > looks good to you?
> > 
> 
> sure

Hmm... Then how to deal the other nh info filled by rt6_nexthop_info()?
I was planed to fix the gw issue[1] by syncing the gw and flags info. Like

diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 18e00ce..62621b4 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -998,6 +998,21 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort)
 	rt->rt6i_prefsrc = ort->fib6_prefsrc;
 }
 
+static void rt6_update_info(struct rt6_info *rt)
+{
+	struct fib6_info *from;
+
+	rcu_read_lock();
+	from = rcu_dereference(rt->from);
+	fib6_info_hold(from);
+	rcu_read_unlock();
+
+	from->fib6_flags = rt->rt6i_flags;
+	from->fib6_nh.nh_gw = rt->rt6i_gateway;
+
+	fib6_info_release(from);
+}
+
 static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
 					struct in6_addr *saddr)
 {
@@ -3446,6 +3463,8 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
 		goto out;
 	}
 
+	rt6_update_info(nrt);
+
 	netevent.old = &rt->dst;
 	netevent.new = &nrt->dst;
 	netevent.daddr = &msg->dest;
-- 
2.5.5

[1] https://patchwork.ozlabs.org/patch/966972/

Thanks
Hangbin