kernel-ark/net/ipv6
David Ahern 6d717134a1 net: ipv6: Do not duplicate DAD on link up
Andrey reported a warning triggered by the rcu code:

------------[ cut here ]------------
WARNING: CPU: 1 PID: 5911 at lib/debugobjects.c:289
debug_print_object+0x175/0x210
ODEBUG: activate active (active state 1) object type: rcu_head hint:
        (null)
Modules linked in:
CPU: 1 PID: 5911 Comm: a.out Not tainted 4.11.0-rc8+ #271
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
Call Trace:
 __dump_stack lib/dump_stack.c:16
 dump_stack+0x192/0x22d lib/dump_stack.c:52
 __warn+0x19f/0x1e0 kernel/panic.c:549
 warn_slowpath_fmt+0xe0/0x120 kernel/panic.c:564
 debug_print_object+0x175/0x210 lib/debugobjects.c:286
 debug_object_activate+0x574/0x7e0 lib/debugobjects.c:442
 debug_rcu_head_queue kernel/rcu/rcu.h:75
 __call_rcu.constprop.76+0xff/0x9c0 kernel/rcu/tree.c:3229
 call_rcu_sched+0x12/0x20 kernel/rcu/tree.c:3288
 rt6_rcu_free net/ipv6/ip6_fib.c:158
 rt6_release+0x1ea/0x290 net/ipv6/ip6_fib.c:188
 fib6_del_route net/ipv6/ip6_fib.c:1461
 fib6_del+0xa42/0xdc0 net/ipv6/ip6_fib.c:1500
 __ip6_del_rt+0x100/0x160 net/ipv6/route.c:2174
 ip6_del_rt+0x140/0x1b0 net/ipv6/route.c:2187
 __ipv6_ifa_notify+0x269/0x780 net/ipv6/addrconf.c:5520
 addrconf_ifdown+0xe60/0x1a20 net/ipv6/addrconf.c:3672
...

Andrey's reproducer program runs in a very tight loop, calling
'unshare -n' and then spawning 2 sets of 14 threads running random ioctl
calls. The relevant networking sequence:

1. New network namespace created via unshare -n
- ip6tnl0 device is created in down state

2. address added to ip6tnl0
- equivalent to ip -6 addr add dev ip6tnl0 fd00::bb/1
- DAD is started on the address and when it completes the host
  route is inserted into the FIB

3. ip6tnl0 is brought up
- the new fixup_permanent_addr function restarts DAD on the address

4. exit namespace
- teardown / cleanup sequence starts
- once in a blue moon, lo teardown appears to happen BEFORE teardown
  of ip6tunl0
  + down on 'lo' removes the host route from the FIB since the dst->dev
    for the route is loobback
  + host route added to rcu callback list
    * rcu callback has not run yet, so rt is NOT on the gc list so it has
      NOT been marked obsolete

5. in parallel to 4. worker_thread runs addrconf_dad_completed
- DAD on the address on ip6tnl0 completes
- calls ipv6_ifa_notify which inserts the host route

All of that happens very quickly. The result is that a host route that
has been deleted from the IPv6 FIB and added to the RCU list is re-inserted
into the FIB.

The exit namespace eventually gets to cleaning up ip6tnl0 which removes the
host route from the FIB again, calls the rcu function for cleanup -- and
triggers the double rcu trace.

The root cause is duplicate DAD on the address -- steps 2 and 3. Arguably,
DAD should not be started in step 2. The interface is in the down state,
so it can not really send out requests for the address which makes starting
DAD pointless.

Since the second DAD was introduced by a recent change, seems appropriate
to use it for the Fixes tag and have the fixup function only start DAD for
addresses in the PREDAD state which occurs in addrconf_ifdown if the
address is retained.

