Repository: trafficserver Updated Branches: refs/heads/master 195259b16 -> f1bedb41e
TS-3080: Optimized SSL Session Cache Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/53bf5d1e Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/53bf5d1e Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/53bf5d1e Branch: refs/heads/master Commit: 53bf5d1e7618ae38b0a8b49263a047282eec68d1 Parents: 72b7c05 Author: Brian Geffon <[email protected]> Authored: Tue Oct 7 18:51:34 2014 -0700 Committer: Brian Geffon <[email protected]> Committed: Tue Oct 7 18:52:34 2014 -0700 ---------------------------------------------------------------------- iocore/net/Makefile.am | 1 + iocore/net/P_SSLConfig.h | 12 +- iocore/net/P_SSLUtils.h | 4 + iocore/net/SSLConfig.cc | 19 ++- iocore/net/SSLSessionCache.cc | 246 +++++++++++++++++++++++++++++++++++++ iocore/net/SSLSessionCache.h | 149 ++++++++++++++++++++++ iocore/net/SSLUtils.cc | 98 ++++++++++++++- lib/ts/ink_mutex.h | 29 +++++ mgmt/RecordsConfig.cc | 8 +- proxy/Makefile.am | 2 +- 10 files changed, 559 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/iocore/net/Makefile.am ---------------------------------------------------------------------- diff --git a/iocore/net/Makefile.am b/iocore/net/Makefile.am index 0120528..da7a476 100644 --- a/iocore/net/Makefile.am +++ b/iocore/net/Makefile.am @@ -88,6 +88,7 @@ libinknet_a_SOURCES = \ P_UnixUDPConnection.h \ Socks.cc \ SSLCertLookup.cc \ + SSLSessionCache.cc \ SSLConfig.cc \ SSLNetAccept.cc \ SSLNetProcessor.cc \ http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/iocore/net/P_SSLConfig.h ---------------------------------------------------------------------- diff --git a/iocore/net/P_SSLConfig.h b/iocore/net/P_SSLConfig.h index aa4926f..0cad7d9 100644 --- a/iocore/net/P_SSLConfig.h +++ b/iocore/net/P_SSLConfig.h @@ -32,6 +32,7 @@ #define __P_SSLCONFIG_H__ #include "ProxyConfig.h" +#include "SSLSessionCache.h" struct SSLCertLookup; @@ -51,7 +52,8 @@ struct SSLConfigParams : public ConfigInfo enum SSL_SESSION_CACHE_MODE { SSL_SESSION_CACHE_MODE_OFF = 0, - SSL_SESSION_CACHE_MODE_SERVER = 1 + SSL_SESSION_CACHE_MODE_SERVER_OPENSSL_IMPL = 1, + SSL_SESSION_CACHE_MODE_SERVER_ATS_IMPL = 2 }; SSLConfigParams(); @@ -69,6 +71,8 @@ struct SSLConfigParams : public ConfigInfo int verify_depth; int ssl_session_cache; // SSL_SESSION_CACHE_MODE int ssl_session_cache_size; + int ssl_session_cache_num_buckets; + int ssl_session_cache_skip_on_contention; int ssl_session_cache_timeout; char * clientCertPath; @@ -88,6 +92,10 @@ struct SSLConfigParams : public ConfigInfo static int ssl_ocsp_request_timeout; static int ssl_ocsp_update_period; + static size_t session_cache_number_buckets; + static size_t session_cache_max_bucket_size; + static bool session_cache_skip_on_lock_contention; + static init_ssl_ctx_func init_ssl_ctx_cb; void initialize(); @@ -126,4 +134,6 @@ private: static int configid; }; +extern SSLSessionCache *session_cache; + #endif http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/iocore/net/P_SSLUtils.h ---------------------------------------------------------------------- diff --git a/iocore/net/P_SSLUtils.h b/iocore/net/P_SSLUtils.h index 3cf0c20..1c9f0b8 100644 --- a/iocore/net/P_SSLUtils.h +++ b/iocore/net/P_SSLUtils.h @@ -70,6 +70,10 @@ enum SSL_Stats ssl_total_tickets_verified_stat, ssl_total_tickets_not_found_stat, ssl_total_tickets_renewed_stat, + ssl_session_cache_hit, + ssl_session_cache_miss, + ssl_session_cache_eviction, + ssl_session_cache_lock_contention, /* error stats */ ssl_error_want_write, http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/iocore/net/SSLConfig.cc ---------------------------------------------------------------------- diff --git a/iocore/net/SSLConfig.cc b/iocore/net/SSLConfig.cc index 402664a..3aaddc1 100644 --- a/iocore/net/SSLConfig.cc +++ b/iocore/net/SSLConfig.cc @@ -37,6 +37,7 @@ #include "P_SSLConfig.h" #include "P_SSLUtils.h" #include "P_SSLCertLookup.h" +#include "SSLSessionCache.h" #include <records/I_RecHttp.h> int SSLConfig::configid = 0; @@ -47,6 +48,10 @@ bool SSLConfigParams::ssl_ocsp_enabled = false; int SSLConfigParams::ssl_ocsp_cache_timeout = 3600; int SSLConfigParams::ssl_ocsp_request_timeout = 10; int SSLConfigParams::ssl_ocsp_update_period = 60; +size_t SSLConfigParams::session_cache_number_buckets = 1024; +bool SSLConfigParams::session_cache_skip_on_lock_contention = false; +size_t SSLConfigParams::session_cache_max_bucket_size = 100; + init_ssl_ctx_func SSLConfigParams::init_ssl_ctx_cb = NULL; static ConfigUpdateHandler<SSLCertificateConfig> * sslCertUpdate; @@ -70,8 +75,10 @@ SSLConfigParams::SSLConfigParams() ssl_ctx_options = 0; ssl_client_ctx_protocols = 0; - ssl_session_cache = SSL_SESSION_CACHE_MODE_SERVER; - ssl_session_cache_size = 1024*20; + ssl_session_cache = SSL_SESSION_CACHE_MODE_SERVER_ATS_IMPL; + ssl_session_cache_size = 1024*100; + ssl_session_cache_num_buckets = 1024; // Sessions per bucket is ceil(ssl_session_cache_size / ssl_session_cache_num_buckets) + ssl_session_cache_skip_on_contention = 0; ssl_session_cache_timeout = 0; } @@ -248,8 +255,16 @@ SSLConfigParams::initialize() // SSL session cache configurations REC_ReadConfigInteger(ssl_session_cache, "proxy.config.ssl.session_cache"); REC_ReadConfigInteger(ssl_session_cache_size, "proxy.config.ssl.session_cache.size"); + REC_ReadConfigInteger(ssl_session_cache_num_buckets, "proxy.config.ssl.session_cache.num_buckets"); + REC_ReadConfigInteger(ssl_session_cache_skip_on_contention, "proxy.config.ssl.session_cache.skip_cache_on_bucket_contention"); REC_ReadConfigInteger(ssl_session_cache_timeout, "proxy.config.ssl.session_cache.timeout"); + SSLConfigParams::session_cache_max_bucket_size = ceil(ssl_session_cache_size/ssl_session_cache_num_buckets ); + SSLConfigParams::session_cache_skip_on_lock_contention = ssl_session_cache_skip_on_contention; + SSLConfigParams::session_cache_number_buckets = ssl_session_cache_num_buckets; + + session_cache = new SSLSessionCache(); + // SSL record size REC_EstablishStaticConfigInt32(ssl_maxrecord, "proxy.config.ssl.max_record_size"); http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/iocore/net/SSLSessionCache.cc ---------------------------------------------------------------------- diff --git a/iocore/net/SSLSessionCache.cc b/iocore/net/SSLSessionCache.cc new file mode 100644 index 0000000..c936ee7 --- /dev/null +++ b/iocore/net/SSLSessionCache.cc @@ -0,0 +1,246 @@ +/** @file + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include <cstring> +#include <deque> +#include "P_SSLConfig.h" +#include "SSLSessionCache.h" + +#define SSLSESSIONCACHE_STRINGIFY0(x) #x +#define SSLSESSIONCACHE_STRINGIFY(x) SSLSESSIONCACHE_STRINGIFY0(x) +#define SSLSESSIONCACHE_LINENO SSLSESSIONCACHE_STRINGIFY(__LINE__) + +#ifdef DEBUG +#define PRINT_BUCKET(x) this->print(x " at " __FILE__ ":" SSLSESSIONCACHE_LINENO); +#else +#define PRINT_BUCKET(x) +#endif + +using ts::detail::RBNode; + +/* Session Cache */ +SSLSessionCache::SSLSessionCache() + : session_bucket(NULL) { + Debug("ssl.session_cache", "Created new ssl session cache %p with %ld buckets each with size max size %ld", this, SSLConfigParams::session_cache_number_buckets, SSLConfigParams::session_cache_max_bucket_size); + + session_bucket = new SSLSessionBucket[SSLConfigParams::session_cache_number_buckets]; +} + +SSLSessionCache::~SSLSessionCache() { + delete []session_bucket; +} + +bool SSLSessionCache::getSession(const SSLSessionID &sid, const char *sni_name, SSL_SESSION **sess) { + uint64_t hash = sid.hash(); + uint64_t target_bucket = hash % SSLConfigParams::session_cache_number_buckets; + SSLSessionBucket *bucket = &session_bucket[target_bucket]; + bool ret = false; + + if (is_debug_tag_set("ssl.session_cache")) { + char buf[sid.len * 2 + 1]; + sid.toString(buf, sizeof(buf)); + Debug("ssl.session_cache.get", "SessionCache looking in bucket %" PRId64 " (%p) for session '%s' (hash: %" PRIX64 ").", target_bucket, bucket, buf, hash); + } + + ret = bucket->getSession(sid, sni_name, sess); + + if (ret) + SSL_INCREMENT_DYN_STAT(ssl_session_cache_hit); + else + SSL_INCREMENT_DYN_STAT(ssl_session_cache_miss); + + return ret; +} + +void SSLSessionCache::removeSession(const SSLSessionID &sid) { + uint64_t hash = sid.hash(); + uint64_t target_bucket = hash % SSLConfigParams::session_cache_number_buckets; + SSLSessionBucket *bucket = &session_bucket[target_bucket]; + + if (is_debug_tag_set("ssl.session_cache")) { + char buf[sid.len * 2 + 1]; + sid.toString(buf, sizeof(buf)); + Debug("ssl.session_cache.remove", "SessionCache using bucket %" PRId64 " (%p): Removing session '%s' (hash: %" PRIX64 ").", target_bucket, bucket, buf, hash); + } + + SSL_INCREMENT_DYN_STAT(ssl_session_cache_eviction); + bucket->removeSession(sid); +} + +void SSLSessionCache::insertSession(const SSLSessionID &sid, const char *sni_name, SSL_SESSION *sess) { + uint64_t hash = sid.hash(); + uint64_t target_bucket = hash % SSLConfigParams::session_cache_number_buckets; + SSLSessionBucket *bucket = &session_bucket[target_bucket]; + + if (is_debug_tag_set("ssl.session_cache")) { + char buf[sid.len * 2 + 1]; + sid.toString(buf, sizeof(buf)); + Debug("ssl.session_cache.insert", "SessionCache using bucket %" PRId64 " (%p): Inserting session '%s' (hash: %" PRIX64 ").", target_bucket, bucket, buf, hash); + } + + bucket->insertSession(sid, sni_name, sess); +} + +void SSLSessionBucket::insertSession(const SSLSessionID &id, const char *sni_name, SSL_SESSION *sess) { + size_t len = i2d_SSL_SESSION(sess, NULL); // make sure we're not going to need more than SSL_MAX_SESSION_SIZE bytes + /* do not cache a session that's too big. */ + if (len > (size_t) SSL_MAX_SESSION_SIZE) { + Debug("ssl.session_cache", "Unable to save SSL session because size of %" PRId64 " exceeds the max of %d", len, SSL_MAX_SESSION_SIZE); + return; + } + + if (is_debug_tag_set("ssl.session_cache")) { + char buf[id.len * 2 + 1]; + id.toString(buf, sizeof(buf)); + Debug("ssl.session_cache", "Inserting session '%s' to bucket %p with sni name '%s'", buf, this, sni_name); + } + + Ptr<IOBufferData> buf; + buf = new_IOBufferData(buffer_size_to_index(len, MAX_BUFFER_SIZE_INDEX), MEMALIGNED); + ink_release_assert(static_cast<size_t>(buf->block_size()) >= len); + unsigned char *loc = reinterpret_cast<unsigned char *>(buf->data()); + i2d_SSL_SESSION(sess, &loc); + + SSLSession *ssl_session = new SSLSession(id, sni_name, buf, len); + + ink_scoped_try_mutex scoped_mutex(mutex); + if (!scoped_mutex.hasLock()) { + SSL_INCREMENT_DYN_STAT(ssl_session_cache_lock_contention); + if (SSLConfigParams::session_cache_skip_on_lock_contention) + return; + + scoped_mutex.lock(); + } + + PRINT_BUCKET("insertSession before") + if (queue.size >= static_cast<int>(SSLConfigParams::session_cache_max_bucket_size)) { + removeOldestSession(); + } + + /* do the actual insert */ + queue.enqueue(ssl_session); + + PRINT_BUCKET("insertSession after") +} + + + +bool SSLSessionBucket::getSession(const SSLSessionID &id, const char *sni_name, SSL_SESSION **sess) { + char buf[id.len * 2 + 1]; + if (is_debug_tag_set("ssl.session_cache")) { + id.toString(buf, sizeof(buf)); + } + + Debug("ssl.session_cache", "Looking for session with id '%s' in bucket %p with sni name '%s'", buf, this, sni_name); + + ink_scoped_try_mutex scoped_mutex(mutex); + if (!scoped_mutex.hasLock()) { + SSL_INCREMENT_DYN_STAT(ssl_session_cache_lock_contention); + if (SSLConfigParams::session_cache_skip_on_lock_contention) + return false; + scoped_mutex.lock(); + } + + PRINT_BUCKET("getSession") + + // We work backwards because that's the most likely place we'll find our session... + SSLSession *node = queue.tail; + while (node) { + if (node->session_id == id) + { + if ((node->sni_name == NULL && sni_name == NULL) /* this session doesn't have an associated SNI name */|| + (node->sni_name && sni_name && strcmp(node->sni_name, sni_name) == 0)) { /* the session does have an associated SNI name */ + Debug("ssl.session_cache", "Found session with id '%s' in bucket %p with sni name '%s'.", buf, this, sni_name); + + const unsigned char *loc = reinterpret_cast<const unsigned char *>(node->asn1_data->data()); + *sess = d2i_SSL_SESSION(NULL, &loc, node->len_asn1_data); + + return true; + } else { + Debug("ssl.session_cache", "Found session with id '%s' in bucket %p but sni names didn't match! '%s' != '%s'.", buf, this, node->sni_name, sni_name); + return false; + } + } + + node = node->link.prev; + } + + Debug("ssl.session_cache", "Session with id '%s' not found in bucket %p.", buf, this); + return false; +} + +void inline SSLSessionBucket::print(const char *ref_str) const { + /* NOTE: This method assumes you're already holding the bucket lock */ + if (!is_debug_tag_set("ssl.session_cache.bucket")) { + return; + } + + fprintf(stderr, "-------------- BUCKET %p (%s) ----------------\n", this, ref_str); + fprintf(stderr, "Current Size: %d, Max Size: %" PRId64 "\n", queue.size, SSLConfigParams::session_cache_max_bucket_size); + fprintf(stderr, "Queue: \n"); + + SSLSession *node = queue.head; + while(node) { + char s_buf[2 * node->session_id.len + 1]; + node->session_id.toString(s_buf, sizeof(s_buf)); + fprintf(stderr, " %s\n", s_buf); + node = node->link.next; + } +} + +void inline SSLSessionBucket::removeOldestSession() { + PRINT_BUCKET("removeOldestSession before") + while (queue.head && queue.size >= static_cast<int>(SSLConfigParams::session_cache_max_bucket_size)) { + SSLSession *old_head = queue.pop(); + if (is_debug_tag_set("ssl.session_cache")) { + char buf[old_head->session_id.len * 2 + 1]; + old_head->session_id.toString(buf, sizeof(buf)); + Debug("ssl.session_cache", "Removing session '%s' from bucket %p because the bucket has size %d and max %" PRId64, buf, this, (queue.size + 1), SSLConfigParams::session_cache_max_bucket_size); + } + delete old_head; + } + PRINT_BUCKET("removeOldestSession after") +} + +void SSLSessionBucket::removeSession(const SSLSessionID &id) { + ink_scoped_mutex scoped_mutex(mutex); // We can't bail on contention here because this session MUST be removed. + SSLSession *node = queue.head; + while (node) { + if (node->session_id == id) + { + queue.remove(node); + delete node; + return; + } + } +} + +/* Session Bucket */ +SSLSessionBucket::SSLSessionBucket() : root(NULL) { + Debug("ssl.session_cache", "Created new bucket %p with max size %ld", this, SSLConfigParams::session_cache_max_bucket_size); + ink_mutex_init(&mutex, "session_bucket"); +} + +SSLSessionBucket::~SSLSessionBucket() { + ink_mutex_destroy(&mutex); +} + + http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/iocore/net/SSLSessionCache.h ---------------------------------------------------------------------- diff --git a/iocore/net/SSLSessionCache.h b/iocore/net/SSLSessionCache.h new file mode 100644 index 0000000..283438a --- /dev/null +++ b/iocore/net/SSLSessionCache.h @@ -0,0 +1,149 @@ +/** @file + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef SSL_SESSION_CACHE_ +#define SSL_SESSION_CACHE_ +#include "Map.h" +#include "List.h" +#include "ink_mutex.h" +#include "P_EventSystem.h" +#include "P_AIO.h" +#include "I_RecProcess.h" +#include "libts.h" +#include "P_SSLUtils.h" +#include "RbTree.h" +#include <openssl/ssl.h> + +#define SSL_MAX_SESSION_SIZE 2048 + +struct SSLSessionID { + char bytes[SSL_MAX_SSL_SESSION_ID_LENGTH]; + size_t len; + + SSLSessionID(const unsigned char *s, size_t l) : len(l) { + ink_release_assert(l <= sizeof(bytes)); + memcpy(bytes, s, l); + } + + SSLSessionID(const SSLSessionID& other) { + if (other.len) + memcpy(bytes, other.bytes, other.len); + + len = other.len; + } + + bool operator<(const SSLSessionID &other) const { + if (len != other.len) + return len < other.len; + + return (memcmp(bytes, other.bytes, len) < 0); + } + + SSLSessionID& operator=(const SSLSessionID& other) { + if (other.len) + memcpy(bytes, other.bytes, other.len); + + len = other.len; + return *this; + } + + bool operator==(const SSLSessionID &other) const { + if (len != other.len) + return false; + + // memcmp returns 0 on equal + return (memcmp(bytes, other.bytes, len) == 0); + } + + const char *toString(char *buf, size_t buflen) const { + char *cur_pos = buf; + for (size_t i = 0; i < len && buflen > 0; ++i) { + if (buflen > 2) { // we have enough space for 3 bytes, 2 hex and 1 null terminator + snprintf(cur_pos, 3 /* including a null terminator */, "%02hhX", static_cast<unsigned char>(bytes[i])); + cur_pos += 2; + buflen -= 2; + } else { // not enough space for any more hex bytes, just null terminate + *cur_pos = '\0'; + break; + } + } + return buf; + } + + uint64_t hash() const { + // because the session ids should be uniformly random let's just use the upper 64 bits as the hash. + if (len >= sizeof(uint64_t)) + return *reinterpret_cast<uint64_t *>(const_cast<char *>(bytes)); + else if (len) + return static_cast<uint64_t>(bytes[0]); + else + return 0; + } + +}; + +class SSLSession { +public: + SSLSessionID session_id; + const char *sni_name; + Ptr<IOBufferData> asn1_data; /* this is the ASN1 representation of the SSL_CTX */ + size_t len_asn1_data; + + SSLSession(const SSLSessionID &id, const char *name, Ptr<IOBufferData> ssl_asn1_data, size_t len_asn1) + : session_id(id), sni_name(name), asn1_data(ssl_asn1_data), len_asn1_data(len_asn1) + { } + + LINK(SSLSession, link); +}; + +class SSLSessionBucket { +public: + SSLSessionBucket(); + ~SSLSessionBucket(); + void removeOldestSession(); + void insertSession(const SSLSessionID &, const char *sni_name, SSL_SESSION *ctx); + bool getSession(const SSLSessionID &, const char *sni_name, SSL_SESSION **ctx); + void removeSession(const SSLSessionID &); + +private: + /* these method must be used while hold the lock */ + void print(const char *) const; + + mutable ink_mutex mutex; + CountQueue<SSLSession> queue; + SSLSession *root; +}; + +class SSLSessionCache { +public: + bool getSession(const SSLSessionID &sid, const char *sni_name, SSL_SESSION **sess); + void insertSession(const SSLSessionID &sid, const char *sni_name, SSL_SESSION *sess); + void removeSession(const SSLSessionID &sid); + SSLSessionCache(); + ~SSLSessionCache(); + + private: + SSLSessionBucket *session_bucket; +}; + +#endif + + http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/iocore/net/SSLUtils.cc ---------------------------------------------------------------------- diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc index 3bf90d7..7fede11 100644 --- a/iocore/net/SSLUtils.cc +++ b/iocore/net/SSLUtils.cc @@ -26,6 +26,7 @@ #include "P_Net.h" #include "ink_cap.h" #include "P_OCSPStapling.h" +#include "SSLSessionCache.h" #include <string> #include <openssl/err.h> @@ -106,6 +107,7 @@ struct ssl_user_config #define HAVE_OPENSSL_SESSION_TICKETS 1 +SSLSessionCache *session_cache; // declared extern in P_SSLConfig.h static void session_ticket_free(void *, void *, CRYPTO_EX_DATA *, int, long, void *); static int ssl_callback_session_ticket(SSL *, unsigned char *, unsigned char *, EVP_CIPHER_CTX *, HMAC_CTX *, int); #endif /* SSL_CTX_set_tlsext_ticket_key_cb */ @@ -176,6 +178,61 @@ SSL_CTX_add_extra_chain_cert_file(SSL_CTX * ctx, const char * chainfile) return true; } + +static SSL_SESSION* ssl_get_cached_session(SSL *ssl, unsigned char *id, int len, int *copy) { + const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + *copy = 0; + + SSLSessionID sid(id, len); + if (diags->tag_activated("ssl.session_cache")) { + char printable_buf[(len * 2) + 1]; + sid.toString(printable_buf, sizeof(printable_buf)); + Debug("ssl.session_cache.get", "ssl_get_cached_session cached session '%s' on name '%s'", printable_buf, servername); + } + + SSL_SESSION *session = NULL; + if(session_cache->getSession(sid, servername, &session)) + return session; + else + return NULL; + +} + +static int ssl_new_cached_session(SSL *ssl, SSL_SESSION *sess) { + unsigned int len = 0; + const unsigned char *id = SSL_SESSION_get_id(sess, &len); + const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + + SSLSessionID sid(id, len); + if (diags->tag_activated("ssl.session_cache")) { + char printable_buf[(len * 2) + 1]; + sid.toString(printable_buf, sizeof(printable_buf)); + Debug("ssl.session_cache.insert", "ssl_new_cached_session session '%s' on name '%s'", printable_buf, servername); + } + + session_cache->insertSession(sid, servername, sess); + + return 0; +} + +static void ssl_rm_cached_session(SSL_CTX *ctx, SSL_SESSION *sess) { + SSL_CTX_remove_session(ctx, sess); + + unsigned int len = 0; + const unsigned char *id = SSL_SESSION_get_id(sess, &len); + + SSLSessionID sid(id, len); + if (diags->tag_activated("ssl.session_cache")) { + char printable_buf[(len * 2) + 1]; + sid.toString(printable_buf, sizeof(printable_buf)); + Debug("ssl.session_cache.remove", "ssl_rm_cached_session cached session '%s'", printable_buf); + } + + session_cache->removeSession(sid); +} + + + #if TS_USE_TLS_SNI static int @@ -691,6 +748,22 @@ SSLInitializeStatistics() RECD_INT, RECP_PERSISTENT, (int) ssl_total_tickets_renewed_stat, RecRawStatSyncCount); + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_hit", + RECD_INT, RECP_PERSISTENT, (int) ssl_session_cache_hit, + RecRawStatSyncCount); + + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_miss", + RECD_INT, RECP_PERSISTENT, (int) ssl_session_cache_miss, + RecRawStatSyncCount); + + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_eviction", + RECD_INT, RECP_PERSISTENT, (int) ssl_session_cache_eviction, + RecRawStatSyncCount); + + RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_session_cache_lock_contention", + RECD_INT, RECP_PERSISTENT, (int) ssl_session_cache_lock_contention, + RecRawStatSyncCount); + /* error stats */ RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_want_write", RECD_INT, RECP_PERSISTENT, (int) ssl_error_want_write, @@ -993,18 +1066,37 @@ SSLInitServerContext( // disable selected protocols SSL_CTX_set_options(ctx, params->ssl_ctx_options); + Debug("ssl.session_cache", "ssl context=%p: using session cache options, enabled=%d, size=%d, num_buckets=%d, skip_on_contention=%d, timeout=%d", + ctx, params->ssl_session_cache, params->ssl_session_cache_size, params->ssl_session_cache_num_buckets, + params->ssl_session_cache_skip_on_contention, params->ssl_session_cache_timeout); + if (params->ssl_session_cache_timeout) { - SSL_CTX_set_timeout(ctx, params->ssl_session_cache_timeout); + SSL_CTX_set_timeout(ctx, params->ssl_session_cache_timeout); } switch (params->ssl_session_cache) { case SSLConfigParams::SSL_SESSION_CACHE_MODE_OFF: - SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF|SSL_SESS_CACHE_NO_INTERNAL); + Debug("ssl.session_cache", "disabling SSL session cache"); + + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF | SSL_SESS_CACHE_NO_INTERNAL); break; - case SSLConfigParams::SSL_SESSION_CACHE_MODE_SERVER: + case SSLConfigParams::SSL_SESSION_CACHE_MODE_SERVER_OPENSSL_IMPL: + Debug("ssl.session_cache", "enabling SSL session cache with OpenSSL implementation"); + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER); SSL_CTX_sess_set_cache_size(ctx, params->ssl_session_cache_size); break; + case SSLConfigParams::SSL_SESSION_CACHE_MODE_SERVER_ATS_IMPL: { + Debug("ssl.session_cache", "enabling SSL session cache with ATS implementation"); + /* Add all the OpenSSL callbacks */ + SSL_CTX_sess_set_new_cb(ctx, ssl_new_cached_session); + SSL_CTX_sess_set_remove_cb(ctx, ssl_rm_cached_session); + SSL_CTX_sess_set_get_cb(ctx, ssl_get_cached_session); + + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_INTERNAL); + + break; + } } #ifdef SSL_MODE_RELEASE_BUFFERS http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/lib/ts/ink_mutex.h ---------------------------------------------------------------------- diff --git a/lib/ts/ink_mutex.h b/lib/ts/ink_mutex.h index 326d6bb..1de3e9a 100644 --- a/lib/ts/ink_mutex.h +++ b/lib/ts/ink_mutex.h @@ -127,4 +127,33 @@ private: ink_mutex& mtx; }; +struct ink_scoped_try_mutex +{ + explicit ink_scoped_try_mutex(ink_mutex& m) : mtx(m), has_lock(false) { + if(ink_mutex_try_acquire(&mtx)) { + has_lock = true; + } + } + + void lock() { + if (!has_lock) + ink_mutex_acquire(&mtx); + has_lock = true; + } + + bool hasLock() const { + return has_lock; + } + + ~ink_scoped_try_mutex() { + if (has_lock) + ink_mutex_release(&mtx); + } + +private: + ink_mutex& mtx; + bool has_lock; +}; + + #endif /* _ink_mutex_h_ */ http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/mgmt/RecordsConfig.cc ---------------------------------------------------------------------- diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 6455831..f042037 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1286,9 +1286,13 @@ RecordElement RecordsConfig[] = { , {RECT_CONFIG, "proxy.config.ssl.client.CA.cert.path", RECD_STRING, TS_BUILD_SYSCONFDIR, RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL} , - {RECT_CONFIG, "proxy.config.ssl.session_cache", RECD_INT, "1", RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL} + {RECT_CONFIG, "proxy.config.ssl.session_cache", RECD_INT, "2", RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL} , - {RECT_CONFIG, "proxy.config.ssl.session_cache.size", RECD_INT, "20480", RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL} + {RECT_CONFIG, "proxy.config.ssl.session_cache.size", RECD_INT, "102400", RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL} + , + {RECT_CONFIG, "proxy.config.ssl.session_cache.num_buckets", RECD_INT, "256", RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL} + , + {RECT_CONFIG, "proxy.config.ssl.session_cache.skip_cache_on_bucket_contention", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_NULL, NULL, RECA_NULL} , {RECT_CONFIG, "proxy.config.ssl.max_record_size", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_NULL, NULL, RECA_NULL} , http://git-wip-us.apache.org/repos/asf/trafficserver/blob/53bf5d1e/proxy/Makefile.am ---------------------------------------------------------------------- diff --git a/proxy/Makefile.am b/proxy/Makefile.am index dc5c2a3..6a659b1 100644 --- a/proxy/Makefile.am +++ b/proxy/Makefile.am @@ -213,11 +213,11 @@ traffic_server_LDADD = \ $(top_builddir)/iocore/cluster/libinkcluster.a \ $(top_builddir)/iocore/cache/libinkcache.a \ $(top_builddir)/iocore/aio/libinkaio.a \ + $(top_builddir)/lib/ts/libtsutil.la \ $(top_builddir)/iocore/net/libinknet.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/lib/records/librecords_p.a \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ - $(top_builddir)/lib/ts/libtsutil.la \ @HWLOC_LIBS@ \ @LIBPCRE@ \ @OPENSSL_LIBS@ \
