Since the commit 1893ff20275b ("net/ipv6: Add l3mdev check to ipv6_chk_addr_and_flags"), traceroute using TCP SYN or ICMP ECHO option and ping fail when specifying a source address typically on a loopback /dummy interface in the same VRF, e.g.:
# ip vrf exec vrfgreen ping 3000::1 -I 2222::2 ping: bind icmp socket: Cannot assign requested address # ip vrf exec vrfgreen traceroute 3000::1 -s 2222::2 -T bind: Cannot assign requested address IPv6 traceroute using default UDP and IPv4 ping & traceroute continue to work inside a VRF using a source address. The reason is that the source address is provided via bind without a device given by these applications in this case. The call to ipv6_check_addr() in rawv6_bind() returns false as the default VRF is assumed if no dev was given, but the src addr is in a non-default VRF. The solution is to check that the address exists in the L3 domain that the dev is part of only if the dev has been specified. Signed-off-by: Mike Manning <mmann...@vyatta.att-mail.com> --- net/ipv6/addrconf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index f96d1de79509..3963306ec27f 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1908,6 +1908,7 @@ int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr, int strict, u32 banned_flags) { unsigned int hash = inet6_addr_hash(net, addr); + const struct net_device *orig_dev = dev; const struct net_device *l3mdev; struct inet6_ifaddr *ifp; u32 ifp_flags; @@ -1922,7 +1923,7 @@ int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr, if (!net_eq(dev_net(ifp->idev->dev), net)) continue; - if (l3mdev_master_dev_rcu(ifp->idev->dev) != l3mdev) + if (orig_dev && l3mdev_master_dev_rcu(ifp->idev->dev) != l3mdev) continue; /* Decouple optimistic from tentative for evaluation here. -- 2.11.0