From: Martin KaFai Lau Date: Fri, 13 Feb 2015 00:14:08 +0000 (-0800) Subject: ipv6: fix ipv6_cow_metrics for non DST_HOST case X-Git-Tag: v3.4.108~135 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=43f5b8aa31910a2e95aa675fba8154d3741c2496;p=thirdparty%2Fkernel%2Fstable.git ipv6: fix ipv6_cow_metrics for non DST_HOST case commit 3b4711757d7903ab6fa88a9e7ab8901b8227da60 upstream. ipv6_cow_metrics() currently assumes only DST_HOST routes require dynamic metrics allocation from inetpeer. The assumption breaks when ndisc discovered router with RTAX_MTU and RTAX_HOPLIMIT metric. Refer to ndisc_router_discovery() in ndisc.c and note that dst_metric_set() is called after the route is created. This patch creates the metrics array (by calling dst_cow_metrics_generic) in ipv6_cow_metrics(). Test: radvd.conf: interface qemubr0 { AdvLinkMTU 1300; AdvCurHopLimit 30; prefix fd00:face:face:face::/64 { AdvOnLink on; AdvAutonomous on; AdvRouterAddr off; }; }; Before: [root@qemu1 ~]# ip -6 r show | egrep -v unreachable fd00:face:face:face::/64 dev eth0 proto kernel metric 256 expires 27sec fe80::/64 dev eth0 proto kernel metric 256 default via fe80::74df:d0ff:fe23:8ef2 dev eth0 proto ra metric 1024 expires 27sec After: [root@qemu1 ~]# ip -6 r show | egrep -v unreachable fd00:face:face:face::/64 dev eth0 proto kernel metric 256 expires 27sec mtu 1300 fe80::/64 dev eth0 proto kernel metric 256 mtu 1300 default via fe80::74df:d0ff:fe23:8ef2 dev eth0 proto ra metric 1024 expires 27sec mtu 1300 hoplimit 30 Fixes: 8e2ec639173f325 (ipv6: don't use inetpeer to store metrics for routes.) Signed-off-by: Martin KaFai Lau Signed-off-by: David S. Miller Signed-off-by: Zefan Li --- diff --git a/net/ipv6/route.c b/net/ipv6/route.c index c8643a3d26586..4cfba3d5ad2c0 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -95,7 +95,7 @@ static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) u32 *p = NULL; if (!(rt->dst.flags & DST_HOST)) - return NULL; + return dst_cow_metrics_generic(dst, old); if (!rt->rt6i_peer) rt6_bind_peer(rt, 1);