NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/49682: reproducable panic when detaching bge (IPv6 related)



The following reply was made to PR kern/49682; it has been noted by GNATS.

From: Martin Husemann <martin%duskware.de@localhost>
To: Christos Zoulas <christos%zoulas.com@localhost>
Cc: gnats-bugs%NetBSD.org@localhost
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);
 


Home | Main Index | Thread Index | Old Index