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

ipv6: Use rt6i_idev index for echo replies to a local address

Tariq repored local pings to linklocal address is failing:
$ ifconfig ens8
ens8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 11.141.16.6 netmask 255.255.0.0 broadcast 11.141.255.255
inet6 fe80::7efe:90ff:fecb:7502 prefixlen 64 scopeid 0x20<link>
ether 7c:fe:90:cb:75:02 txqueuelen 1000 (Ethernet)
RX packets 12 bytes 1164 (1.1 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 30 bytes 2484 (2.4 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

$ /bin/ping6 -c 3 fe80::7efe:90ff:fecb:7502%ens8
PING fe80::7efe:90ff:fecb:7502%ens8(fe80::7efe:90ff:fecb:7502) 56 data bytes

Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

David Ahern and committed by
David S. Miller
1b70d792 f602b976

+30 -13
+10
include/net/ip6_route.h
··· 164 164 void rt6_remove_prefsrc(struct inet6_ifaddr *ifp); 165 165 void rt6_clean_tohost(struct net *net, struct in6_addr *gateway); 166 166 167 + static inline const struct rt6_info *skb_rt6_info(const struct sk_buff *skb) 168 + { 169 + const struct dst_entry *dst = skb_dst(skb); 170 + const struct rt6_info *rt6 = NULL; 171 + 172 + if (dst) 173 + rt6 = container_of(dst, struct rt6_info, dst); 174 + 175 + return rt6; 176 + } 167 177 168 178 /* 169 179 * Store a destination cache entry in a socket
+20 -13
net/ipv6/icmp.c
··· 399 399 return ERR_PTR(err); 400 400 } 401 401 402 + static int icmp6_iif(const struct sk_buff *skb) 403 + { 404 + int iif = skb->dev->ifindex; 405 + 406 + /* for local traffic to local address, skb dev is the loopback 407 + * device. Check if there is a dst attached to the skb and if so 408 + * get the real device index. 409 + */ 410 + if (unlikely(iif == LOOPBACK_IFINDEX)) { 411 + const struct rt6_info *rt6 = skb_rt6_info(skb); 412 + 413 + if (rt6) 414 + iif = rt6->rt6i_idev->dev->ifindex; 415 + } 416 + 417 + return iif; 418 + } 419 + 402 420 /* 403 421 * Send an ICMP message in response to a packet in error 404 422 */ ··· 478 460 */ 479 461 480 462 if (__ipv6_addr_needs_scope_id(addr_type)) { 481 - iif = skb->dev->ifindex; 482 - 483 - /* for local packets, get the real device index */ 484 - if (iif == LOOPBACK_IFINDEX) { 485 - dst = skb_dst(skb); 486 - if (dst) { 487 - struct rt6_info *rt; 488 - 489 - rt = container_of(dst, struct rt6_info, dst); 490 - iif = rt->rt6i_idev->dev->ifindex; 491 - } 492 - } 463 + iif = icmp6_iif(skb); 493 464 } else { 494 465 dst = skb_dst(skb); 495 466 iif = l3mdev_master_ifindex(dst ? dst->dev : skb->dev); ··· 701 694 fl6.daddr = ipv6_hdr(skb)->saddr; 702 695 if (saddr) 703 696 fl6.saddr = *saddr; 704 - fl6.flowi6_oif = skb->dev->ifindex; 697 + fl6.flowi6_oif = icmp6_iif(skb); 705 698 fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY; 706 699 fl6.flowi6_mark = mark; 707 700 fl6.flowi6_uid = sock_net_uid(net, NULL);