MEDIUM: shctx: allow the use of multiple shctx

Add an shctx argument which permits to create new independent shctx
area.
This commit is contained in:
William Lallemand 2017-10-09 16:30:50 +02:00 committed by Willy Tarreau
parent 24a7a75be6
commit 3f85c9aec8
4 changed files with 82 additions and 63 deletions

View File

@ -41,7 +41,9 @@
* Returns: -1 on alloc failure, <size> if it performs context alloc, * Returns: -1 on alloc failure, <size> if it performs context alloc,
* and 0 if cache is already allocated. * and 0 if cache is already allocated.
*/ */
int shared_context_init(int size, int shared);
int shared_context_init(struct shared_context **orig_shctx, int size, int shared);
/* Set shared cache callbacks on an ssl context. /* Set shared cache callbacks on an ssl context.
* Set session cache mode to server and disable openssl internal cache. * Set session cache mode to server and disable openssl internal cache.
* Shared context MUST be firstly initialized */ * Shared context MUST be firstly initialized */
@ -153,7 +155,7 @@ static inline unsigned char atomic_dec(unsigned int *ptr)
#endif #endif
static inline void _shared_context_lock() static inline void _shared_context_lock(struct shared_context *shctx)
{ {
unsigned int x; unsigned int x;
unsigned int count = 4; unsigned int count = 4;
@ -170,7 +172,7 @@ static inline void _shared_context_lock()
} }
} }
static inline void _shared_context_unlock() static inline void _shared_context_unlock(struct shared_context *shctx)
{ {
if (atomic_dec(&shctx->waiters)) { if (atomic_dec(&shctx->waiters)) {
shctx->waiters = 0; shctx->waiters = 0;
@ -178,9 +180,9 @@ static inline void _shared_context_unlock()
} }
} }
#define shared_context_lock() if (use_shared_mem) _shared_context_lock() #define shared_context_lock(shctx) if (use_shared_mem) _shared_context_lock(shctx)
#define shared_context_unlock() if (use_shared_mem) _shared_context_unlock() #define shared_context_unlock(shctx) if (use_shared_mem) _shared_context_unlock(shctx)
#endif #endif

View File

@ -46,6 +46,6 @@ struct shared_context {
struct shared_block free; struct shared_block free;
}; };
extern struct shared_context *shctx; extern struct shared_context *ssl_shctx;
#endif #endif

View File

