Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 29 May 2014 20:53:53 +0000 (UTC)
From:      Hiroki Sato <hrs@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r266857 - head/sys/netinet6
Message-ID:  <201405292053.s4TKrrcd014205@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hrs
Date: Thu May 29 20:53:53 2014
New Revision: 266857
URL: http://svnweb.freebsd.org/changeset/base/266857

Log:
  Add rwlock to struct dadq.  A panic could occur when a large number of
  addresses performed DAD at the same time.

Modified:
  head/sys/netinet6/nd6_nbr.c

Modified: head/sys/netinet6/nd6_nbr.c
==============================================================================
--- head/sys/netinet6/nd6_nbr.c	Thu May 29 20:26:01 2014	(r266856)
+++ head/sys/netinet6/nd6_nbr.c	Thu May 29 20:53:53 2014	(r266857)
@@ -88,8 +88,10 @@ static void nd6_dad_na_input(struct ifad
 static void nd6_na_output_fib(struct ifnet *, const struct in6_addr *,
     const struct in6_addr *, u_long, int, struct sockaddr *, u_int);
 
-VNET_DEFINE(int, dad_ignore_ns) = 0;	/* ignore NS in DAD - specwise incorrect*/
-VNET_DEFINE(int, dad_maxtry) = 15;	/* max # of *tries* to transmit DAD packet */
+static VNET_DEFINE(int, dad_ignore_ns) = 0;	/* ignore NS in DAD
+						   - specwise incorrect */
+static VNET_DEFINE(int, dad_maxtry) = 15;	/* max # of *tries* to
+						   transmit DAD packet */
 #define	V_dad_ignore_ns			VNET(dad_ignore_ns)
 #define	V_dad_maxtry			VNET(dad_maxtry)
 
@@ -1165,20 +1167,30 @@ struct dadq {
 };
 
 static VNET_DEFINE(TAILQ_HEAD(, dadq), dadq);
-VNET_DEFINE(int, dad_init) = 0;
-#define	V_dadq				VNET(dadq)
-#define	V_dad_init			VNET(dad_init)
+static VNET_DEFINE(struct rwlock, dad_rwlock);
+#define	V_dadq			VNET(dadq)
+#define	V_dad_rwlock		VNET(dad_rwlock)
+
+#define	DADQ_LOCK_INIT()	rw_init(&V_dad_rwlock, "nd6 DAD queue")	
+#define	DADQ_LOCK_DESTROY()	rw_destroy(&V_dad_rwlock)	
+#define	DADQ_LOCK_INITIALIZED()	rw_initialized(&V_dad_rwlock)	
+#define	DADQ_RLOCK()		rw_rlock(&V_dad_rwlock)	
+#define	DADQ_RUNLOCK()		rw_runlock(&V_dad_rwlock)	
+#define	DADQ_WLOCK()		rw_wlock(&V_dad_rwlock)	
+#define	DADQ_WUNLOCK()		rw_wunlock(&V_dad_rwlock)	
 
 static struct dadq *
 nd6_dad_find(struct ifaddr *ifa)
 {
 	struct dadq *dp;
 
+	DADQ_RLOCK();
 	TAILQ_FOREACH(dp, &V_dadq, dad_list)
 		if (dp->dad_ifa == ifa)
-			return (dp);
+			break;
+	DADQ_RUNLOCK();
 
-	return (NULL);
+	return (dp);
 }
 
 static void
@@ -1206,9 +1218,9 @@ nd6_dad_start(struct ifaddr *ifa, int de
 	struct dadq *dp;
 	char ip6buf[INET6_ADDRSTRLEN];
 
-	if (!V_dad_init) {
+	if (DADQ_LOCK_INITIALIZED() == 0) {
+		DADQ_LOCK_INIT();
 		TAILQ_INIT(&V_dadq);
-		V_dad_init++;
 	}
 
 	/*
@@ -1258,7 +1270,9 @@ nd6_dad_start(struct ifaddr *ifa, int de
 #ifdef VIMAGE
 	dp->dad_vnet = curvnet;
 #endif
+	DADQ_WLOCK();
 	TAILQ_INSERT_TAIL(&V_dadq, (struct dadq *)dp, dad_list);
+	DADQ_WUNLOCK();
 
 	nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
 	    ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
@@ -1291,7 +1305,7 @@ nd6_dad_stop(struct ifaddr *ifa)
 {
 	struct dadq *dp;
 
-	if (!V_dad_init)
+	if (DADQ_LOCK_INITIALIZED() == 0)
 		return;
 	dp = nd6_dad_find(ifa);
 	if (!dp) {
@@ -1301,7 +1315,9 @@ nd6_dad_stop(struct ifaddr *ifa)
 
 	nd6_dad_stoptimer(dp);
 
+	DADQ_WLOCK();
 	TAILQ_REMOVE(&V_dadq, (struct dadq *)dp, dad_list);
+	DADQ_WUNLOCK();
 	free(dp, M_IP6NDP);
 	dp = NULL;
 	ifa_free(ifa);
@@ -1351,7 +1367,9 @@ nd6_dad_timer(struct dadq *dp)
 		nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n",
 		    if_name(ifa->ifa_ifp)));
 
+		DADQ_WLOCK();
 		TAILQ_REMOVE(&V_dadq, (struct dadq *)dp, dad_list);
+		DADQ_WUNLOCK();
 		free(dp, M_IP6NDP);
 		dp = NULL;
 		ifa_free(ifa);
@@ -1407,7 +1425,9 @@ nd6_dad_timer(struct dadq *dp)
 			    if_name(ifa->ifa_ifp),
 			    ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
 
+			DADQ_WLOCK();
 			TAILQ_REMOVE(&V_dadq, (struct dadq *)dp, dad_list);
+			DADQ_WUNLOCK();
 			free(dp, M_IP6NDP);
 			dp = NULL;
 			ifa_free(ifa);
@@ -1484,7 +1504,9 @@ nd6_dad_duplicated(struct ifaddr *ifa)
 		}
 	}
 
+	DADQ_WLOCK();
 	TAILQ_REMOVE(&V_dadq, (struct dadq *)dp, dad_list);
+	DADQ_WUNLOCK();
 	free(dp, M_IP6NDP);
 	dp = NULL;
 	ifa_free(ifa);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405292053.s4TKrrcd014205>