PERFORCE change 34866 for review

Sam Leffler sam at FreeBSD.org
Tue Jul 22 18:40:06 PDT 2003


http://perforce.freebsd.org/chv.cgi?CH=34866

Change 34866 by sam at sam_ebb on 2003/07/22 18:39:12

	fast ipsec locking (needs revisiting)

Affected files ...

.. //depot/projects/netperf/sys/netipsec/ipsec.c#2 edit
.. //depot/projects/netperf/sys/netipsec/ipsec.h#2 edit
.. //depot/projects/netperf/sys/netipsec/ipsec_input.c#2 edit
.. //depot/projects/netperf/sys/netipsec/ipsec_output.c#2 edit
.. //depot/projects/netperf/sys/netipsec/key.c#2 edit
.. //depot/projects/netperf/sys/netipsec/key.h#2 edit
.. //depot/projects/netperf/sys/netipsec/keydb.h#2 edit
.. //depot/projects/netperf/sys/netipsec/xform_ah.c#2 edit
.. //depot/projects/netperf/sys/netipsec/xform_esp.c#2 edit
.. //depot/projects/netperf/sys/netipsec/xform_ipcomp.c#2 edit

Differences ...

==== //depot/projects/netperf/sys/netipsec/ipsec.c#2 (text+ko) ====

@@ -202,6 +202,8 @@
 static void vshiftl __P((unsigned char *, int, int));
 static size_t ipsec_hdrsiz __P((struct secpolicy *));
 
+MALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy");
+
 /*
  * Return a held reference to the default SP.
  */
@@ -836,7 +838,7 @@
 ipsec_delpcbpolicy(p)
 	struct inpcbpolicy *p;
 {
-	free(p, M_SECA);
+	free(p, M_IPSEC_INPCB);
 }
 
 /* initialize policy in PCB */
@@ -852,7 +854,7 @@
 		panic("ipsec_init_policy: NULL pointer was passed.\n");
 
 	new = (struct inpcbpolicy *) malloc(sizeof(struct inpcbpolicy),
-					    M_SECA, M_NOWAIT|M_ZERO);
+					    M_IPSEC_INPCB, M_NOWAIT|M_ZERO);
 	if (new == NULL) {
 		ipseclog((LOG_DEBUG, "ipsec_init_policy: No more memory.\n"));
 		return ENOBUFS;
@@ -909,6 +911,24 @@
 	return 0;
 }
 
+struct ipsecrequest *
+ipsec_newisr(void)
+{
+	struct ipsecrequest *p;
+
+	p = malloc(sizeof(struct ipsecrequest), M_IPSEC_SR, M_NOWAIT|M_ZERO);
+	if (p != NULL)
+		mtx_init(&p->lock, "ipsec request", NULL, MTX_DEF);
+	return p;
+}
+
+void
+ipsec_delisr(struct ipsecrequest *p)
+{
+	mtx_destroy(&p->lock);
+	free(p, M_IPSEC_SR);
+}
+
 /* deep-copy a policy in PCB */
 static struct secpolicy *
 ipsec_deepcopy_policy(src)
@@ -932,13 +952,9 @@
 	 */
 	q = &newchain;
 	for (p = src->req; p; p = p->next) {
-		*q = (struct ipsecrequest *)malloc(sizeof(struct ipsecrequest),
-			M_SECA, M_NOWAIT);
+		*q = ipsec_newisr();
 		if (*q == NULL)
 			goto fail;
-		bzero(*q, sizeof(**q));
-		(*q)->next = NULL;
-
 		(*q)->saidx.proto = p->saidx.proto;
 		(*q)->saidx.mode = p->saidx.mode;
 		(*q)->level = p->level;
@@ -947,7 +963,6 @@
 		bcopy(&p->saidx.src, &(*q)->saidx.src, sizeof((*q)->saidx.src));
 		bcopy(&p->saidx.dst, &(*q)->saidx.dst, sizeof((*q)->saidx.dst));
 
-		(*q)->sav = NULL;
 		(*q)->sp = dst;
 
 		q = &((*q)->next);
@@ -963,7 +978,7 @@
 fail:
 	for (p = newchain; p; p = r) {
 		r = p->next;
-		free(p, M_SECA);
+		ipsec_delisr(p);
 		p = NULL;
 	}
 	return NULL;

==== //depot/projects/netperf/sys/netipsec/ipsec.h#2 (text+ko) ====

@@ -71,6 +71,7 @@
 /* Security Policy Data Base */
 struct secpolicy {
 	LIST_ENTRY(secpolicy) chain;
+	struct mtx lock;
 
 	u_int refcnt;			/* reference count */
 	struct secpolicyindex spidx;	/* selector */
@@ -108,6 +109,7 @@
 
 	struct secasvar *sav;	/* place holder of SA for use */
 	struct secpolicy *sp;	/* back pointer to SP */
+	struct mtx lock;	/* to interlock updates */
 };
 
 /* security policy in PCB */
@@ -322,6 +324,9 @@
 /* for openbsd compatibility */
 #define	DPRINTF(x)	do { if (ipsec_debug) printf x; } while (0)
 
+extern	struct ipsecrequest *ipsec_newisr(void);
+extern	void ipsec_delisr(struct ipsecrequest *);
+
 struct tdb_ident;
 extern struct secpolicy *ipsec_getpolicy __P((struct tdb_ident*, u_int));
 struct inpcb;

==== //depot/projects/netperf/sys/netipsec/ipsec_input.c#2 (text+ko) ====

@@ -108,7 +108,7 @@
 	union sockaddr_union dst_address;
 	struct secasvar *sav;
 	u_int32_t spi;
-	int s, error;
+	int error;
 
 	IPSEC_ISTAT(sproto, espstat.esps_input, ahstat.ahs_input,
 		ipcompstat.ipcomps_input);
@@ -178,8 +178,6 @@
 		return EPFNOSUPPORT;
 	}
 
-	s = splnet();
-
 	/* NB: only pass dst since key_allocsa follows RFC2401 */
 	sav = KEY_ALLOCSA(&dst_address, sproto, spi);
 	if (sav == NULL) {
@@ -189,7 +187,6 @@
 			  (u_long) ntohl(spi), sproto));
 		IPSEC_ISTAT(sproto, espstat.esps_notdb, ahstat.ahs_notdb,
 		    ipcompstat.ipcomps_notdb);
-		splx(s);
 		m_freem(m);
 		return ENOENT;
 	}
@@ -202,7 +199,6 @@
 		IPSEC_ISTAT(sproto, espstat.esps_noxform, ahstat.ahs_noxform,
 		    ipcompstat.ipcomps_noxform);
 		KEY_FREESAV(&sav);
-		splx(s);
 		m_freem(m);
 		return ENXIO;
 	}
@@ -213,7 +209,6 @@
 	 */
 	error = (*sav->tdb_xform->xf_input)(m, sav, skip, protoff);
 	KEY_FREESAV(&sav);
-	splx(s);
 	return error;
 }
 

==== //depot/projects/netperf/sys/netipsec/ipsec_output.c#2 (text+ko) ====

@@ -345,12 +345,12 @@
 	struct secasindex saidx;
 	struct secasvar *sav;
 	struct ip *ip;
-	int s, error, i, off;
+	int error, i, off;
 
 	KASSERT(m != NULL, ("ipsec4_process_packet: null mbuf"));
 	KASSERT(isr != NULL, ("ipsec4_process_packet: null isr"));
 
-	s = splnet();			/* insure SA contents don't change */
+	mtx_lock(&isr->lock);		/* insure SA contents don't change */
 
 	isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error);
 	if (isr == NULL)
@@ -469,10 +469,10 @@
 	} else {
 		error = ipsec_process_done(m, isr);
 	}
-	splx(s);
+	mtx_unlock(&isr->lock);
 	return error;
 bad:
-	splx(s);
+	mtx_unlock(&isr->lock);
 	if (m)
 		m_freem(m);
 	return error;

==== //depot/projects/netperf/sys/netipsec/key.c#2 (text+ko) ====

@@ -42,6 +42,8 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
 #include <sys/mbuf.h>
 #include <sys/domain.h>
 #include <sys/protosw.h>
@@ -122,16 +124,18 @@
 static int key_prefered_oldsa = 1;	/* prefered old sa rather than new sa.*/
 
 static u_int32_t acq_seq = 0;
-static int key_tick_init_random = 0;
 
 static LIST_HEAD(_sptree, secpolicy) sptree[IPSEC_DIR_MAX];	/* SPD */
+static struct mtx sptree_lock;
 static LIST_HEAD(_sahtree, secashead) sahtree;			/* SAD */
+static struct mtx sahtree_lock;
+							/* registed list */
 static LIST_HEAD(_regtree, secreg) regtree[SADB_SATYPE_MAX + 1];
-							/* registed list */
-#ifndef IPSEC_NONBLOCK_ACQUIRE
+static struct mtx regtree_lock;
 static LIST_HEAD(_acqtree, secacq) acqtree;		/* acquiring list */
-#endif
+static struct mtx acq_lock;
 static LIST_HEAD(_spacqtree, secspacq) spacqtree;	/* SP acquiring list */
+static struct mtx spacq_lock;
 
 /* search order for SAs */
 static u_int saorder_state_valid[] = {
@@ -286,28 +290,14 @@
 	}								\
 } while (0)
 
-MALLOC_DEFINE(M_SECA, "key mgmt", "security associations, key management");
+MALLOC_DEFINE(M_IPSEC_SA, "secasvar", "ipsec security association");
+MALLOC_DEFINE(M_IPSEC_SAH, "sahead", "ipsec sa head");
+MALLOC_DEFINE(M_IPSEC_SP, "ipsecpolicy", "ipsec security policy");
+MALLOC_DEFINE(M_IPSEC_SR, "ipsecrequest", "ipsec security request");
+MALLOC_DEFINE(M_IPSEC_MISC, "ipsec-misc", "ipsec miscellaneous");
+MALLOC_DEFINE(M_IPSEC_SAQ, "ipsec-saq", "ipsec sa acquire");
+MALLOC_DEFINE(M_IPSEC_SAR, "ipsec-reg", "ipsec sa acquire");
 
-#if 1
-#define KMALLOC(p, t, n)                                                     \
-	((p) = (t) malloc((unsigned long)(n), M_SECA, M_NOWAIT))
-#define KFREE(p)                                                             \
-	free((caddr_t)(p), M_SECA)
-#else
-#define KMALLOC(p, t, n) \
-do { \
-	((p) = (t)malloc((unsigned long)(n), M_SECA, M_NOWAIT));             \
-	printf("%s %d: %p <- KMALLOC(%s, %d)\n",                             \
-		__FILE__, __LINE__, (p), #t, n);                             \
-} while (0)
-
-#define KFREE(p)                                                             \
-	do {                                                                 \
-		printf("%s %d: %p -> KFREE()\n", __FILE__, __LINE__, (p));   \
-		free((caddr_t)(p), M_SECA);                                  \
-	} while (0)
-#endif
-
 /*
  * set parameters into secpolicyindex buffer.
  * Must allocate secpolicyindex buffer passed to this function.
@@ -354,6 +344,7 @@
 static struct secasvar *key_do_allocsa_policy __P((struct secashead *, u_int));
 static void key_delsp __P((struct secpolicy *));
 static struct secpolicy *key_getsp __P((struct secpolicyindex *));
+static void _key_delsp(struct secpolicy *sp);
 static struct secpolicy *key_getspbyid __P((u_int32_t));
 static u_int32_t key_newreqid __P((void));
 static struct mbuf *key_gather_mbuf __P((struct mbuf *,
@@ -396,14 +387,10 @@
 static struct mbuf *key_setsadbsa __P((struct secasvar *));
 static struct mbuf *key_setsadbaddr __P((u_int16_t,
 	const struct sockaddr *, u_int8_t, u_int16_t));
-#if 0
-static struct mbuf *key_setsadbident __P((u_int16_t, u_int16_t, caddr_t,
-	int, u_int64_t));
-#endif
 static struct mbuf *key_setsadbxsa2 __P((u_int8_t, u_int32_t, u_int32_t));
 static struct mbuf *key_setsadbxpolicy __P((u_int16_t, u_int8_t,
 	u_int32_t));
-static void *key_newbuf __P((const void *, u_int));
+static void *key_dup(const void *, u_int, struct malloc_type *);
 #ifdef INET6
 static int key_ismyaddr6 __P((struct sockaddr_in6 *));
 #endif
@@ -422,7 +409,6 @@
 	__P((struct secpolicyindex *, struct secpolicyindex *));
 static int key_sockaddrcmp __P((const struct sockaddr *, const struct sockaddr *, int));
 static int key_bbcmp __P((const void *, const void *, u_int));
-static void key_srandom __P((void));
 static u_int16_t key_satype2proto __P((u_int8_t));
 static u_int8_t key_proto2satype __P((u_int16_t));
 
@@ -453,11 +439,9 @@
 static struct mbuf *key_getprop __P((const struct secasindex *));
 
 static int key_acquire __P((const struct secasindex *, struct secpolicy *));
-#ifndef IPSEC_NONBLOCK_ACQUIRE
 static struct secacq *key_newacq __P((const struct secasindex *));
 static struct secacq *key_getacq __P((const struct secasindex *));
 static struct secacq *key_getacqbyseq __P((u_int32_t));
-#endif
 static struct secspacq *key_newspacq __P((struct secpolicyindex *));
 static struct secspacq *key_getspacq __P((struct secpolicyindex *));
 static int key_acquire2 __P((struct socket *, struct mbuf *,
@@ -526,7 +510,6 @@
 key_allocsp(struct secpolicyindex *spidx, u_int dir, const char* where, int tag)
 {
 	struct secpolicy *sp;
-	int s;
 
 	KASSERT(spidx != NULL, ("key_allocsp: null spidx"));
 	KASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND,
@@ -536,11 +519,11 @@
 		printf("DP key_allocsp from %s:%u\n", where, tag));
 
 	/* get a SP entry */
-	s = splnet();	/*called from softclock()*/
 	KEYDEBUG(KEYDEBUG_IPSEC_DATA,
 		printf("*** objects\n");
 		kdebug_secpolicyindex(spidx));
 
+	mtx_lock(&sptree_lock);
 	LIST_FOREACH(sp, &sptree[dir], chain) {
 		KEYDEBUG(KEYDEBUG_IPSEC_DATA,
 			printf("*** in SPD\n");
@@ -561,7 +544,7 @@
 		sp->lastused = time_second;
 		SP_ADDREF(sp);
 	}
-	splx(s);
+	mtx_unlock(&sptree_lock);
 
 	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
 		printf("DP key_allocsp return SP:%p (ID=%u) refcnt %u\n",
@@ -583,7 +566,6 @@
 	     const char* where, int tag)
 {
 	struct secpolicy *sp;
-	int s;
 
 	KASSERT(dst != NULL, ("key_allocsp2: null dst"));
 	KASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND,
@@ -593,12 +575,12 @@
 		printf("DP key_allocsp2 from %s:%u\n", where, tag));
 
 	/* get a SP entry */
-	s = splnet();	/*called from softclock()*/
 	KEYDEBUG(KEYDEBUG_IPSEC_DATA,
 		printf("*** objects\n");
 		printf("spi %u proto %u dir %u\n", spi, proto, dir);
 		kdebug_sockaddr(&dst->sa));
 
+	mtx_lock(&sptree_lock);
 	LIST_FOREACH(sp, &sptree[dir], chain) {
 		KEYDEBUG(KEYDEBUG_IPSEC_DATA,
 			printf("*** in SPD\n");
@@ -625,7 +607,7 @@
 		sp->lastused = time_second;
 		SP_ADDREF(sp);
 	}
-	splx(s);
+	mtx_unlock(&sptree_lock);
 
 	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
 		printf("DP key_allocsp2 return SP:%p (ID=%u) refcnt %u\n",
@@ -646,7 +628,6 @@
 {
 	struct secpolicy *sp;
 	const int dir = IPSEC_DIR_INBOUND;
-	int s;
 	struct ipsecrequest *r1, *r2, *p;
 	struct secpolicyindex spidx;
 
@@ -660,7 +641,7 @@
 		goto done;
 	}
 
-	s = splnet();	/*called from softclock()*/
+	mtx_lock(&sptree_lock);
 	LIST_FOREACH(sp, &sptree[dir], chain) {
 		if (sp->state == IPSEC_SPSTATE_DEAD)
 			continue;
@@ -702,7 +683,7 @@
 		sp->lastused = time_second;
 		SP_ADDREF(sp);
 	}
-	splx(s);
+	mtx_unlock(&sptree_lock);
 done:
 	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
 		printf("DP key_gettunnel return SP:%p (ID=%u) refcnt %u\n",
@@ -728,19 +709,17 @@
 		saidx->mode == IPSEC_MODE_TUNNEL,
 		("key_checkrequest: unexpected policy %u", saidx->mode));
 
-	/* get current level */
-	level = ipsec_get_reqlevel(isr);
-
 	/*
 	 * XXX guard against protocol callbacks from the crypto
 	 * thread as they reference ipsecrequest.sav which we
 	 * temporarily null out below.  Need to rethink how we
 	 * handle bundled SA's in the callback thread.
 	 */
+	mtx_assert(&isr->lock, MA_OWNED);
+
+	/* get current level */
+	level = ipsec_get_reqlevel(isr);
 #if 0
-	SPLASSERT(net, "key_checkrequest");
-#endif
-#if 0
 	/*
 	 * We do allocate new SA only if the state of SA in the holder is
 	 * SADB_SASTATE_DEAD.  The SA for outbound must be the oldest.
@@ -819,12 +798,16 @@
 	struct secasvar *sav;
 	u_int stateidx, state;
 
+	mtx_lock(&sahtree_lock);
 	LIST_FOREACH(sah, &sahtree, chain) {
 		if (sah->state == SADB_SASTATE_DEAD)
 			continue;
-		if (key_cmpsaidx(&sah->saidx, saidx, CMP_MODE_REQID))
+		if (key_cmpsaidx(&sah->saidx, saidx, CMP_MODE_REQID)) {
+			mtx_unlock(&sahtree_lock);	/* XXX??? */
 			goto found;
+		}
 	}
+	mtx_unlock(&sahtree_lock);
 
 	return NULL;
 
@@ -860,6 +843,7 @@
 	/* initilize */
 	candidate = NULL;
 
+	mtx_lock(&sahtree_lock);
 	for (sav = LIST_FIRST(&sah->savtree[state]);
 	     sav != NULL;
 	     sav = nextsav) {
@@ -962,7 +946,6 @@
 			KEY_FREESAV(&d);
 		}
 	}
-
 	if (candidate) {
 		SA_ADDREF(candidate);
 		KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
@@ -970,6 +953,8 @@
 				"refcnt++:%d SA:%p\n",
 				candidate->refcnt, candidate));
 	}
