Module Name:    src
Committed By:   martin
Date:           Wed Mar  7 13:46:42 UTC 2018

Modified Files:
        src/sys/netipsec [netbsd-8]: key.c keydb.h

Log Message:
Pull up following revision(s) (requested by ozaki-r in ticket #609):
        sys/netipsec/key.c: revision 1.249
        sys/netipsec/keydb.h: revision 1.21
Avoid data races on lifetime counters by using percpu(9)
We don't make them percpu(9) directly because the structure is exposed to
userland and we don't want to break ABI.  So we add another member variable
for percpu(9) and use it internally.  When we export them to userland, they
are converted to the original format.


To generate a diff of this commit:
cvs rdiff -u -r1.163.2.6 -r1.163.2.7 src/sys/netipsec/key.c
cvs rdiff -u -r1.15.2.1 -r1.15.2.2 src/sys/netipsec/keydb.h

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

Modified files:

Index: src/sys/netipsec/key.c
diff -u src/sys/netipsec/key.c:1.163.2.6 src/sys/netipsec/key.c:1.163.2.7
--- src/sys/netipsec/key.c:1.163.2.6	Sun Feb 11 21:17:34 2018
+++ src/sys/netipsec/key.c	Wed Mar  7 13:46:41 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: key.c,v 1.163.2.6 2018/02/11 21:17:34 snj Exp $	*/
+/*	$NetBSD: key.c,v 1.163.2.7 2018/03/07 13:46:41 martin Exp $	*/
 /*	$FreeBSD: src/sys/netipsec/key.c,v 1.3.2.3 2004/02/14 22:23:23 bms Exp $	*/
 /*	$KAME: key.c,v 1.191 2001/06/27 10:46:49 sakane Exp $	*/
 
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.163.2.6 2018/02/11 21:17:34 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.163.2.7 2018/03/07 13:46:41 martin Exp $");
 
 /*
  * This code is referred to RFC 2367
@@ -788,6 +788,26 @@ static struct callout	key_timehandler_ch
 static struct workqueue	*key_timehandler_wq;
 static struct work	key_timehandler_wk;
 
+/*
+ * Utilities for percpu counters for sadb_lifetime_allocations and
+ * sadb_lifetime_bytes.
+ */
+#define LIFETIME_COUNTER_ALLOCATIONS	0
+#define LIFETIME_COUNTER_BYTES		1
+#define LIFETIME_COUNTER_SIZE		2
+
+typedef uint64_t lifetime_counters_t[LIFETIME_COUNTER_SIZE];
+
+static void
+key_sum_lifetime_counters(void *p, void *arg, struct cpu_info *ci __unused)
+{
+	lifetime_counters_t *one = p;
+	lifetime_counters_t *sum = arg;
+
+	(*sum)[LIFETIME_COUNTER_ALLOCATIONS] += (*one)[LIFETIME_COUNTER_ALLOCATIONS];
+	(*sum)[LIFETIME_COUNTER_BYTES] += (*one)[LIFETIME_COUNTER_BYTES];
+}
+
 u_int
 key_sp_refcnt(const struct secpolicy *sp)
 {
@@ -3260,6 +3280,8 @@ key_newsav(struct mbuf *m, const struct 
 		/* We don't allow lft_c to be NULL */
 		newsav->lft_c = kmem_zalloc(sizeof(struct sadb_lifetime),
 		    KM_SLEEP);
+		newsav->lft_c_counters_percpu =
+		    percpu_alloc(sizeof(lifetime_counters_t));
 	}
 
 	/* reset created */
@@ -3470,6 +3492,10 @@ key_freesaval(struct secasvar *sav)
 		kmem_intr_free(sav->key_auth, sav->key_auth_len);
 	if (sav->key_enc != NULL)
 		kmem_intr_free(sav->key_enc, sav->key_enc_len);
+	if (sav->lft_c_counters_percpu != NULL) {
+		percpu_free(sav->lft_c_counters_percpu,
+		    sizeof(lifetime_counters_t));
+	}
 	if (sav->lft_c != NULL)
 		kmem_intr_free(sav->lft_c, sizeof(*(sav->lft_c)));
 	if (sav->lft_h != NULL)
@@ -3638,6 +3664,8 @@ key_setsaval(struct secasvar *sav, struc
 	sav->lft_c->sadb_lifetime_addtime = time_uptime;
 	sav->lft_c->sadb_lifetime_usetime = 0;
 
+	sav->lft_c_counters_percpu = percpu_alloc(sizeof(lifetime_counters_t));
+
 	/* lifetimes for HARD and SOFT */
     {
 	const struct sadb_lifetime *lft0;
@@ -3821,7 +3849,9 @@ key_setdumpsa(struct secasvar *sav, u_in
 			p = sav->key_enc;
 			break;
 
-		case SADB_EXT_LIFETIME_CURRENT:
+		case SADB_EXT_LIFETIME_CURRENT: {
+			lifetime_counters_t sum = {0};
+
 			KASSERT(sav->lft_c != NULL);
 			l = PFKEY_UNUNIT64(((struct sadb_ext *)sav->lft_c)->sadb_ext_len);
 			memcpy(&lt, sav->lft_c, sizeof(struct sadb_lifetime));
@@ -3829,8 +3859,15 @@ key_setdumpsa(struct secasvar *sav, u_in
 			    time_mono_to_wall(lt.sadb_lifetime_addtime);
 			lt.sadb_lifetime_usetime =
 			    time_mono_to_wall(lt.sadb_lifetime_usetime);
+			percpu_foreach(sav->lft_c_counters_percpu,
+			    key_sum_lifetime_counters, sum);
+			lt.sadb_lifetime_allocations =
+			    sum[LIFETIME_COUNTER_ALLOCATIONS];
+			lt.sadb_lifetime_bytes =
+			    sum[LIFETIME_COUNTER_BYTES];
 			p = &lt;
 			break;
+		    }
 
 		case SADB_EXT_LIFETIME_HARD:
 			if (!sav->lft_h)
@@ -4860,9 +4897,17 @@ restart:
 			 * when new SA is installed.  Caution when it's
 			 * installed too big lifetime by time.
 			 */
-			else if (sav->lft_s->sadb_lifetime_bytes != 0 &&
-			         sav->lft_s->sadb_lifetime_bytes <
-			         sav->lft_c->sadb_lifetime_bytes) {
+			else {
+				uint64_t lft_c_bytes = 0;
+				lifetime_counters_t sum = {0};
+
+				percpu_foreach(sav->lft_c_counters_percpu,
+				    key_sum_lifetime_counters, sum);
+				lft_c_bytes = sum[LIFETIME_COUNTER_BYTES];
+
+				if (sav->lft_s->sadb_lifetime_bytes == 0 ||
+				    sav->lft_s->sadb_lifetime_bytes >= lft_c_bytes)
+					continue;
 
 				key_sa_chgstate(sav, SADB_SASTATE_DYING);
 				mutex_exit(&key_sad.lock);
@@ -4910,9 +4955,18 @@ restart:
 			}
 #endif
 			/* check HARD lifetime by bytes */
-			else if (sav->lft_h->sadb_lifetime_bytes != 0 &&
-			         sav->lft_h->sadb_lifetime_bytes <
-			         sav->lft_c->sadb_lifetime_bytes) {
+			else {
+				uint64_t lft_c_bytes = 0;
+				lifetime_counters_t sum = {0};
+
+				percpu_foreach(sav->lft_c_counters_percpu,
+				    key_sum_lifetime_counters, sum);
+				lft_c_bytes = sum[LIFETIME_COUNTER_BYTES];
+
+				if (sav->lft_h->sadb_lifetime_bytes == 0 ||
+				    sav->lft_h->sadb_lifetime_bytes >= lft_c_bytes)
+					continue;
+
 				key_sa_chgstate(sav, SADB_SASTATE_DEAD);
 				goto restart_sav_DYING;
 			}
@@ -7181,6 +7235,7 @@ key_expire(struct secasvar *sav)
 	int len;
 	int error = -1;
 	struct sadb_lifetime *lt;
+	lifetime_counters_t sum = {0};
 
 	/* XXX: Why do we lock ? */
 	s = splsoftnet();	/*called from softclock()*/
@@ -7213,8 +7268,10 @@ key_expire(struct secasvar *sav)
 	lt = mtod(m, struct sadb_lifetime *);
 	lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime));
 	lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
-	lt->sadb_lifetime_allocations = sav->lft_c->sadb_lifetime_allocations;
-	lt->sadb_lifetime_bytes = sav->lft_c->sadb_lifetime_bytes;
+	percpu_foreach(sav->lft_c_counters_percpu,
+	    key_sum_lifetime_counters, sum);
+	lt->sadb_lifetime_allocations = sum[LIFETIME_COUNTER_ALLOCATIONS];
+	lt->sadb_lifetime_bytes = sum[LIFETIME_COUNTER_BYTES];
 	lt->sadb_lifetime_addtime =
 	    time_mono_to_wall(sav->lft_c->sadb_lifetime_addtime);
 	lt->sadb_lifetime_usetime =
@@ -8174,16 +8231,19 @@ key_getuserfqdn(void)
 void
 key_sa_recordxfer(struct secasvar *sav, struct mbuf *m)
 {
+	lifetime_counters_t *counters;
 
 	KASSERT(sav != NULL);
 	KASSERT(sav->lft_c != NULL);
 	KASSERT(m != NULL);
 
+	counters = percpu_getref(sav->lft_c_counters_percpu);
+
 	/*
 	 * XXX Currently, there is a difference of bytes size
 	 * between inbound and outbound processing.
 	 */
-	sav->lft_c->sadb_lifetime_bytes += m->m_pkthdr.len;
+	(*counters)[LIFETIME_COUNTER_BYTES] += m->m_pkthdr.len;
 	/* to check bytes lifetime is done in key_timehandler(). */
 
 	/*
@@ -8191,9 +8251,11 @@ key_sa_recordxfer(struct secasvar *sav, 
 	 * sadb_lifetime_allocations.  We increment the variable
 	 * whenever {esp,ah}_{in,out}put is called.
 	 */
-	sav->lft_c->sadb_lifetime_allocations++;
+	(*counters)[LIFETIME_COUNTER_ALLOCATIONS]++;
 	/* XXX check for expires? */
 
+	percpu_putref(sav->lft_c_counters_percpu);
+
 	/*
 	 * NOTE: We record CURRENT sadb_lifetime_usetime by using wall clock,
 	 * in seconds.  HARD and SOFT lifetime are measured by the time

Index: src/sys/netipsec/keydb.h
diff -u src/sys/netipsec/keydb.h:1.15.2.1 src/sys/netipsec/keydb.h:1.15.2.2
--- src/sys/netipsec/keydb.h:1.15.2.1	Sat Oct 21 19:43:54 2017
+++ src/sys/netipsec/keydb.h	Wed Mar  7 13:46:41 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: keydb.h,v 1.15.2.1 2017/10/21 19:43:54 snj Exp $	*/
+/*	$NetBSD: keydb.h,v 1.15.2.2 2018/03/07 13:46:41 martin Exp $	*/
 /*	$FreeBSD: src/sys/netipsec/keydb.h,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $	*/
 /*	$KAME: keydb.h,v 1.14 2000/08/02 17:58:26 sakane Exp $	*/
 
@@ -37,6 +37,7 @@
 #ifdef _KERNEL
 
 #include <sys/localcount.h>
+#include <sys/percpu.h>
 
 #include <netipsec/key_var.h>
 #include <net/route.h>
@@ -118,6 +119,9 @@ struct secasvar {
 	struct sadb_lifetime *lft_h;	/* HARD lifetime */
 	struct sadb_lifetime *lft_s;	/* SOFT lifetime */
 
+	/* percpu counters for lft_c->sadb_lifetime_{allocations,bytes} */
+	percpu_t *lft_c_counters_percpu;
+
 	u_int32_t seq;			/* sequence number */
 	pid_t pid;			/* message's pid */
 

Reply via email to