OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From e16e888b525503be05b3aea64190e8b3bdef44d0 Mon Sep 17 00:00:00 2001 |
2 | From: Markus Stenberg <markus.stenberg@iki.fi> |
||
3 | Date: Tue, 5 May 2015 13:36:59 +0300 |
||
4 | Subject: [PATCH] ipv6: Fixed source specific default route handling. |
||
5 | |||
6 | If there are only IPv6 source specific default routes present, the |
||
7 | host gets -ENETUNREACH on e.g. connect() because ip6_dst_lookup_tail |
||
8 | calls ip6_route_output first, and given source address any, it fails, |
||
9 | and ip6_route_get_saddr is never called. |
||
10 | |||
11 | The change is to use the ip6_route_get_saddr, even if the initial |
||
12 | ip6_route_output fails, and then doing ip6_route_output _again_ after |
||
13 | we have appropriate source address available. |
||
14 | |||
15 | Note that this is '99% fix' to the problem; a correct fix would be to |
||
16 | do route lookups only within addrconf.c when picking a source address, |
||
17 | and never call ip6_route_output before source address has been |
||
18 | populated. |
||
19 | |||
20 | Signed-off-by: Markus Stenberg <markus.stenberg@iki.fi> |
||
21 | Signed-off-by: David S. Miller <davem@davemloft.net> |
||
22 | --- |
||
23 | net/ipv6/ip6_output.c | 39 +++++++++++++++++++++++++++++++-------- |
||
24 | net/ipv6/route.c | 5 +++-- |
||
25 | 2 files changed, 34 insertions(+), 10 deletions(-) |
||
26 | |||
27 | --- a/net/ipv6/ip6_output.c |
||
28 | +++ b/net/ipv6/ip6_output.c |
||
29 | @@ -909,21 +909,45 @@ static int ip6_dst_lookup_tail(struct so |
||
30 | #endif |
||
31 | int err; |
||
32 | |||
33 | - if (*dst == NULL) |
||
34 | - *dst = ip6_route_output(net, sk, fl6); |
||
35 | - |
||
36 | - if ((err = (*dst)->error)) |
||
37 | - goto out_err_release; |
||
38 | + /* The correct way to handle this would be to do |
||
39 | + * ip6_route_get_saddr, and then ip6_route_output; however, |
||
40 | + * the route-specific preferred source forces the |
||
41 | + * ip6_route_output call _before_ ip6_route_get_saddr. |
||
42 | + * |
||
43 | + * In source specific routing (no src=any default route), |
||
44 | + * ip6_route_output will fail given src=any saddr, though, so |
||
45 | + * that's why we try it again later. |
||
46 | + */ |
||
47 | + if (ipv6_addr_any(&fl6->saddr) && (!*dst || !(*dst)->error)) { |
||
48 | + struct rt6_info *rt; |
||
49 | + bool had_dst = *dst != NULL; |
||
50 | |||
51 | - if (ipv6_addr_any(&fl6->saddr)) { |
||
52 | - struct rt6_info *rt = (struct rt6_info *) *dst; |
||
53 | + if (!had_dst) |
||
54 | + *dst = ip6_route_output(net, sk, fl6); |
||
55 | + rt = (*dst)->error ? NULL : (struct rt6_info *)*dst; |
||
56 | err = ip6_route_get_saddr(net, rt, &fl6->daddr, |
||
57 | sk ? inet6_sk(sk)->srcprefs : 0, |
||
58 | &fl6->saddr); |
||
59 | if (err) |
||
60 | goto out_err_release; |
||
61 | + |
||
62 | + /* If we had an erroneous initial result, pretend it |
||
63 | + * never existed and let the SA-enabled version take |
||
64 | + * over. |
||
65 | + */ |
||
66 | + if (!had_dst && (*dst)->error) { |
||
67 | + dst_release(*dst); |
||
68 | + *dst = NULL; |
||
69 | + } |
||
70 | } |
||
71 | |||
72 | + if (!*dst) |
||
73 | + *dst = ip6_route_output(net, sk, fl6); |
||
74 | + |
||
75 | + err = (*dst)->error; |
||
76 | + if (err) |
||
77 | + goto out_err_release; |
||
78 | + |
||
79 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD |
||
80 | /* |
||
81 | * Here if the dst entry we've looked up |
||
82 | --- a/net/ipv6/route.c |
||
83 | +++ b/net/ipv6/route.c |
||
84 | @@ -2185,9 +2185,10 @@ int ip6_route_get_saddr(struct net *net, |
||
85 | unsigned int prefs, |
||
86 | struct in6_addr *saddr) |
||
87 | { |
||
88 | - struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt); |
||
89 | + struct inet6_dev *idev = |
||
90 | + rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL; |
||
91 | int err = 0; |
||
92 | - if (rt->rt6i_prefsrc.plen) |
||
93 | + if (rt && rt->rt6i_prefsrc.plen) |
||
94 | *saddr = rt->rt6i_prefsrc.addr; |
||
95 | else |
||
96 | err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, |