summaryrefslogtreecommitdiffstats
path: root/net/ipv4/route.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-02-04 23:37:30 +0100
committerDavid S. Miller <davem@davemloft.net>2011-02-04 23:37:30 +0100
commit0131ba451e20239c5dc701027c1a2edef95e1a6e (patch)
tree880906b7030daf840fc1e903de4381cb70cf473c /net/ipv4/route.c
parentMerge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/ne... (diff)
downloadlinux-0131ba451e20239c5dc701027c1a2edef95e1a6e.tar.xz
linux-0131ba451e20239c5dc701027c1a2edef95e1a6e.zip
ipv4: Don't miss existing cached metrics in new routes.
Always lookup to see if we have an existing inetpeer entry for a route. Let FLOWI_FLAG_PRECOW_METRICS merely influence the "create" argument to rt_bind_peer(). Also, call rt_bind_peer() unconditionally since it is not possible for rt->peer to be non-NULL at this point. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r--net/ipv4/route.c31
1 files changed, 17 insertions, 14 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index e4c81652f17d..0ba6a382b2b4 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1859,25 +1859,28 @@ static unsigned int ipv4_default_mtu(const struct dst_entry *dst)
static void rt_init_metrics(struct rtable *rt, struct fib_info *fi)
{
- if (!(rt->fl.flags & FLOWI_FLAG_PRECOW_METRICS)) {
- no_cow:
- if (fi->fib_metrics != (u32 *) dst_default_metrics) {
- rt->fi = fi;
- atomic_inc(&fi->fib_clntref);
- }
- dst_init_metrics(&rt->dst, fi->fib_metrics, true);
- } else {
- struct inet_peer *peer;
+ struct inet_peer *peer;
+ int create = 0;
- if (!rt->peer)
- rt_bind_peer(rt, 1);
- peer = rt->peer;
- if (!peer)
- goto no_cow;
+ /* If a peer entry exists for this destination, we must hook
+ * it up in order to get at cached metrics.
+ */
+ if (rt->fl.flags & FLOWI_FLAG_PRECOW_METRICS)
+ create = 1;
+
+ rt_bind_peer(rt, create);
+ peer = rt->peer;
+ if (peer) {
if (inet_metrics_new(peer))
memcpy(peer->metrics, fi->fib_metrics,
sizeof(u32) * RTAX_MAX);
dst_init_metrics(&rt->dst, peer->metrics, false);
+ } else {
+ if (fi->fib_metrics != (u32 *) dst_default_metrics) {
+ rt->fi = fi;
+ atomic_inc(&fi->fib_clntref);
+ }
+ dst_init_metrics(&rt->dst, fi->fib_metrics, true);
}
}