Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 23 Nov 2016 08:54:51 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r309040 - projects/ipsec/sys/netipsec
Message-ID:  <201611230854.uAN8spRg032784@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Wed Nov 23 08:54:51 2016
New Revision: 309040
URL: https://svnweb.freebsd.org/changeset/base/309040

Log:
  Rework ACQ list functions.
  
  Move all ACQ logic into ACQ releated functions. Add two hash tables
  to speedup lookup.  Make key_getacq() to return ACQ sequence number
  instead of secacq structure. When we already have ACQ for given
  secasindex, do not send SADB_ACQUIRE for each packet. Send SADB_ACQUIRE
  only for first packet and then repeat it for each V_key_blockacq_count
  packets. If ACQ doesn't exists, key_getacq() will use key_newacq().
  Add key_acqreset() function to reset counter of blocked packets and
  renew ACQ's TTL. Add key_acqdone() function to force ACQ expiration.

Modified:
  projects/ipsec/sys/netipsec/key.c

Modified: projects/ipsec/sys/netipsec/key.c
==============================================================================
--- projects/ipsec/sys/netipsec/key.c	Wed Nov 23 08:30:02 2016	(r309039)
+++ projects/ipsec/sys/netipsec/key.c	Wed Nov 23 08:54:51 2016	(r309040)
@@ -265,16 +265,40 @@ static struct mtx regtree_lock;
 #define	REGTREE_UNLOCK()	mtx_unlock(&regtree_lock)
 #define	REGTREE_LOCK_ASSERT()	mtx_assert(&regtree_lock, MA_OWNED)
 
-static VNET_DEFINE(LIST_HEAD(_acqtree, secacq), acqtree); /* acquiring list */
+/* Acquiring list */
+LIST_HEAD(secacq_list, secacq);
+static VNET_DEFINE(struct secacq_list, acqtree);
 #define	V_acqtree		VNET(acqtree)
 static struct mtx acq_lock;
 #define	ACQ_LOCK_INIT() \
-	mtx_init(&acq_lock, "acqtree", "fast ipsec acquire list", MTX_DEF)
+    mtx_init(&acq_lock, "acqtree", "ipsec SA acquiring list", MTX_DEF)
 #define	ACQ_LOCK_DESTROY()	mtx_destroy(&acq_lock)
 #define	ACQ_LOCK()		mtx_lock(&acq_lock)
 #define	ACQ_UNLOCK()		mtx_unlock(&acq_lock)
 #define	ACQ_LOCK_ASSERT()	mtx_assert(&acq_lock, MA_OWNED)
 
+/* Hash table for lookup in ACQ list using SA addresses */
+static VNET_DEFINE(struct secacq_list *, acqaddrhashtbl);
+static VNET_DEFINE(u_long, acqaddrhash_mask);
+#define	V_acqaddrhashtbl	VNET(acqaddrhashtbl)
+#define	V_acqaddrhash_mask	VNET(acqaddrhash_mask)
+
+/* Hash table for lookup in ACQ list using SEQ number */
+static VNET_DEFINE(struct secacq_list *, acqseqhashtbl);
+static VNET_DEFINE(u_long, acqseqhash_mask);
+#define	V_acqseqhashtbl		VNET(acqseqhashtbl)
+#define	V_acqseqhash_mask	VNET(acqseqhash_mask)
+
+#define	ACQHASH_NHASH_LOG2	7
+#define	ACQHASH_NHASH		(1 << ACQHASH_NHASH_LOG2)
+#define	ACQADDRHASH_HASHVAL(saidx)	\
+    (key_saidxhash(saidx) & V_acqaddrhash_mask)
+#define	ACQSEQHASH_HASHVAL(seq)		\
+    (key_u32hash(seq) & V_acqseqhash_mask)
+#define	ACQADDRHASH_HASH(saidx)	\
+    &V_acqaddrhashtbl[ACQADDRHASH_HASHVAL(saidx)]
+#define	ACQSEQHASH_HASH(seq)	\
+    &V_acqseqhashtbl[ACQSEQHASH_HASHVAL(seq)]
 							/* SP acquiring list */
 static VNET_DEFINE(LIST_HEAD(_spacqtree, secspacq), spacqtree);
 #define	V_spacqtree		VNET(spacqtree)
