Resolve Bug https://bugs.linaro.org/show_bug.cgi?id=2798 by adding
OpenSSL callbacks for locking that use ticketlocks to provide
thread-safety for OpenSSL calls made by ODP components such as random
number generation.

Signed-off-by: Bill Fischofer <bill.fischo...@linaro.org>
---
 platform/linux-generic/include/odp_internal.h |  5 +++
 platform/linux-generic/odp_init.c             | 63 +++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)

diff --git a/platform/linux-generic/include/odp_internal.h 
b/platform/linux-generic/include/odp_internal.h
index b313b1f..2280e3f 100644
--- a/platform/linux-generic/include/odp_internal.h
+++ b/platform/linux-generic/include/odp_internal.h
@@ -20,6 +20,8 @@ extern "C" {
 #include <odp/api/init.h>
 #include <odp/api/cpumask.h>
 #include <odp/api/thread.h>
+#include <odp/api/shared_memory.h>
+#include <odp/api/ticketlock.h>
 #include <stdio.h>
 #include <sys/types.h>
 
@@ -50,6 +52,8 @@ struct odp_global_data_s {
        odp_cpumask_t control_cpus;
        odp_cpumask_t worker_cpus;
        int num_cpus_installed;
+       odp_shm_t openssl_shm;
+       odp_ticketlock_t **openssl_lock;
 };
 
 enum init_stage {
@@ -66,6 +70,7 @@ enum init_stage {
        PKTIO_INIT,
        TIMER_INIT,
        CRYPTO_INIT,
+       OPENSSL_INIT,
        CLASSIFICATION_INIT,
        TRAFFIC_MNGR_INIT,
        NAME_TABLE_INIT,
diff --git a/platform/linux-generic/odp_init.c 
b/platform/linux-generic/odp_init.c
index 1b0d8f8..6873bb5 100644
--- a/platform/linux-generic/odp_init.c
+++ b/platform/linux-generic/odp_init.c
@@ -6,6 +6,8 @@
 #include <odp/api/init.h>
 #include <odp_debug_internal.h>
 #include <odp/api/debug.h>
+#include <openssl/opensslconf.h>
+#include <openssl/crypto.h>
 #include <unistd.h>
 #include <odp_internal.h>
 #include <odp_schedule_if.h>
@@ -21,8 +23,30 @@
 #define _ODP_FILES_FMT "odp-%d-"
 #define _ODP_TMPDIR    "/tmp"
 
+static inline int openssl_numlocks(void)
+{
+       return CRYPTO_num_locks();
+}
+
 struct odp_global_data_s odp_global_data;
 
+static unsigned long openssl_thread_id(void)
+{
+       return (unsigned long)odp_thread_id();
+}
+
+static void openssl_lock(int mode, int n,
+                        const char *file ODP_UNUSED,
+                        int line ODP_UNUSED)
+{
+       if (mode & CRYPTO_LOCK)
+               odp_ticketlock_lock((odp_ticketlock_t *)
+                                   &odp_global_data.openssl_lock[n]);
+       else
+               odp_ticketlock_unlock((odp_ticketlock_t *)
+                                     &odp_global_data.openssl_lock[n]);
+}
+
 /* remove all files staring with "odp-<pid>" from a directory "dir" */
 static int cleanup_files(const char *dirpath, int odp_pid)
 {
@@ -70,6 +94,8 @@ int odp_init_global(odp_instance_t *instance,
                    const odp_platform_init_t *platform_params ODP_UNUSED)
 {
        char *hpdir;
+       int nlocks = openssl_numlocks();
+       int i;
 
        memset(&odp_global_data, 0, sizeof(struct odp_global_data_s));
        odp_global_data.main_pid = getpid();
@@ -162,6 +188,34 @@ int odp_init_global(odp_instance_t *instance,
        }
        stage = CRYPTO_INIT;
 
+       if (nlocks > 0) {
+               odp_global_data.openssl_shm =
+                       odp_shm_reserve("ODP OpenSSL Mutexes",
+                                       nlocks * sizeof(odp_ticketlock_t),
+                                       sizeof(odp_ticketlock_t),
+                                       ODP_SHM_SW_ONLY);
+               if (odp_global_data.openssl_shm == ODP_SHM_INVALID) {
+                       ODP_ERR("ODP OpenSSL init reserve failed.\n");
+                       goto init_failed;
+               }
+
+               odp_global_data.openssl_lock =
+                       odp_shm_addr(odp_global_data.openssl_shm);
+               if (odp_global_data.openssl_lock == NULL) {
+                       odp_shm_free(odp_global_data.openssl_shm);
+                       ODP_ERR("ODP OpenSSL init addr failed.\n");
+                       goto init_failed;
+               }
+
+               for (i = 0; i < nlocks; i++)
+                       odp_ticketlock_init((odp_ticketlock_t *)
+                                           &odp_global_data.openssl_lock[i]);
+
+               CRYPTO_set_id_callback(openssl_thread_id);
+               CRYPTO_set_locking_callback(openssl_lock);
+       }
+       stage = OPENSSL_INIT;
+
        if (odp_classification_init_global()) {
                ODP_ERR("ODP classification init failed.\n");
                goto init_failed;
@@ -224,6 +278,15 @@ int _odp_term_global(enum init_stage stage)
                }
                /* Fall through */
 
+       case OPENSSL_INIT:
+               if (odp_global_data.openssl_lock) {
+                       CRYPTO_set_locking_callback(NULL);
+                       CRYPTO_set_id_callback(NULL);
+
+                       odp_shm_free(odp_global_data.openssl_shm);
+               }
+               /* Fall through */
+
        case CRYPTO_INIT:
                if (odp_crypto_term_global()) {
                        ODP_ERR("ODP crypto term failed.\n");
-- 
2.7.4

Reply via email to