This is an automated email from the ASF dual-hosted git repository.

maskit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new f6bf8bd16f Add interface for NetVC services (#9482)
f6bf8bd16f is described below

commit f6bf8bd16ff2a6e2847d7e5672d7382d8fcb8a01
Author: Masakazu Kitajo <[email protected]>
AuthorDate: Wed Jul 12 03:01:54 2023 +0900

    Add interface for NetVC services (#9482)
    
    It turned out that the use of dynamic_cast unignorably affects performance. 
#8003
    
    A couple of approaches were suggested where we need to remove dynamic_cast 
for better performance and also want to avoid bringing much dependency into 
NetVConnection, and we took an approach that stores pre-casted pointers for 
mixins into a simple array. This avoids the use of RTTI when it access the 
mixins, and also allows us to use composition pattern, which can reduce the 
sizes of base classes.
    
    Since the dynamic_casts were added separately little by little, we don't 
know how much it decreased the performance, but this change increased RPS by 4%.
    
    Co-authored-by: James Peach <[email protected]>
---
 iocore/net/I_NetVConnection.h           | 133 ++++++++++++++++++++++++++++++++
 iocore/net/QUICNetVConnection_quiche.cc |   9 ++-
 iocore/net/SSLNetVConnection.cc         |  11 ++-
 proxy/ProxySession.cc                   |   2 +-
 proxy/http/Http1ClientSession.cc        |   5 +-
 proxy/http/HttpSM.cc                    |  49 ++++++------
 proxy/http2/Http2ClientSession.cc       |   6 +-
 proxy/private/SSLProxySession.cc        |   2 +-
 src/traffic_server/InkAPI.cc            |  16 ++--
 9 files changed, 188 insertions(+), 45 deletions(-)

diff --git a/iocore/net/I_NetVConnection.h b/iocore/net/I_NetVConnection.h
index f16b5e84d1..d99fbc9df5 100644
--- a/iocore/net/I_NetVConnection.h
+++ b/iocore/net/I_NetVConnection.h
@@ -507,7 +507,20 @@ public:
   bool has_proxy_protocol(IOBufferReader *);
   bool has_proxy_protocol(char *, int64_t *);
 
+  template <typename S> S *get_service() const;
+
 protected:
+  enum class Service : uint8_t {
+    TLS_ALPN,
+    TLS_Basic,
+    TLS_CertSwitch,
+    TLS_EarlyData,
+    TLS_SNI,
+    TLS_SessionResumption,
+    TLS_Tunnel,
+    N_SERVICES,
+  };
+
   IpEndpoint local_addr;
   IpEndpoint remote_addr;
   ProxyProtocol pp_info;
@@ -526,6 +539,16 @@ protected:
   int write_buffer_empty_event = 0;
   /// NetVConnection Context.
   NetVConnectionContext_t netvc_context = NET_VCONNECTION_UNSET;
+
+  template <typename S> void _set_service(S *instance);
+
+private:
+  void *_services[static_cast<unsigned int>(Service::N_SERVICES)] = {
+    nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+  };
+
+  void *_get_service(enum Service mixin_index) const;
+  void _set_service(enum Service mixin_index, void *instance);
 };
 
 inline NetVConnection::NetVConnection() : VConnection(nullptr)
@@ -540,3 +563,113 @@ NetVConnection::trapWriteBufferEmpty(int event)
 {
   write_buffer_empty_event = event;
 }
+
+inline void *
+NetVConnection::_get_service(enum NetVConnection::Service service) const
+{
+  return _services[static_cast<unsigned int>(service)];
+}
+
+inline void
+NetVConnection::_set_service(enum NetVConnection::Service service, void 
*instance)
+{
+  this->_services[static_cast<unsigned int>(service)] = instance;
+}
+
+class ALPNSupport;
+template <>
+inline ALPNSupport *
+NetVConnection::get_service() const
+{
+  return static_cast<ALPNSupport 
*>(this->_get_service(NetVConnection::Service::TLS_ALPN));
+}
+template <>
+inline void
+NetVConnection::_set_service(ALPNSupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_ALPN, instance);
+}
+
+class TLSBasicSupport;
+template <>
+inline TLSBasicSupport *
+NetVConnection::get_service() const
+{
+  return static_cast<TLSBasicSupport 
*>(this->_get_service(NetVConnection::Service::TLS_Basic));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSBasicSupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_Basic, instance);
+}
+
+class TLSEarlyDataSupport;
+template <>
+inline TLSEarlyDataSupport *
+NetVConnection::get_service() const
+{
+  return static_cast<TLSEarlyDataSupport 
*>(this->_get_service(NetVConnection::Service::TLS_EarlyData));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSEarlyDataSupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_EarlyData, instance);
+}
+
+class TLSCertSwitchSupport;
+template <>
+inline TLSCertSwitchSupport *
+NetVConnection::get_service() const
+{
+  return static_cast<TLSCertSwitchSupport 
*>(this->_get_service(NetVConnection::Service::TLS_CertSwitch));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSCertSwitchSupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_CertSwitch, instance);
+}
+
+class TLSSNISupport;
+template <>
+inline TLSSNISupport *
+NetVConnection::get_service() const
+{
+  return static_cast<TLSSNISupport 
*>(this->_get_service(NetVConnection::Service::TLS_SNI));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSSNISupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_SNI, instance);
+}
+
+class TLSSessionResumptionSupport;
+template <>
+inline TLSSessionResumptionSupport *
+NetVConnection::get_service() const
+{
+  return static_cast<TLSSessionResumptionSupport 
*>(this->_get_service(NetVConnection::Service::TLS_SessionResumption));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSSessionResumptionSupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_SessionResumption, instance);
+}
+
+class TLSTunnelSupport;
+template <>
+inline TLSTunnelSupport *
+NetVConnection::get_service() const
+{
+  return static_cast<TLSTunnelSupport 
*>(this->_get_service(NetVConnection::Service::TLS_Tunnel));
+}
+template <>
+inline void
+NetVConnection::_set_service(TLSTunnelSupport *instance)
+{
+  this->_set_service(NetVConnection::Service::TLS_Tunnel, instance);
+}
diff --git a/iocore/net/QUICNetVConnection_quiche.cc 
b/iocore/net/QUICNetVConnection_quiche.cc
index 2d638f9928..321e356980 100644
--- a/iocore/net/QUICNetVConnection_quiche.cc
+++ b/iocore/net/QUICNetVConnection_quiche.cc
@@ -37,7 +37,14 @@ static constexpr ink_hrtime WRITE_READY_INTERVAL = 
HRTIME_MSECONDS(2);
 
 ClassAllocator<QUICNetVConnection> quicNetVCAllocator("quicNetVCAllocator");
 
