diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 70 |
1 files changed, 44 insertions, 26 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 4b4944c3e4c4..fba54a407bb2 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -66,8 +66,9 @@ | |||
66 | #endif | 66 | #endif |
67 | 67 | ||
68 | enum rt6_nud_state { | 68 | enum rt6_nud_state { |
69 | RT6_NUD_FAIL_HARD = -2, | 69 | RT6_NUD_FAIL_HARD = -3, |
70 | RT6_NUD_FAIL_SOFT = -1, | 70 | RT6_NUD_FAIL_PROBE = -2, |
71 | RT6_NUD_FAIL_DO_RR = -1, | ||
71 | RT6_NUD_SUCCEED = 1 | 72 | RT6_NUD_SUCCEED = 1 |
72 | }; | 73 | }; |
73 | 74 | ||
@@ -103,6 +104,36 @@ static struct rt6_info *rt6_get_route_info(struct net *net, | |||
103 | const struct in6_addr *gwaddr, int ifindex); | 104 | const struct in6_addr *gwaddr, int ifindex); |
104 | #endif | 105 | #endif |
105 | 106 | ||
107 | static void rt6_bind_peer(struct rt6_info *rt, int create) | ||
108 | { | ||
109 | struct inet_peer_base *base; | ||
110 | struct inet_peer *peer; | ||
111 | |||
112 | base = inetpeer_base_ptr(rt->_rt6i_peer); | ||
113 | if (!base) | ||
114 | return; | ||
115 | |||
116 | peer = inet_getpeer_v6(base, &rt->rt6i_dst.addr, create); | ||
117 | if (peer) { | ||
118 | if (!rt6_set_peer(rt, peer)) | ||
119 | inet_putpeer(peer); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | static struct inet_peer *__rt6_get_peer(struct rt6_info *rt, int create) | ||
124 | { | ||
125 | if (rt6_has_peer(rt)) | ||
126 | return rt6_peer_ptr(rt); | ||
127 | |||
128 | rt6_bind_peer(rt, create); | ||
129 | return (rt6_has_peer(rt) ? rt6_peer_ptr(rt) : NULL); | ||
130 | } | ||
131 | |||
132 | static struct inet_peer *rt6_get_peer_create(struct rt6_info *rt) | ||
133 | { | ||
134 | return __rt6_get_peer(rt, 1); | ||
135 | } | ||
136 | |||
106 | static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) | 137 | static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) |
107 | { | 138 | { |
108 | struct rt6_info *rt = (struct rt6_info *) dst; | 139 | struct rt6_info *rt = (struct rt6_info *) dst; |
@@ -311,22 +342,6 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
311 | } | 342 | } |
312 | } | 343 | } |
313 | 344 | ||
314 | void rt6_bind_peer(struct rt6_info *rt, int create) | ||
315 | { | ||
316 | struct inet_peer_base *base; | ||
317 | struct inet_peer *peer; | ||
318 | |||
319 | base = inetpeer_base_ptr(rt->_rt6i_peer); | ||
320 | if (!base) | ||
321 | return; | ||
322 | |||
323 | peer = inet_getpeer_v6(base, &rt->rt6i_dst.addr, create); | ||
324 | if (peer) { | ||
325 | if (!rt6_set_peer(rt, peer)) | ||
326 | inet_putpeer(peer); | ||
327 | } | ||
328 | } | ||
329 | |||
330 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | 345 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, |
331 | int how) | 346 | int how) |
332 | { | 347 | { |
@@ -521,7 +536,7 @@ static void rt6_probe(struct rt6_info *rt) | |||
521 | work = kmalloc(sizeof(*work), GFP_ATOMIC); | 536 | work = kmalloc(sizeof(*work), GFP_ATOMIC); |
522 | 537 | ||
523 | if (neigh && work) | 538 | if (neigh && work) |
524 | neigh->updated = jiffies; | 539 | __neigh_set_probe_once(neigh); |
525 | 540 | ||
526 | if (neigh) | 541 | if (neigh) |
527 | write_unlock(&neigh->lock); | 542 | write_unlock(&neigh->lock); |
@@ -577,11 +592,13 @@ static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt) | |||
577 | #ifdef CONFIG_IPV6_ROUTER_PREF | 592 | #ifdef CONFIG_IPV6_ROUTER_PREF |
578 | else if (!(neigh->nud_state & NUD_FAILED)) | 593 | else if (!(neigh->nud_state & NUD_FAILED)) |
579 | ret = RT6_NUD_SUCCEED; | 594 | ret = RT6_NUD_SUCCEED; |
595 | else | ||
596 | ret = RT6_NUD_FAIL_PROBE; | ||
580 | #endif | 597 | #endif |
581 | read_unlock(&neigh->lock); | 598 | read_unlock(&neigh->lock); |
582 | } else { | 599 | } else { |
583 | ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ? | 600 | ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ? |
584 | RT6_NUD_SUCCEED : RT6_NUD_FAIL_SOFT; | 601 | RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR; |
585 | } | 602 | } |
586 | rcu_read_unlock_bh(); | 603 | rcu_read_unlock_bh(); |
587 | 604 | ||
@@ -618,16 +635,17 @@ static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict, | |||
618 | goto out; | 635 | goto out; |
619 | 636 | ||
620 | m = rt6_score_route(rt, oif, strict); | 637 | m = rt6_score_route(rt, oif, strict); |
621 | if (m == RT6_NUD_FAIL_SOFT) { | 638 | if (m == RT6_NUD_FAIL_DO_RR) { |
622 | match_do_rr = true; | 639 | match_do_rr = true; |
623 | m = 0; /* lowest valid score */ | 640 | m = 0; /* lowest valid score */ |
624 | } else if (m < 0) { | 641 | } else if (m == RT6_NUD_FAIL_HARD) { |
625 | goto out; | 642 | goto out; |
626 | } | 643 | } |
627 | 644 | ||
628 | if (strict & RT6_LOOKUP_F_REACHABLE) | 645 | if (strict & RT6_LOOKUP_F_REACHABLE) |
629 | rt6_probe(rt); | 646 | rt6_probe(rt); |
630 | 647 | ||
648 | /* note that m can be RT6_NUD_FAIL_PROBE at this point */ | ||
631 | if (m > *mpri) { | 649 | if (m > *mpri) { |
632 | *do_rr = match_do_rr; | 650 | *do_rr = match_do_rr; |
633 | *mpri = m; | 651 | *mpri = m; |
@@ -1495,7 +1513,7 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1495 | if (!table) | 1513 | if (!table) |
1496 | goto out; | 1514 | goto out; |
1497 | 1515 | ||
1498 | rt = ip6_dst_alloc(net, NULL, DST_NOCOUNT, table); | 1516 | rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table); |
1499 | 1517 | ||
1500 | if (!rt) { | 1518 | if (!rt) { |
1501 | err = -ENOMEM; | 1519 | err = -ENOMEM; |
@@ -2238,7 +2256,7 @@ void rt6_remove_prefsrc(struct inet6_ifaddr *ifp) | |||
2238 | .net = net, | 2256 | .net = net, |
2239 | .addr = &ifp->addr, | 2257 | .addr = &ifp->addr, |
2240 | }; | 2258 | }; |
2241 | fib6_clean_all(net, fib6_remove_prefsrc, 0, &adni); | 2259 | fib6_clean_all(net, fib6_remove_prefsrc, &adni); |
2242 | } | 2260 | } |
2243 | 2261 | ||
2244 | struct arg_dev_net { | 2262 | struct arg_dev_net { |
@@ -2265,7 +2283,7 @@ void rt6_ifdown(struct net *net, struct net_device *dev) | |||
2265 | .net = net, | 2283 | .net = net, |
2266 | }; | 2284 | }; |
2267 | 2285 | ||
2268 | fib6_clean_all(net, fib6_ifdown, 0, &adn); | 2286 | fib6_clean_all(net, fib6_ifdown, &adn); |
2269 | icmp6_clean_all(fib6_ifdown, &adn); | 2287 | icmp6_clean_all(fib6_ifdown, &adn); |
2270 | } | 2288 | } |
2271 | 2289 | ||
@@ -2320,7 +2338,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned int mtu) | |||
2320 | .mtu = mtu, | 2338 | .mtu = mtu, |
2321 | }; | 2339 | }; |
2322 | 2340 | ||
2323 | fib6_clean_all(dev_net(dev), rt6_mtu_change_route, 0, &arg); | 2341 | fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg); |
2324 | } | 2342 | } |
2325 | 2343 | ||
2326 | static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { | 2344 | static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { |