Hi,

Hrvoje had some problems with to many network packets in the unlimited
queues of the crypto task queues.

Removing the queues and just calling the crypto operations directly
improves throughput by 20%.  See the sys-crypto-dispatch-klock
column.
http://bluhm.genua.de/perform/results/2021-07-21T06:50:10Z/perform.html
http://bluhm.genua.de/perform/results/2021-07-21T06:50:10Z/gnuplot/ipsec.html

Even more important the functions inherit the locks and we have
much less contention.
With task queue:
http://bluhm.genua.de/perform/results/2021-07-21T06:50:10Z/2021-07-21T00%3A00%3A00Z/btrace/ssh_perform%40lt13_iperf3_-c10.4.56.36_-P10_-t10-btrace-kstack.0.svg
Direct call:
http://bluhm.genua.de/perform/results/2021-07-21T06:50:10Z/patch-sys-crypto-dispatch-klock.1/btrace/ssh_perform%40lt13_iperf3_-c10.4.56.36_-P10_-t10-btrace-kstack.0.svg

Note that I have software crypto.  Softcrypto is so expensive that
network operations are no longer visible.  Before the latter were
spinning for kernel lock.

I would be interested in results with AES-NI.  Maybe we needed the
queues when sleeping hardware drivers were used and softnet was
running as soft interrupt.

This diff makes IPsec faster, less complex, more reliable, and more
MP friendly.

There is also a small bugfix.  After crypto dispatch error we should
goto drop to free the packet.  But this error should happen anyway.

ok?

bluhm