-QUICNetVConnection::QUICNetVConnection() {}
+QUICNetVConnection::QUICNetVConnection()
+{
+  this->_set_service(static_cast<ALPNSupport *>(this));
+  this->_set_service(static_cast<TLSBasicSupport *>(this));
+  this->_set_service(static_cast<TLSCertSwitchSupport *>(this));
+  this->_set_service(static_cast<TLSSNISupport *>(this));
+  this->_set_service(static_cast<TLSSessionResumptionSupport *>(this));
+}
 
 QUICNetVConnection::~QUICNetVConnection() {}
 
diff --git a/iocore/net/SSLNetVConnection.cc b/iocore/net/SSLNetVConnection.cc
index 5f63126d58..376969af06 100644
--- a/iocore/net/SSLNetVConnection.cc
+++ b/iocore/net/SSLNetVConnection.cc
@@ -862,7 +862,16 @@ SSLNetVConnection::load_buffer_and_write(int64_t towrite, 
MIOBufferAccessor &buf
   return num_really_written;
 }
 
-SSLNetVConnection::SSLNetVConnection() {}
+SSLNetVConnection::SSLNetVConnection()
+{
+  this->_set_service(static_cast<ALPNSupport *>(this));
+  this->_set_service(static_cast<TLSBasicSupport *>(this));
+  this->_set_service(static_cast<TLSCertSwitchSupport *>(this));
+  this->_set_service(static_cast<TLSEarlyDataSupport *>(this));
+  this->_set_service(static_cast<TLSSNISupport *>(this));
+  this->_set_service(static_cast<TLSSessionResumptionSupport *>(this));
+  this->_set_service(static_cast<TLSTunnelSupport *>(this));
+}
 
 void
 SSLNetVConnection::do_io_close(int lerrno)
