aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-07-19 16:18:36 -0400
committerDavid S. Miller <davem@davemloft.net>2011-07-22 00:24:25 -0400
commit21efcfa0ff27776902a8a15e810147be4d937d69 (patch)
treea0ab4f071d257c4faa0bfa52051b4039ce3d1f96 /net
parent61463a30f65225e19e68f59dbd7b888bb308ec99 (diff)
ipv6: unshare inetpeers
We currently cow metrics a bit too soon in IPv6 case : All routes are tied to a single inetpeer entry. Change ip6_rt_copy() to get destination address as second argument, so that we fill rt6i_dst before the dst_copy_metrics() call. icmp6_dst_alloc() must set rt6i_dst before calling dst_metric_set(), or else the cow is done while rt6i_dst is still NULL. If orig route points to readonly metrics, we can share the pointer instead of performing the memory allocation and copy. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/route.c33
1 files changed, 20 insertions, 13 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index ddef80f568b0..e8987da06667 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -72,7 +72,8 @@
72#define RT6_TRACE(x...) do { ; } while (0) 72#define RT6_TRACE(x...) do { ; } while (0)
73#endif 73#endif
74 74
75static struct rt6_info * ip6_rt_copy(struct rt6_info *ort); 75static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort,
76 const struct in6_addr *dest);
76static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); 77static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
77static unsigned int ip6_default_advmss(const struct dst_entry *dst); 78static unsigned int ip6_default_advmss(const struct dst_entry *dst);
78static unsigned int ip6_default_mtu(const struct dst_entry *dst); 79static unsigned int ip6_default_mtu(const struct dst_entry *dst);
@@ -690,7 +691,8 @@ int ip6_ins_rt(struct rt6_info *rt)
690 return __ip6_ins_rt(rt, &info); 691 return __ip6_ins_rt(rt, &info);
691} 692}
692 693
693static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_addr *daddr, 694static struct rt6_info *rt6_alloc_cow(const struct rt6_info *ort,
695 const struct in6_addr *daddr,
694 const struct in6_addr *saddr) 696 const struct in6_addr *saddr)
695{ 697{
696 struct rt6_info *rt; 698 struct rt6_info *rt;
@@ -699,7 +701,7 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_add
699 * Clone the route. 701 * Clone the route.
700 */ 702 */
701 703
702 rt = ip6_rt_copy(ort); 704 rt = ip6_rt_copy(ort, daddr);
703 705
704 if (rt) { 706 if (rt) {
705 struct neighbour *neigh; 707 struct neighbour *neigh;
@@ -707,12 +709,11 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_add
707 709
708 if (!(rt->rt6i_flags&RTF_GATEWAY)) { 710 if (!(rt->rt6i_flags&RTF_GATEWAY)) {
709 if (rt->rt6i_dst.plen != 128 && 711 if (rt->rt6i_dst.plen != 128 &&
710 ipv6_addr_equal(&rt->rt6i_dst.addr, daddr)) 712 ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
711 rt->rt6i_flags |= RTF_ANYCAST; 713 rt->rt6i_flags |= RTF_ANYCAST;
712 ipv6_addr_copy(&rt->rt6i_gateway, daddr); 714 ipv6_addr_copy(&rt->rt6i_gateway, daddr);
713 } 715 }
714 716
715 ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
716 rt->rt6i_dst.plen = 128; 717 rt->rt6i_dst.plen = 128;
717 rt->rt6i_flags |= RTF_CACHE; 718 rt->rt6i_flags |= RTF_CACHE;
718 rt->dst.flags |= DST_HOST; 719 rt->dst.flags |= DST_HOST;
@@ -759,11 +760,12 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_add
759 return rt; 760 return rt;
760} 761}
761 762
762static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, const struct in6_addr *daddr) 763static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort,
764 const struct in6_addr *daddr)
763{ 765{
764 struct rt6_info *rt = ip6_rt_copy(ort); 766 struct rt6_info *rt = ip6_rt_copy(ort, daddr);
767
765 if (rt) { 768 if (rt) {
766 ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
767 rt->rt6i_dst.plen = 128; 769 rt->rt6i_dst.plen = 128;
768 rt->rt6i_flags |= RTF_CACHE; 770 rt->rt6i_flags |= RTF_CACHE;
769 rt->dst.flags |= DST_HOST; 771 rt->dst.flags |= DST_HOST;
@@ -907,7 +909,10 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori
907 new->input = dst_discard; 909 new->input = dst_discard;
908 new->output = dst_discard; 910 new->output = dst_discard;
909 911
910 dst_copy_metrics(new, &ort->dst); 912 if (dst_metrics_read_only(&ort->dst))
913 new->_metrics = ort->dst._metrics;
914 else
915 dst_copy_metrics(new, &ort->dst);
911 rt->rt6i_idev = ort->rt6i_idev; 916 rt->rt6i_idev = ort->rt6i_idev;
912 if (rt->rt6i_idev) 917 if (rt->rt6i_idev)
913 in6_dev_hold(rt->rt6i_idev); 918 in6_dev_hold(rt->rt6i_idev);
@@ -1067,6 +1072,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
1067 rt->rt6i_idev = idev; 1072 rt->rt6i_idev = idev;
1068 dst_set_neighbour(&rt->dst, neigh); 1073 dst_set_neighbour(&rt->dst, neigh);
1069 atomic_set(&rt->dst.__refcnt, 1); 1074 atomic_set(&rt->dst.__refcnt, 1);
1075 ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
1070 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255); 1076 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255);
1071 rt->dst.output = ip6_output; 1077 rt->dst.output = ip6_output;
1072 1078
@@ -1584,7 +1590,7 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src,
1584 if (neigh == dst_get_neighbour(&rt->dst)) 1590 if (neigh == dst_get_neighbour(&rt->dst))
1585 goto out; 1591 goto out;
1586 1592
1587 nrt = ip6_rt_copy(rt); 1593 nrt = ip6_rt_copy(rt, dest);
1588 if (nrt == NULL) 1594 if (nrt == NULL)
1589 goto out; 1595 goto out;
1590 1596
@@ -1592,7 +1598,6 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src,
1592 if (on_link) 1598 if (on_link)
1593 nrt->rt6i_flags &= ~RTF_GATEWAY; 1599 nrt->rt6i_flags &= ~RTF_GATEWAY;
1594 1600
1595 ipv6_addr_copy(&nrt->rt6i_dst.addr, dest);
1596 nrt->rt6i_dst.plen = 128; 1601 nrt->rt6i_dst.plen = 128;
1597 nrt->dst.flags |= DST_HOST; 1602 nrt->dst.flags |= DST_HOST;
1598 1603
@@ -1730,7 +1735,8 @@ void rt6_pmtu_discovery(const struct in6_addr *daddr, const struct in6_addr *sad
1730 * Misc support functions 1735 * Misc support functions
1731 */ 1736 */
1732 1737
1733static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) 1738static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort,
1739 const struct in6_addr *dest)
1734{ 1740{
1735 struct net *net = dev_net(ort->rt6i_dev); 1741 struct net *net = dev_net(ort->rt6i_dev);
1736 struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops, 1742 struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops,
@@ -1740,6 +1746,8 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
1740 rt->dst.input = ort->dst.input; 1746 rt->dst.input = ort->dst.input;
1741 rt->dst.output = ort->dst.output; 1747 rt->dst.output = ort->dst.output;
1742 1748
1749 ipv6_addr_copy(&rt->rt6i_dst.addr, dest);
1750 rt->rt6i_dst.plen = ort->rt6i_dst.plen;
1743 dst_copy_metrics(&rt->dst, &ort->dst); 1751 dst_copy_metrics(&rt->dst, &ort->dst);
1744 rt->dst.error = ort->dst.error; 1752 rt->dst.error = ort->dst.error;
1745 rt->rt6i_idev = ort->rt6i_idev; 1753 rt->rt6i_idev = ort->rt6i_idev;
@@ -1752,7 +1760,6 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
1752 rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES; 1760 rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES;
1753 rt->rt6i_metric = 0; 1761 rt->rt6i_metric = 0;
1754 1762
1755 memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
1756#ifdef CONFIG_IPV6_SUBTREES 1763#ifdef CONFIG_IPV6_SUBTREES
1757 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); 1764 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1758#endif 1765#endif