@@ -4270,13 +4294,16 @@ key_flush_acq(time_t now)
 
 	/* ACQ tree */
 	ACQ_LOCK();
-	for (acq = LIST_FIRST(&V_acqtree); acq != NULL; acq = nextacq) {
+	acq = LIST_FIRST(&V_acqtree);
+	while (acq != NULL) {
 		nextacq = LIST_NEXT(acq, chain);
-		if (now - acq->created > V_key_blockacq_lifetime
-		 && __LIST_CHAINED(acq)) {
+		if (now - acq->created > V_key_blockacq_lifetime) {
 			LIST_REMOVE(acq, chain);
+			LIST_REMOVE(acq, addrhash);
+			LIST_REMOVE(acq, seqhash);
 			free(acq, M_IPSEC_SAQ);
 		}
+		acq = nextacq;
 	}
 	ACQ_UNLOCK();
 }
@@ -6021,34 +6048,122 @@ key_newacq(const struct secasindex *said
 	return newacq;
 }
 
-static struct secacq *
-key_getacq(const struct secasindex *saidx)
+static uint32_t
+key_newacq(const struct secasindex *saidx, int *perror)
 {
 	struct secacq *acq;
+	uint32_t seq;
 
+	acq = malloc(sizeof(*acq), M_IPSEC_SAQ, M_NOWAIT | M_ZERO);
+	if (acq == NULL) {
+		ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__));
+		*perror = ENOBUFS;
+		return (0);
+	}
+
+	/* copy secindex */
+	bcopy(saidx, &acq->saidx, sizeof(acq->saidx));
+	acq->created = time_second;
+	acq->count = 0;
+
+	/* add to acqtree */
 	ACQ_LOCK();
-	LIST_FOREACH(acq, &V_acqtree, chain) {
-		if (key_cmpsaidx(saidx, &acq->saidx, CMP_EXACTLY))
+	seq = acq->seq = (V_acq_seq == ~0 ? 1 : ++V_acq_seq);
+	LIST_INSERT_HEAD(&V_acqtree, acq, chain);
+	LIST_INSERT_HEAD(ACQADDRHASH_HASH(saidx), acq, addrhash);
+	LIST_INSERT_HEAD(ACQSEQHASH_HASH(seq), acq, seqhash);
+	ACQ_UNLOCK();
+	*perror = 0;
+	return (seq);
+}
+
+static uint32_t
+key_getacq(const struct secasindex *saidx, int *perror)
+{
+	struct secacq *acq;
+	uint32_t seq;
+
+	ACQ_LOCK();
+	LIST_FOREACH(acq, ACQADDRHASH_HASH(saidx), addrhash) {
+		if (key_cmpsaidx(&acq->saidx, saidx, CMP_EXACTLY)) {
+			if (acq->count > V_key_blockacq_count) {
+				/*
+				 * Reset counter and send message.
+				 * Also reset created time to keep ACQ for
+				 * this saidx.
+				 */
+				acq->created = time_second;
+				acq->count = 0;
+				seq = acq->seq;
+			} else {
+				/*
+				 * Increment counter and do nothing.
+				 * We send SADB_ACQUIRE message only
+				 * for each V_key_blockacq_count packet.
+				 */
+				acq->count++;
+				seq = 0;
+			}
 			break;
+		}
 	}
 	ACQ_UNLOCK();
-
-	return acq;
+	if (acq != NULL) {
+		*perror = 0;
+		return (seq);
+	}
+	/* allocate new  entry */
+	return (key_newacq(saidx, perror));
 }
 
