Source-Changes-HG archive

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

[src/trunk]: src/sys/netipsec MP-ify SAD (key_sad.sahlist and sah entries)



details:   https://anonhg.NetBSD.org/src/rev/46e9627edb1c
branches:  trunk
changeset: 355648:46e9627edb1c
user:      ozaki-r <ozaki-r%NetBSD.org@localhost>
date:      Tue Aug 08 04:17:34 2017 +0000

description:
MP-ify SAD (key_sad.sahlist and sah entries)

localcount(9) is used to protect key_sad.sahlist and sah entries
as well as SPD (and will be used for SAD sav).

Please read the locking notes of SAD for more details.

diffstat:

 sys/netipsec/key.c   |  296 ++++++++++++++++++++++++++++++++++++++------------
 sys/netipsec/keydb.h |    5 +-
 2 files changed, 229 insertions(+), 72 deletions(-)

diffs (truncated from 691 to 300 lines):

diff -r 253d1e6d015d -r 46e9627edb1c sys/netipsec/key.c
--- a/sys/netipsec/key.c        Tue Aug 08 03:58:43 2017 +0000
+++ b/sys/netipsec/key.c        Tue Aug 08 04:17:34 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: key.c,v 1.215 2017/08/08 01:56:49 ozaki-r Exp $        */
+/*     $NetBSD: key.c,v 1.216 2017/08/08 04:17:34 ozaki-r 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.215 2017/08/08 01:56:49 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.216 2017/08/08 04:17:34 ozaki-r Exp $");
 
 /*
  * This code is referd to RFC 2367
@@ -198,12 +198,35 @@
  *     until GC by the timer
  */
 /*
+ * Locking notes on SAD:
+ * - Data structures
+ *   - SAs are managed by the list called key_sad.sahlist and sav lists of sah
+ *     entries
+ *   - A sah has sav lists for each SA state
+ *   - Multiple sahs with the same saidx can exist
+ *     - Only one entry has MATURE state and others should be DEAD
+ *     - DEAD entries are just ignored from searching
+ * - Modifications to the key_sad.sahlist must be done with holding key_sad.lock
+ *   which is a adaptive mutex
+ * - Read accesses to the key_sad.sahlist must be in pserialize(9) read sections
+ * - sah's lifetime is managed by localcount(9)
+ * - Getting an sah entry
+ *   - We get an SP from the key_spd.splist
+ *     - Must iterate the list and increment the reference count of a found sah
+ *       (by key_sah_ref) in a pserialize read section
+ *   - A gotten sah must be released after use by key_sah_unref
+ * - An sah is destroyed when its state become DEAD and no sav is
+ *   listed to the sah
+ *   - The destruction is done only in the timer (see key_timehandler_sad)
+ */
+/*
  * Locking notes on misc data:
  * - All lists of key_misc are protected by key_misc.lock
  *   - key_misc.lock must be held even for read accesses
  */
 