+	mtx_unlock(&sahtree_lock);
+
 	return candidate;
 }
 
@@ -998,7 +983,6 @@
 	struct secashead *sah;
 	struct secasvar *sav;
 	u_int stateidx, state;
-	int s;
 
 	KASSERT(dst != NULL, ("key_allocsa: null dst address"));
 
@@ -1011,7 +995,7 @@
 	 * IPsec tunnel packet is received.  But ESP tunnel mode is
 	 * encrypted so we can't check internal IP header.
 	 */
-	s = splnet();	/*called from softclock()*/
+	mtx_lock(&sahtree_lock);
 	LIST_FOREACH(sah, &sahtree, chain) {
 		/* search valid state */
 		for (stateidx = 0;
@@ -1044,7 +1028,7 @@
 	}
 	sav = NULL;
 done:
-	splx(s);
+	mtx_unlock(&sahtree_lock);
 
 	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
 		printf("DP key_allocsa return SA:%p; refcnt %u\n",
@@ -1063,6 +1047,7 @@
 
 	KASSERT(sp != NULL, ("key_freesp: null sp"));
 
+	mtx_lock(&sptree_lock);
 	SP_DELREF(sp);
 
 	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
@@ -1073,6 +1058,7 @@
 		*spp = NULL;
 		key_delsp(sp);
 	}
+	mtx_unlock(&sptree_lock);
 }
 
 /*
@@ -1174,9 +1160,10 @@
 static void
 key_delsp(struct secpolicy *sp)
 {
-	int s;
+	struct ipsecrequest *isr, *nextisr;
 
 	KASSERT(sp != NULL, ("key_delsp: null sp"));
+	mtx_assert(&sptree_lock, MA_OWNED);
 
 	sp->state = IPSEC_SPSTATE_DEAD;
 
@@ -1184,29 +1171,20 @@
 		("key_delsp: SP with references deleted (refcnt %u)",
 		sp->refcnt));
 
-	s = splnet();	/*called from softclock()*/
 	/* remove from SP index */
 	if (__LIST_CHAINED(sp))
 		LIST_REMOVE(sp, chain);
 
