aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r--net/ipv6/route.c70
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
68enum rt6_nud_state { 68enum 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
107static 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
123static 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
132static struct inet_peer *rt6_get_peer_create(struct rt6_info *rt)
133{
134 return __rt6_get_peer(rt, 1);
135}
136
106static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) 137static 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
314void 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
330static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, 345static 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
2244struct arg_dev_net { 2262struct 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
2326static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { 2344static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {