On 2/26/18 12:17 PM, David Miller wrote:
> From: David Ahern <[email protected]>
> 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.