You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2022/06/01 21:39:37 UTC

[trafficserver] branch 9.2.x updated: Expose setting some HTTP/2 tunables via sni.yaml (#8818) (#8875)

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

zwoop pushed a commit to branch 9.2.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/9.2.x by this push:
     new 6550d8184 Expose setting some HTTP/2 tunables via sni.yaml (#8818) (#8875)
6550d8184 is described below

commit 6550d81849b66a1f52c73bdce15b2c03d93cac29
Author: Randall Meyer <rr...@apache.org>
AuthorDate: Wed Jun 1 14:39:31 2022 -0700

    Expose setting some HTTP/2 tunables via sni.yaml (#8818) (#8875)
    
    proxy.config.http2.default_buffer_water_mark can now be set on a
    per-domain basis.
    
    (cherry picked from commit 63d09be0f470628045f9c19848944a990dde3de9)
---
 doc/admin-guide/files/records.config.en.rst |  8 +++++---
 doc/admin-guide/files/sni.yaml.en.rst       | 10 ++++++++++
 iocore/net/I_NetVConnection.h               |  4 ++--
 iocore/net/P_SNIActionPerformer.h           | 20 ++++++++++++++++++++
 iocore/net/SSLSNIConfig.cc                  |  3 +++
 iocore/net/TLSSNISupport.h                  |  5 +++++
 iocore/net/YamlSNIConfig.cc                 |  4 ++++
 iocore/net/YamlSNIConfig.h                  |  2 ++
 proxy/http2/Http2ClientSession.cc           | 15 ++++++++++++---
 9 files changed, 63 insertions(+), 8 deletions(-)

diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst
index 462777f60..0ac72efba 100644
--- a/doc/admin-guide/files/records.config.en.rst
+++ b/doc/admin-guide/files/records.config.en.rst
@@ -2047,7 +2047,7 @@ Security
    mismatch check is only performed if a relevant security policy for the SNI is set in :file:`sni.yaml`. The
    ``proxy.config.http.host_sni_policy`` :file:`records.config` value is used as the default value if either of these
    policies is set in the corresponding :file:`sni.yaml` file entry and the :file:`sni.yaml` entry does not override
-   this value via a :ref:`host_sni_policy attribute<override-host-sni-policy>` action.
+   this value via a :ref:`host_sni_policy<override-host-sni-policy>` attribute.
 
 
 Cache Control
@@ -3832,7 +3832,7 @@ Client-Related Configuration
    Configures |TS| to verify the origin server certificate
    with the Certificate Authority (CA). This configuration takes a value of :code:`DISABLED`, :code:`PERMISSIVE`, or :code:`ENFORCED`
 
-   You can override this global setting on a per domain basis in the :file:`sni.yaml` file using the :ref:`verify_server_policy attribute<override-verify-server-policy>`.
+   You can override this global setting on a per domain basis in the :file:`sni.yaml` file using the :ref:`verify_server_policy<override-verify-server-policy>` attribute.
 
    You can also override via the conf_remap plugin. Those changes will take precedence over the changes in :file:`sni.yaml`.
 
@@ -3849,7 +3849,7 @@ Client-Related Configuration
 
    Configures |TS| for what the default verify callback should check during origin server verification.
 
-   You can override this global setting on a per domain basis in the :file:`sni.yaml` file using the :ref:`verify_server_properties attribute<override-verify-server-properties>`.
+   You can override this global setting on a per domain basis in the :file:`sni.yaml` file using the :ref:`verify_server_properties<override-verify-server-properties>` attribute.
 
    You can also override via the conf_remap plugin. Those changes will take precedence over the changes in .:file:`sni.yaml`
 
@@ -4254,6 +4254,8 @@ HTTP/2 Configuration
    Specifies the high water mark for all HTTP/2 frames on an outoging connection.
    Default is -1 to preserve existing water marking behavior.
 
+   You can override this global setting on a per domain basis in the :file:`sni.yaml` file using the :ref:`http2_buffer_water_mark <override-h2-properties>` attribute.
+
 HTTP/3 Configuration
 ====================
 
diff --git a/doc/admin-guide/files/sni.yaml.en.rst b/doc/admin-guide/files/sni.yaml.en.rst
index 7a04e4b15..5c1142014 100644
--- a/doc/admin-guide/files/sni.yaml.en.rst
+++ b/doc/admin-guide/files/sni.yaml.en.rst
@@ -42,9 +42,15 @@ Each table is a set of key / value pairs that create a configuration item. This
 wildcard entries. To apply an SNI based setting on all the server names with a common upper level domain name,
 the user needs to enter the fqdn in the configuration with a ``*.`` followed by the common domain name. (``*.yahoo.com`` for example).
 
+For some settings, there is no guarantee that they will be applied to a connection under certain conditions.
+An established TLS connection may be reused for another server name if it’s used for HTTP/2. This also means that settings
+for server name A may affects requests for server name B as well. See https://daniel.haxx.se/blog/2016/08/18/http2-connection-coalescing/
+for a more detailed description of HTTP/2 connection coalescing.
+
 .. _override-verify-server-policy:
 .. _override-verify-server-properties:
 .. _override-host-sni-policy:
+.. _override-h2-properties:
 
 ========================= ========= ========================================================================================
 Key                       Direction Meaning
@@ -130,6 +136,10 @@ client_sni_policy         Outbound  Policy of SNI on outbound connection.
 http2                     Inbound   Indicates whether the H2 protocol should be added to or removed from the
                                     protocol negotiation list.  The valid values are :code:`on` or :code:`off`.
 
+http2_buffer_water_mark   Inbound   Specifies the high water mark for all HTTP/2 frames on an outoging connection.
+                                    By default this is :ts:cv:`proxy.config.http2.default_buffer_water_mark`.
+                                    NOTE: Connection coalescing may prevent this taking effect.
+
 disable_h2                Inbound   Deprecated for the more general h2 setting.  Setting disable_h2
                                     to :code:`true` is the same as setting http2 to :code:`on`.
 
diff --git a/iocore/net/I_NetVConnection.h b/iocore/net/I_NetVConnection.h
index f74c75091..12a889040 100644
--- a/iocore/net/I_NetVConnection.h
+++ b/iocore/net/I_NetVConnection.h
@@ -228,8 +228,6 @@ struct NetVCOptions {
 
   bool tls_upstream = false;
 
-  /// Reset all values to defaults.
-
   /**
    * Set to DISABLED, PERFMISSIVE, or ENFORCED
    * Controls how the server certificate verification is handled
@@ -241,6 +239,8 @@ struct NetVCOptions {
    * Currently SIGNATURE and NAME
    */
   YamlSNIConfig::Property verifyServerProperties = YamlSNIConfig::Property::NONE;
+
+  /// Reset all values to defaults.
   void reset();
 
   void set_sock_param(int _recv_bufsize, int _send_bufsize, unsigned long _opt_flags, unsigned long _packet_mark = 0,
diff --git a/iocore/net/P_SNIActionPerformer.h b/iocore/net/P_SNIActionPerformer.h
index 13668816c..32d803dea 100644
--- a/iocore/net/P_SNIActionPerformer.h
+++ b/iocore/net/P_SNIActionPerformer.h
@@ -98,6 +98,26 @@ private:
   bool enable_h2 = false;
 };
 
+class HTTP2BufferWaterMark : public ActionItem
+{
+public:
+  HTTP2BufferWaterMark(int value) : value(value) {}
+  ~HTTP2BufferWaterMark() override {}
+
+  int
+  SNIAction(TLSSNISupport *snis, const Context &ctx) const override
+  {
+    auto ssl_vc = dynamic_cast<SSLNetVConnection *>(snis);
+    if (ssl_vc) {
+      ssl_vc->hints_from_sni.http2_buffer_water_mark = value;
+    }
+    return SSL_TLSEXT_ERR_OK;
+  }
+
+private:
+  int value = -1;
+};
+
 class TunnelDestination : public ActionItem
 {
 public:
diff --git a/iocore/net/SSLSNIConfig.cc b/iocore/net/SSLSNIConfig.cc
index f48211205..b7938dcd7 100644
--- a/iocore/net/SSLSNIConfig.cc
+++ b/iocore/net/SSLSNIConfig.cc
@@ -87,6 +87,9 @@ SNIConfigParams::loadSNIConfig()
     if (!item.client_sni_policy.empty()) {
       ai->actions.push_back(std::make_unique<OutboundSNIPolicy>(item.client_sni_policy));
     }
+    if (item.http2_buffer_water_mark.has_value()) {
+      ai->actions.push_back(std::make_unique<HTTP2BufferWaterMark>(item.http2_buffer_water_mark.value()));
+    }
 
     ai->actions.push_back(std::make_unique<SNI_IpAllow>(item.ip_allow, item.fqdn));
 
diff --git a/iocore/net/TLSSNISupport.h b/iocore/net/TLSSNISupport.h
index 0470b6c28..2f5d6467c 100644
--- a/iocore/net/TLSSNISupport.h
+++ b/iocore/net/TLSSNISupport.h
@@ -23,6 +23,7 @@
  */
 #pragma once
 
+#include <optional>
 #include <string_view>
 #include <memory>
 #include <openssl/ssl.h>
@@ -49,6 +50,10 @@ public:
 #endif
   void on_servername(SSL *ssl, int *al, void *arg);
 
+  struct HintsFromSNI {
+    std::optional<uint32_t> http2_buffer_water_mark;
+  } hints_from_sni;
+
 protected:
   virtual void _fire_ssl_servername_event() = 0;
 
diff --git a/iocore/net/YamlSNIConfig.cc b/iocore/net/YamlSNIConfig.cc
index 6ee194af3..3f90fe99c 100644
--- a/iocore/net/YamlSNIConfig.cc
+++ b/iocore/net/YamlSNIConfig.cc
@@ -143,6 +143,7 @@ std::set<std::string> valid_sni_config_keys = {TS_fqdn,
                                                TS_client_key,
                                                TS_client_sni_policy,
                                                TS_http2,
+                                               TS_http2_buffer_water_mark,
                                                TS_ip_allow,
 #if TS_USE_HELLO_CB || defined(OPENSSL_IS_BORINGSSL)
                                                TS_valid_tls_versions_in,
@@ -173,6 +174,9 @@ template <> struct convert<YamlSNIConfig::Item> {
     if (node[TS_http2]) {
       item.offer_h2 = node[TS_http2].as<bool>();
     }
+    if (node[TS_http2_buffer_water_mark]) {
+      item.http2_buffer_water_mark = node[TS_http2_buffer_water_mark].as<int>();
+    }
 
     // enum
     if (node[TS_verify_client]) {
diff --git a/iocore/net/YamlSNIConfig.h b/iocore/net/YamlSNIConfig.h
index 13887b683..dbb79ba29 100644
--- a/iocore/net/YamlSNIConfig.h
+++ b/iocore/net/YamlSNIConfig.h
@@ -55,6 +55,7 @@ TSDECL(client_sni_policy);
 TSDECL(ip_allow);
 TSDECL(valid_tls_versions_in);
 TSDECL(http2);
+TSDECL(http2_buffer_water_mark);
 TSDECL(host_sni_policy);
 #undef TSDECL
 
@@ -84,6 +85,7 @@ struct YamlSNIConfig {
     bool protocol_unset = true;
     unsigned long protocol_mask;
     std::vector<int> tunnel_alpn{};
+    std::optional<int> http2_buffer_water_mark;
 
     bool tunnel_prewarm_srv                  = false;
     uint32_t tunnel_prewarm_min              = 0;
diff --git a/proxy/http2/Http2ClientSession.cc b/proxy/http2/Http2ClientSession.cc
index 403e26c74..8203ebcbf 100644
--- a/proxy/http2/Http2ClientSession.cc
+++ b/proxy/http2/Http2ClientSession.cc
@@ -26,6 +26,7 @@
 #include "tscore/ink_base64.h"
 #include "Http2CommonSessionInternal.h"
 #include "P_SSLNetVConnection.h"
+#include "TLSSNISupport.h"
 
 ClassAllocator<Http2ClientSession, true> http2ClientSessionAllocator("http2ClientSessionAllocator");
 
@@ -116,9 +117,17 @@ Http2ClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOB
   this->_read_buffer_reader     = reader ? reader : this->read_buffer->alloc_reader();
 
   // This block size is the buffer size that we pass to SSLWriteBuffer
-  auto buffer_block_size_index   = iobuffer_size_to_index(Http2::write_buffer_block_size, MAX_BUFFER_SIZE_INDEX);
-  this->write_buffer             = new_MIOBuffer(buffer_block_size_index);
-  this->write_buffer->water_mark = Http2::buffer_water_mark;
+  auto buffer_block_size_index = iobuffer_size_to_index(Http2::write_buffer_block_size, MAX_BUFFER_SIZE_INDEX);
+  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()) {
+    buffer_water_mark = snis->hints_from_sni.http2_buffer_water_mark.value();
+  } else {
+    buffer_water_mark = Http2::buffer_water_mark;
+  }
+  this->write_buffer->water_mark = buffer_water_mark;
 
   this->_write_buffer_reader  = this->write_buffer->alloc_reader();
   this->_write_size_threshold = index_to_buffer_size(buffer_block_size_index) * Http2::write_size_threshold;