summaryrefslogtreecommitdiff
path: root/net/ipv6/icmp.c
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@gmail.com>2017-08-17 12:17:20 -0700
committerDavid S. Miller <davem@davemloft.net>2017-08-21 10:40:17 -0700
commit4832c30d5458387ff2533ff66fbde26ad8bb5a2d (patch)
tree5ebff9f5d2d7e58529a87b6963ca70c9f8401b4d /net/ipv6/icmp.c
parent89e49506bc62520f93e64a278293444319a6aebb (diff)
net: ipv6: put host and anycast routes on device with address
One nagging difference between ipv4 and ipv6 is host routes for ipv6 addresses are installed using the loopback device or VRF / L3 Master device. e.g., 2001:db8:1::/120 dev veth0 proto kernel metric 256 pref medium local 2001:db8:1::1 dev lo table local proto kernel metric 0 pref medium Using the loopback device is convenient -- necessary for local tx, but has some nasty side effects, most notably setting the 'lo' device down causes all host routes for all local IPv6 address to be removed from the FIB and completely breaks IPv6 networking across all interfaces. This patch puts FIB entries for IPv6 routes against the device. This simplifies the routes in the FIB, for example by making dst->dev and rt6i_idev->dev the same (a future patch can look at removing the device reference taken for rt6i_idev for FIB entries). When copies are made on FIB lookups, the cloned route has dst->dev set to loopback (or the L3 master device). This is needed for the local Tx of packets to local addresses. With fib entries allocated against the real network device, the addrconf code that reinserts host routes on admin up of 'lo' is no longer needed. Signed-off-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/icmp.c')
-rw-r--r--net/ipv6/icmp.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 8d7b113958b1..4f82830fc068 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -459,9 +459,20 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
* Source addr check
*/
- if (__ipv6_addr_needs_scope_id(addr_type))
+ if (__ipv6_addr_needs_scope_id(addr_type)) {
iif = skb->dev->ifindex;
- else {
+
+ /* for local packets, get the real device index */
+ if (iif == LOOPBACK_IFINDEX) {
+ dst = skb_dst(skb);
+ if (dst) {
+ struct rt6_info *rt;
+
+ rt = container_of(dst, struct rt6_info, dst);
+ iif = rt->rt6i_idev->dev->ifindex;
+ }
+ }
+ } else {
dst = skb_dst(skb);
iif = l3mdev_master_ifindex(dst ? dst->dev : skb->dev);
}