@ -21,8 +21,6 @@
#include <types/global.h> #include <types/global.h>
#include <types/shctx.h> #include <types/shctx.h>
struct shared_context *shctx = NULL;
#if !defined (USE_PRIVATE_CACHE) #if !defined (USE_PRIVATE_CACHE)
int use_shared_mem = 0; int use_shared_mem = 0;
#endif #endif
@ -32,55 +30,61 @@ int use_shared_mem = 0;
#define shblock_unset(s) (s)->n->p = (s)->p; \ #define shblock_unset(s) (s)->n->p = (s)->p; \
(s)->p->n = (s)->n; (s)->p->n = (s)->n;
#define shblock_set_free(s) shblock_unset(s) \ static inline void shblock_set_free(struct shared_context *shctx,
(s)->n = &shctx->free; \ struct shared_block *s)
(s)->p = shctx->free.p; \ {
shctx->free.p->n = s; \ shblock_unset(s);
(s)->n = &shctx->free;
(s)->p = shctx->free.p;
shctx->free.p->n = s;
shctx->free.p = s; shctx->free.p = s;
}
static inline void shblock_set_active(struct shared_context *shctx,
#define shblock_set_active(s) shblock_unset(s) \ struct shared_block *s)
(s)->n = &shctx->active; \ {
(s)->p = shctx->active.p; \ shblock_unset(s)
shctx->active.p->n = s; \ (s)->n = &shctx->active;
(s)->p = shctx->active.p;
shctx->active.p->n = s;
shctx->active.p = s; shctx->active.p = s;
}
/* Tree Macros */ /* Tree Macros */
#define shsess_tree_delete(s) ebmb_delete(&(s)->key); #define shsess_tree_delete(s) ebmb_delete(&(s)->key);
#define shsess_tree_insert(s) (struct shared_session *)ebmb_insert(&shctx->active.data.session.key.node.branches, \ #define shsess_tree_insert(shctx, s) (struct shared_session *)ebmb_insert(&shctx->active.data.session.key.node.branches, \
&(s)->key, SSL_MAX_SSL_SESSION_ID_LENGTH); &(s)->key, SSL_MAX_SSL_SESSION_ID_LENGTH);
#define shsess_tree_lookup(k) (struct shared_session *)ebmb_lookup(&shctx->active.data.session.key.node.branches, \ #define shsess_tree_lookup(shctx, k) (struct shared_session *)ebmb_lookup(&shctx->active.data.session.key.node.branches, \
(k), SSL_MAX_SSL_SESSION_ID_LENGTH); (k), SSL_MAX_SSL_SESSION_ID_LENGTH);
/* shared session functions */ /* shared session functions */
/* Free session blocks, returns number of freed blocks */ /* Free session blocks, returns number of freed blocks */
static int shsess_free(struct shared_session *shsess) static int shsess_free(struct shared_context *shctx, struct shared_session *shsess)
{ {
struct shared_block *block; struct shared_block *block;
int ret = 1; int ret = 1;
if (((struct shared_block *)shsess)->data_len <= sizeof(shsess->data)) { if (((struct shared_block *)shsess)->data_len <= sizeof(shsess->data)) {
shblock_set_free((struct shared_block *)shsess); shblock_set_free(shctx, (struct shared_block *)shsess);
return ret; return ret;
} }
block = ((struct shared_block *)shsess)->n; block = ((struct shared_block *)shsess)->n;
shblock_set_free((struct shared_block *)shsess); shblock_set_free(shctx, (struct shared_block *)shsess);
while (1) { while (1) {
struct shared_block *next; struct shared_block *next;
if (block->data_len <= sizeof(block->data)) { if (block->data_len <= sizeof(block->data)) {
/* last block */ /* last block */
shblock_set_free(block); shblock_set_free(shctx, block);
ret++; ret++;
break; break;
} }
next = block->n; next = block->n;
shblock_set_free(block); shblock_set_free(shctx, block);
ret++; ret++;
block = next; block = next;
} }
@ -91,7 +95,7 @@ static int shsess_free(struct shared_session *shsess)
* Returns a ptr on a free block if it succeeds, or NULL if there are not * Returns a ptr on a free block if it succeeds, or NULL if there are not
* enough blocks to store that session. * enough blocks to store that session.
*/ */
static struct shared_session *shsess_get_next(int data_len) static struct shared_session *shsess_get_next(struct shared_context *shctx, int data_len)
{ {
int head = 0; int head = 0;
struct shared_block *b; struct shared_block *b;
@ -113,7 +117,7 @@ static struct shared_session *shsess_get_next(int data_len)
int freed; int freed;
shsess_tree_delete(&b->data.session); shsess_tree_delete(&b->data.session);
freed = shsess_free(&b->data.session); freed = shsess_free(shctx, &b->data.session);
if (!head) if (!head)
data_len -= sizeof(b->data.session.data) + (freed-1)*sizeof(b->data.data); data_len -= sizeof(b->data.session.data) + (freed-1)*sizeof(b->data.data);
else else
@ -131,11 +135,11 @@ static struct shared_session *shsess_get_next(int data_len)
* data_len: asn1 encoded session length * data_len: asn1 encoded session length
* Returns 1 id session was stored (else 0) * Returns 1 id session was stored (else 0)
*/ */
static int shsess_store(unsigned char *s_id, unsigned char *data, int data_len) static int shsess_store(struct shared_context *shctx, unsigned char *s_id, unsigned char *data, int data_len)
{ {
struct shared_session *shsess, *oldshsess; struct shared_session *shsess, *oldshsess;
shsess = shsess_get_next(data_len); shsess = shsess_get_next(shctx, data_len);
if (!shsess) { if (!shsess) {
/* Could not retrieve enough free blocks to store that session */ /* Could not retrieve enough free blocks to store that session */
return 0; return 0;
@ -146,10 +150,10 @@ static int shsess_store(unsigned char *s_id, unsigned char *data, int data_len)
/* it returns the already existing node /* it returns the already existing node
or current node if none, never returns null */ or current node if none, never returns null */
oldshsess = shsess_tree_insert(shsess); oldshsess = shsess_tree_insert(shctx, shsess);
if (oldshsess != shsess) { if (oldshsess != shsess) {
/* free all blocks used by old node */ /* free all blocks used by old node */
shsess_free(oldshsess); shsess_free(shctx, oldshsess);
shsess = oldshsess; shsess = oldshsess;
} }
@ -157,7 +161,7 @@ static int shsess_store(unsigned char *s_id, unsigned char *data, int data_len)
if (data_len <= sizeof(shsess->data)) { if (data_len <= sizeof(shsess->data)) {
/* Store on a single block */ /* Store on a single block */
memcpy(shsess->data, data, data_len); memcpy(shsess->data, data, data_len);
shblock_set_active((struct shared_block *)shsess); shblock_set_active(shctx, (struct shared_block *)shsess);
} }
else { else {
unsigned char *p; unsigned char *p;
@ -167,7 +171,7 @@ static int shsess_store(unsigned char *s_id, unsigned char *data, int data_len)
memcpy(shsess->data, data, sizeof(shsess->data)); memcpy(shsess->data, data, sizeof(shsess->data));
p = data + sizeof(shsess->data); p = data + sizeof(shsess->data);
cur_len = data_len - sizeof(shsess->data); cur_len = data_len - sizeof(shsess->data);
shblock_set_active((struct shared_block *)shsess); shblock_set_active(shctx, (struct shared_block *)shsess);
while (1) { while (1) {
/* Store next data on free block. /* Store next data on free block.
* shsess_get_next guarantees that there are enough * shsess_get_next guarantees that there are enough
@ -180,7 +184,7 @@ static int shsess_store(unsigned char *s_id, unsigned char *data, int data_len)
/* This is the last block */ /* This is the last block */
block->data_len = cur_len; block->data_len = cur_len;
memcpy(block->data.data, p, cur_len); memcpy(block->data.data, p, cur_len);
shblock_set_active(block); shblock_set_active(shctx, block);
break; break;
} }
/* Intermediate block */ /* Intermediate block */
@ -188,7 +192,7 @@ static int shsess_store(unsigned char *s_id, unsigned char *data, int data_len)
memcpy(block->data.data, p, sizeof(block->data)); memcpy(block->data.data, p, sizeof(block->data));
p += sizeof(block->data.data); p += sizeof(block->data.data);
cur_len -= sizeof(block->data.data); cur_len -= sizeof(block->data.data);
shblock_set_active(block); shblock_set_active(shctx, block);
} }
} }
@ -232,12 +236,12 @@ int shctx_new_cb(SSL *ssl, SSL_SESSION *sess)
if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH) if (sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH)
memset(encid + sid_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH-sid_length); memset(encid + sid_length, 0, SSL_MAX_SSL_SESSION_ID_LENGTH-sid_length);
shared_context_lock(); shared_context_lock(ssl_shctx);
/* store to cache */ /* store to cache */
shsess_store(encid, encsess, data_len); shsess_store(ssl_shctx, encid, encsess, data_len);
shared_context_unlock(); shared_context_unlock(ssl_shctx);
err: err:
/* reset original length values */ /* reset original length values */
@ -269,13 +273,13 @@ SSL_SESSION *shctx_get_cb(SSL *ssl, __OPENSSL_110_CONST__ unsigned char *key, in
} }
/* lock cache */ /* lock cache */
shared_context_lock(); shared_context_lock(ssl_shctx);
/* lookup for session */ /* lookup for session */
shsess = shsess_tree_lookup(key); shsess = shsess_tree_lookup(ssl_shctx, key);
if (!shsess) { if (!shsess) {
/* no session found: unlock cache and exit */ /* no session found: unlock cache and exit */
shared_context_unlock(); shared_context_unlock(ssl_shctx);
global.shctx_misses++; global.shctx_misses++;
return NULL; return NULL;
} }
@ -284,7 +288,7 @@ SSL_SESSION *shctx_get_cb(SSL *ssl, __OPENSSL_110_CONST__ unsigned char *key, in
if (data_len <= sizeof(shsess->data)) { if (data_len <= sizeof(shsess->data)) {
/* Session stored on single block */ /* Session stored on single block */
memcpy(data, shsess->data, data_len); memcpy(data, shsess->data, data_len);
shblock_set_active((struct shared_block *)shsess); shblock_set_active(ssl_shctx, (struct shared_block *)shsess);
} }
else { else {
/* Session stored on multiple blocks */ /* Session stored on multiple blocks */
@ -293,7 +297,7 @@ SSL_SESSION *shctx_get_cb(SSL *ssl, __OPENSSL_110_CONST__ unsigned char *key, in
memcpy(data, shsess->data, sizeof(shsess->data)); memcpy(data, shsess->data, sizeof(shsess->data));
p = data + sizeof(shsess->data); p = data + sizeof(shsess->data);
block = ((struct shared_block *)shsess)->n; block = ((struct shared_block *)shsess)->n;
shblock_set_active((struct shared_block *)shsess); shblock_set_active(ssl_shctx, (struct shared_block *)shsess);
while (1) { while (1) {
/* Retrieve data from next block */ /* Retrieve data from next block */
struct shared_block *next; struct shared_block *next;
@ -302,19 +306,19 @@ SSL_SESSION *shctx_get_cb(SSL *ssl, __OPENSSL_110_CONST__ unsigned char *key, in
/* This is the last block */ /* This is the last block */
memcpy(p, block->data.data, block->data_len); memcpy(p, block->data.data, block->data_len);
p += block->data_len; p += block->data_len;
shblock_set_active(block); shblock_set_active(ssl_shctx, block);
break; break;
} }
/* Intermediate block */ /* Intermediate block */
memcpy(p, block->data.data, sizeof(block->data.data)); memcpy(p, block->data.data, sizeof(block->data.data));
p += sizeof(block->data.data); p += sizeof(block->data.data);
next = block->n; next = block->n;
shblock_set_active(block); shblock_set_active(ssl_shctx, block);
block = next; block = next;
} }
} }
shared_context_unlock(); shared_context_unlock(ssl_shctx);
/* decode ASN1 session */ /* decode ASN1 session */
p = data; p = data;
@ -345,18 +349,18 @@ void shctx_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
sid_data = tmpkey; sid_data = tmpkey;
} }
shared_context_lock(); shared_context_lock(ssl_shctx);
/* lookup for session */ /* lookup for session */
shsess = shsess_tree_lookup(sid_data); shsess = shsess_tree_lookup(ssl_shctx, sid_data);
if (shsess) { if (shsess) {
/* free session */ /* free session */
shsess_tree_delete(shsess); shsess_tree_delete(shsess);
shsess_free(shsess); shsess_free(ssl_shctx, shsess);
} }
/* unlock cache */ /* unlock cache */
shared_context_unlock(); shared_context_unlock(ssl_shctx);
} }
/* Allocate shared memory context. /* Allocate shared memory context.
@ -365,9 +369,11 @@ void shctx_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
* Returns: -1 on alloc failure, <size> if it performs context alloc, * Returns: -1 on alloc failure, <size> if it performs context alloc,
* and 0 if cache is already allocated. * and 0 if cache is already allocated.
*/ */
int shared_context_init(int size, int shared) int shared_context_init(struct shared_context **orig_shctx, int size, int shared)
{ {
int i; int i;
struct shared_context *shctx;
int ret;
#ifndef USE_PRIVATE_CACHE #ifndef USE_PRIVATE_CACHE
#ifdef USE_PTHREAD_PSHARED #ifdef USE_PTHREAD_PSHARED
pthread_mutexattr_t attr; pthread_mutexattr_t attr;
@ -376,7 +382,7 @@ int shared_context_init(int size, int shared)
struct shared_block *prev,*cur; struct shared_block *prev,*cur;
int maptype = MAP_PRIVATE; int maptype = MAP_PRIVATE;
if (shctx) if (orig_shctx && *orig_shctx)
return 0; return 0;
if (size<=0) if (size<=0)
@ -393,7 +399,8 @@ int shared_context_init(int size, int shared)
PROT_READ | PROT_WRITE, maptype | MAP_ANON, -1, 0); PROT_READ | PROT_WRITE, maptype | MAP_ANON, -1, 0);
if (!shctx || shctx == MAP_FAILED) { if (!shctx || shctx == MAP_FAILED) {
shctx = NULL; shctx = NULL;
return SHCTX_E_ALLOC_CACHE; ret = SHCTX_E_ALLOC_CACHE;
goto err;
} }
#ifndef USE_PRIVATE_CACHE #ifndef USE_PRIVATE_CACHE
@ -402,21 +409,24 @@ int shared_context_init(int size, int shared)
if (pthread_mutexattr_init(&attr)) { if (pthread_mutexattr_init(&attr)) {
munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block))); munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
shctx = NULL; shctx = NULL;
return SHCTX_E_INIT_LOCK; ret = SHCTX_E_INIT_LOCK;
goto err;
} }
if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) { if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
pthread_mutexattr_destroy(&attr); pthread_mutexattr_destroy(&attr);
munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block))); munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
shctx = NULL; shctx = NULL;
return SHCTX_E_INIT_LOCK; ret = SHCTX_E_INIT_LOCK;
goto err;
} }
if (pthread_mutex_init(&shctx->mutex, &attr)) { if (pthread_mutex_init(&shctx->mutex, &attr)) {
pthread_mutexattr_destroy(&attr); pthread_mutexattr_destroy(&attr);
munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block))); munmap(shctx, sizeof(struct shared_context)+(size*sizeof(struct shared_block)));
shctx = NULL; shctx = NULL;
return SHCTX_E_INIT_LOCK; ret = SHCTX_E_INIT_LOCK;
goto err;
} }
#else #else
shctx->waiters = 0; shctx->waiters = 0;
@ -444,7 +454,11 @@ int shared_context_init(int size, int shared)
cur->n = &shctx->free; cur->n = &shctx->free;
shctx->free.p = cur; shctx->free.p = cur;
return size; ret = size;
err:
*orig_shctx = shctx;
return ret;
} }
@ -455,7 +469,7 @@ void shared_context_set_cache(SSL_CTX *ctx)
{ {
SSL_CTX_set_session_id_context(ctx, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME)); SSL_CTX_set_session_id_context(ctx, (const unsigned char *)SHCTX_APPNAME, strlen(SHCTX_APPNAME));
if (!shctx) { if (!ssl_shctx) {
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
return; return;
} }

View File

@ -157,6 +157,7 @@ enum {
SSL_SOCK_VERIFY_NONE = 3, SSL_SOCK_VERIFY_NONE = 3,
}; };
int sslconns = 0; int sslconns = 0;
int totalsslconns = 0; int totalsslconns = 0;
static struct xprt_ops ssl_sock; static struct xprt_ops ssl_sock;
@ -274,6 +275,8 @@ const char *SSL_SOCK_KEYTYPE_NAMES[] = {
#define SSL_SOCK_NUM_KEYTYPES 1 #define SSL_SOCK_NUM_KEYTYPES 1
#endif #endif
struct shared_context *ssl_shctx = NULL;
/* /*
* This function gives the detail of the SSL error. It is used only * This function gives the detail of the SSL error. It is used only
* if the debug mode and the verbose mode are activated. It dump all * if the debug mode and the verbose mode are activated. It dump all
@ -4376,7 +4379,7 @@ int ssl_sock_prepare_bind_conf(struct bind_conf *bind_conf)
} }
} }
alloc_ctx = shared_context_init(global.tune.sslcachesize, (!global_ssl.private_cache && (global.nbproc > 1)) ? 1 : 0); alloc_ctx = shared_context_init(&ssl_shctx, global.tune.sslcachesize, (!global_ssl.private_cache && (global.nbproc > 1)) ? 1 : 0);
if (alloc_ctx < 0) { if (alloc_ctx < 0) {
if (alloc_ctx == SHCTX_E_INIT_LOCK) if (alloc_ctx == SHCTX_E_INIT_LOCK)
Alert("Unable to initialize the lock for the shared SSL session cache. You can retry using the global statement 'tune.ssl.force-private-cache' but it could increase CPU usage due to renegotiations if nbproc > 1.\n"); Alert("Unable to initialize the lock for the shared SSL session cache. You can retry using the global statement 'tune.ssl.force-private-cache' but it could increase CPU usage due to renegotiations if nbproc > 1.\n");