On 2/26/18 12:17 PM, David Miller wrote: > From: David Ahern <dsah...@gmail.com> > Date: Sun, 25 Feb 2018 11:47:18 -0800 > >> +static void ip6_rt_init_dst(struct rt6_info *rt, struct rt6_info *ort) >> +{ > ... >> + rt->dst.error = 0; >> + rt->dst.output = ip6_output; > ... >> @@ -930,14 +999,12 @@ static void rt6_set_from(struct rt6_info *rt, struct >> rt6_info *from) >> >> static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort) >> { >> - rt->dst.input = ort->dst.input; >> - rt->dst.output = ort->dst.output; >> + ip6_rt_init_dst(rt, ort); >> + >> rt->rt6i_dst = ort->rt6i_dst; >> - rt->dst.error = ort->dst.error; >> rt->rt6i_idev = ort->rt6i_idev; >> if (rt->rt6i_idev) >> in6_dev_hold(rt->rt6i_idev); >> - rt->dst.lastuse = jiffies; >> rt->rt6i_gateway = ort->fib6_nh.nh_gw; >> rt->rt6i_flags = ort->rt6i_flags; >> rt6_set_from(rt, ort); > > This seems to change behavior. > > In the old code, the dst error value is propagated from 'ort' into 'rt'. > > Here you set it to zero and that's it. > > Is it set somewhere else? > > I don't think you can assume that all routes that go via this copy > path are not reject routes or other kinds that need the error code > set, if that is what you were thinking.
Only REJECT routes have dst->error set and the only place that happens is ip6_route_info_create: $ egrep -r 'dst.error = |dst->error = ' include net net/core/dst.c: dst->error = 0; net/ipv6/route.c: rt->dst.error = -EINVAL; net/ipv6/route.c: rt->dst.error = -EACCES; net/ipv6/route.c: rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN net/ipv6/route.c: rt->dst.error = ort->dst.error; You cut the context, so I will add the diff here: +static void ip6_rt_init_dst_reject(struct rt6_info *rt, struct rt6_info *ort) +{ + rt->dst.error = ip6_rt_type_to_error(ort->fib6_type); + + switch (ort->fib6_type) { + case RTN_BLACKHOLE: + rt->dst.output = dst_discard_out; + rt->dst.input = dst_discard; + break; + case RTN_PROHIBIT: + rt->dst.output = ip6_pkt_prohibit_out; + rt->dst.input = ip6_pkt_prohibit; + break; + case RTN_THROW: + case RTN_UNREACHABLE: + default: + rt->dst.output = ip6_pkt_discard_out; + rt->dst.input = ip6_pkt_discard; + break; + } +} + +static void ip6_rt_init_dst(struct rt6_info *rt, struct rt6_info *ort) +{ + if (ort->rt6i_flags & RTF_REJECT) { + ip6_rt_init_dst_reject(rt, ort); + return; + } + + rt->dst.error = 0; + rt->dst.output = ip6_output; + +... So for reject routes we have the above helper which is basically a code move from ip6_route_info_create. For non-reject routes dst.error is 0 which is the rest of ip6_rt_init_dst.