-    {
-	struct ipsecrequest *isr = sp->req, *nextisr;
-
-	while (isr != NULL) {
+	for (isr = sp->req; isr != NULL; isr = nextisr) {
 		if (isr->sav != NULL) {
 			KEY_FREESAV(&isr->sav);
 			isr->sav = NULL;
 		}
 
 		nextisr = isr->next;
-		KFREE(isr);
-		isr = nextisr;
+		ipsec_delisr(isr);
 	}
-    }
-
-	KFREE(sp);
-
-	splx(s);
+	_key_delsp(sp);
 }
 
 /*
@@ -1221,16 +1199,18 @@
 
 	KASSERT(spidx != NULL, ("key_getsp: null spidx"));
 
+	mtx_lock(&sptree_lock);
 	LIST_FOREACH(sp, &sptree[spidx->dir], chain) {
 		if (sp->state == IPSEC_SPSTATE_DEAD)
 			continue;
 		if (key_cmpspidx_exactly(spidx, &sp->spidx)) {
 			SP_ADDREF(sp);
-			return sp;
+			break;
 		}
 	}
+	mtx_unlock(&sptree_lock);
 
-	return NULL;
+	return sp;
 }
 
 /*
@@ -1243,12 +1223,13 @@
 {
 	struct secpolicy *sp;
 
+	mtx_lock(&sptree_lock);
 	LIST_FOREACH(sp, &sptree[IPSEC_DIR_INBOUND], chain) {
 		if (sp->state == IPSEC_SPSTATE_DEAD)
 			continue;
 		if (sp->id == id) {
 			SP_ADDREF(sp);
-			return sp;
+			goto done;
 		}
 	}
 
@@ -1257,11 +1238,13 @@
 			continue;
 		if (sp->id == id) {
 			SP_ADDREF(sp);
-			return sp;
+			goto done;
 		}
 	}
+done:
+	mtx_unlock(&sptree_lock);
 
-	return NULL;
+	return sp;
 }
 
 struct secpolicy *
@@ -1270,8 +1253,9 @@
 	struct secpolicy *newsp = NULL;
 
 	newsp = (struct secpolicy *)
-		malloc(sizeof(struct secpolicy), M_SECA, M_NOWAIT|M_ZERO);
+		malloc(sizeof(struct secpolicy), M_IPSEC_SP, M_NOWAIT|M_ZERO);
 	if (newsp) {
+		mtx_init(&newsp->lock, "ipsec policy", NULL, MTX_DEF);
 		newsp->refcnt = 1;
 		newsp->req = NULL;
 	}
@@ -1282,6 +1266,13 @@
 	return newsp;
 }
 
+static void
+_key_delsp(struct secpolicy *sp)
+{
+	mtx_destroy(&sp->lock);
+	free(sp, M_IPSEC_SP);
+}
+
 /*
  * create secpolicy structure from sadb_x_policy structure.
  * NOTE: `state', `secpolicyindex' in secpolicy structure are not set,
@@ -1352,7 +1343,8 @@
 			}
 
 			/* allocate request buffer */
