diff options
author | YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org> | 2013-01-17 07:54:05 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-01-17 18:38:19 -0500 |
commit | 887c95cc1da53f66a5890fdeab13414613010097 (patch) | |
tree | d713bbf88a69ca7d17762ff6c3a97376485ca049 /net/ipv6/route.c | |
parent | 6fd6ce2056de27090f4723138e0ce0a816f4ba0d (diff) |
ipv6: Complete neighbour entry removal from dst_entry.
CC: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 84 |
1 files changed, 1 insertions, 83 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index afc8386e3d9f..3a562a103312 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -151,19 +151,6 @@ static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst, | |||
151 | return neigh_create(&nd_tbl, daddr, dst->dev); | 151 | return neigh_create(&nd_tbl, daddr, dst->dev); |
152 | } | 152 | } |
153 | 153 | ||
154 | static int rt6_bind_neighbour(struct rt6_info *rt, struct net_device *dev) | ||
155 | { | ||
156 | struct neighbour *n = __ipv6_neigh_lookup(dev, &rt->rt6i_gateway); | ||
157 | if (!n) { | ||
158 | n = neigh_create(&nd_tbl, &rt->rt6i_gateway, dev); | ||
159 | if (IS_ERR(n)) | ||
160 | return PTR_ERR(n); | ||
161 | } | ||
162 | rt->n = n; | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static struct dst_ops ip6_dst_ops_template = { | 154 | static struct dst_ops ip6_dst_ops_template = { |
168 | .family = AF_INET6, | 155 | .family = AF_INET6, |
169 | .protocol = cpu_to_be16(ETH_P_IPV6), | 156 | .protocol = cpu_to_be16(ETH_P_IPV6), |
@@ -301,9 +288,6 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
301 | struct rt6_info *rt = (struct rt6_info *)dst; | 288 | struct rt6_info *rt = (struct rt6_info *)dst; |
302 | struct inet6_dev *idev = rt->rt6i_idev; | 289 | struct inet6_dev *idev = rt->rt6i_idev; |
303 | 290 | ||
304 | if (rt->n) | ||
305 | neigh_release(rt->n); | ||
306 | |||
307 | if (!(rt->dst.flags & DST_HOST)) | 291 | if (!(rt->dst.flags & DST_HOST)) |
308 | dst_destroy_metrics_generic(dst); | 292 | dst_destroy_metrics_generic(dst); |
309 | 293 | ||
@@ -354,11 +338,6 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | |||
354 | in6_dev_put(idev); | 338 | in6_dev_put(idev); |
355 | } | 339 | } |
356 | } | 340 | } |
357 | if (rt->n && rt->n->dev == dev) { | ||
358 | rt->n->dev = loopback_dev; | ||
359 | dev_hold(loopback_dev); | ||
360 | dev_put(dev); | ||
361 | } | ||
362 | } | 341 | } |
363 | } | 342 | } |
364 | 343 | ||
@@ -845,8 +824,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, | |||
845 | rt = ip6_rt_copy(ort, daddr); | 824 | rt = ip6_rt_copy(ort, daddr); |
846 | 825 | ||
847 | if (rt) { | 826 | if (rt) { |
848 | int attempts = !in_softirq(); | ||
849 | |||
850 | if (!(rt->rt6i_flags & RTF_GATEWAY)) { | 827 | if (!(rt->rt6i_flags & RTF_GATEWAY)) { |
851 | if (ort->rt6i_dst.plen != 128 && | 828 | if (ort->rt6i_dst.plen != 128 && |
852 | ipv6_addr_equal(&ort->rt6i_dst.addr, daddr)) | 829 | ipv6_addr_equal(&ort->rt6i_dst.addr, daddr)) |
@@ -862,32 +839,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, | |||
862 | rt->rt6i_src.plen = 128; | 839 | rt->rt6i_src.plen = 128; |
863 | } | 840 | } |
864 | #endif | 841 | #endif |
865 | |||
866 | retry: | ||
867 | if (rt6_bind_neighbour(rt, rt->dst.dev)) { | ||
868 | struct net *net = dev_net(rt->dst.dev); | ||
869 | int saved_rt_min_interval = | ||
870 | net->ipv6.sysctl.ip6_rt_gc_min_interval; | ||
871 | int saved_rt_elasticity = | ||
872 | net->ipv6.sysctl.ip6_rt_gc_elasticity; | ||
873 | |||
874 | if (attempts-- > 0) { | ||
875 | net->ipv6.sysctl.ip6_rt_gc_elasticity = 1; | ||
876 | net->ipv6.sysctl.ip6_rt_gc_min_interval = 0; | ||
877 | |||
878 | ip6_dst_gc(&net->ipv6.ip6_dst_ops); | ||
879 | |||
880 | net->ipv6.sysctl.ip6_rt_gc_elasticity = | ||
881 | saved_rt_elasticity; | ||
882 | net->ipv6.sysctl.ip6_rt_gc_min_interval = | ||
883 | saved_rt_min_interval; | ||
884 | goto retry; | ||
885 | } | ||
886 | |||
887 | net_warn_ratelimited("Neighbour table overflow\n"); | ||
888 | dst_free(&rt->dst); | ||
889 | return NULL; | ||
890 | } | ||
891 | } | 842 | } |
892 | 843 | ||
893 | return rt; | 844 | return rt; |
@@ -898,10 +849,8 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, | |||
898 | { | 849 | { |
899 | struct rt6_info *rt = ip6_rt_copy(ort, daddr); | 850 | struct rt6_info *rt = ip6_rt_copy(ort, daddr); |
900 | 851 | ||
901 | if (rt) { | 852 | if (rt) |
902 | rt->rt6i_flags |= RTF_CACHE; | 853 | rt->rt6i_flags |= RTF_CACHE; |
903 | rt->n = neigh_clone(ort->n); | ||
904 | } | ||
905 | return rt; | 854 | return rt; |
906 | } | 855 | } |
907 | 856 | ||
@@ -1272,20 +1221,8 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | |||
1272 | goto out; | 1221 | goto out; |
1273 | } | 1222 | } |
1274 | 1223 | ||
1275 | if (neigh) | ||
1276 | neigh_hold(neigh); | ||
1277 | else { | ||
1278 | neigh = ip6_neigh_lookup(&rt->dst, NULL, &fl6->daddr); | ||
1279 | if (IS_ERR(neigh)) { | ||
1280 | in6_dev_put(idev); | ||
1281 | dst_free(&rt->dst); | ||
1282 | return ERR_CAST(neigh); | ||
1283 | } | ||
1284 | } | ||
1285 | |||
1286 | rt->dst.flags |= DST_HOST; | 1224 | rt->dst.flags |= DST_HOST; |
1287 | rt->dst.output = ip6_output; | 1225 | rt->dst.output = ip6_output; |
1288 | rt->n = neigh; | ||
1289 | atomic_set(&rt->dst.__refcnt, 1); | 1226 | atomic_set(&rt->dst.__refcnt, 1); |
1290 | rt->rt6i_dst.addr = fl6->daddr; | 1227 | rt->rt6i_dst.addr = fl6->daddr; |
1291 | rt->rt6i_dst.plen = 128; | 1228 | rt->rt6i_dst.plen = 128; |
@@ -1594,12 +1531,6 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1594 | } else | 1531 | } else |
1595 | rt->rt6i_prefsrc.plen = 0; | 1532 | rt->rt6i_prefsrc.plen = 0; |
1596 | 1533 | ||
1597 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { | ||
1598 | err = rt6_bind_neighbour(rt, dev); | ||
1599 | if (err) | ||
1600 | goto out; | ||
1601 | } | ||
1602 | |||
1603 | rt->rt6i_flags = cfg->fc_flags; | 1534 | rt->rt6i_flags = cfg->fc_flags; |
1604 | 1535 | ||
1605 | install_route: | 1536 | install_route: |
@@ -1713,7 +1644,6 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu | |||
1713 | struct netevent_redirect netevent; | 1644 | struct netevent_redirect netevent; |
1714 | struct rt6_info *rt, *nrt = NULL; | 1645 | struct rt6_info *rt, *nrt = NULL; |
1715 | struct ndisc_options ndopts; | 1646 | struct ndisc_options ndopts; |
1716 | struct neighbour *old_neigh; | ||
1717 | struct inet6_dev *in6_dev; | 1647 | struct inet6_dev *in6_dev; |
1718 | struct neighbour *neigh; | 1648 | struct neighbour *neigh; |
1719 | struct rd_msg *msg; | 1649 | struct rd_msg *msg; |
@@ -1786,11 +1716,6 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu | |||
1786 | if (!neigh) | 1716 | if (!neigh) |
1787 | return; | 1717 | return; |
1788 | 1718 | ||
1789 | /* Duplicate redirect: silently ignore. */ | ||
1790 | old_neigh = rt->n; | ||
1791 | if (neigh == old_neigh) | ||
1792 | goto out; | ||
1793 | |||
1794 | /* | 1719 | /* |
1795 | * We have finally decided to accept it. | 1720 | * We have finally decided to accept it. |
1796 | */ | 1721 | */ |
@@ -1811,7 +1736,6 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu | |||
1811 | nrt->rt6i_flags &= ~RTF_GATEWAY; | 1736 | nrt->rt6i_flags &= ~RTF_GATEWAY; |
1812 | 1737 | ||
1813 | nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key; | 1738 | nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key; |
1814 | nrt->n = neigh_clone(neigh); | ||
1815 | 1739 | ||
1816 | if (ip6_ins_rt(nrt)) | 1740 | if (ip6_ins_rt(nrt)) |
1817 | goto out; | 1741 | goto out; |
@@ -2125,7 +2049,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
2125 | { | 2049 | { |
2126 | struct net *net = dev_net(idev->dev); | 2050 | struct net *net = dev_net(idev->dev); |
2127 | struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL); | 2051 | struct rt6_info *rt = ip6_dst_alloc(net, net->loopback_dev, 0, NULL); |
2128 | int err; | ||
2129 | 2052 | ||
2130 | if (!rt) { | 2053 | if (!rt) { |
2131 | net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n"); | 2054 | net_warn_ratelimited("Maximum number of routes reached, consider increasing route/max_size\n"); |
@@ -2144,11 +2067,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
2144 | rt->rt6i_flags |= RTF_ANYCAST; | 2067 | rt->rt6i_flags |= RTF_ANYCAST; |
2145 | else | 2068 | else |
2146 | rt->rt6i_flags |= RTF_LOCAL; | 2069 | rt->rt6i_flags |= RTF_LOCAL; |
2147 | err = rt6_bind_neighbour(rt, rt->dst.dev); | ||
2148 | if (err) { | ||
2149 | dst_free(&rt->dst); | ||
2150 | return ERR_PTR(err); | ||
2151 | } | ||
2152 | 2070 | ||
2153 | rt->rt6i_dst.addr = *addr; | 2071 | rt->rt6i_dst.addr = *addr; |
2154 | rt->rt6i_dst.plen = 128; | 2072 | rt->rt6i_dst.plen = 128; |