-static pserialize_t key_psz __read_mostly;
+static pserialize_t key_spd_psz __read_mostly;
+static pserialize_t key_sad_psz __read_mostly;
 
 /* SPD */
 static struct {
@@ -220,6 +243,7 @@
 /* SAD */
 static struct {
        kmutex_t lock;
+       kcondvar_t cv;
        struct pslist_head sahlist;
 } key_sad __cacheline_aligned;
 
@@ -614,13 +638,18 @@
 static u_int key_getspreqmsglen (const struct secpolicy *);
 static int key_spdexpire (struct secpolicy *);
 static struct secashead *key_newsah (const struct secasindex *);
-static void key_delsah (struct secashead *);
+static void key_unlink_sah(struct secashead *);
+static void key_destroy_sah(struct secashead *);
+static bool key_sah_has_sav(struct secashead *);
+static void key_sah_ref(struct secashead *);
+static void key_sah_unref(struct secashead *);
 static struct secasvar *key_newsav(struct mbuf *,
        const struct sadb_msghdr *, int *, const char*, int);
 #define        KEY_NEWSAV(m, sadb, e)                          \
        key_newsav(m, sadb, e, __func__, __LINE__)
 static void key_delsav (struct secasvar *);
 static struct secashead *key_getsah(const struct secasindex *, int);
+static struct secashead *key_getsah_ref(const struct secasindex *, int);
 static bool key_checkspidup(const struct secasindex *, u_int32_t);
 static struct secasvar *key_getsavbyspi (struct secashead *, u_int32_t);
 static int key_setsaval (struct secasvar *, struct mbuf *,
@@ -800,7 +829,7 @@
 
 #ifdef NET_MPSAFE
        KASSERT(mutex_ownable(softnet_lock));
-       pserialize_perform(key_psz);
+       pserialize_perform(key_spd_psz);
 #endif
 
        localcount_drain(&sp->localcount, &key_spd.cv, &key_spd.lock);
@@ -2954,9 +2983,13 @@
                PSLIST_INIT(&newsah->savlist[i]);
        newsah->saidx = *saidx;
 
-       /* add to saidxtree */
+       localcount_init(&newsah->localcount);
+       /* Take a reference for the caller */
+       localcount_acquire(&newsah->localcount);
+
+       /* Add to the sah list */
+       SAHLIST_ENTRY_INIT(newsah);
        newsah->state = SADB_SASTATE_MATURE;
-       SAHLIST_ENTRY_INIT(newsah);
        mutex_enter(&key_sad.lock);
        SAHLIST_WRITER_INSERT_HEAD(newsah);
        mutex_exit(&key_sad.lock);
@@ -2964,51 +2997,55 @@
        return newsah;
 }
 
-/*
- * delete SA index and all SA registerd.
- */
+static bool
+key_sah_has_sav(struct secashead *sah)
+{
+       u_int state;
+
+       KASSERT(mutex_owned(&key_sad.lock));
+
+       SASTATE_ANY_FOREACH(state) {
+               if (!SAVLIST_WRITER_EMPTY(sah, state))
+                       return true;
+       }
+
+       return false;
+}
+
 static void
-key_delsah(struct secashead *sah)
-{
-       struct secasvar *sav;
-       u_int state;
-       int s;
-       int zombie = 0;
+key_unlink_sah(struct secashead *sah)
+{
 
        KASSERT(!cpu_softintr_p());
-       KASSERT(sah != NULL);
-
-       s = splsoftnet();
-
-       /* searching all SA registerd in the secindex. */
-       SASTATE_ANY_FOREACH(state) {
-               SAVLIST_READER_FOREACH(sav, sah, state) {
-                       /* give up to delete this sa */
-                       zombie++;
-               }
-       }
-
-       /* don't delete sah only if there are savs. */
-       if (zombie) {
-               splx(s);
-               return;
-       }
+       KASSERT(mutex_owned(&key_sad.lock));
+       KASSERT(sah->state == SADB_SASTATE_DEAD);
+
+       /* Remove from the sah list */
+       SAHLIST_WRITER_REMOVE(sah);
+
+#ifdef NET_MPSAFE
+       KASSERT(mutex_ownable(softnet_lock));
+       pserialize_perform(key_sad_psz);
+#endif
+
+       localcount_drain(&sah->localcount, &key_sad.cv, &key_sad.lock);
+}
+
+static void
+key_destroy_sah(struct secashead *sah)
+{
 
        rtcache_free(&sah->sa_route);
 
-       /* remove from tree of SA index */
-       SAHLIST_WRITER_REMOVE(sah);
+       SAHLIST_ENTRY_DESTROY(sah);
+       localcount_fini(&sah->localcount);
 
        if (sah->idents != NULL)
                kmem_free(sah->idents, sah->idents_len);
        if (sah->identd != NULL)
                kmem_free(sah->identd, sah->identd_len);
 
-       SAHLIST_ENTRY_DESTROY(sah);
        kmem_free(sah, sizeof(*sah));
-
-       splx(s);
-       return;
 }
 
 /*
@@ -3136,7 +3173,32 @@
 }
 
 /*
- * search SAD.
+ * Must be called in a pserialize read section. A held sah
+ * must be released by key_sah_unref after use.
+ */
+static void
+key_sah_ref(struct secashead *sah)
+{
+
+       localcount_acquire(&sah->localcount);
+}
+
+/*
+ * Must be called without holding key_sad.lock because the lock
+ * would be held in localcount_release.
+ */
+static void
+key_sah_unref(struct secashead *sah)
+{
+
+       KDASSERT(mutex_ownable(&key_sad.lock));
+
+       localcount_release(&sah->localcount, &key_sad.cv, &key_sad.lock);
+}
+
+/*
+ * Search SAD and return sah. Must be called in a pserialize
+ * read section.
  * OUT:
  *     NULL    : not found
  *     others  : found, pointer to a SA.
@@ -3157,6 +3219,28 @@
 }
 
 /*
+ * Search SAD and return sah. If sah is returned, the caller must call
+ * key_sah_unref to releaset a reference.
+ * OUT:
+ *     NULL    : not found
+ *     others  : found, pointer to a SA.
+ */
+static struct secashead *
+key_getsah_ref(const struct secasindex *saidx, int flag)
+{
+       struct secashead *sah;
+       int s;
+
+       s = pserialize_read_enter();
+       sah = key_getsah(saidx, flag);
+       if (sah != NULL)
+               key_sah_ref(sah);
+       pserialize_read_exit(s);
+
+       return sah;
+}
+
+/*
  * check not to be duplicated SPI.
  * NOTE: this function is too slow due to searching all SAD.
  * OUT:
@@ -3168,6 +3252,7 @@
 {
        struct secashead *sah;
        struct secasvar *sav;
+       int s;
 
        /* check address family */
        if (saidx->src.sa.sa_family != saidx->dst.sa.sa_family) {
@@ -3176,15 +3261,18 @@
        }
 
        /* check all SAD */
+       s = pserialize_read_enter();
        SAHLIST_READER_FOREACH(sah) {
                if (!key_ismyaddr((struct sockaddr *)&sah->saidx.dst))
                        continue;
                sav = key_getsavbyspi(sah, spi);
                if (sav != NULL) {
+                       pserialize_read_exit(s);
                        KEY_SA_UNREF(&sav);
                        return true;
                }
        }
+       pserialize_read_exit(s);
 
        return false;
 }
@@ -4594,15 +4682,28 @@
 key_timehandler_sad(time_t now)
 {
        struct secashead *sah;
-       struct secasvar *sav;
+       int s;
 
 restart:
+       mutex_enter(&key_sad.lock);
        SAHLIST_WRITER_FOREACH(sah) {
-               /* if sah has been dead, then delete it and process next sah. */
-               if (sah->state == SADB_SASTATE_DEAD) {
-                       key_delsah(sah);
+               /* If sah has been dead and has no sav, then delete it */



Home | Main Index | Thread Index | Old Index