diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2011-07-19 16:18:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-07-22 00:24:25 -0400 |
commit | 21efcfa0ff27776902a8a15e810147be4d937d69 (patch) | |
tree | a0ab4f071d257c4faa0bfa52051b4039ce3d1f96 /net | |
parent | 61463a30f65225e19e68f59dbd7b888bb308ec99 (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.c | 33 |
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 | ||
75 | static struct rt6_info * ip6_rt_copy(struct rt6_info *ort); | 75 | static struct rt6_info *ip6_rt_copy(const struct rt6_info *ort, |
76 | const struct in6_addr *dest); | ||
76 | static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); | 77 | static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); |
77 | static unsigned int ip6_default_advmss(const struct dst_entry *dst); | 78 | static unsigned int ip6_default_advmss(const struct dst_entry *dst); |
78 | static unsigned int ip6_default_mtu(const struct dst_entry *dst); | 79 | static 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 | ||
693 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_addr *daddr, | 694 | static 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 | ||
762 | static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, const struct in6_addr *daddr) | 763 | static 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 | ||
1733 | static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | 1738 | static 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 |