diff options
-rw-r--r-- | include/net/ip6_fib.h | 2 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 8 | ||||
-rw-r--r-- | net/ipv6/route.c | 42 | ||||
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 1 |
4 files changed, 35 insertions, 18 deletions
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index a192f7807659..0fedbd8d747a 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h | |||
@@ -86,6 +86,8 @@ struct fib6_table; | |||
86 | struct rt6_info { | 86 | struct rt6_info { |
87 | struct dst_entry dst; | 87 | struct dst_entry dst; |
88 | 88 | ||
89 | struct neighbour *n; | ||
90 | |||
89 | /* | 91 | /* |
90 | * Tail elements of dst_entry (__refcnt etc.) | 92 | * Tail elements of dst_entry (__refcnt etc.) |
91 | * and these elements (rarely used in hot path) are in | 93 | * and these elements (rarely used in hot path) are in |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index c94e4aabe11b..6d9c0abc8c20 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -88,6 +88,7 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
88 | struct dst_entry *dst = skb_dst(skb); | 88 | struct dst_entry *dst = skb_dst(skb); |
89 | struct net_device *dev = dst->dev; | 89 | struct net_device *dev = dst->dev; |
90 | struct neighbour *neigh; | 90 | struct neighbour *neigh; |
91 | struct rt6_info *rt; | ||
91 | 92 | ||
92 | skb->protocol = htons(ETH_P_IPV6); | 93 | skb->protocol = htons(ETH_P_IPV6); |
93 | skb->dev = dev; | 94 | skb->dev = dev; |
@@ -123,7 +124,8 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
123 | } | 124 | } |
124 | 125 | ||
125 | rcu_read_lock(); | 126 | rcu_read_lock(); |
126 | neigh = dst_get_neighbour_noref(dst); | 127 | rt = (struct rt6_info *) dst; |
128 | neigh = rt->n; | ||
127 | if (neigh) { | 129 | if (neigh) { |
128 | int res = dst_neigh_output(dst, neigh, skb); | 130 | int res = dst_neigh_output(dst, neigh, skb); |
129 | 131 | ||
@@ -944,6 +946,7 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
944 | struct net *net = sock_net(sk); | 946 | struct net *net = sock_net(sk); |
945 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | 947 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD |
946 | struct neighbour *n; | 948 | struct neighbour *n; |
949 | struct rt6_info *rt; | ||
947 | #endif | 950 | #endif |
948 | int err; | 951 | int err; |
949 | 952 | ||
@@ -972,7 +975,8 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
972 | * dst entry of the nexthop router | 975 | * dst entry of the nexthop router |
973 | */ | 976 | */ |
974 | rcu_read_lock(); | 977 | rcu_read_lock(); |
975 | n = dst_get_neighbour_noref(*dst); | 978 | rt = (struct rt6_info *) dst; |
979 | n = rt->n; | ||
976 | if (n && !(n->nud_state & NUD_VALID)) { | 980 | if (n && !(n->nud_state & NUD_VALID)) { |
977 | struct inet6_ifaddr *ifp; | 981 | struct inet6_ifaddr *ifp; |
978 | struct flowi6 fl_gw6; | 982 | struct flowi6 fl_gw6; |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 34b29881e22d..ceff71d24f8e 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -155,7 +155,7 @@ static int rt6_bind_neighbour(struct rt6_info *rt, struct net_device *dev) | |||
155 | if (IS_ERR(n)) | 155 | if (IS_ERR(n)) |
156 | return PTR_ERR(n); | 156 | return PTR_ERR(n); |
157 | } | 157 | } |
158 | dst_set_neighbour(&rt->dst, n); | 158 | rt->n = n; |
159 | 159 | ||
160 | return 0; | 160 | return 0; |
161 | } | 161 | } |
@@ -285,6 +285,9 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
285 | struct rt6_info *rt = (struct rt6_info *)dst; | 285 | struct rt6_info *rt = (struct rt6_info *)dst; |
286 | struct inet6_dev *idev = rt->rt6i_idev; | 286 | struct inet6_dev *idev = rt->rt6i_idev; |
287 | 287 | ||
288 | if (rt->n) | ||
289 | neigh_release(rt->n); | ||
290 | |||
288 | if (!(rt->dst.flags & DST_HOST)) | 291 | if (!(rt->dst.flags & DST_HOST)) |
289 | dst_destroy_metrics_generic(dst); | 292 | dst_destroy_metrics_generic(dst); |
290 | 293 | ||
@@ -335,12 +338,19 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | |||
335 | struct net_device *loopback_dev = | 338 | struct net_device *loopback_dev = |
336 | dev_net(dev)->loopback_dev; | 339 | dev_net(dev)->loopback_dev; |
337 | 340 | ||
338 | if (dev != loopback_dev && idev && idev->dev == dev) { | 341 | if (dev != loopback_dev) { |
339 | struct inet6_dev *loopback_idev = | 342 | if (idev && idev->dev == dev) { |
340 | in6_dev_get(loopback_dev); | 343 | struct inet6_dev *loopback_idev = |
341 | if (loopback_idev) { | 344 | in6_dev_get(loopback_dev); |
342 | rt->rt6i_idev = loopback_idev; | 345 | if (loopback_idev) { |
343 | in6_dev_put(idev); | 346 | rt->rt6i_idev = loopback_idev; |
347 | in6_dev_put(idev); | ||
348 | } | ||
349 | } | ||
350 | if (rt->n && rt->n->dev == dev) { | ||
351 | rt->n->dev = loopback_dev; | ||
352 | dev_hold(loopback_dev); | ||
353 | dev_put(dev); | ||
344 | } | 354 | } |
345 | } | 355 | } |
346 | } | 356 | } |
@@ -430,7 +440,7 @@ static void rt6_probe(struct rt6_info *rt) | |||
430 | * to no more than one per minute. | 440 | * to no more than one per minute. |
431 | */ | 441 | */ |
432 | rcu_read_lock(); | 442 | rcu_read_lock(); |
433 | neigh = rt ? dst_get_neighbour_noref(&rt->dst) : NULL; | 443 | neigh = rt ? rt->n : NULL; |
434 | if (!neigh || (neigh->nud_state & NUD_VALID)) | 444 | if (!neigh || (neigh->nud_state & NUD_VALID)) |
435 | goto out; | 445 | goto out; |
436 | read_lock_bh(&neigh->lock); | 446 | read_lock_bh(&neigh->lock); |
@@ -477,7 +487,7 @@ static inline int rt6_check_neigh(struct rt6_info *rt) | |||
477 | int m; | 487 | int m; |
478 | 488 | ||
479 | rcu_read_lock(); | 489 | rcu_read_lock(); |
480 | neigh = dst_get_neighbour_noref(&rt->dst); | 490 | neigh = rt->n; |
481 | if (rt->rt6i_flags & RTF_NONEXTHOP || | 491 | if (rt->rt6i_flags & RTF_NONEXTHOP || |
482 | !(rt->rt6i_flags & RTF_GATEWAY)) | 492 | !(rt->rt6i_flags & RTF_GATEWAY)) |
483 | m = 1; | 493 | m = 1; |
@@ -824,7 +834,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, | |||
824 | 834 | ||
825 | if (rt) { | 835 | if (rt) { |
826 | rt->rt6i_flags |= RTF_CACHE; | 836 | rt->rt6i_flags |= RTF_CACHE; |
827 | dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_noref_raw(&ort->dst))); | 837 | rt->n = neigh_clone(ort->n); |
828 | } | 838 | } |
829 | return rt; | 839 | return rt; |
830 | } | 840 | } |
@@ -858,7 +868,7 @@ restart: | |||
858 | dst_hold(&rt->dst); | 868 | dst_hold(&rt->dst); |
859 | read_unlock_bh(&table->tb6_lock); | 869 | read_unlock_bh(&table->tb6_lock); |
860 | 870 | ||
861 | if (!dst_get_neighbour_noref_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 871 | if (!rt->n && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
862 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); | 872 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); |
863 | else if (!(rt->dst.flags & DST_HOST)) | 873 | else if (!(rt->dst.flags & DST_HOST)) |
864 | nrt = rt6_alloc_clone(rt, &fl6->daddr); | 874 | nrt = rt6_alloc_clone(rt, &fl6->daddr); |
@@ -1178,7 +1188,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | |||
1178 | 1188 | ||
1179 | rt->dst.flags |= DST_HOST; | 1189 | rt->dst.flags |= DST_HOST; |
1180 | rt->dst.output = ip6_output; | 1190 | rt->dst.output = ip6_output; |
1181 | dst_set_neighbour(&rt->dst, neigh); | 1191 | rt->n = neigh; |
1182 | atomic_set(&rt->dst.__refcnt, 1); | 1192 | atomic_set(&rt->dst.__refcnt, 1); |
1183 | rt->rt6i_dst.addr = fl6->daddr; | 1193 | rt->rt6i_dst.addr = fl6->daddr; |
1184 | rt->rt6i_dst.plen = 128; | 1194 | rt->rt6i_dst.plen = 128; |
@@ -1715,7 +1725,7 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src, | |||
1715 | dst_confirm(&rt->dst); | 1725 | dst_confirm(&rt->dst); |
1716 | 1726 | ||
1717 | /* Duplicate redirect: silently ignore. */ | 1727 | /* Duplicate redirect: silently ignore. */ |
1718 | old_neigh = dst_get_neighbour_noref_raw(&rt->dst); | 1728 | old_neigh = rt->n; |
1719 | if (neigh == old_neigh) | 1729 | if (neigh == old_neigh) |
1720 | goto out; | 1730 | goto out; |
1721 | 1731 | ||
@@ -1728,7 +1738,7 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src, | |||
1728 | nrt->rt6i_flags &= ~RTF_GATEWAY; | 1738 | nrt->rt6i_flags &= ~RTF_GATEWAY; |
1729 | 1739 | ||
1730 | nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key; | 1740 | nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key; |
1731 | dst_set_neighbour(&nrt->dst, neigh_clone(neigh)); | 1741 | nrt->n = neigh_clone(neigh); |
1732 | 1742 | ||
1733 | if (ip6_ins_rt(nrt)) | 1743 | if (ip6_ins_rt(nrt)) |
1734 | goto out; | 1744 | goto out; |
@@ -2442,7 +2452,7 @@ static int rt6_fill_node(struct net *net, | |||
2442 | goto nla_put_failure; | 2452 | goto nla_put_failure; |
2443 | 2453 | ||
2444 | rcu_read_lock(); | 2454 | rcu_read_lock(); |
2445 | n = dst_get_neighbour_noref(&rt->dst); | 2455 | n = rt->n; |
2446 | if (n) { | 2456 | if (n) { |
2447 | if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0) { | 2457 | if (nla_put(skb, RTA_GATEWAY, 16, &n->primary_key) < 0) { |
2448 | rcu_read_unlock(); | 2458 | rcu_read_unlock(); |
@@ -2666,7 +2676,7 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) | |||
2666 | seq_puts(m, "00000000000000000000000000000000 00 "); | 2676 | seq_puts(m, "00000000000000000000000000000000 00 "); |
2667 | #endif | 2677 | #endif |
2668 | rcu_read_lock(); | 2678 | rcu_read_lock(); |
2669 | n = dst_get_neighbour_noref(&rt->dst); | 2679 | n = rt->n; |
2670 | if (n) { | 2680 | if (n) { |
2671 | seq_printf(m, "%pi6", n->primary_key); | 2681 | seq_printf(m, "%pi6", n->primary_key); |
2672 | } else { | 2682 | } else { |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index d7494845efbf..bb02038b822b 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -103,6 +103,7 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | |||
103 | 103 | ||
104 | /* Sheit... I remember I did this right. Apparently, | 104 | /* Sheit... I remember I did this right. Apparently, |
105 | * it was magically lost, so this code needs audit */ | 105 | * it was magically lost, so this code needs audit */ |
106 | xdst->u.rt6.n = neigh_clone(rt->n); | ||
106 | xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | | 107 | xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | |
107 | RTF_LOCAL); | 108 | RTF_LOCAL); |
108 | xdst->u.rt6.rt6i_metric = rt->rt6i_metric; | 109 | xdst->u.rt6.rt6i_metric = rt->rt6i_metric; |