aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
authorYan, Zheng <zheng.z.yan@intel.com>2011-09-05 17:34:30 -0400
committerDavid S. Miller <davem@davemloft.net>2011-09-17 00:57:26 -0400
commit8e2ec639173f325977818c45011ee176ef2b11f6 (patch)
tree2b194fa7556bcde37cdc4d28042a5bdf86d0f2ff /net/ipv6/route.c
parent34b8686d278f00fb16234e74be44c253d6d6b676 (diff)
ipv6: don't use inetpeer to store metrics for routes.
Current IPv6 implementation uses inetpeer to store metrics for routes. The problem of inetpeer is that it doesn't take subnet prefix length in to consideration. If two routes have the same address but different prefix length, they share same inetpeer. So changing metrics of one route also affects the other. The fix is to allocate separate metrics storage for each route. Signed-off-by: Zheng Yan <zheng.z.yan@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r--net/ipv6/route.c33
1 files changed, 22 insertions, 11 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 9e69eb0ec6d..1250f902067 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -104,6 +104,9 @@ static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
104 struct inet_peer *peer; 104 struct inet_peer *peer;
105 u32 *p = NULL; 105 u32 *p = NULL;
106 106
107 if (!(rt->dst.flags & DST_HOST))
108 return NULL;
109
107 if (!rt->rt6i_peer) 110 if (!rt->rt6i_peer)
108 rt6_bind_peer(rt, 1); 111 rt6_bind_peer(rt, 1);
109 112
@@ -252,6 +255,9 @@ static void ip6_dst_destroy(struct dst_entry *dst)
252 struct inet6_dev *idev = rt->rt6i_idev; 255 struct inet6_dev *idev = rt->rt6i_idev;
253 struct inet_peer *peer = rt->rt6i_peer; 256 struct inet_peer *peer = rt->rt6i_peer;
254 257
258 if (!(rt->dst.flags & DST_HOST))
259 dst_destroy_metrics_generic(dst);
260
255 if (idev != NULL) { 261 if (idev != NULL) {
256 rt->rt6i_idev = NULL; 262 rt->rt6i_idev = NULL;
257 in6_dev_put(idev); 263 in6_dev_put(idev);
@@ -723,9 +729,7 @@ static struct rt6_info *rt6_alloc_cow(const struct rt6_info *ort,
723 ipv6_addr_copy(&rt->rt6i_gateway, daddr); 729 ipv6_addr_copy(&rt->rt6i_gateway, daddr);
724 } 730 }
725 731
726 rt->rt6i_dst.plen = 128;
727 rt->rt6i_flags |= RTF_CACHE; 732 rt->rt6i_flags |= RTF_CACHE;
728 rt->dst.flags |= DST_HOST;
729 733
730#ifdef CONFIG_IPV6_SUBTREES 734#ifdef CONFIG_IPV6_SUBTREES
731 if (rt->rt6i_src.plen && saddr) { 735 if (rt->rt6i_src.plen && saddr) {
@@ -775,9 +779,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
775 struct rt6_info *rt = ip6_rt_copy(ort, daddr); 779 struct rt6_info *rt = ip6_rt_copy(ort, daddr);
776 780
777 if (rt) { 781 if (rt) {
778 rt->rt6i_dst.plen = 128;
779 rt->rt6i_flags |= RTF_CACHE; 782 rt->rt6i_flags |= RTF_CACHE;
780 rt->dst.flags |= DST_HOST;
781 dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_raw(&ort->dst))); 783 dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_raw(&ort->dst)));
782 } 784 }
783 return rt; 785 return rt;
@@ -1078,12 +1080,15 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
1078 neigh = NULL; 1080 neigh = NULL;
1079 } 1081 }
1080 1082
1081 rt->rt6i_idev = idev; 1083 rt->dst.flags |= DST_HOST;
1084 rt->dst.output = ip6_output;
1082 dst_set_neighbour(&rt->dst, neigh); 1085 dst_set_neighbour(&rt->dst, neigh);
1083 atomic_set(&rt->dst.__refcnt, 1); 1086 atomic_set(&rt->dst.__refcnt, 1);
1084 ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
1085 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255); 1087 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255);
1086 rt->dst.output = ip6_output; 1088
1089 ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
1090 rt->rt6i_dst.plen = 128;
1091 rt->rt6i_idev = idev;
1087 1092
1088 spin_lock_bh(&icmp6_dst_lock); 1093 spin_lock_bh(&icmp6_dst_lock);
1089 rt->dst.next = icmp6_dst_gc_list; 1094 rt->dst.next = icmp6_dst_gc_list;
@@ -1261,6 +1266,14 @@ int ip6_route_add(struct fib6_config *cfg)
1261 if (rt->rt6i_dst.plen == 128) 1266 if (rt->rt6i_dst.plen == 128)
1262 rt->dst.flags |= DST_HOST; 1267 rt->dst.flags |= DST_HOST;
1263 1268
1269 if (!(rt->dst.flags & DST_HOST) && cfg->fc_mx) {
1270 u32 *metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
1271 if (!metrics) {
1272 err = -ENOMEM;
1273 goto out;
1274 }
1275 dst_init_metrics(&rt->dst, metrics, 0);
1276 }
1264#ifdef CONFIG_IPV6_SUBTREES 1277#ifdef CONFIG_IPV6_SUBTREES
1265 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); 1278 ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
1266 rt->rt6i_src.plen = cfg->fc_src_len; 1279 rt->rt6i_src.plen = cfg->fc_src_len;
@@ -1607,9 +1620,6 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src,
1607 if (on_link) 1620 if (on_link)
1608 nrt->rt6i_flags &= ~RTF_GATEWAY; 1621 nrt->rt6i_flags &= ~RTF_GATEWAY;
1609 1622
1610 nrt->rt6i_dst.plen = 128;
1611 nrt->dst.flags |= DST_HOST;
1612
1613 ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); 1623 ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key);
1614 dst_set_neighbour(&nrt->dst, neigh_clone(neigh)); 1624 dst_set_neighbour(&nrt->dst, neigh_clone(neigh));
1615 1625
@@ -1754,9 +1764,10 @@ static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort,
1754 if (rt) { 1764 if (rt) {
1755 rt->dst.input = ort->dst.input; 1765 rt->dst.input = ort->dst.input;
1756 rt->dst.output = ort->dst.output; 1766 rt->dst.output = ort->dst.output;
1767 rt->dst.flags |= DST_HOST;
1757 1768
1758 ipv6_addr_copy(&rt->rt6i_dst.addr, dest); 1769 ipv6_addr_copy(&rt->rt6i_dst.addr, dest);
1759 rt->rt6i_dst.plen = ort->rt6i_dst.plen; 1770 rt->rt6i_dst.plen = 128;
1760 dst_copy_metrics(&rt->dst, &ort->dst); 1771 dst_copy_metrics(&rt->dst, &ort->dst);
1761 rt->dst.error = ort->dst.error; 1772 rt->dst.error = ort->dst.error;
1762 rt->rt6i_idev = ort->rt6i_idev; 1773 rt->rt6i_idev = ort->rt6i_idev;