-			KMALLOC(*p_isr, struct ipsecrequest *, sizeof(**p_isr));
+			/* NB: data structure is zero'd */
+			*p_isr = ipsec_newisr();
 			if ((*p_isr) == NULL) {
 				ipseclog((LOG_DEBUG,
 				    "key_msg2sp: No more memory.\n"));
@@ -1360,11 +1352,8 @@
 				*error = ENOBUFS;
 				return NULL;
 			}
-			bzero(*p_isr, sizeof(**p_isr));
 
 			/* set values */
-			(*p_isr)->next = NULL;
-
 			switch (xisr->sadb_x_ipsecrequest_proto) {
 			case IPPROTO_ESP:
 			case IPPROTO_AH:
@@ -1475,7 +1464,6 @@
 					paddr->sa_len);
 			}
 
-			(*p_isr)->sav = NULL;
 			(*p_isr)->sp = newsp;
 
 			/* initialization for the next. */
@@ -1792,7 +1780,7 @@
 	}
 
 	if ((newsp->id = key_getnewspid()) == 0) {
-		KFREE(newsp);
+		_key_delsp(newsp);
 		return key_senderror(so, m, ENOBUFS);
 	}
 
@@ -1808,12 +1796,12 @@
 	/* sanity check on addr pair */
 	if (((struct sockaddr *)(src0 + 1))->sa_family !=
 			((struct sockaddr *)(dst0+ 1))->sa_family) {
-		KFREE(newsp);
+		_key_delsp(newsp);
 		return key_senderror(so, m, EINVAL);
 	}
 	if (((struct sockaddr *)(src0 + 1))->sa_len !=
 			((struct sockaddr *)(dst0+ 1))->sa_len) {
-		KFREE(newsp);
+		_key_delsp(newsp);
 		return key_senderror(so, m, EINVAL);
 	}
 #if 1
@@ -1821,7 +1809,7 @@
 		struct sockaddr *sa;
 		sa = (struct sockaddr *)(src0 + 1);
 		if (sa->sa_family != newsp->req->saidx.src.sa.sa_family) {
-			KFREE(newsp);
+			_key_delsp(newsp);
 			return key_senderror(so, m, EINVAL);
 		}
 	}
@@ -1829,7 +1817,7 @@
 		struct sockaddr *sa;
 		sa = (struct sockaddr *)(dst0 + 1);
 		if (sa->sa_family != newsp->req->saidx.dst.sa.sa_family) {
-			KFREE(newsp);
+			_key_delsp(newsp);
 			return key_senderror(so, m, EINVAL);
 		}
 	}