Big thanks to Andrey for isolating a reliable reproducer for this problem.
Fixes: f1705ec197 ("net: ipv6: Make address flushing on ifdown optional")
Reported-by: Andrey Konovalov <andreyknvl@google.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
Tested-by: Andrey Konovalov <andreyknvl@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-05-03 09:45:56 -04:00
..
ila netlink: pass extended ACK struct to parsing functions 2017-04-13 13:58:22 -04:00
netfilter netfilter: don't attach a nat extension by default 2017-04-26 09:30:22 +02:00
addrconf_core.c
addrconf.c net: ipv6: Do not duplicate DAD on link up 2017-05-03 09:45:56 -04:00
addrlabel.c net: rtnetlink: plumb extended ack to doit function 2017-04-17 15:35:38 -04:00
af_inet6.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-04-26 22:39:08 -04:00
ah6.c IPsec: do not ignore crypto err in ah6 input 2017-01-16 12:57:48 +01:00
anycast.c
calipso.c calipso: fix resource leak on calipso_genopt failure 2016-08-13 14:56:17 -07:00
datagram.c net-timestamp: avoid use-after-free in ip_recv_error 2017-04-17 12:59:22 -04:00
esp6_offload.c esp4/6: Fix GSO path for non-GSO SW-crypto packets 2017-04-19 07:48:57 +02:00
esp6.c esp: Fix misplaced spin_unlock_bh. 2017-04-24 07:56:31 +02:00
exthdrs_core.c ipv6: constify the skb pointer of ipv6_find_tlv(). 2016-06-27 15:06:15 -04:00
exthdrs_offload.c
exthdrs.c ipv6: Need to export ipv6_push_frag_opts for tunneling now. 2017-05-01 15:10:20 -04:00
fib6_rules.c net: flow: Add l3mdev flow update 2016-09-10 23:12:51 -07:00
fou6.c fou: add Kconfig options for IPv6 support 2016-05-29 22:24:21 -07:00
icmp.c net: for rate-limited ICMP replies save one atomic operation 2017-01-09 15:49:12 -05:00
inet6_connection_sock.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-01-28 10:33:06 -05:00
inet6_hashtables.c inet: collapse ipv4/v6 rcv_saddr_equal functions into one 2017-01-18 13:04:28 -05:00
ip6_checksum.c ipv6: fix checksum annotation in udp6_csum_init 2016-06-14 15:26:42 -04:00
ip6_fib.c ipv6: make ECMP route replacement less greedy 2017-03-13 12:16:17 -07:00
ip6_flowlabel.c Replace <asm/uaccess.h> with <linux/uaccess.h> globally 2016-12-24 11:46:01 -08:00
ip6_gre.c ip6_tunnel: Allow policy-based routing through tunnels 2017-04-21 13:21:30 -04:00
ip6_icmp.c ipv6: icmp: add a force_saddr param to icmp6_send() 2016-06-18 22:11:38 -07:00
ip6_input.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-04-20 10:35:33 -04:00
ip6_offload.c net/tunnel: set inner protocol in network gro hooks 2017-03-09 13:19:52 -08:00
ip6_offload.h udp: Add GRO functions to UDP socket 2016-04-07 16:53:29 -04:00
ip6_output.c ipv6: avoid write to a possibly cloned skb 2017-03-13 12:53:35 -07:00
ip6_tunnel.c ip6_tunnel: Fix missing tunnel encapsulation limit option 2017-05-01 14:52:45 -04:00
ip6_udp_tunnel.c ip6_udp_tunnel: remove unused IPCB related codes 2016-11-02 15:18:36 -04:00
ip6_vti.c ip6_tunnel: Allow policy-based routing through tunnels 2017-04-21 13:21:30 -04:00
ip6mr.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-04-21 20:23:53 -07:00
ipcomp6.c net: inet: Support UID-based routing in IP protocols. 2016-11-04 14:45:23 -04:00
ipv6_sockglue.c net: Allow IP_MULTICAST_IF to set index to L3 slave 2016-12-30 15:24:47 -05:00
Kconfig ipv6: sr: select DST_CACHE by default 2017-03-27 16:05:06 -07:00
Makefile esp: Add a software GRO codepath 2017-02-15 11:04:11 +01:00
mcast_snoop.c
mcast.c ipv6: add support for NETDEV_RESEND_IGMP event 2017-03-28 22:02:21 -07:00
mip6.c ktime: Get rid of ktime_equal() 2016-12-25 17:21:23 +01:00
ndisc.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-04-26 22:39:08 -04:00
netfilter.c net: inet: Support UID-based routing in IP protocols. 2016-11-04 14:45:23 -04:00
output_core.c ipv6: Set skb->protocol properly for local output 2016-12-02 12:34:22 -05:00
ping.c ipv6: remove unnecessary inet6_sk check 2016-12-29 12:05:49 -05:00
proc.c proc: Reduce cache miss in snmp6_seq_show 2016-09-30 01:50:44 -04:00
protocol.c net: Add sysctl to toggle early demux for tcp and udp 2017-03-24 13:17:07 -07:00
raw.c ipv6: check raw payload size correctly in ioctl 2017-04-26 14:59:35 -04:00
reassembly.c ipv6: on reassembly, record frag_max_size 2016-11-03 15:41:11 -04:00
route.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-04-21 20:23:53 -07:00
seg6_hmac.c Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2017-02-07 16:29:30 -05:00
seg6_iptunnel.c ipv6: sr: fix BUG due to headroom too small after SRH push 2017-04-17 15:33:53 -04:00
seg6.c ipv6: sr: fix out-of-bounds access in SRH validation 2017-04-20 15:40:33 -04:00
sit.c ip_tunnel: Allow policy-based routing through tunnels 2017-04-21 13:21:31 -04:00
syncookies.c syncookies: use SipHash in place of SHA1 2017-01-09 13:58:57 -05:00
sysctl_net_ipv6.c calipso: Add a label cache. 2016-06-27 15:06:17 -04:00
tcp_ipv6.c tcp: Record Rx hash and NAPI ID in tcp_child_process 2017-03-24 20:49:30 -07:00
tcpv6_offload.c
tunnel6.c
udp_impl.h udplite: call proper backlog handlers 2016-11-24 15:32:14 -05:00
udp_offload.c gso: Remove arbitrary checks for unsupported GSO 2016-05-20 18:03:15 -04:00
udp.c net: ipv6: Fix UDP early demux lookup with udp_l3mdev_accept=0 2017-04-20 15:50:27 -04:00
udplite.c udplite: call proper backlog handlers 2016-11-24 15:32:14 -05:00
xfrm6_input.c esp: Add a software GRO codepath 2017-02-15 11:04:11 +01:00
xfrm6_mode_beet.c
xfrm6_mode_ro.c
xfrm6_mode_transport.c xfrm: Add encapsulation header offsets while SKB is not encrypted 2017-04-14 10:07:39 +02:00
xfrm6_mode_tunnel.c xfrm: Add encapsulation header offsets while SKB is not encrypted 2017-04-14 10:07:39 +02:00
xfrm6_output.c xfrm: Add an IPsec hardware offloading API 2017-04-14 10:06:10 +02:00
xfrm6_policy.c xfrm: policy: make policy backend const 2017-02-09 10:22:19 +01:00
xfrm6_protocol.c xfrm: input: constify xfrm_input_afinfo 2017-02-09 10:22:17 +01:00
xfrm6_state.c
xfrm6_tunnel.c netns: make struct pernet_operations::id unsigned int 2016-11-18 10:59:15 -05:00