-static struct secacq *
-key_getacqbyseq(u_int32_t seq)
+static int
+key_acqreset(uint32_t seq)
 {
 	struct secacq *acq;
 
 	ACQ_LOCK();
-	LIST_FOREACH(acq, &V_acqtree, chain) {
-		if (acq->seq == seq)
+	LIST_FOREACH(acq, ACQSEQHASH_HASH(seq), seqhash) {
+		if (acq->seq == seq) {
+			acq->count = 0;
+			acq->created = time_second;
 			break;
+		}
 	}
 	ACQ_UNLOCK();
+	if (acq == NULL)
+		return (ESRCH);
+	return (0);
+}
+/*
+ * Mark ACQ entry as stale to remove it in key_flush_acq().
+ * Called after successful SADB_GETSPI message.
+ */
+static int
+key_acqdone(const struct secasindex *saidx, uint32_t seq)
+{
+	struct secacq *acq;
 
-	return acq;
+	ACQ_LOCK();
+	LIST_FOREACH(acq, ACQSEQHASH_HASH(seq), seqhash) {
+		if (acq->seq == seq)
+			break;
+	}
+	if (acq != NULL) {
+		if (key_cmpsaidx(&acq->saidx, saidx, CMP_EXACTLY) == 0) {
+			ipseclog((LOG_DEBUG,
+			    "%s: Mismatched saidx for ACQ %u", __func__, seq));
+			acq = NULL;
+		} else {
+			acq->created = 0;
+		}
+	} else {
+		ipseclog((LOG_DEBUG,
+		    "%s: ACQ %u is not found.", __func__, seq));
+	}
+	ACQ_UNLOCK();
+	if (acq == NULL)
+		return (ESRCH);
+	return (0);
 }
 
 static struct secspacq *
@@ -7285,11 +7400,15 @@ key_init(void)
 	    sizeof(uint64_t) * 2, NULL, NULL, NULL, NULL,
 	    UMA_ALIGN_PTR, UMA_ZONE_PCPU);
 
-	LIST_INIT(&V_sahtree);
+	TAILQ_INIT(&V_sahtree);
 	V_sphashtbl = hashinit(SPHASH_NHASH, M_IPSEC_SP, &V_sphash_mask);
 	V_savhashtbl = hashinit(SAVHASH_NHASH, M_IPSEC_SA, &V_savhash_mask);
 	V_sahaddrhashtbl = hashinit(SAHHASH_NHASH, M_IPSEC_SAH,
 	    &V_sahaddrhash_mask);
+	V_acqaddrhashtbl = hashinit(ACQHASH_NHASH, M_IPSEC_SAQ,
+	    &V_acqaddrhash_mask);
+	V_acqseqhashtbl = hashinit(ACQHASH_NHASH, M_IPSEC_SAQ,
+	    &V_acqseqhash_mask);
 
 	for (i = 0; i <= SADB_SATYPE_MAX; i++)
 		LIST_INIT(&V_regtree[i]);
@@ -7370,12 +7489,12 @@ key_destroy(void)
 	REGTREE_UNLOCK();
 
 	ACQ_LOCK();
-	for (acq = LIST_FIRST(&V_acqtree); acq != NULL; acq = nextacq) {
+	acq = LIST_FIRST(&V_acqtree);
+	while (acq != NULL) {
 		nextacq = LIST_NEXT(acq, chain);
-		if (__LIST_CHAINED(acq)) {
-			LIST_REMOVE(acq, chain);
-			free(acq, M_IPSEC_SAQ);
-		}
+		LIST_REMOVE(acq, chain);
+		free(acq, M_IPSEC_SAQ);
+		acq = nextacq;
 	}
 	ACQ_UNLOCK();
 
@@ -7389,6 +7508,8 @@ key_destroy(void)
 		}
 	}
 	SPACQ_UNLOCK();
+	hashdestroy(V_acqaddrhashtbl, M_IPSEC_SAQ, V_acqaddrhash_mask);
+	hashdestroy(V_acqseqhashtbl, M_IPSEC_SAQ, V_acqseqhash_mask);
 	uma_zdestroy(V_key_lft_zone);
 }
 #endif



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