@@ -1846,11 +1834,12 @@
 
 	/* delete the entry in spacqtree */
 	if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) {
-		struct secspacq *spacq;
-		if ((spacq = key_getspacq(&spidx)) != NULL) {
+		struct secspacq *spacq = key_getspacq(&spidx);
+		if (spacq != NULL) {
 			/* reset counter in order to deletion by timehandler. */
 			spacq->created = time_second;
 			spacq->count = 0;
+			mtx_unlock(&spacq_lock);
 		}
     	}
 
@@ -2005,6 +1994,7 @@
 	xpl0->sadb_x_policy_id = sp->id;
 
 	sp->state = IPSEC_SPSTATE_DEAD;
+	mtx_destroy(&sp->lock);
 	KEY_FREESP(&sp);
 
     {
@@ -2067,6 +2057,7 @@
 	}
 
 	sp->state = IPSEC_SPSTATE_DEAD;
+	mtx_destroy(&sp->lock);
 	KEY_FREESP(&sp);
 
     {
@@ -2202,7 +2193,8 @@
 		panic("key_spdacquire: policy mismathed. IPsec is expected.\n");
 
 	/* Get an entry to check whether sent message or not. */
-	if ((newspacq = key_getspacq(&sp->spidx)) != NULL) {
+	newspacq = key_getspacq(&sp->spidx);
+	if (newspacq != NULL) {
 		if (key_blockacq_count < newspacq->count) {
 			/* reset counter and do send message. */
 			newspacq->count = 0;
@@ -2211,13 +2203,12 @@
 			newspacq->count++;
 			return 0;
 		}
+		mtx_unlock(&spacq_lock);
 	} else {
 		/* make new entry for blocking to send SADB_ACQUIRE. */
-		if ((newspacq = key_newspacq(&sp->spidx)) == NULL)
+		newspacq = key_newspacq(&sp->spidx);
+		if (newspacq == NULL)
 			return ENOBUFS;
-
-		/* add to acqtree */
-		LIST_INSERT_HEAD(&spacqtree, newspacq, chain);
 	}
 
 	/* create new sadb_msg to reply. */
@@ -2446,14 +2437,12 @@
 key_spdexpire(sp)
 	struct secpolicy *sp;
 {
-	int s;
 	struct mbuf *result = NULL, *m;
 	int len;
 	int error = -1;
 	struct sadb_lifetime *lt;
 
 	/* XXX: Why do we lock ? */
-	s = splnet();	/*called from softclock()*/
 
 	/* sanity check */
 	if (sp == NULL)
@@ -2546,7 +2535,6 @@
  fail:
 	if (result)
 		m_freem(result);
-	splx(s);
 	return error;
 }
 
@@ -2564,8 +2552,7 @@
 
 	KASSERT(saidx != NULL, ("key_newsaidx: null saidx"));
 
-	newsah = (struct secashead *)
-		malloc(sizeof(struct secashead), M_SECA, M_NOWAIT|M_ZERO);
+	newsah = malloc(sizeof(struct secashead), M_IPSEC_SAH, M_NOWAIT|M_ZERO);
 	if (newsah != NULL) {
 		int i;
 		for (i = 0; i < sizeof(newsah->savtree)/sizeof(newsah->savtree[0]); i++)
@@ -2574,7 +2561,10 @@
 
 		/* add to saidxtree */
 		newsah->state = SADB_SASTATE_MATURE;
+
+		mtx_lock(&sahtree_lock);
 		LIST_INSERT_HEAD(&sahtree, newsah, chain);
+		mtx_unlock(&sahtree_lock);
 	}
 	return(newsah);
 }
@@ -2588,14 +2578,11 @@
 {
 	struct secasvar *sav, *nextsav;
 	u_int stateidx, state;
-	int s;
 	int zombie = 0;
 
 	/* sanity check */
-	if (sah == NULL)
-		panic("key_delsah: NULL pointer is passed.\n");
-
-	s = splnet();	/*called from softclock()*/
+	KASSERT(sah != NULL, ("key_delsah: NULL sah"));
+	mtx_assert(&sahtree_lock, MA_OWNED);
 
 	/* searching all SA registerd in the secindex. */
 	for (stateidx = 0;
@@ -2619,26 +2606,20 @@
 			}
 		}
 	}
+	/* remove from tree of SA index */
+	if (!zombie && __LIST_CHAINED(sah))
+		LIST_REMOVE(sah, chain);
 
 	/* don't delete sah only if there are savs. */
-	if (zombie) {
-		splx(s);
+	if (zombie)
 		return;
-	}
 
 	if (sah->sa_route.ro_rt) {
 		RTFREE(sah->sa_route.ro_rt);
 		sah->sa_route.ro_rt = (struct rtentry *)NULL;
 	}
 
-	/* remove from tree of SA index */
-	if (__LIST_CHAINED(sah))
-		LIST_REMOVE(sah, chain);
-
-	KFREE(sah);
-
-	splx(s);
-	return;
+	free(sah, M_IPSEC_SAH);
 }
 
 /*
@@ -2669,13 +2650,12 @@
 	if (m == NULL || mhp == NULL || mhp->msg == NULL || sah == NULL)
 		panic("key_newsa: NULL pointer is passed.\n");
 
-	KMALLOC(newsav, struct secasvar *, sizeof(struct secasvar));
+	newsav = malloc(sizeof(struct secasvar), M_IPSEC_SA, M_NOWAIT|M_ZERO);
 	if (newsav == NULL) {
 		ipseclog((LOG_DEBUG, "key_newsa: No more memory.\n"));
 		*errp = ENOBUFS;
 		goto done;
 	}
-	bzero((caddr_t)newsav, sizeof(struct secasvar));
 
 	switch (mhp->msg->sadb_msg_type) {
 	case SADB_GETSPI:
@@ -2694,7 +2674,8 @@
 	case SADB_ADD:
 		/* sanity check */
 		if (mhp->ext[SADB_EXT_SA] == NULL) {
-			KFREE(newsav), newsav = NULL;
+			free(newsav, M_IPSEC_SA);
+			newsav = NULL;
 			ipseclog((LOG_DEBUG, "key_newsa: invalid message is passed.\n"));
 			*errp = EINVAL;
 			goto done;
@@ -2704,20 +2685,25 @@
 		newsav->seq = mhp->msg->sadb_msg_seq;
 		break;
 	default:
-		KFREE(newsav), newsav = NULL;
+		free(newsav, M_IPSEC_SA);
+		newsav = NULL;
 		*errp = EINVAL;
 		goto done;
 	}
 
