NetBSD Problem Report #49682

From martin@duskware.de  Fri Feb 20 13:55:28 2015
Return-Path: <martin@duskware.de>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
	(Client CN "mail.netbsd.org", Issuer "Postmaster NetBSD.org" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id B93DDA6554
	for <gnats-bugs@gnats.NetBSD.org>; Fri, 20 Feb 2015 13:55:28 +0000 (UTC)
Message-Id: <20150220135222.70918ED0E4F@emmas.aprisoft.de>
Date: Fri, 20 Feb 2015 14:52:22 CET
From: martin@NetBSD.org
Reply-To: martin@NetBSD.org
To: gnats-bugs@NetBSD.org
Subject: reproducable panic when detaching bge (IPv6 related)
X-Send-Pr-Version: 3.95

>Number:         49682
>Category:       kern
>Synopsis:       reproducable panic when detaching bge (IPv6 related)
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    kern-bug-people
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Feb 20 14:00:00 +0000 2015
>Closed-Date:    Mon Feb 23 19:21:14 +0000 2015
>Last-Modified:  Mon Apr 06 01:35:01 +0000 2015
>Originator:     Martin Husemann
>Release:        NetBSD 7.99.5
>Organization:
The NetBSD Foundation, Inc.
>Environment:
System: NetBSD night-owl.duskware.de 7.99.5 NetBSD 7.99.5 (NIGHT-OWL) #299: Fri Feb 20 09:55:15 CET 2015 martin@night-owl.duskware.de:/usr/src/sys/arch/amd64/compile/NIGHT-OWL amd64
Architecture: x86_64
Machine: amd64
>Description:

When shutting down this notebook I get (since a few weeks?) a reproducable
panic when bge0 tries to detach:

defrtlist_del+0x19
nd6_purge+0x14c
in6_ifdetach+0x21
udp6_purgeif_wrapper+0x35
if_detach+0x168
bge_detach

and this is:

(gdb) list *(nd6_purge+0x14c)
0xffffffff80539a8a is in nd6_purge (../../../../netinet6/nd6.c:774).
769             TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, ndr) {
770                     if (!dr->installed)
771                             continue;
772     
773                     if (dr->ifp == ifp)
774                             defrtrlist_del(dr);
775             }
776     
777             /* Nuke prefix list entries toward ifp */
778             LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, npr) {

and there:

0xffffffff8053fc54 is in defrtrlist_del (../../../../netinet6/nd6_rtr.c:488).
483     }
484     
485     void
486     defrtrlist_del(struct nd_defrouter *dr)
487     {
488             struct nd_ifinfo *ndi = ND_IFINFO(dr->ifp);
489             struct nd_defrouter *deldr = NULL;
490             struct nd_prefix *pr;
491             struct in6_ifextra *ext = dr->ifp->if_afdata[AF_INET6];

to be exact:

(gdb) x/16i defrtrlist_del     
   0xffffffff8053fc3b <defrtrlist_del>: push   %rbp
   0xffffffff8053fc3c <defrtrlist_del+1>:       mov    %rsp,%rbp
   0xffffffff8053fc3f <defrtrlist_del+4>:       push   %r14
   0xffffffff8053fc41 <defrtrlist_del+6>:       push   %r13
   0xffffffff8053fc43 <defrtrlist_del+8>:       push   %r12
   0xffffffff8053fc45 <defrtrlist_del+10>:      push   %rbx
   0xffffffff8053fc46 <defrtrlist_del+11>:      mov    %rdi,%rbx
   0xffffffff8053fc49 <defrtrlist_del+14>:      mov    0x30(%rdi),%rax
   0xffffffff8053fc4d <defrtrlist_del+18>:      mov    0x2b0(%rax),%r13
   0xffffffff8053fc54 <defrtrlist_del+25>:      mov    0x10(%r13),%rdi

%r13 must be bogus.

#define ND_IFINFO(ifp) \
        (((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->nd_ifinfo)

so the ->nd_ifinfo fails - how can this happen?

>How-To-Repeat:
Just run a machine with bge0 and configure IPv6 via dhcpcd - not sure why
my sparc64 machines with bge do not show the issue (but those use a static
IPv6 configuration).

>Fix:
n/a

>Release-Note:

>Audit-Trail:
From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 related)
Date: Fri, 20 Feb 2015 17:14:01 +0100

 I made it crash again, drop into ddb and forced a crash dump.

 Here is what gdb shows about it:

 #8  0xffffffff8053fc54 in defrtrlist_del (dr=0xfffffe813667dc98)
     at ../../../../netinet6/nd6_rtr.c:488
 488             struct nd_ifinfo *ndi = ND_IFINFO(dr->ifp);
 (gdb) p *dr
 $1 = {dr_entry = {tqe_next = 0x0, 
     tqe_prev = 0xffffffff80e97730 <nd_defrouter>}, rtaddr = {__u6_addr = {
       __u6_addr8 = "\376€\000\001\000\000\000\000R\345I\377\376\334\065E", 
       __u6_addr16 = {33022, 256, 0, 0, 58706, 65353, 56574, 17717}, 
       __u6_addr32 = {16810238, 0, 4283032914, 1161157886}}}, flags = 0 '\000', 
   rtlifetime = 1800, expire = 1424449849, ifp = 0xffff800007be3008, 
   installed = 1}
 (gdb) p dr
 $2 = (struct nd_defrouter *) 0xfffffe813667dc98
 (gdb) p dr->ifp
 $3 = (struct ifnet *) 0xffff800007be3008
 (gdb) p *dr->ifp
 $4 = {if_softc = 0xffff800007be3000, if_list = {tqe_next = 0xffff800007033d30, 
     tqe_prev = 0xffffffff80e89630 <ifnet_list>}, if_addrlist = {
     tqh_first = 0x0, tqh_last = 0xffff800007be3020}, 
   if_xname = "bge0", '\000' <repeats 11 times>, if_pcount = 0, if_bpf = 0x0, 
   if_index = 1, if_timer = 0, if_flags = -30718, if__pad1 = 0, if_data = {
     ifi_type = 6 '\006', ifi_addrlen = 6 '\006', ifi_hdrlen = 14 '\016', 
     ifi_link_state = 2, ifi_mtu = 1500, ifi_metric = 0, 
     ifi_baudrate = 1000000000, ifi_ipackets = 699, ifi_ierrors = 0, 
     ifi_opackets = 523, ifi_oerrors = 0, ifi_collisions = 0, 
     ifi_ibytes = 93654, ifi_obytes = 73498, ifi_imcasts = 222, 
     ifi_omcasts = 11, ifi_iqdrops = 0, ifi_noproto = 0, ifi_lastchange = {
       tv_sec = 1424448224, tv_nsec = 983391989}}, 
   if_output = 0xffffffff803ab28c <ether_output>, 
   if_input = 0xffffffff803aacc0 <ether_input>, 
   if_start = 0xffffffff8038ef11 <bge_start>, 
   if_ioctl = 0xffffffff804cfc8c <enxio>, 
   if_init = 0xffffffff80393721 <bge_init>, 
   if_stop = 0xffffffff8039317e <bge_stop>, if_slowtimo = 0x0, if_drain = 0x0, 
   if_snd = {ifq_head = 0x0, ifq_tail = 0x0, ifq_len = 0, ifq_maxlen = 511, 
     ifq_drops = 0, ifq_lock = 0x0, altq_type = 0, altq_flags = 0, 
     altq_disc = 0x0, altq_ifp = 0x0, altq_enqueue = 0x0, altq_dequeue = 0x0, 
     altq_request = 0x0, altq_clfier = 0x0, altq_classify = 0x0, 
     altq_tbr = 0x0, altq_cdnr = 0x0}, if_dl = 0x0, if_sadl = 0x0, 
   if_hwdl = 0x0, 
   if_broadcastaddr = 0xffffffff809414de <etherbroadcastaddr> "\377\377\377\377\377\377", if_bridge = 0x0, if_bridgeif = 0x0, if_dlt = 1, 
   if_pfil = 0xfffffe810721bc48, if_capabilities = 16256, if_capenable = 0, 
   if_carp_ptr = {carp_s = 0x0, carp_d = 0x0}, if_csum_flags_tx = 0, 
   if_csum_flags_rx = 0, if_afdata = {0x0 <repeats 35 times>}, if_mowner = 0x0, 
   if_agrprivate = 0x0, if_pf_kif = 0x0, if_pf_groups = 0x0, if_index_gen = 0, 
   if_sysctl_log = 0x0, if_initaddr = 0x0, if_mcastop = 0x0, if_setflags = 0x0, 
   if_ioctl_lock = 0xfffffe8107153188, if_slowtimo_ch = 0xfffffe810719fac8}
 [..]
    0xffffffff8053fc46 <defrtrlist_del+11>:      mov    %rdi,%rbx
    0xffffffff8053fc49 <defrtrlist_del+14>:      mov    0x30(%rdi),%rax
    0xffffffff8053fc4d <defrtrlist_del+18>:      mov    0x2b0(%rax),%r13
 => 0xffffffff8053fc54 <defrtrlist_del+25>:      mov    0x10(%r13),%rdi
 (gdb) info reg rax rbx rdi  r13
 rax            0xffff800007be3008       -140737358450680
 rbx            0xfffffe813667dc98       -1644059698024
 rdi            0xfffffe813667dc98       -1644059698024
 r13            0x0      0


 Martin

From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 related)
Date: Sat, 21 Feb 2015 12:09:24 +0100

 How about this patch?

 Martin

 Index: if.c
 ===================================================================
 RCS file: /cvsroot/src/sys/net/if.c,v
 retrieving revision 1.308
 diff -u -p -r1.308 if.c
 --- if.c	16 Jan 2015 10:36:14 -0000	1.308
 +++ if.c	21 Feb 2015 11:08:54 -0000
 @@ -876,8 +876,8 @@ again:
  		{
  			void *p = ifp->if_afdata[dp->dom_family];
  			if (p) {
 -				ifp->if_afdata[dp->dom_family] = NULL;
  				(*dp->dom_ifdetach)(ifp, p);
 +				ifp->if_afdata[dp->dom_family] = NULL;
  			}
  		}


From: christos@zoulas.com (Christos Zoulas)
To: gnats-bugs@NetBSD.org, kern-bug-people@netbsd.org, 
	gnats-admin@netbsd.org, netbsd-bugs@netbsd.org, martin@NetBSD.org
Cc: 
Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 related)
Date: Sat, 21 Feb 2015 09:54:20 -0500

 On Feb 21, 11:10am, martin@duskware.de (Martin Husemann) wrote:
 -- Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 relat

 | The following reply was made to PR kern/49682; it has been noted by GNATS.
 | 
 | From: Martin Husemann <martin@duskware.de>
 | To: gnats-bugs@NetBSD.org
 | Cc: 
 | Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 related)
 | Date: Sat, 21 Feb 2015 12:09:24 +0100
 | 
 |  How about this patch?

 As long as: PR/45764, PR/45914 don't break again....

 christos

