Skip to content

Commit

Permalink
Pre-warming TLS Tunnel (#7661)
Browse files Browse the repository at this point in the history
  • Loading branch information
masaori335 authored Oct 4, 2021
1 parent cba5e85 commit d1e2dd8
Show file tree
Hide file tree
Showing 27 changed files with 2,367 additions and 19 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ proxy/http/remap/test_PluginDso
proxy/http/remap/test_PluginFactory
proxy/http/remap/test_RemapPluginInfo
proxy/http/test_proxy_http
proxy/http/test_PreWarm
proxy/http/remap/test_*
proxy/http2/test_libhttp2
proxy/http2/test_Http2DependencyTree
Expand Down
24 changes: 24 additions & 0 deletions doc/admin-guide/files/records.config.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3949,6 +3949,30 @@ SNI Routing
Frequency of checking the activity of SNI Routing Tunnel. Set to ``0`` to disable monitoring of the activity of the SNI tunnels.
The feature is disabled by default.

.. ts:cv:: CONFIG proxy.config.tunnel.prewarm INT 0
Enable :ref:`pre-warming-tls-tunnel`. The feature is disabled by default.

.. ts:cv:: CONFIG proxy.config.tunnel.prewarm.max_stats_size INT 100
Max size of :ref:`dynamic stats for Pre-warming TLS Tunnel <pre-warming-tls-tunnel-stats>`.

.. ts:cv:: CONFIG proxy.config.tunnel.prewarm.algorithm INT 2
Version of pre-warming algorithm.

===== ======================================================================
Value Description
===== ======================================================================
``1`` Periodical pre-warming only
``2`` Event based pre-warming + Periodical pre-warming
===== ======================================================================

.. ts:cv:: CONFIG proxy.config.tunnel.prewarm.event_period INT 1000
:units: milliseconds

Frequency of periodical pre-warming in milli-seconds.

OCSP Stapling Configuration
===========================

Expand Down
21 changes: 21 additions & 0 deletions doc/admin-guide/files/sni.yaml.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,27 @@ tunnel_alpn Inbound List of ALPN Protocol Ids for Partial Blind
This only works with ``partial_blind_route``.
========================= ========= ========================================================================================

Pre-warming TLS Tunnel
----------------------

=============================== ========================================================================================
Key Meaning
=============================== ========================================================================================
tunnel_prewarm Override :ts:cv:`proxy.config.tunnel.prewarm` in records.config.

tunnel_prewarm_srv Enable SRV record lookup on pre-warming. Default is ``false``.

tunnel_prewarm_rate Rate of how many connections to pre-warm. Default is ``1.0``.

tunnel_prewarm_min Minimum number of pre-warming queue size (per thread). Default is ``0``.

tunnel_prewarm_max Maximum number of pre-warming queue size (per thread). Default is ``-1`` (unlimited).

tunnel_prewarm_connect_timeout Timeout for TCP/TLS handshake (in seconds).

tunnel_prewarm_inactive_timeout Inactive timeout for connections in the pool (in seconds).
=============================== ========================================================================================

Client verification, via ``verify_client``, corresponds to setting
:ts:cv:`proxy.config.ssl.client.certification_level` for this connection as noted below.

Expand Down
48 changes: 48 additions & 0 deletions doc/admin-guide/layer-4-routing.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,51 @@ tunneled connection like this, the only transaction hooks that will be triggered
:c:macro:`TS_HTTP_TXN_START_HOOK` and :c:macro:`TS_HTTP_TXN_CLOSE_HOOK`. In addition, because |TS|
does not terminate (and therefore does not decrypt) the connection, it cannot be cached or served from
cache.

.. _pre-warming-tls-tunnel:

Pre-warming TLS Tunnel
======================

Pre-warming TLS Tunnel reduces the latency of TLS connections (``forward_route`` and ``partial_blind_route`` type SNI
Routing). When this feature is enabled, each ET_NET thread makes TLS connections pool per routing type, SNI, and ALPN.

.. figure:: ../uml/images/l4-pre-warming-overview.svg
:align: center

Stats for connection pools are registered dynamically on start up. Details in :ref:`pre-warming-tls-tunnel-stats`.

Examples
--------

.. code:: yaml
sni:
- fqdn: foo.com
http2: off
partial_blind_route: bar.com
client_sni_policy: server_name
tunnel_prewarm: true
tunnel_prewarm_connect_timeout: 10
tunnel_prewarm_inactive_timeout: 150
tunnel_prewarm_max: 100
tunnel_prewarm_min: 10
tunnel_alpn:
- h2
.. code::
proxy.process.tunnel.prewarm.bar.com:443.tls.current_init 0
proxy.process.tunnel.prewarm.bar.com:443.tls.current_open 10
proxy.process.tunnel.prewarm.bar.com:443.tls.total_hit 0
proxy.process.tunnel.prewarm.bar.com:443.tls.total_miss 0
proxy.process.tunnel.prewarm.bar.com:443.tls.total_handshake_time 1106250000
proxy.process.tunnel.prewarm.bar.com:443.tls.total_handshake_count 10
proxy.process.tunnel.prewarm.bar.com:443.tls.total_retry 0
proxy.process.tunnel.prewarm.bar.com:443.tls.http2.current_init 0
proxy.process.tunnel.prewarm.bar.com:443.tls.http2.current_open 10
proxy.process.tunnel.prewarm.bar.com:443.tls.http2.total_hit 0
proxy.process.tunnel.prewarm.bar.com:443.tls.http2.total_miss 0
proxy.process.tunnel.prewarm.bar.com:443.tls.http2.total_handshake_time 1142368000
proxy.process.tunnel.prewarm.bar.com:443.tls.http2.total_handshake_count 10
proxy.process.tunnel.prewarm.bar.com:443.tls.http2.total_retry 0
42 changes: 42 additions & 0 deletions doc/admin-guide/monitoring/statistics/core/ssl.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,45 @@ SSL/TLS
:type: gauge

A gauge of current active SNI Routing Tunnels.

.. _pre-warming-tls-tunnel-stats:

Pre-warming TLS Tunnel
----------------------

Stats for Pre-warming TLS Tunnel is registered dynamically. The ``POOL`` in below represents combination of ``<Hostname of destination>.<Type of Tunnel>.<ALPN Name (if there)>``.

.. ts:stat:: global proxy.process.tunnel.prewarm.POOL.current_init integer
:type: gauge

Represents the current number of initializing connections in the pool.

.. ts:stat:: global proxy.process.tunnel.prewarm.POOL.current_open integer
:type: gauge

Represents the current number of established connections in the pool.

.. ts:stat:: global proxy.process.tunnel.prewarm.POOL.total_hit integer
:type: counter

Represents the total number of pre-warmed connection is used.

.. ts:stat:: global proxy.process.tunnel.prewarm.POOL.total_miss integer
:type: counter

Represents the total number of pre-warmed connection is not used.

.. ts:stat:: global proxy.process.tunnel.prewarm.POOL.total_handshake_time integer
:type: counter

Represents the total number of handshake duration of pre-warming.

.. ts:stat:: global proxy.process.tunnel.prewarm.POOL.total_handshake_count integer
:type: counter

Represents the total number of handshake time of pre-warming.

.. ts:stat:: global proxy.process.tunnel.prewarm.POOL.total_retry integer
:type: counter

Represents the total number of pre-warming retry.
32 changes: 32 additions & 0 deletions doc/uml/l4-pre-warming-overview.uml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
' Licensed 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.

@startuml
'title Pre-warm TLS Tunnel
skinparam sequenceMessageAlign direction
skinparam ParticipantPadding 75
'skinparam monochrome reverse
skinparam backgroundColor #white
hide footbox

participant client
participant proxy
participant origin_server

group pre-warm connection pool
proxy -> origin_server : open connection
proxy -> origin_server : open connection
proxy -> origin_server : open connection
...
end
...
group pool size > 0
client -> proxy : open connection
hnote over proxy #white: use pre-warmed connection from pool
rnote over client, origin_server #lightgreen: TLS Partial Blind Tunnel
end
@enduml
3 changes: 3 additions & 0 deletions iocore/eventsystem/I_EThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ struct DiskHandler;
struct EventIO;

class ServerSessionPool;
class PreWarmQueue;

class Event;
class Continuation;

Expand Down Expand Up @@ -349,6 +351,7 @@ class EThread : public Thread
Event *start_event = nullptr;

ServerSessionPool *server_session_pool = nullptr;
PreWarmQueue *prewarm_queue = nullptr;

/** Default handler used until it is overridden.
Expand Down
1 change: 1 addition & 0 deletions iocore/eventsystem/I_Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ class Thread
ProxyAllocator ioDataAllocator;
ProxyAllocator ioAllocator;
ProxyAllocator ioBlockAllocator;
ProxyAllocator preWarmSMAllocator;
// From InkAPI (plugins wrappers)
ProxyAllocator apiHookAllocator;
ProxyAllocator INKContAllocator;
Expand Down
12 changes: 7 additions & 5 deletions iocore/net/P_SNIActionPerformer.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,9 @@ class ControlH2 : public ActionItem
class TunnelDestination : public ActionItem
{
public:
TunnelDestination(const std::string_view &dest, SNIRoutingType type, const std::vector<int> &alpn)
: destination(dest), type(type), alpn_ids(alpn)
TunnelDestination(const std::string_view &dest, SNIRoutingType type, YamlSNIConfig::TunnelPreWarm prewarm,
const std::vector<int> &alpn)
: destination(dest), type(type), tunnel_prewarm(prewarm), alpn_ids(alpn)
{
need_fix = (destination.find_first_of('$') != std::string::npos);
}
Expand All @@ -115,10 +116,10 @@ class TunnelDestination : public ActionItem
// If needed, we will try to amend the tunnel destination.
if (ctx._fqdn_wildcard_captured_groups && need_fix) {
const auto &fixed_dst = replace_match_groups(destination, *ctx._fqdn_wildcard_captured_groups);
ssl_netvc->set_tunnel_destination(fixed_dst, type);
ssl_netvc->set_tunnel_destination(fixed_dst, type, tunnel_prewarm);
Debug("ssl_sni", "Destination now is [%s], configured [%s], fqdn [%s]", fixed_dst.c_str(), destination.c_str(), servername);
} else {
ssl_netvc->set_tunnel_destination(destination, type);
ssl_netvc->set_tunnel_destination(destination, type, tunnel_prewarm);
Debug("ssl_sni", "Destination now is [%s], fqdn [%s]", destination.c_str(), servername);
}

Expand Down Expand Up @@ -202,7 +203,8 @@ class TunnelDestination : public ActionItem
}

std::string destination;
SNIRoutingType type = SNIRoutingType::NONE;
SNIRoutingType type = SNIRoutingType::NONE;
YamlSNIConfig::TunnelPreWarm tunnel_prewarm = YamlSNIConfig::TunnelPreWarm::UNSET;
const std::vector<int> &alpn_ids;
bool need_fix;
};
Expand Down
23 changes: 17 additions & 6 deletions iocore/net/P_SSLNetVConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,11 +298,13 @@ class SSLNetVConnection : public UnixNetVConnection,
bool decrypt_tunnel() const;
bool upstream_tls() const;
SNIRoutingType tunnel_type() const;
YamlSNIConfig::TunnelPreWarm tunnel_prewarm() const;

void
set_tunnel_destination(const std::string_view &destination, SNIRoutingType type)
set_tunnel_destination(const std::string_view &destination, SNIRoutingType type, YamlSNIConfig::TunnelPreWarm prewarm)
{
_tunnel_type = type;
_tunnel_type = type;
_tunnel_prewarm = prewarm;

auto pos = destination.find(":");
if (nullptr != tunnel_host) {
Expand Down Expand Up @@ -486,10 +488,13 @@ class SSLNetVConnection : public UnixNetVConnection,
HANDSHAKE_HOOKS_DONE
} sslHandshakeHookState = HANDSHAKE_HOOKS_PRE;

int64_t redoWriteSize = 0;
char *tunnel_host = nullptr;
in_port_t tunnel_port = 0;
SNIRoutingType _tunnel_type = SNIRoutingType::NONE;
int64_t redoWriteSize = 0;

char *tunnel_host = nullptr;
in_port_t tunnel_port = 0;
SNIRoutingType _tunnel_type = SNIRoutingType::NONE;
YamlSNIConfig::TunnelPreWarm _tunnel_prewarm = YamlSNIConfig::TunnelPreWarm::UNSET;

X509_STORE_CTX *verify_cert = nullptr;

// Null-terminated string, or nullptr if there is no SNI server name.
Expand Down Expand Up @@ -523,6 +528,12 @@ SSLNetVConnection::tunnel_type() const
return _tunnel_type;
}

inline YamlSNIConfig::TunnelPreWarm
SSLNetVConnection::tunnel_prewarm() const
{
return _tunnel_prewarm;
}

/**
Returns true if this vc was configured for forward_route or partial_blind_route
*/
Expand Down
8 changes: 7 additions & 1 deletion iocore/net/SSLSNIConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
****************************************************************************/

#include "P_SSLSNI.h"

#include "PreWarmManager.h"

#include "tscore/Diags.h"
#include "tscore/SimpleTokenizer.h"
#include "tscore/ink_memory.h"
Expand Down Expand Up @@ -77,7 +80,8 @@ SNIConfigParams::loadSNIConfig()
ai->actions.push_back(std::make_unique<TLSValidProtocols>(item.protocol_mask));
}
if (item.tunnel_destination.length() > 0) {
ai->actions.push_back(std::make_unique<TunnelDestination>(item.tunnel_destination, item.tunnel_type, item.tunnel_alpn));
ai->actions.push_back(
std::make_unique<TunnelDestination>(item.tunnel_destination, item.tunnel_type, item.tunnel_prewarm, item.tunnel_alpn));
}
if (!item.client_sni_policy.empty()) {
ai->actions.push_back(std::make_unique<OutboundSNIPolicy>(item.client_sni_policy));
Expand Down Expand Up @@ -200,6 +204,8 @@ SNIConfig::reconfigure()

params->Initialize();
configid = configProcessor.set(configid, params);

prewarmManager.reconfigure();
}

SNIConfigParams *
Expand Down
Loading

0 comments on commit d1e2dd8

Please sign in to comment.