Index: crypto/crypto.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/crypto/crypto.c,v
retrieving revision 1.84
diff -u -p -r1.84 crypto.c
--- crypto/crypto.c     21 Jul 2021 11:11:41 -0000      1.84
+++ crypto/crypto.c     21 Jul 2021 16:58:57 -0000
@@ -387,23 +387,32 @@ crypto_unregister(u_int32_t driverid, in
 int
 crypto_dispatch(struct cryptop *crp)
 {
-       struct taskq *tq = crypto_taskq;
-       int error = 0, s;
+       int error = 0, lock = 1, s;
        u_int32_t hid;
 
        s = splvm();
        hid = (crp->crp_sid >> 32) & 0xffffffff;
        if (hid < crypto_drivers_num) {
                if (crypto_drivers[hid].cc_flags & CRYPTOCAP_F_MPSAFE)
-                       tq = crypto_taskq_mpsafe;
+                       lock = 0;
        }
        splx(s);
 
-       if ((crp->crp_flags & CRYPTO_F_NOQUEUE) == 0) {
+       /* XXXSMP crypto_invoke() is not MP safe */
+       lock = 1;
+
+       if (crp->crp_flags & CRYPTO_F_NOQUEUE) {
+               if (lock)
+                       KERNEL_LOCK();
+               error = crypto_invoke(crp);
+               if (lock)
+                       KERNEL_UNLOCK();
+       } else {
+               struct taskq *tq;
+
+               tq = lock ? crypto_taskq : crypto_taskq_mpsafe;
                task_set(&crp->crp_task, (void (*))crypto_invoke, crp);
                task_add(tq, &crp->crp_task);
-       } else {
-               error = crypto_invoke(crp);
        }
 
        return error;
@@ -424,6 +433,8 @@ crypto_invoke(struct cryptop *crp)
        if (crp == NULL || crp->crp_callback == NULL)
                return EINVAL;
 
+       KERNEL_ASSERT_LOCKED();
+
        s = splvm();
        if (crp->crp_ndesc < 1 || crypto_drivers == NULL) {
                crp->crp_etype = EINVAL;
@@ -535,11 +546,16 @@ void
 crypto_done(struct cryptop *crp)
 {
        crp->crp_flags |= CRYPTO_F_DONE;
+
        if (crp->crp_flags & CRYPTO_F_NOQUEUE) {
                /* not from the crypto queue, wakeup the userland process */
                crp->crp_callback(crp);
        } else {
+               struct taskq *tq;
+
+               tq = (crp->crp_flags & CRYPTO_F_MPSAFE) ?
+                   crypto_taskq_mpsafe : crypto_taskq;
                task_set(&crp->crp_task, (void (*))crp->crp_callback, crp);
-               task_add(crypto_taskq, &crp->crp_task);
+               task_add(tq, &crp->crp_task);
        }
 }
Index: crypto/cryptodev.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/crypto/cryptodev.h,v
retrieving revision 1.73
diff -u -p -r1.73 cryptodev.h
--- crypto/cryptodev.h  9 Jul 2021 20:43:28 -0000       1.73
+++ crypto/cryptodev.h  21 Jul 2021 16:58:57 -0000
@@ -171,6 +171,7 @@ struct cryptop {
 
 #define CRYPTO_F_IMBUF 0x0001  /* Input/output are mbuf chains, otherwise 
contig */
 #define CRYPTO_F_IOV   0x0002  /* Input/output are uio */
+#define CRYPTO_F_MPSAFE        0x0004  /* Do not use kernel lock for callback 
*/
 #define CRYPTO_F_NOQUEUE       0x0008  /* Don't use crypto queue/thread */
 #define CRYPTO_F_DONE  0x0010  /* request completed */
 
Index: netinet/ip_ah.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ah.c,v
retrieving revision 1.151
diff -u -p -r1.151 ip_ah.c
--- netinet/ip_ah.c     18 Jul 2021 14:38:20 -0000      1.151
+++ netinet/ip_ah.c     21 Jul 2021 16:58:57 -0000
@@ -684,7 +684,7 @@ ah_input(struct mbuf *m, struct tdb *tdb
 
        /* Crypto operation descriptor. */
        crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
-       crp->crp_flags = CRYPTO_F_IMBUF;
+       crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_MPSAFE;
        crp->crp_buf = (caddr_t)m;
        crp->crp_callback = ipsec_input_cb;
        crp->crp_sid = tdb->tdb_cryptoid;
@@ -699,9 +699,7 @@ ah_input(struct mbuf *m, struct tdb *tdb
        memcpy(&tc->tc_dst, &tdb->tdb_dst, sizeof(union sockaddr_union));
        tc->tc_rpl = tdb->tdb_rpl;
 
-       KERNEL_LOCK();
        error = crypto_dispatch(crp);
-       KERNEL_UNLOCK();
        return error;
 
  drop:
@@ -1134,7 +1132,7 @@ ah_output(struct mbuf *m, struct tdb *td
 
        /* Crypto operation descriptor. */
        crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
-       crp->crp_flags = CRYPTO_F_IMBUF;
+       crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_MPSAFE;
        crp->crp_buf = (caddr_t)m;
        crp->crp_callback = ipsec_output_cb;
        crp->crp_sid = tdb->tdb_cryptoid;
@@ -1148,9 +1146,7 @@ ah_output(struct mbuf *m, struct tdb *td
        tc->tc_rdomain = tdb->tdb_rdomain;
        memcpy(&tc->tc_dst, &tdb->tdb_dst, sizeof(union sockaddr_union));
 
-       KERNEL_LOCK();
        error = crypto_dispatch(crp);
-       KERNEL_UNLOCK();
        return error;
 
  drop:
Index: netinet/ip_esp.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_esp.c,v
retrieving revision 1.169
diff -u -p -r1.169 ip_esp.c
--- netinet/ip_esp.c    18 Jul 2021 14:38:20 -0000      1.169
+++ netinet/ip_esp.c    21 Jul 2021 16:58:57 -0000
@@ -498,7 +498,7 @@ esp_input(struct mbuf *m, struct tdb *td
 
        /* Crypto operation descriptor */
        crp->crp_ilen = m->m_pkthdr.len; /* Total input length */
-       crp->crp_flags = CRYPTO_F_IMBUF;
+       crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_MPSAFE;
        crp->crp_buf = (caddr_t)m;
        crp->crp_callback = ipsec_input_cb;
        crp->crp_sid = tdb->tdb_cryptoid;
@@ -528,9 +528,7 @@ esp_input(struct mbuf *m, struct tdb *td
                        crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
        }
 
-       KERNEL_LOCK();
        error = crypto_dispatch(crp);
-       KERNEL_UNLOCK();
        return error;
 
  drop:
@@ -983,7 +981,7 @@ esp_output(struct mbuf *m, struct tdb *t
 
        /* Crypto operation descriptor. */
        crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
-       crp->crp_flags = CRYPTO_F_IMBUF;
+       crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_MPSAFE;
        crp->crp_buf = (caddr_t)m;
        crp->crp_callback = ipsec_output_cb;
        crp->crp_opaque = (caddr_t)tc;
@@ -1015,9 +1013,7 @@ esp_output(struct mbuf *m, struct tdb *t
                        crda->crd_len = m->m_pkthdr.len - (skip + alen);
        }
 
-       KERNEL_LOCK();
        error = crypto_dispatch(crp);
-       KERNEL_UNLOCK();
        return error;
 
  drop:
Index: netinet/ip_ipcomp.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipcomp.c,v
retrieving revision 1.71
diff -u -p -r1.71 ip_ipcomp.c
--- netinet/ip_ipcomp.c 8 Jul 2021 21:07:19 -0000       1.71
+++ netinet/ip_ipcomp.c 21 Jul 2021 16:58:57 -0000
@@ -174,7 +174,7 @@ ipcomp_input(struct mbuf *m, struct tdb 
 
        /* Crypto operation descriptor */
        crp->crp_ilen = m->m_pkthdr.len - (skip + hlen);
-       crp->crp_flags = CRYPTO_F_IMBUF;
+       crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_MPSAFE;
        crp->crp_buf = (caddr_t)m;
        crp->crp_callback = ipsec_input_cb;
        crp->crp_sid = tdb->tdb_cryptoid;
@@ -188,9 +188,7 @@ ipcomp_input(struct mbuf *m, struct tdb 
        tc->tc_rdomain = tdb->tdb_rdomain;
        tc->tc_dst = tdb->tdb_dst;
 
-       KERNEL_LOCK();
        error = crypto_dispatch(crp);
-       KERNEL_UNLOCK();
        return error;
 }
 
@@ -479,15 +477,13 @@ ipcomp_output(struct mbuf *m, struct tdb
 
        /* Crypto operation descriptor */
        crp->crp_ilen = m->m_pkthdr.len;        /* Total input length */
-       crp->crp_flags = CRYPTO_F_IMBUF;
+       crp->crp_flags = CRYPTO_F_IMBUF | CRYPTO_F_MPSAFE;
        crp->crp_buf = (caddr_t)m;
        crp->crp_callback = ipsec_output_cb;
        crp->crp_opaque = (caddr_t)tc;
        crp->crp_sid = tdb->tdb_cryptoid;
 
-       KERNEL_LOCK();
        error = crypto_dispatch(crp);
-       KERNEL_UNLOCK();
        return error;
 
  drop:
Index: netinet/ipsec_input.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ipsec_input.c,v
retrieving revision 1.176
diff -u -p -r1.176 ipsec_input.c
--- netinet/ipsec_input.c       21 Jul 2021 12:23:32 -0000      1.176
+++ netinet/ipsec_input.c       21 Jul 2021 16:58:57 -0000
@@ -380,21 +380,19 @@ ipsec_input_cb(struct cryptop *crp)
        struct tdb *tdb = NULL;
        int clen, error;
 
-       KERNEL_ASSERT_LOCKED();
+       NET_ASSERT_LOCKED();
 
        if (m == NULL) {
                DPRINTF("bogus returned buffer from crypto");
                ipsecstat_inc(ipsec_crypto);
-               goto droponly;
+               goto drop;
        }
 
-
-       NET_LOCK();
        tdb = gettdb(tc->tc_rdomain, tc->tc_spi, &tc->tc_dst, tc->tc_proto);
        if (tdb == NULL) {
                DPRINTF("TDB is expired while in crypto");
                ipsecstat_inc(ipsec_notdb);
-               goto baddone;
+               goto drop;
        }
 
        /* Check for crypto errors */
@@ -403,18 +401,16 @@ ipsec_input_cb(struct cryptop *crp)
                        /* Reset the session ID */
                        if (tdb->tdb_cryptoid != 0)
                                tdb->tdb_cryptoid = crp->crp_sid;
-                       NET_UNLOCK();
                        error = crypto_dispatch(crp);
                        if (error) {
                                DPRINTF("crypto dispatch error %d", error);
-                               ipsecstat_inc(ipsec_idrops);
-                               tdb->tdb_idrops++;
+                               goto drop;
                        }
                        return;
                }
                DPRINTF("crypto error %d", crp->crp_etype);
                ipsecstat_inc(ipsec_noxform);
-               goto baddone;
+               goto drop;
        }
 
        /* Length of data after processing */
@@ -438,16 +434,13 @@ ipsec_input_cb(struct cryptop *crp)
                    __func__, tdb->tdb_sproto);
        }
 
-       NET_UNLOCK();
        if (error) {
                ipsecstat_inc(ipsec_idrops);
                tdb->tdb_idrops++;
        }
        return;
 
- baddone:
-       NET_UNLOCK();
- droponly:
+ drop:
        ipsecstat_inc(ipsec_idrops);
        if (tdb != NULL)
                tdb->tdb_idrops++;
Index: netinet/ipsec_output.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ipsec_output.c,v
retrieving revision 1.83
diff -u -p -r1.83 ipsec_output.c
--- netinet/ipsec_output.c      21 Jul 2021 11:11:41 -0000      1.83
+++ netinet/ipsec_output.c      21 Jul 2021 16:58:57 -0000
@@ -395,20 +395,19 @@ ipsec_output_cb(struct cryptop *crp)
        struct tdb *tdb = NULL;
        int error, ilen, olen;
 
-       KERNEL_ASSERT_LOCKED();
+       NET_ASSERT_LOCKED();
 
        if (m == NULL) {
                DPRINTF("bogus returned buffer from crypto");
                ipsecstat_inc(ipsec_crypto);
-               goto droponly;
+               goto drop;
        }
 
-       NET_LOCK();
        tdb = gettdb(tc->tc_rdomain, tc->tc_spi, &tc->tc_dst, tc->tc_proto);
        if (tdb == NULL) {
                DPRINTF("TDB is expired while in crypto");
                ipsecstat_inc(ipsec_notdb);
-               goto baddone;
+               goto drop;
        }
 
        /* Check for crypto errors. */
@@ -417,18 +416,16 @@ ipsec_output_cb(struct cryptop *crp)
                        /* Reset the session ID */
                        if (tdb->tdb_cryptoid != 0)
                                tdb->tdb_cryptoid = crp->crp_sid;
-                       NET_UNLOCK();
                        error = crypto_dispatch(crp);
                        if (error) {
                                DPRINTF("crypto dispatch error %d", error);
-                               ipsecstat_inc(ipsec_odrops);
-                               tdb->tdb_odrops++;
+                               goto drop;
                        }
                        return;
                }
                DPRINTF("crypto error %d", crp->crp_etype);
                ipsecstat_inc(ipsec_noxform);
-               goto baddone;
+               goto drop;
        }
 
        olen = crp->crp_olen;
@@ -452,16 +449,13 @@ ipsec_output_cb(struct cryptop *crp)
                    __func__, tdb->tdb_sproto);
        }
 
-       NET_UNLOCK();
        if (error) {
                ipsecstat_inc(ipsec_odrops);
                tdb->tdb_odrops++;
        }
        return;
 
- baddone:
-       NET_UNLOCK();
- droponly:
+ drop:
        if (tdb != NULL)
                tdb->tdb_odrops++;
        m_freem(m);
@@ -484,6 +478,8 @@ ipsp_process_done(struct mbuf *m, struct
        struct tdb_ident *tdbi;
        struct m_tag *mtag;
        int roff, error;
+
+       NET_ASSERT_LOCKED();
 
        tdb->tdb_last_used = gettime();
 

Reply via email to