Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+17 -14
+17 -14
net/ipv4/route.c
··· 1859 1859 1860 1860 static void rt_init_metrics(struct rtable *rt, struct fib_info *fi) 1861 1861 { 1862 - if (!(rt->fl.flags & FLOWI_FLAG_PRECOW_METRICS)) { 1863 - no_cow: 1862 + struct inet_peer *peer; 1863 + int create = 0; 1864 + 1865 + /* If a peer entry exists for this destination, we must hook 1866 + * it up in order to get at cached metrics. 1867 + */ 1868 + if (rt->fl.flags & FLOWI_FLAG_PRECOW_METRICS) 1869 + create = 1; 1870 + 1871 + rt_bind_peer(rt, create); 1872 + peer = rt->peer; 1873 + if (peer) { 1874 + if (inet_metrics_new(peer)) 1875 + memcpy(peer->metrics, fi->fib_metrics, 1876 + sizeof(u32) * RTAX_MAX); 1877 + dst_init_metrics(&rt->dst, peer->metrics, false); 1878 + } else { 1864 1879 if (fi->fib_metrics != (u32 *) dst_default_metrics) { 1865 1880 rt->fi = fi; 1866 1881 atomic_inc(&fi->fib_clntref); 1867 1882 } 1868 1883 dst_init_metrics(&rt->dst, fi->fib_metrics, true); 1869 - } else { 1870 - struct inet_peer *peer; 1871 - 1872 - if (!rt->peer) 1873 - rt_bind_peer(rt, 1); 1874 - peer = rt->peer; 1875 - if (!peer) 1876 - goto no_cow; 1877 - if (inet_metrics_new(peer)) 1878 - memcpy(peer->metrics, fi->fib_metrics, 1879 - sizeof(u32) * RTAX_MAX); 1880 - dst_init_metrics(&rt->dst, peer->metrics, false); 1881 1884 } 1882 1885 } 1883 1886