diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/ipv4/ip_output.c | 10 | ||||
| -rw-r--r-- | net/ipv4/route.c | 14 | ||||
| -rw-r--r-- | net/ipv6/addrconf.c | 2 | ||||
| -rw-r--r-- | net/ipv6/ip6_fib.c | 2 | ||||
| -rw-r--r-- | net/ipv6/ip6_output.c | 13 | ||||
| -rw-r--r-- | net/ipv6/route.c | 35 |
6 files changed, 54 insertions, 22 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index ccaaa851ab42..77d3eded665a 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
| @@ -204,9 +204,15 @@ static inline int ip_finish_output2(struct sk_buff *skb) | |||
| 204 | skb = skb2; | 204 | skb = skb2; |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | rcu_read_lock(); | ||
| 207 | neigh = dst_get_neighbour(dst); | 208 | neigh = dst_get_neighbour(dst); |
| 208 | if (neigh) | 209 | if (neigh) { |
| 209 | return neigh_output(neigh, skb); | 210 | int res = neigh_output(neigh, skb); |
| 211 | |||
| 212 | rcu_read_unlock(); | ||
| 213 | return res; | ||
| 214 | } | ||
| 215 | rcu_read_unlock(); | ||
| 210 | 216 | ||
| 211 | if (net_ratelimit()) | 217 | if (net_ratelimit()) |
| 212 | printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n"); | 218 | printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n"); |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 1730689f560e..6afc4eb50591 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
| @@ -1628,16 +1628,18 @@ static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) | |||
| 1628 | { | 1628 | { |
| 1629 | struct rtable *rt = (struct rtable *) dst; | 1629 | struct rtable *rt = (struct rtable *) dst; |
| 1630 | __be32 orig_gw = rt->rt_gateway; | 1630 | __be32 orig_gw = rt->rt_gateway; |
| 1631 | struct neighbour *n; | 1631 | struct neighbour *n, *old_n; |
| 1632 | 1632 | ||
| 1633 | dst_confirm(&rt->dst); | 1633 | dst_confirm(&rt->dst); |
| 1634 | 1634 | ||
| 1635 | neigh_release(dst_get_neighbour(&rt->dst)); | ||
| 1636 | dst_set_neighbour(&rt->dst, NULL); | ||
| 1637 | |||
| 1638 | rt->rt_gateway = peer->redirect_learned.a4; | 1635 | rt->rt_gateway = peer->redirect_learned.a4; |
| 1639 | rt_bind_neighbour(rt); | 1636 | |
| 1640 | n = dst_get_neighbour(&rt->dst); | 1637 | n = ipv4_neigh_lookup(&rt->dst, &rt->rt_gateway); |
| 1638 | if (IS_ERR(n)) | ||
| 1639 | return PTR_ERR(n); | ||
| 1640 | old_n = xchg(&rt->dst._neighbour, n); | ||
| 1641 | if (old_n) | ||
| 1642 | neigh_release(old_n); | ||
| 1641 | if (!n || !(n->nud_state & NUD_VALID)) { | 1643 | if (!n || !(n->nud_state & NUD_VALID)) { |
| 1642 | if (n) | 1644 | if (n) |
| 1643 | neigh_event_send(n, NULL); | 1645 | neigh_event_send(n, NULL); |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a55500cc0b29..f012ebd87b43 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -656,7 +656,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
| 656 | * layer address of our nexhop router | 656 | * layer address of our nexhop router |
| 657 | */ | 657 | */ |
| 658 | 658 | ||
| 659 | if (dst_get_neighbour(&rt->dst) == NULL) | 659 | if (dst_get_neighbour_raw(&rt->dst) == NULL) |
| 660 | ifa->flags &= ~IFA_F_OPTIMISTIC; | 660 | ifa->flags &= ~IFA_F_OPTIMISTIC; |
| 661 | 661 | ||
| 662 | ifa->idev = idev; | 662 | ifa->idev = idev; |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 54a4678955bf..320d91d20ad7 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
| @@ -1455,7 +1455,7 @@ static int fib6_age(struct rt6_info *rt, void *arg) | |||
| 1455 | RT6_TRACE("aging clone %p\n", rt); | 1455 | RT6_TRACE("aging clone %p\n", rt); |
| 1456 | return -1; | 1456 | return -1; |
| 1457 | } else if ((rt->rt6i_flags & RTF_GATEWAY) && | 1457 | } else if ((rt->rt6i_flags & RTF_GATEWAY) && |
| 1458 | (!(dst_get_neighbour(&rt->dst)->flags & NTF_ROUTER))) { | 1458 | (!(dst_get_neighbour_raw(&rt->dst)->flags & NTF_ROUTER))) { |
| 1459 | RT6_TRACE("purging route %p via non-router but gateway\n", | 1459 | RT6_TRACE("purging route %p via non-router but gateway\n", |
| 1460 | rt); | 1460 | rt); |
| 1461 | return -1; | 1461 | return -1; |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 32e5339db0c8..4c882cf4e8a1 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
| @@ -135,10 +135,15 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
| 135 | skb->len); | 135 | skb->len); |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | rcu_read_lock(); | ||
| 138 | neigh = dst_get_neighbour(dst); | 139 | neigh = dst_get_neighbour(dst); |
| 139 | if (neigh) | 140 | if (neigh) { |
| 140 | return neigh_output(neigh, skb); | 141 | int res = neigh_output(neigh, skb); |
| 141 | 142 | ||
| 143 | rcu_read_unlock(); | ||
| 144 | return res; | ||
| 145 | } | ||
| 146 | rcu_read_unlock(); | ||
| 142 | IP6_INC_STATS_BH(dev_net(dst->dev), | 147 | IP6_INC_STATS_BH(dev_net(dst->dev), |
| 143 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | 148 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
| 144 | kfree_skb(skb); | 149 | kfree_skb(skb); |
| @@ -975,12 +980,14 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
| 975 | * dst entry and replace it instead with the | 980 | * dst entry and replace it instead with the |
| 976 | * dst entry of the nexthop router | 981 | * dst entry of the nexthop router |
| 977 | */ | 982 | */ |
| 983 | rcu_read_lock(); | ||
| 978 | n = dst_get_neighbour(*dst); | 984 | n = dst_get_neighbour(*dst); |
| 979 | if (n && !(n->nud_state & NUD_VALID)) { | 985 | if (n && !(n->nud_state & NUD_VALID)) { |
| 980 | struct inet6_ifaddr *ifp; | 986 | struct inet6_ifaddr *ifp; |
| 981 | struct flowi6 fl_gw6; | 987 | struct flowi6 fl_gw6; |
| 982 | int redirect; | 988 | int redirect; |
| 983 | 989 | ||
| 990 | rcu_read_unlock(); | ||
| 984 | ifp = ipv6_get_ifaddr(net, &fl6->saddr, | 991 | ifp = ipv6_get_ifaddr(net, &fl6->saddr, |
| 985 | (*dst)->dev, 1); | 992 | (*dst)->dev, 1); |
| 986 | 993 | ||
| @@ -1000,6 +1007,8 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
| 1000 | if ((err = (*dst)->error)) | 1007 | if ((err = (*dst)->error)) |
| 1001 | goto out_err_release; | 1008 | goto out_err_release; |
| 1002 | } | 1009 | } |
| 1010 | } else { | ||
| 1011 | rcu_read_unlock(); | ||
| 1003 | } | 1012 | } |
| 1004 | #endif | 1013 | #endif |
| 1005 | 1014 | ||
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e8987da06667..9e69eb0ec6dd 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
| @@ -364,7 +364,7 @@ out: | |||
| 364 | #ifdef CONFIG_IPV6_ROUTER_PREF | 364 | #ifdef CONFIG_IPV6_ROUTER_PREF |
| 365 | static void rt6_probe(struct rt6_info *rt) | 365 | static void rt6_probe(struct rt6_info *rt) |
| 366 | { | 366 | { |
| 367 | struct neighbour *neigh = rt ? dst_get_neighbour(&rt->dst) : NULL; | 367 | struct neighbour *neigh; |
| 368 | /* | 368 | /* |
| 369 | * Okay, this does not seem to be appropriate | 369 | * Okay, this does not seem to be appropriate |
| 370 | * for now, however, we need to check if it | 370 | * for now, however, we need to check if it |
| @@ -373,8 +373,10 @@ static void rt6_probe(struct rt6_info *rt) | |||
| 373 | * Router Reachability Probe MUST be rate-limited | 373 | * Router Reachability Probe MUST be rate-limited |
| 374 | * to no more than one per minute. | 374 | * to no more than one per minute. |
| 375 | */ | 375 | */ |
| 376 | rcu_read_lock(); | ||
| 377 | neigh = rt ? dst_get_neighbour(&rt->dst) : NULL; | ||
| 376 | if (!neigh || (neigh->nud_state & NUD_VALID)) | 378 | if (!neigh || (neigh->nud_state & NUD_VALID)) |
| 377 | return; | 379 | goto out; |
| 378 | read_lock_bh(&neigh->lock); | 380 | read_lock_bh(&neigh->lock); |
| 379 | if (!(neigh->nud_state & NUD_VALID) && | 381 | if (!(neigh->nud_state & NUD_VALID) && |
| 380 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { | 382 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { |
| @@ -387,8 +389,11 @@ static void rt6_probe(struct rt6_info *rt) | |||
| 387 | target = (struct in6_addr *)&neigh->primary_key; | 389 | target = (struct in6_addr *)&neigh->primary_key; |
| 388 | addrconf_addr_solict_mult(target, &mcaddr); | 390 | addrconf_addr_solict_mult(target, &mcaddr); |
| 389 | ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL); | 391 | ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL); |
| 390 | } else | 392 | } else { |
| 391 | read_unlock_bh(&neigh->lock); | 393 | read_unlock_bh(&neigh->lock); |
| 394 | } | ||
| 395 | out: | ||
| 396 | rcu_read_unlock(); | ||
| 392 | } | 397 | } |
| 393 | #else | 398 | #else |
| 394 | static inline void rt6_probe(struct rt6_info *rt) | 399 | static inline void rt6_probe(struct rt6_info *rt) |
| @@ -412,8 +417,11 @@ static inline int rt6_check_dev(struct rt6_info *rt, int oif) | |||
| 412 | 417 | ||
| 413 | static inline int rt6_check_neigh(struct rt6_info *rt) | 418 | static inline int rt6_check_neigh(struct rt6_info *rt) |
| 414 | { | 419 | { |
| 415 | struct neighbour *neigh = dst_get_neighbour(&rt->dst); | 420 | struct neighbour *neigh; |
| 416 | int m; | 421 | int m; |
| 422 | |||
| 423 | rcu_read_lock(); | ||
| 424 | neigh = dst_get_neighbour(&rt->dst); | ||
| 417 | if (rt->rt6i_flags & RTF_NONEXTHOP || | 425 | if (rt->rt6i_flags & RTF_NONEXTHOP || |
| 418 | !(rt->rt6i_flags & RTF_GATEWAY)) | 426 | !(rt->rt6i_flags & RTF_GATEWAY)) |
| 419 | m = 1; | 427 | m = 1; |
| @@ -430,6 +438,7 @@ static inline int rt6_check_neigh(struct rt6_info *rt) | |||
| 430 | read_unlock_bh(&neigh->lock); | 438 | read_unlock_bh(&neigh->lock); |
| 431 | } else | 439 | } else |
| 432 | m = 0; | 440 | m = 0; |
| 441 | rcu_read_unlock(); | ||
| 433 | return m; | 442 | return m; |
| 434 | } | 443 | } |
| 435 | 444 | ||
| @@ -769,7 +778,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, | |||
| 769 | rt->rt6i_dst.plen = 128; | 778 | rt->rt6i_dst.plen = 128; |
| 770 | rt->rt6i_flags |= RTF_CACHE; | 779 | rt->rt6i_flags |= RTF_CACHE; |
| 771 | rt->dst.flags |= DST_HOST; | 780 | rt->dst.flags |= DST_HOST; |
| 772 | dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour(&ort->dst))); | 781 | dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_raw(&ort->dst))); |
| 773 | } | 782 | } |
| 774 | return rt; | 783 | return rt; |
| 775 | } | 784 | } |
| @@ -803,7 +812,7 @@ restart: | |||
| 803 | dst_hold(&rt->dst); | 812 | dst_hold(&rt->dst); |
| 804 | read_unlock_bh(&table->tb6_lock); | 813 | read_unlock_bh(&table->tb6_lock); |
| 805 | 814 | ||
| 806 | if (!dst_get_neighbour(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 815 | if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
| 807 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); | 816 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); |
| 808 | else if (!(rt->dst.flags & DST_HOST)) | 817 | else if (!(rt->dst.flags & DST_HOST)) |
| 809 | nrt = rt6_alloc_clone(rt, &fl6->daddr); | 818 | nrt = rt6_alloc_clone(rt, &fl6->daddr); |
| @@ -1587,7 +1596,7 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src, | |||
| 1587 | dst_confirm(&rt->dst); | 1596 | dst_confirm(&rt->dst); |
| 1588 | 1597 | ||
| 1589 | /* Duplicate redirect: silently ignore. */ | 1598 | /* Duplicate redirect: silently ignore. */ |
| 1590 | if (neigh == dst_get_neighbour(&rt->dst)) | 1599 | if (neigh == dst_get_neighbour_raw(&rt->dst)) |
| 1591 | goto out; | 1600 | goto out; |
| 1592 | 1601 | ||
| 1593 | nrt = ip6_rt_copy(rt, dest); | 1602 | nrt = ip6_rt_copy(rt, dest); |
| @@ -1682,7 +1691,7 @@ again: | |||
| 1682 | 1. It is connected route. Action: COW | 1691 | 1. It is connected route. Action: COW |
| 1683 | 2. It is gatewayed route or NONEXTHOP route. Action: clone it. | 1692 | 2. It is gatewayed route or NONEXTHOP route. Action: clone it. |
| 1684 | */ | 1693 | */ |
| 1685 | if (!dst_get_neighbour(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 1694 | if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
| 1686 | nrt = rt6_alloc_cow(rt, daddr, saddr); | 1695 | nrt = rt6_alloc_cow(rt, daddr, saddr); |
| 1687 | else | 1696 | else |
| 1688 | nrt = rt6_alloc_clone(rt, daddr); | 1697 | nrt = rt6_alloc_clone(rt, daddr); |
| @@ -2326,6 +2335,7 @@ static int rt6_fill_node(struct net *net, | |||
| 2326 | struct nlmsghdr *nlh; | 2335 | struct nlmsghdr *nlh; |
| 2327 | long expires; | 2336 | long expires; |
| 2328 | u32 table; | 2337 | u32 table; |
| 2338 | struct neighbour *n; | ||
| 2329 | 2339 | ||
| 2330 | if (prefix) { /* user wants prefix routes only */ | 2340 | if (prefix) { /* user wants prefix routes only */ |
| 2331 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { | 2341 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { |
| @@ -2414,8 +2424,11 @@ static int rt6_fill_node(struct net *net, | |||
| 2414 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) | 2424 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) |
| 2415 | goto nla_put_failure; | 2425 | goto nla_put_failure; |
| 2416 | 2426 | ||
| 2417 | if (dst_get_neighbour(&rt->dst)) | 2427 | rcu_read_lock(); |
| 2418 | NLA_PUT(skb, RTA_GATEWAY, 16, &dst_get_neighbour(&rt->dst)->primary_key); | 2428 | n = dst_get_neighbour(&rt->dst); |
| 2429 | if (n) | ||
| 2430 | NLA_PUT(skb, RTA_GATEWAY, 16, &n->primary_key); | ||
| 2431 | rcu_read_unlock(); | ||
| 2419 | 2432 | ||
| 2420 | if (rt->dst.dev) | 2433 | if (rt->dst.dev) |
| 2421 | NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); | 2434 | NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); |
| @@ -2608,12 +2621,14 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) | |||
| 2608 | #else | 2621 | #else |
| 2609 | seq_puts(m, "00000000000000000000000000000000 00 "); | 2622 | seq_puts(m, "00000000000000000000000000000000 00 "); |
| 2610 | #endif | 2623 | #endif |
| 2624 | rcu_read_lock(); | ||
| 2611 | n = dst_get_neighbour(&rt->dst); | 2625 | n = dst_get_neighbour(&rt->dst); |
| 2612 | if (n) { | 2626 | if (n) { |
| 2613 | seq_printf(m, "%pi6", n->primary_key); | 2627 | seq_printf(m, "%pi6", n->primary_key); |
| 2614 | } else { | 2628 | } else { |
| 2615 | seq_puts(m, "00000000000000000000000000000000"); | 2629 | seq_puts(m, "00000000000000000000000000000000"); |
| 2616 | } | 2630 | } |
| 2631 | rcu_read_unlock(); | ||
| 2617 | seq_printf(m, " %08x %08x %08x %08x %8s\n", | 2632 | seq_printf(m, " %08x %08x %08x %08x %8s\n", |
| 2618 | rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), | 2633 | rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), |
| 2619 | rt->dst.__use, rt->rt6i_flags, | 2634 | rt->dst.__use, rt->rt6i_flags, |