+
 	/* copy sav values */
 	if (mhp->msg->sadb_msg_type != SADB_GETSPI) {
 		*errp = key_setsaval(newsav, m, mhp);
 		if (*errp) {
-			KFREE(newsav), newsav = NULL;
+			free(newsav, M_IPSEC_SA);
+			newsav = NULL;
 			goto done;
 		}
 	}
 
+	mtx_init(&newsav->lock, "ipsec sa", NULL, MTX_DEF);
+
 	/* reset created */
 	newsav->created = time_second;
 	newsav->pid = mhp->msg->sadb_msg_pid;
@@ -2726,6 +2712,8 @@
 	newsav->sah = sah;
 	newsav->refcnt = 1;
 	newsav->state = SADB_SASTATE_LARVAL;
+
+	/* XXX locking??? */
 	LIST_INSERT_TAIL(&sah->savtree[SADB_SASTATE_LARVAL], newsav,
 			secasvar, chain);
 done:
@@ -2740,17 +2728,8 @@
  * free() SA variable entry.
  */
 static void
-key_delsav(sav)
-	struct secasvar *sav;
+key_cleansav(struct secasvar *sav)
 {
-	KASSERT(sav != NULL, ("key_delsav: null sav"));
-	KASSERT(sav->refcnt == 0,
-		("key_delsav: reference count %u > 0", sav->refcnt));
-
-	/* remove from SA header */
-	if (__LIST_CHAINED(sav))
-		LIST_REMOVE(sav, chain);
-
 	/*
 	 * Cleanup xform state.  Note that zeroize'ing causes the
 	 * keys to be cleared; otherwise we must do it ourself.
@@ -2765,42 +2744,57 @@
 			bzero(_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc));
 	}
 	if (sav->key_auth != NULL) {
-		KFREE(sav->key_auth);
+		free(sav->key_auth, M_IPSEC_MISC);
 		sav->key_auth = NULL;
 	}
 	if (sav->key_enc != NULL) {
-		KFREE(sav->key_enc);
+		free(sav->key_enc, M_IPSEC_MISC);
 		sav->key_enc = NULL;
 	}
 	if (sav->sched) {
 		bzero(sav->sched, sav->schedlen);
-		KFREE(sav->sched);
+		free(sav->sched, M_IPSEC_MISC);
 		sav->sched = NULL;
 	}
 	if (sav->replay != NULL) {
-		KFREE(sav->replay);
+		free(sav->replay, M_IPSEC_MISC);
 		sav->replay = NULL;
 	}
 	if (sav->lft_c != NULL) {
-		KFREE(sav->lft_c);
+		free(sav->lft_c, M_IPSEC_MISC);
 		sav->lft_c = NULL;
 	}
 	if (sav->lft_h != NULL) {
-		KFREE(sav->lft_h);
+		free(sav->lft_h, M_IPSEC_MISC);
 		sav->lft_h = NULL;
 	}
 	if (sav->lft_s != NULL) {
-		KFREE(sav->lft_s);
+		free(sav->lft_s, M_IPSEC_MISC);
 		sav->lft_s = NULL;
 	}
 	if (sav->iv != NULL) {
-		KFREE(sav->iv);
+		free(sav->iv, M_IPSEC_MISC);
 		sav->iv = NULL;
 	}
+}
 
-	KFREE(sav);
+/*
+ * free() SA variable entry.
+ */
+static void
+key_delsav(sav)
+	struct secasvar *sav;

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list