diff --git a/proxy/ProxySession.cc b/proxy/ProxySession.cc
index a4feee97ae..ab4211cd3c 100644
--- a/proxy/ProxySession.cc
+++ b/proxy/ProxySession.cc
@@ -287,7 +287,7 @@ ProxySession::get_local_addr()
 void
 ProxySession::_handle_if_ssl(NetVConnection *new_vc)
 {
-  auto tbs = dynamic_cast<TLSBasicSupport *>(new_vc);
+  auto tbs = new_vc->get_service<TLSBasicSupport>();
   if (tbs) {
     _ssl = std::make_unique<SSLProxySession>();
     _ssl.get()->init(*new_vc);
diff --git a/proxy/http/Http1ClientSession.cc b/proxy/http/Http1ClientSession.cc
index 23f7696ca3..ff1f58bbfd 100644
--- a/proxy/http/Http1ClientSession.cc
+++ b/proxy/http/Http1ClientSession.cc
@@ -141,8 +141,7 @@ Http1ClientSession::new_connection(NetVConnection *new_vc, 
MIOBuffer *iobuf, IOB
   trans.mutex = mutex; // Share this mutex with the transaction
   in_destroy  = false;
 
-  TLSEarlyDataSupport *eds = dynamic_cast<TLSEarlyDataSupport *>(new_vc);
-  if (eds != nullptr) {
+  if (TLSEarlyDataSupport *eds = new_vc->get_service<TLSEarlyDataSupport>()) {
     read_from_early_data = eds->get_early_data_len();
     Debug("ssl_early_data", "read_from_early_data = %" PRId64, 
read_from_early_data);
   }
@@ -534,7 +533,7 @@ bool
 Http1ClientSession::allow_half_open() const
 {
   // Only allow half open connections if the not over TLS
-  return (_vc && dynamic_cast<TLSBasicSupport *>(_vc) == nullptr);
+  return (_vc && _vc->get_service<TLSBasicSupport>() == nullptr);
 }
 
 void
diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc
index af3a5167ad..e5339a234b 100644
--- a/proxy/http/HttpSM.cc
+++ b/proxy/http/HttpSM.cc
@@ -522,7 +522,7 @@ HttpSM::attach_client_session(ProxyTransaction *client_vc)
   mptcp_state       = netvc->get_mptcp_state();
   client_tcp_reused = !(ua_txn->is_first_transaction());
 
-  if (auto tbs = dynamic_cast<TLSBasicSupport *>(netvc)) {
+  if (auto tbs = netvc->get_service<TLSBasicSupport>()) {
     client_connection_is_ssl = true;
     const char *protocol     = tbs->get_tls_protocol_name();
     client_sec_protocol      = protocol ? protocol : "-";
@@ -538,11 +538,11 @@ HttpSM::attach_client_session(ProxyTransaction *client_vc)
     }
   }
 
-  if (auto as = dynamic_cast<ALPNSupport *>(netvc)) {
+  if (auto as = netvc->get_service<ALPNSupport>()) {
     client_alpn_id = as->get_negotiated_protocol_id();
   }
 
-  if (auto tsrs = dynamic_cast<TLSSessionResumptionSupport *>(netvc)) {
+  if (auto tsrs = netvc->get_service<TLSSessionResumptionSupport>()) {
     client_ssl_reused = tsrs->getSSLSessionCacheHit();
   }
 
@@ -585,7 +585,7 @@ HttpSM::attach_client_session(ProxyTransaction *client_vc)
   t_state.hdr_info.client_request.create(HTTP_TYPE_REQUEST);
 
   // Prepare raw reader which will live until we are sure this is HTTP indeed
-  auto *tts = dynamic_cast<TLSTunnelSupport *>(netvc);
+  auto tts = netvc->get_service<TLSTunnelSupport>();
   if (is_transparent_passthrough_allowed() || (tts && 
tts->is_decryption_needed())) {
     ua_raw_buffer_reader = ua_txn->get_remote_reader()->clone();
   }
@@ -649,7 +649,7 @@ HttpSM::setup_blind_tunnel_port()
   }
 
   TLSTunnelSupport *tts = nullptr;
-  if (!ua_txn->is_outbound_transparent() && (tts = 
dynamic_cast<TLSTunnelSupport *>(netvc))) {
+  if (!ua_txn->is_outbound_transparent() && (tts = 
netvc->get_service<TLSTunnelSupport>())) {
     if (!t_state.hdr_info.client_request.url_get()->host_get(&host_len)) {
       if (tts->has_tunnel_destination()) {
         auto tunnel_host = tts->get_tunnel_host();
@@ -1513,20 +1513,21 @@ plugins required to work with sni_routing.
       t_state.hdr_info.client_request.url_set(&u);
 
       NetVConnection *netvc = ua_txn->get_netvc();
-      auto *tts             = dynamic_cast<TLSTunnelSupport *>(netvc);
 
-      if (tts && tts->has_tunnel_destination()) {
-        auto tunnel_host = tts->get_tunnel_host();
-        
t_state.hdr_info.client_request.url_get()->host_set(tunnel_host.data(), 
tunnel_host.size());
-        ushort tunnel_port = tts->get_tunnel_port();
-        if (tunnel_port > 0) {
-          t_state.hdr_info.client_request.url_get()->port_set(tunnel_port);
+      if (auto tts = netvc->get_service<TLSTunnelSupport>(); tts) {
+        if (tts->has_tunnel_destination()) {
+          auto tunnel_host = tts->get_tunnel_host();
+          
t_state.hdr_info.client_request.url_get()->host_set(tunnel_host.data(), 
tunnel_host.size());
+          ushort tunnel_port = tts->get_tunnel_port();
+          if (tunnel_port > 0) {
+            t_state.hdr_info.client_request.url_get()->port_set(tunnel_port);
+          } else {
+            
t_state.hdr_info.client_request.url_get()->port_set(netvc->get_local_port());
+          }
         } else {
+          
t_state.hdr_info.client_request.url_get()->host_set(netvc->get_server_name(), 
strlen(netvc->get_server_name()));
           
t_state.hdr_info.client_request.url_get()->port_set(netvc->get_local_port());
         }
-      } else if (tts) {
-        
t_state.hdr_info.client_request.url_get()->host_set(netvc->get_server_name(), 
strlen(netvc->get_server_name()));
-        
t_state.hdr_info.client_request.url_get()->port_set(netvc->get_local_port());
       }
     }
   // FALLTHROUGH
@@ -1678,7 +1679,7 @@ HttpSM::handle_api_return()
   switch (t_state.api_next_action) {
   case HttpTransact::SM_ACTION_API_SM_START: {
     NetVConnection *netvc = ua_txn->get_netvc();
-    auto *tts             = dynamic_cast<TLSTunnelSupport *>(netvc);
+    auto *tts             = netvc->get_service<TLSTunnelSupport>();
     bool forward_dest     = tts != nullptr && tts->is_decryption_needed();
     if (t_state.client_info.port_attribute == 
HttpProxyPort::TRANSPORT_BLIND_TUNNEL || forward_dest) {
       setup_blind_tunnel_port();
@@ -1821,10 +1822,9 @@ PoolableSession *
 HttpSM::create_server_session(NetVConnection *netvc, MIOBuffer 
*netvc_read_buffer, IOBufferReader *netvc_reader)
 {
   // Figure out what protocol was negotiated
-  int proto_index      = SessionProtocolNameRegistry::INVALID;
-  auto const *sslnetvc = dynamic_cast<ALPNSupport *>(netvc);
-  if (sslnetvc) {
-    proto_index = sslnetvc->get_negotiated_protocol_id();
+  int proto_index = SessionProtocolNameRegistry::INVALID;
+  if (auto const alpn = netvc->get_service<ALPNSupport>(); alpn) {
+    proto_index = alpn->get_negotiated_protocol_id();
   }
   // No ALPN occurred. Assume it was HTTP/1.x and hope for the best
   if (proto_index == SessionProtocolNameRegistry::INVALID) {
@@ -5576,7 +5576,7 @@ HttpSM::do_http_server_open(bool raw, bool only_direct)
   int scheme_to_use = t_state.scheme; // get initial scheme
   bool tls_upstream = scheme_to_use == URL_WKSIDX_HTTPS;
   if (ua_txn) {
-    auto *tts = dynamic_cast<TLSTunnelSupport *>(ua_txn->get_netvc());
+    auto tts = ua_txn->get_netvc()->get_service<TLSTunnelSupport>();
     if (tts && raw) {
       tls_upstream = tts->is_upstream_tls();
       _tunnel_type = tts->get_tunnel_type();
@@ -5584,7 +5584,7 @@ HttpSM::do_http_server_open(bool raw, bool only_direct)
       // ALPN on TLS Partial Blind Tunnel - set negotiated ALPN id
       int pid = SessionProtocolNameRegistry::INVALID;
       if (tts->get_tunnel_type() == SNIRoutingType::PARTIAL_BLIND) {
-        auto *alpns = dynamic_cast<ALPNSupport *>(ua_txn->get_netvc());
+        auto alpns = ua_txn->get_netvc()->get_service<ALPNSupport>();
         ink_assert(alpns);
         pid = alpns->get_negotiated_protocol_id();
         if (pid != SessionProtocolNameRegistry::INVALID) {
@@ -6605,12 +6605,11 @@ HttpSM::attach_server_session()
   UnixNetVConnection *server_vc = static_cast<UnixNetVConnection 
*>(server_txn->get_netvc());
 
   // set flag for server session is SSL
-  TLSBasicSupport *tbs = dynamic_cast<TLSBasicSupport *>(server_vc);
-  if (tbs) {
+  if (server_vc->get_service<TLSBasicSupport>()) {
     server_connection_is_ssl = true;
   }
 
-  if (auto tsrs = dynamic_cast<TLSSessionResumptionSupport *>(server_vc)) {
+  if (auto tsrs = server_vc->get_service<TLSSessionResumptionSupport>(); tsrs) 
{
     server_ssl_reused = tsrs->getSSLOriginSessionCacheHit();
   }
 
diff --git a/proxy/http2/Http2ClientSession.cc 
b/proxy/http2/Http2ClientSession.cc
index 56ce64928f..d7a43d773b 100644
--- a/proxy/http2/Http2ClientSession.cc
+++ b/proxy/http2/Http2ClientSession.cc
@@ -101,8 +101,7 @@ Http2ClientSession::new_connection(NetVConnection *new_vc, 
MIOBuffer *iobuf, IOB
 
   this->connection_state.mutex = this->mutex;
 
-  TLSEarlyDataSupport *eds = dynamic_cast<TLSEarlyDataSupport *>(new_vc);
-  if (eds != nullptr) {
+  if (auto eds = new_vc->get_service<TLSEarlyDataSupport>(); eds) {
     this->read_from_early_data = eds->get_early_data_len();
     Debug("ssl_early_data", "read_from_early_data = %" PRId64, 
this->read_from_early_data);
   }
@@ -120,8 +119,7 @@ Http2ClientSession::new_connection(NetVConnection *new_vc, 
MIOBuffer *iobuf, IOB
   this->write_buffer           = new_MIOBuffer(buffer_block_size_index);
 
   uint32_t buffer_water_mark;
-  TLSSNISupport *snis = dynamic_cast<TLSSNISupport *>(this->_vc);
-  if (snis && snis->hints_from_sni.http2_buffer_water_mark.has_value()) {
+  if (auto snis = this->_vc->get_service<TLSSNISupport>(); snis && 
snis->hints_from_sni.http2_buffer_water_mark.has_value()) {
     buffer_water_mark = snis->hints_from_sni.http2_buffer_water_mark.value();
   } else {
     buffer_water_mark = Http2::buffer_water_mark;
diff --git a/proxy/private/SSLProxySession.cc b/proxy/private/SSLProxySession.cc
index 32da935cf6..1838cb839f 100644
--- a/proxy/private/SSLProxySession.cc
+++ b/proxy/private/SSLProxySession.cc
@@ -29,7 +29,7 @@
 void
 SSLProxySession::init(NetVConnection const &new_vc)
 {
-  if (dynamic_cast<const TLSSNISupport *>(&new_vc) != nullptr) {
+  if (new_vc.get_service<TLSSNISupport>() != nullptr) {
     if (char const *name = new_vc.get_server_name()) {
       _client_sni_server_name.assign(name);
     }
diff --git a/src/traffic_server/InkAPI.cc b/src/traffic_server/InkAPI.cc
index a58bb29981..3afca1e576 100644
--- a/src/traffic_server/InkAPI.cc
+++ b/src/traffic_server/InkAPI.cc
@@ -6571,7 +6571,7 @@ const char *
 TSVConnSslCipherGet(TSVConn sslp)
 {
   NetVConnection *vc     = reinterpret_cast<NetVConnection *>(sslp);
-  TLSBasicSupport *tlsbs = dynamic_cast<TLSBasicSupport *>(vc);
+  TLSBasicSupport *tlsbs = vc->get_service<TLSBasicSupport>();
 
   return tlsbs ? tlsbs->get_tls_cipher_suite() : nullptr;
 }
@@ -6580,7 +6580,7 @@ const char *
 TSVConnSslProtocolGet(TSVConn sslp)
 {
   NetVConnection *vc     = reinterpret_cast<NetVConnection *>(sslp);
-  TLSBasicSupport *tlsbs = dynamic_cast<TLSBasicSupport *>(vc);
+  TLSBasicSupport *tlsbs = vc->get_service<TLSBasicSupport>();
 
   return tlsbs ? tlsbs->get_tls_protocol_name() : nullptr;
 }
@@ -6589,7 +6589,7 @@ const char *
 TSVConnSslCurveGet(TSVConn sslp)
 {
   NetVConnection *vc     = reinterpret_cast<NetVConnection *>(sslp);
-  TLSBasicSupport *tlsbs = dynamic_cast<TLSBasicSupport *>(vc);
+  TLSBasicSupport *tlsbs = vc->get_service<TLSBasicSupport>();
 
   return tlsbs ? tlsbs->get_tls_curve() : nullptr;
 }
@@ -9674,9 +9674,8 @@ TSVConnProtocolEnable(TSVConn connp, const char 
*protocol_name)
   TSReturnCode retval = TS_ERROR;
   int protocol_idx    = 
globalSessionProtocolNameRegistry.toIndexConst(std::string_view{protocol_name});
   auto net_vc         = reinterpret_cast<UnixNetVConnection *>(connp);
-  auto alpn_vc        = dynamic_cast<ALPNSupport *>(net_vc);
-  if (alpn_vc) {
-    alpn_vc->enableProtocol(protocol_idx);
+  if (auto alpn = net_vc->get_service<ALPNSupport>(); alpn) {
+    alpn->enableProtocol(protocol_idx);
     retval = TS_SUCCESS;
   }
   return retval;
@@ -9688,9 +9687,8 @@ TSVConnProtocolDisable(TSVConn connp, const char 
*protocol_name)
   TSReturnCode retval = TS_ERROR;
   int protocol_idx    = 
globalSessionProtocolNameRegistry.toIndexConst(std::string_view{protocol_name});
   auto net_vc         = reinterpret_cast<UnixNetVConnection *>(connp);
-  auto alpn_vc        = dynamic_cast<ALPNSupport *>(net_vc);
-  if (alpn_vc) {
-    alpn_vc->disableProtocol(protocol_idx);
+  if (auto alpn = net_vc->get_service<ALPNSupport>(); alpn) {
+    alpn->disableProtocol(protocol_idx);
     retval = TS_SUCCESS;
   }
   return retval;

Reply via email to