diff options
author | David S. Miller <davem@davemloft.net> | 2011-01-27 17:58:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-01-27 17:59:31 -0500 |
commit | 065825402c058f4a123ddc53dbbe864cc5caaf64 (patch) | |
tree | 7d0d5122a5315c5850a0b01ed7349e9eebf794e2 /net/ipv6/route.c | |
parent | 1397e171f143878dd16ad5f8c99f7b9440cc8911 (diff) |
net: Store ipv4/ipv6 COW'd metrics in inetpeer cache.
Please note that the IPSEC dst entry metrics keep using
the generic metrics COW'ing mechanism using kmalloc/kfree.
This gives the IPSEC routes an opportunity to use metrics
which are unique to their encapsulated paths.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 691798c169a5..72609f1c6158 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -97,6 +97,36 @@ static struct rt6_info *rt6_get_route_info(struct net *net, | |||
97 | struct in6_addr *gwaddr, int ifindex); | 97 | struct in6_addr *gwaddr, int ifindex); |
98 | #endif | 98 | #endif |
99 | 99 | ||
100 | static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) | ||
101 | { | ||
102 | struct rt6_info *rt = (struct rt6_info *) dst; | ||
103 | struct inet_peer *peer; | ||
104 | u32 *p = NULL; | ||
105 | |||
106 | if (!rt->rt6i_peer) | ||
107 | rt6_bind_peer(rt, 1); | ||
108 | |||
109 | peer = rt->rt6i_peer; | ||
110 | if (peer) { | ||
111 | u32 *old_p = __DST_METRICS_PTR(old); | ||
112 | unsigned long prev, new; | ||
113 | |||
114 | p = peer->metrics; | ||
115 | if (inet_metrics_new(peer)) | ||
116 | memcpy(p, old_p, sizeof(u32) * RTAX_MAX); | ||
117 | |||
118 | new = (unsigned long) p; | ||
119 | prev = cmpxchg(&dst->_metrics, old, new); | ||
120 | |||
121 | if (prev != old) { | ||
122 | p = __DST_METRICS_PTR(prev); | ||
123 | if (prev & DST_METRICS_READ_ONLY) | ||
124 | p = NULL; | ||
125 | } | ||
126 | } | ||
127 | return p; | ||
128 | } | ||
129 | |||
100 | static struct dst_ops ip6_dst_ops_template = { | 130 | static struct dst_ops ip6_dst_ops_template = { |
101 | .family = AF_INET6, | 131 | .family = AF_INET6, |
102 | .protocol = cpu_to_be16(ETH_P_IPV6), | 132 | .protocol = cpu_to_be16(ETH_P_IPV6), |
@@ -105,7 +135,7 @@ static struct dst_ops ip6_dst_ops_template = { | |||
105 | .check = ip6_dst_check, | 135 | .check = ip6_dst_check, |
106 | .default_advmss = ip6_default_advmss, | 136 | .default_advmss = ip6_default_advmss, |
107 | .default_mtu = ip6_default_mtu, | 137 | .default_mtu = ip6_default_mtu, |
108 | .cow_metrics = dst_cow_metrics_generic, | 138 | .cow_metrics = ipv6_cow_metrics, |
109 | .destroy = ip6_dst_destroy, | 139 | .destroy = ip6_dst_destroy, |
110 | .ifdown = ip6_dst_ifdown, | 140 | .ifdown = ip6_dst_ifdown, |
111 | .negative_advice = ip6_negative_advice, | 141 | .negative_advice = ip6_negative_advice, |
@@ -198,7 +228,6 @@ static void ip6_dst_destroy(struct dst_entry *dst) | |||
198 | rt->rt6i_idev = NULL; | 228 | rt->rt6i_idev = NULL; |
199 | in6_dev_put(idev); | 229 | in6_dev_put(idev); |
200 | } | 230 | } |
201 | dst_destroy_metrics_generic(dst); | ||
202 | if (peer) { | 231 | if (peer) { |
203 | rt->rt6i_peer = NULL; | 232 | rt->rt6i_peer = NULL; |
204 | inet_putpeer(peer); | 233 | inet_putpeer(peer); |