From: Martin Husemann <martin@duskware.de>
To: Christos Zoulas <christos@zoulas.com>
Cc: gnats-bugs@NetBSD.org
Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 related)
Date: Sat, 21 Feb 2015 17:14:10 +0100

 On Sat, Feb 21, 2015 at 09:54:20AM -0500, Christos Zoulas wrote:
 > As long as: PR/45764, PR/45914 don't break again....

 If nd6_purge is meant to be callable AFTER dom_ifdetach, the fix
 should be different. Is there a good reason for it?

 Martin

From: christos@zoulas.com (Christos Zoulas)
To: Martin Husemann <martin@duskware.de>
Cc: gnats-bugs@NetBSD.org
Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 related)
Date: Sat, 21 Feb 2015 11:19:41 -0500

 On Feb 21,  5:14pm, martin@duskware.de (Martin Husemann) wrote:
 -- Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 relat

 | If nd6_purge is meant to be callable AFTER dom_ifdetach, the fix
 | should be different. Is there a good reason for it?

 I don't remember, sorrty.

 christos

From: Martin Husemann <martin@duskware.de>
To: Christos Zoulas <christos@zoulas.com>
Cc: gnats-bugs@NetBSD.org
Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 related)
Date: Sun, 22 Feb 2015 22:06:11 +0100

 The last time we have a chance to successfully clean this up is before
 dom_ifdetach frees the adress family specific data - so we need to make
 sure nd6_purge is called from there as well, and gets the info explicitly
 passed.

 The patch below works for me.

 Martin

 Index: in6.c
 ===================================================================
 RCS file: /cvsroot/src/sys/netinet6/in6.c,v
 retrieving revision 1.181
 diff -u -p -r1.181 in6.c
 --- in6.c	20 Feb 2015 22:13:48 -0000	1.181
 +++ in6.c	22 Feb 2015 21:04:15 -0000
 @@ -2318,7 +2318,7 @@ in6_domifdetach(struct ifnet *ifp, void 
  {
  	struct in6_ifextra *ext = (struct in6_ifextra *)aux;

 -	nd6_ifdetach(ext->nd_ifinfo);
 +	nd6_ifdetach(ifp, ext);
  	free(ext->in6_ifstat, M_IFADDR);
  	free(ext->icmp6_ifstat, M_IFADDR);
  	scope6_ifdetach(ext->scope6_id);
 Index: in6_ifattach.c
 ===================================================================
 RCS file: /cvsroot/src/sys/netinet6/in6_ifattach.c,v
 retrieving revision 1.94
 diff -u -p -r1.94 in6_ifattach.c
 --- in6_ifattach.c	14 Nov 2014 17:34:23 -0000	1.94
 +++ in6_ifattach.c	22 Feb 2015 21:04:15 -0000
 @@ -847,8 +847,9 @@ in6_ifdetach(struct ifnet *ifp)
  	/* remove ip6_mrouter stuff */
  	ip6_mrouter_detach(ifp);

 -	/* remove neighbor management table */
 -	nd6_purge(ifp);
 +	/* remove neighbor management table, if ND data is still available */
 +	if (ifp->if_afdata[AF_INET6] != NULL)
 +		nd6_purge(ifp, ifp->if_afdata[AF_INET6]);

  	/* XXX this code is duplicated in in6_purgeif() --dyoung */
  	/* nuke any of IPv6 addresses we have */
 @@ -919,7 +920,8 @@ in6_ifdetach(struct ifnet *ifp)
  	 * prefixes after removing all addresses above.
  	 * (Or can we just delay calling nd6_purge until at this point?)
  	 */
 -	nd6_purge(ifp);
 +	if (ifp->if_afdata[AF_INET6] != NULL)
 +		nd6_purge(ifp, ifp->if_afdata[AF_INET6]);
  }

  int
 Index: nd6.c
 ===================================================================
 RCS file: /cvsroot/src/sys/netinet6/nd6.c,v
 retrieving revision 1.157
 diff -u -p -r1.157 nd6.c
 --- nd6.c	17 Feb 2015 15:14:28 -0000	1.157
 +++ nd6.c	22 Feb 2015 21:04:15 -0000
 @@ -205,10 +205,11 @@ nd6_ifattach(struct ifnet *ifp)
  }

  void
 -nd6_ifdetach(struct nd_ifinfo *nd)
 +nd6_ifdetach(struct ifnet *ifp, struct in6_ifextra *ext)
  {

 -	free(nd, M_IP6NDP);
 +	nd6_purge(ifp, ext);
 +	free(ext->nd_ifinfo, M_IP6NDP);
  }

  void
 @@ -556,7 +557,7 @@ nd6_timer(void *ignored_arg)

  	TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, next_dr) {
  		if (dr->expire && dr->expire < time_second) {
 -			defrtrlist_del(dr);
 +			defrtrlist_del(dr, NULL);
  		}
  	}

 @@ -746,13 +747,21 @@ nd6_accepts_rtadv(const struct nd_ifinfo
   * ifp goes away.
   */
  void
 -nd6_purge(struct ifnet *ifp)
 +nd6_purge(struct ifnet *ifp, struct in6_ifextra *ext)
  {
  	struct llinfo_nd6 *ln, *nln;
  	struct nd_defrouter *dr, *ndr;
  	struct nd_prefix *pr, *npr;

  	/*
 +	 * During detach, the ND info might be already removed, but
 +	 * then is explitly passed as argument.
 +	 * Otherwise get it from ifp->if_afdata.
 +	 */
 +	if (ext == NULL)
 +		ext = ifp->if_afdata[AF_INET6];
 +
 +	/*
  	 * Nuke default router list entries toward ifp.
  	 * We defer removal of default router list entries that is installed
  	 * in the routing table, in order to keep additional side effects as
 @@ -762,16 +771,20 @@ nd6_purge(struct ifnet *ifp)
  		if (dr->installed)
  			continue;

 -		if (dr->ifp == ifp)
 -			defrtrlist_del(dr);
 +		if (dr->ifp == ifp) {
 +			KASSERT(ext != NULL);
 +			defrtrlist_del(dr, ext);
 +		}
  	}

  	TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, ndr) {
  		if (!dr->installed)
  			continue;

 -		if (dr->ifp == ifp)
 -			defrtrlist_del(dr);
 +		if (dr->ifp == ifp) {
 +			KASSERT(ext != NULL);
 +			defrtrlist_del(dr, ext);
 +		}
  	}

  	/* Nuke prefix list entries toward ifp */
 @@ -1797,7 +1810,7 @@ nd6_ioctl(u_long cmd, void *data, struct
  		s = splsoftnet();
  		defrouter_reset();
  		TAILQ_FOREACH_SAFE(drtr, &nd_defrouter, dr_entry, next) {
 -			defrtrlist_del(drtr);
 +			defrtrlist_del(drtr, NULL);
  		}
  		defrouter_select();
  		splx(s);
 Index: nd6.h
 ===================================================================
 RCS file: /cvsroot/src/sys/netinet6/nd6.h,v
 retrieving revision 1.61
 diff -u -p -r1.61 nd6.h
 --- nd6.h	16 Dec 2014 11:42:27 -0000	1.61
 +++ nd6.h	22 Feb 2015 21:04:15 -0000
 @@ -407,7 +407,7 @@ union nd_opts {
  /* nd6.c */
  void nd6_init(void);
  struct nd_ifinfo *nd6_ifattach(struct ifnet *);
 -void nd6_ifdetach(struct nd_ifinfo *);
 +void nd6_ifdetach(struct ifnet *, struct in6_ifextra *);
  int nd6_is_addr_neighbor(const struct sockaddr_in6 *, struct ifnet *);
  void nd6_option_init(void *, int, union nd_opts *);
  struct nd_opt_hdr *nd6_option(union nd_opts *);
 @@ -417,7 +417,7 @@ void nd6_rtmsg(int, struct rtentry *);
  void nd6_setmtu(struct ifnet *);
  void nd6_llinfo_settimer(struct llinfo_nd6 *, long);
  void nd6_timer(void *);
 -void nd6_purge(struct ifnet *);
 +void nd6_purge(struct ifnet *, struct in6_ifextra *);
  void nd6_nud_hint(struct rtentry *, struct in6_addr *, int);
  int nd6_resolve(struct ifnet *, struct rtentry *,
  	struct mbuf *, struct sockaddr *, u_char *);
 @@ -454,7 +454,7 @@ void prelist_del(struct nd_prefix *);
  void defrouter_addreq(struct nd_defrouter *);
  void defrouter_reset(void);
  void defrouter_select(void);
 -void defrtrlist_del(struct nd_defrouter *);
 +void defrtrlist_del(struct nd_defrouter *, struct in6_ifextra *);
  void prelist_remove(struct nd_prefix *);
  int nd6_prelist_add(struct nd_prefixctl *, struct nd_defrouter *,
  	struct nd_prefix **);
 Index: nd6_nbr.c
 ===================================================================
 RCS file: /cvsroot/src/sys/netinet6/nd6_nbr.c,v
 retrieving revision 1.103
 diff -u -p -r1.103 nd6_nbr.c
 --- nd6_nbr.c	16 Dec 2014 11:42:27 -0000	1.103
 +++ nd6_nbr.c	22 Feb 2015 21:04:15 -0000
 @@ -804,7 +804,7 @@ nd6_na_input(struct mbuf *m, int off, in
  			s = splsoftnet();
  			dr = defrouter_lookup(in6, rt->rt_ifp);
  			if (dr)
 -				defrtrlist_del(dr);
 +				defrtrlist_del(dr, NULL);
  			else if (!ip6_forwarding) {
  				/*
  				 * Even if the neighbor is not in the default
 Index: nd6_rtr.c
 ===================================================================
 RCS file: /cvsroot/src/sys/netinet6/nd6_rtr.c,v
 retrieving revision 1.95
 diff -u -p -r1.95 nd6_rtr.c
 --- nd6_rtr.c	16 Dec 2014 11:42:27 -0000	1.95
 +++ nd6_rtr.c	22 Feb 2015 21:04:15 -0000
 @@ -483,12 +483,20 @@ defrouter_lookup(const struct in6_addr *
  }

  void
 -defrtrlist_del(struct nd_defrouter *dr)
 +defrtrlist_del(struct nd_defrouter *dr, struct in6_ifextra *ext)
  {
 -	struct nd_ifinfo *ndi = ND_IFINFO(dr->ifp);
  	struct nd_defrouter *deldr = NULL;
  	struct nd_prefix *pr;
 -	struct in6_ifextra *ext = dr->ifp->if_afdata[AF_INET6];
 +	struct nd_ifinfo *ndi;
 +
 +	if (ext == NULL)
 +		ext = dr->ifp->if_afdata[AF_INET6];
 +
 +	/* detach already in progress, can not do anything */
 +	if (ext == NULL)
 +		return;
 +
 +	ndi = ext->nd_ifinfo;

  	/*
  	 * Flush all the routing table entries that use the router
 @@ -749,7 +757,7 @@ defrtrlist_update(struct nd_defrouter *n
  	if ((dr = defrouter_lookup(&newdr->rtaddr, newdr->ifp)) != NULL) {
  		/* entry exists */
  		if (newdr->rtlifetime == 0) {
 -			defrtrlist_del(dr);
 +			defrtrlist_del(dr, ext);
  			dr = NULL;
  		} else {
  			int oldpref = rtpref(dr);

From: christos@zoulas.com (Christos Zoulas)
To: Martin Husemann <martin@duskware.de>
Cc: gnats-bugs@NetBSD.org
Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 related)
Date: Sun, 22 Feb 2015 16:14:50 -0500

 On Feb 22, 10:06pm, martin@duskware.de (Martin Husemann) wrote:
 -- Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 relat

 | The last time we have a chance to successfully clean this up is before
 | dom_ifdetach frees the adress family specific data - so we need to make
 | sure nd6_purge is called from there as well, and gets the info explicitly
 | passed.
 | 
 | The patch below works for me.
 | 
 | Martin

 See below:

 | --- in6_ifattach.c	14 Nov 2014 17:34:23 -0000	1.94
 | +++ in6_ifattach.c	22 Feb 2015 21:04:15 -0000
 | @@ -847,8 +847,9 @@ in6_ifdetach(struct ifnet *ifp)
 |  	/* remove ip6_mrouter stuff */
 |  	ip6_mrouter_detach(ifp);
 |  
 | -	/* remove neighbor management table */
 | -	nd6_purge(ifp);
 | +	/* remove neighbor management table, if ND data is still available */
 | +	if (ifp->if_afdata[AF_INET6] != NULL)
 | +		nd6_purge(ifp, ifp->if_afdata[AF_INET6]);

 Why don't you do nd6_purge(ifp, NULL); here.

 |  
 |  	/* XXX this code is duplicated in in6_purgeif() --dyoung */
 |  	/* nuke any of IPv6 addresses we have */
 | @@ -919,7 +920,8 @@ in6_ifdetach(struct ifnet *ifp)
 |  	 * prefixes after removing all addresses above.
 |  	 * (Or can we just delay calling nd6_purge until at this point?)
 |  	 */
 | -	nd6_purge(ifp);
 | +	if (ifp->if_afdata[AF_INET6] != NULL)
 | +		nd6_purge(ifp, ifp->if_afdata[AF_INET6]);

 And here.

 |  }
 |  
 |  int
 | Index: nd6.c
 | ===================================================================
 | RCS file: /cvsroot/src/sys/netinet6/nd6.c,v
 | retrieving revision 1.157
 | diff -u -p -r1.157 nd6.c
 | --- nd6.c	17 Feb 2015 15:14:28 -0000	1.157
 | +++ nd6.c	22 Feb 2015 21:04:15 -0000
 | @@ -205,10 +205,11 @@ nd6_ifattach(struct ifnet *ifp)
 |  }
 |  
 |  void
 | -nd6_ifdetach(struct nd_ifinfo *nd)
 | +nd6_ifdetach(struct ifnet *ifp, struct in6_ifextra *ext)
 |  {
 |  
 | -	free(nd, M_IP6NDP);
 | +	nd6_purge(ifp, ext);
 | +	free(ext->nd_ifinfo, M_IP6NDP);
 |  }
 |  
 |  void
 | @@ -556,7 +557,7 @@ nd6_timer(void *ignored_arg)
 |  	
 |  	TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, next_dr) {
 |  		if (dr->expire && dr->expire < time_second) {
 | -			defrtrlist_del(dr);
 | +			defrtrlist_del(dr, NULL);
 |  		}
 |  	}
 |  
 | @@ -746,13 +747,21 @@ nd6_accepts_rtadv(const struct nd_ifinfo
 |   * ifp goes away.
 |   */
 |  void
 | -nd6_purge(struct ifnet *ifp)
 | +nd6_purge(struct ifnet *ifp, struct in6_ifextra *ext)
 |  {
 |  	struct llinfo_nd6 *ln, *nln;
 |  	struct nd_defrouter *dr, *ndr;
 |  	struct nd_prefix *pr, *npr;
 |  
 |  	/*
 | +	 * During detach, the ND info might be already removed, but
 | +	 * then is explitly passed as argument.
 | +	 * Otherwise get it from ifp->if_afdata.
 | +	 */
 | +	if (ext == NULL)
 | +		ext = ifp->if_afdata[AF_INET6];
 | +

 And here add:

 	if (ext == NULL)
 		return;

 like you did below in defrtrlist_del?


 christos

From: Martin Husemann <martin@duskware.de>
To: Christos Zoulas <christos@zoulas.com>
Cc: gnats-bugs@NetBSD.org
Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 related)
Date: Mon, 23 Feb 2015 08:48:10 +0100

 On Sun, Feb 22, 2015 at 04:14:50PM -0500, Christos Zoulas wrote:
 > | +	if (ifp->if_afdata[AF_INET6] != NULL)
 > | +		nd6_purge(ifp, ifp->if_afdata[AF_INET6]);
 > 
 > Why don't you do nd6_purge(ifp, NULL); here.

 Could do that, but isn't it kinda pointless after explicitly testing
 ifp->if_afdata[AF_INET6] ?

 Martin

From: christos@zoulas.com (Christos Zoulas)
To: Martin Husemann <martin@duskware.de>
Cc: gnats-bugs@NetBSD.org
Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 related)
Date: Mon, 23 Feb 2015 08:12:00 -0500

 On Feb 23,  8:48am, martin@duskware.de (Martin Husemann) wrote:
 -- Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 relat

 | On Sun, Feb 22, 2015 at 04:14:50PM -0500, Christos Zoulas wrote:
 | > | +	if (ifp->if_afdata[AF_INET6] != NULL)
 | > | +		nd6_purge(ifp, ifp->if_afdata[AF_INET6]);
 | > 
 | > Why don't you do nd6_purge(ifp, NULL); here.
 | 
 | Could do that, but isn't it kinda pointless after explicitly testing
 | ifp->if_afdata[AF_INET6] ?

 Remove the test too... What I am trying to do is abstract out the if_afdata
 access.

 christos

From: Martin Husemann <martin@duskware.de>
To: Christos Zoulas <christos@zoulas.com>
Cc: gnats-bugs@NetBSD.org
Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 related)
Date: Mon, 23 Feb 2015 14:19:54 +0100

 On Mon, Feb 23, 2015 at 08:12:00AM -0500, Christos Zoulas wrote:
 > Remove the test too... What I am trying to do is abstract out the if_afdata
 > access.

 But that is the test that prevents my crash!

 Martin

From: christos@zoulas.com (Christos Zoulas)
To: Martin Husemann <martin@duskware.de>
Cc: gnats-bugs@NetBSD.org
Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 related)
Date: Mon, 23 Feb 2015 08:25:17 -0500

 On Feb 23,  2:19pm, martin@duskware.de (Martin Husemann) wrote:
 -- Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 relat

 | On Mon, Feb 23, 2015 at 08:12:00AM -0500, Christos Zoulas wrote:
 | > Remove the test too... What I am trying to do is abstract out the if_afdata
 | > access.
 | 
 | But that is the test that prevents my crash!

 The test is also happening inside the function now. 

 christos

From: Martin Husemann <martin@duskware.de>
To: Christos Zoulas <christos@zoulas.com>
Cc: gnats-bugs@NetBSD.org
Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 related)
Date: Mon, 23 Feb 2015 18:47:53 +0100

 Ok, got it - this one works as well.

 Martin


 Index: in6.c
 ===================================================================
 RCS file: /cvsroot/src/sys/netinet6/in6.c,v
 retrieving revision 1.181
 diff -u -p -r1.181 in6.c
 --- in6.c	20 Feb 2015 22:13:48 -0000	1.181
 +++ in6.c	23 Feb 2015 16:32:13 -0000
 @@ -2318,7 +2318,7 @@ in6_domifdetach(struct ifnet *ifp, void 
  {
  	struct in6_ifextra *ext = (struct in6_ifextra *)aux;

 -	nd6_ifdetach(ext->nd_ifinfo);
 +	nd6_ifdetach(ifp, ext);
  	free(ext->in6_ifstat, M_IFADDR);
  	free(ext->icmp6_ifstat, M_IFADDR);
  	scope6_ifdetach(ext->scope6_id);
 Index: in6_ifattach.c
 ===================================================================
 RCS file: /cvsroot/src/sys/netinet6/in6_ifattach.c,v
 retrieving revision 1.94
 diff -u -p -r1.94 in6_ifattach.c
 --- in6_ifattach.c	14 Nov 2014 17:34:23 -0000	1.94
 +++ in6_ifattach.c	23 Feb 2015 16:32:13 -0000
 @@ -848,7 +848,7 @@ in6_ifdetach(struct ifnet *ifp)
  	ip6_mrouter_detach(ifp);

  	/* remove neighbor management table */
 -	nd6_purge(ifp);
 +	nd6_purge(ifp, NULL);

  	/* XXX this code is duplicated in in6_purgeif() --dyoung */
  	/* nuke any of IPv6 addresses we have */
 @@ -919,7 +919,7 @@ in6_ifdetach(struct ifnet *ifp)
  	 * prefixes after removing all addresses above.
  	 * (Or can we just delay calling nd6_purge until at this point?)
  	 */
 -	nd6_purge(ifp);
 +	nd6_purge(ifp, NULL);
  }

  int
 Index: nd6.c
 ===================================================================
 RCS file: /cvsroot/src/sys/netinet6/nd6.c,v
 retrieving revision 1.157
 diff -u -p -r1.157 nd6.c
 --- nd6.c	17 Feb 2015 15:14:28 -0000	1.157
 +++ nd6.c	23 Feb 2015 16:32:13 -0000
 @@ -205,10 +205,11 @@ nd6_ifattach(struct ifnet *ifp)
  }

  void
 -nd6_ifdetach(struct nd_ifinfo *nd)
 +nd6_ifdetach(struct ifnet *ifp, struct in6_ifextra *ext)
  {

 -	free(nd, M_IP6NDP);
 +	nd6_purge(ifp, ext);
 +	free(ext->nd_ifinfo, M_IP6NDP);
  }

  void
 @@ -556,7 +557,7 @@ nd6_timer(void *ignored_arg)

  	TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, next_dr) {
  		if (dr->expire && dr->expire < time_second) {
 -			defrtrlist_del(dr);
 +			defrtrlist_del(dr, NULL);
  		}
  	}

 @@ -746,13 +747,23 @@ nd6_accepts_rtadv(const struct nd_ifinfo
   * ifp goes away.
   */
  void
 -nd6_purge(struct ifnet *ifp)
 +nd6_purge(struct ifnet *ifp, struct in6_ifextra *ext)
  {
  	struct llinfo_nd6 *ln, *nln;
  	struct nd_defrouter *dr, *ndr;
  	struct nd_prefix *pr, *npr;

  	/*
 +	 * During detach, the ND info might be already removed, but
 +	 * then is explitly passed as argument.
 +	 * Otherwise get it from ifp->if_afdata.
 +	 */
 +	if (ext == NULL)
 +		ext = ifp->if_afdata[AF_INET6];
 +	if (ext == NULL)
 +		return;
 +
 +	/*
  	 * Nuke default router list entries toward ifp.
  	 * We defer removal of default router list entries that is installed
  	 * in the routing table, in order to keep additional side effects as
 @@ -762,16 +773,20 @@ nd6_purge(struct ifnet *ifp)
  		if (dr->installed)
  			continue;

 -		if (dr->ifp == ifp)
 -			defrtrlist_del(dr);
 +		if (dr->ifp == ifp) {
 +			KASSERT(ext != NULL);
 +			defrtrlist_del(dr, ext);
 +		}
  	}

  	TAILQ_FOREACH_SAFE(dr, &nd_defrouter, dr_entry, ndr) {
  		if (!dr->installed)
  			continue;

 -		if (dr->ifp == ifp)
 -			defrtrlist_del(dr);
 +		if (dr->ifp == ifp) {
 +			KASSERT(ext != NULL);
 +			defrtrlist_del(dr, ext);
 +		}
  	}

  	/* Nuke prefix list entries toward ifp */
 @@ -1797,7 +1812,7 @@ nd6_ioctl(u_long cmd, void *data, struct
  		s = splsoftnet();
  		defrouter_reset();
  		TAILQ_FOREACH_SAFE(drtr, &nd_defrouter, dr_entry, next) {
 -			defrtrlist_del(drtr);
 +			defrtrlist_del(drtr, NULL);
  		}
  		defrouter_select();
  		splx(s);
 Index: nd6.h
 ===================================================================
 RCS file: /cvsroot/src/sys/netinet6/nd6.h,v
 retrieving revision 1.61
 diff -u -p -r1.61 nd6.h
 --- nd6.h	16 Dec 2014 11:42:27 -0000	1.61
 +++ nd6.h	23 Feb 2015 16:32:13 -0000
 @@ -407,7 +407,7 @@ union nd_opts {
  /* nd6.c */
  void nd6_init(void);
  struct nd_ifinfo *nd6_ifattach(struct ifnet *);
 -void nd6_ifdetach(struct nd_ifinfo *);
 +void nd6_ifdetach(struct ifnet *, struct in6_ifextra *);
  int nd6_is_addr_neighbor(const struct sockaddr_in6 *, struct ifnet *);
  void nd6_option_init(void *, int, union nd_opts *);
  struct nd_opt_hdr *nd6_option(union nd_opts *);
 @@ -417,7 +417,7 @@ void nd6_rtmsg(int, struct rtentry *);
  void nd6_setmtu(struct ifnet *);
  void nd6_llinfo_settimer(struct llinfo_nd6 *, long);
  void nd6_timer(void *);
 -void nd6_purge(struct ifnet *);
 +void nd6_purge(struct ifnet *, struct in6_ifextra *);
  void nd6_nud_hint(struct rtentry *, struct in6_addr *, int);
  int nd6_resolve(struct ifnet *, struct rtentry *,
  	struct mbuf *, struct sockaddr *, u_char *);
 @@ -454,7 +454,7 @@ void prelist_del(struct nd_prefix *);
  void defrouter_addreq(struct nd_defrouter *);
  void defrouter_reset(void);
  void defrouter_select(void);
 -void defrtrlist_del(struct nd_defrouter *);
 +void defrtrlist_del(struct nd_defrouter *, struct in6_ifextra *);
  void prelist_remove(struct nd_prefix *);
  int nd6_prelist_add(struct nd_prefixctl *, struct nd_defrouter *,
  	struct nd_prefix **);
 Index: nd6_nbr.c
 ===================================================================
 RCS file: /cvsroot/src/sys/netinet6/nd6_nbr.c,v
 retrieving revision 1.103
 diff -u -p -r1.103 nd6_nbr.c
 --- nd6_nbr.c	16 Dec 2014 11:42:27 -0000	1.103
 +++ nd6_nbr.c	23 Feb 2015 16:32:13 -0000
 @@ -804,7 +804,7 @@ nd6_na_input(struct mbuf *m, int off, in
  			s = splsoftnet();
  			dr = defrouter_lookup(in6, rt->rt_ifp);
  			if (dr)
 -				defrtrlist_del(dr);
 +				defrtrlist_del(dr, NULL);
  			else if (!ip6_forwarding) {
  				/*
  				 * Even if the neighbor is not in the default
 Index: nd6_rtr.c
 ===================================================================
 RCS file: /cvsroot/src/sys/netinet6/nd6_rtr.c,v
 retrieving revision 1.95
 diff -u -p -r1.95 nd6_rtr.c
 --- nd6_rtr.c	16 Dec 2014 11:42:27 -0000	1.95
 +++ nd6_rtr.c	23 Feb 2015 16:32:13 -0000
 @@ -483,12 +483,20 @@ defrouter_lookup(const struct in6_addr *
  }

  void
 -defrtrlist_del(struct nd_defrouter *dr)
 +defrtrlist_del(struct nd_defrouter *dr, struct in6_ifextra *ext)
  {
 -	struct nd_ifinfo *ndi = ND_IFINFO(dr->ifp);
  	struct nd_defrouter *deldr = NULL;
  	struct nd_prefix *pr;
 -	struct in6_ifextra *ext = dr->ifp->if_afdata[AF_INET6];
 +	struct nd_ifinfo *ndi;
 +
 +	if (ext == NULL)
 +		ext = dr->ifp->if_afdata[AF_INET6];
 +
 +	/* detach already in progress, can not do anything */
 +	if (ext == NULL)
 +		return;
 +
 +	ndi = ext->nd_ifinfo;

  	/*
  	 * Flush all the routing table entries that use the router
 @@ -749,7 +757,7 @@ defrtrlist_update(struct nd_defrouter *n
  	if ((dr = defrouter_lookup(&newdr->rtaddr, newdr->ifp)) != NULL) {
  		/* entry exists */
  		if (newdr->rtlifetime == 0) {
 -			defrtrlist_del(dr);
 +			defrtrlist_del(dr, ext);
  			dr = NULL;
  		} else {
  			int oldpref = rtpref(dr);

From: christos@zoulas.com (Christos Zoulas)
To: Martin Husemann <martin@duskware.de>
Cc: gnats-bugs@NetBSD.org
Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 related)
Date: Mon, 23 Feb 2015 12:54:41 -0500

 On Feb 23,  6:47pm, martin@duskware.de (Martin Husemann) wrote:
 -- Subject: Re: kern/49682: reproducable panic when detaching bge (IPv6 relat

 | Ok, got it - this one works as well.

 Yup, this looks good!

 christos

From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/49682 CVS commit: src/sys/netinet6
Date: Mon, 23 Feb 2015 19:15:59 +0000

 Module Name:	src
 Committed By:	martin
 Date:		Mon Feb 23 19:15:59 UTC 2015

 Modified Files:
 	src/sys/netinet6: in6.c in6_ifattach.c nd6.c nd6.h nd6_nbr.c nd6_rtr.c

 Log Message:
 Rearange interface detachement slightly: before we free the INET6 specific
 per-interface data, make sure to call nd6_purge() with it to remove
 routing entries pointing to the going interface.
 When we should happen to call this function again later, with the data
 already gone, just return.
 Fixes PR kern/49682, ok: christos.


 To generate a diff of this commit:
 cvs rdiff -u -r1.181 -r1.182 src/sys/netinet6/in6.c
 cvs rdiff -u -r1.94 -r1.95 src/sys/netinet6/in6_ifattach.c
 cvs rdiff -u -r1.157 -r1.158 src/sys/netinet6/nd6.c
 cvs rdiff -u -r1.61 -r1.62 src/sys/netinet6/nd6.h
 cvs rdiff -u -r1.103 -r1.104 src/sys/netinet6/nd6_nbr.c
 cvs rdiff -u -r1.95 -r1.96 src/sys/netinet6/nd6_rtr.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: open->closed
State-Changed-By: martin@NetBSD.org
State-Changed-When: Mon, 23 Feb 2015 19:21:14 +0000
State-Changed-Why:
Fixed


From: "Soren Jacobsen" <snj@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/49682 CVS commit: [netbsd-7] src/sys/netinet6
Date: Mon, 6 Apr 2015 01:32:34 +0000

 Module Name:	src
 Committed By:	snj
 Date:		Mon Apr  6 01:32:33 UTC 2015

 Modified Files:
 	src/sys/netinet6 [netbsd-7]: in6.c in6_ifattach.c nd6.c nd6.h nd6_nbr.c
 	    nd6_rtr.c

 Log Message:
 Pull up following revision(s) (requested by martin in ticket #655):
 	sys/netinet6/in6.c: revision 1.182 via patch
 	sys/netinet6/in6_ifattach.c: revision 1.95 via patch
 	sys/netinet6/nd6.c: revision 1.158 via patch
 	sys/netinet6/nd6.h: revision 1.62 via patch
 	sys/netinet6/nd6_nbr.c: revision 1.104 via patch
 	sys/netinet6/nd6_rtr.c: revision 1.96 via patch
 Rearange interface detachement slightly: before we free the INET6 specific
 per-interface data, make sure to call nd6_purge() with it to remove
 routing entries pointing to the going interface.
 When we should happen to call this function again later, with the data
 already gone, just return.
 Fixes PR kern/49682, ok: christos.


 To generate a diff of this commit:
 cvs rdiff -u -r1.174.2.1 -r1.174.2.2 src/sys/netinet6/in6.c
 cvs rdiff -u -r1.91.2.1 -r1.91.2.2 src/sys/netinet6/in6_ifattach.c
 cvs rdiff -u -r1.152.2.2 -r1.152.2.3 src/sys/netinet6/nd6.c
 cvs rdiff -u -r1.59.2.1 -r1.59.2.2 src/sys/netinet6/nd6.h
 cvs rdiff -u -r1.100.2.1 -r1.100.2.2 src/sys/netinet6/nd6_nbr.c
 cvs rdiff -u -r1.93.2.1 -r1.93.2.2 src/sys/netinet6/nd6_rtr.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2014 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.