diff --git a/gennghttpxfun.py b/gennghttpxfun.py index cadd11a2..be2c8390 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -183,6 +183,10 @@ OPTIONS = [ "frontend-http3-read-timeout", "frontend-quic-idle-timeout", "frontend-quic-debug-log", + "frontend-http3-window-size", + "frontend-http3-connection-window-size", + "frontend-http3-max-window-size", + "frontend-http3-max-connection-window-size", ] LOGVARS = [ diff --git a/src/shrpx.cc b/src/shrpx.cc index 0edcca75..e2733a6c 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1563,6 +1563,16 @@ void fill_default_config(Config *config) { auto &bpfconf = quicconf.bpf; bpfconf.prog_file = StringRef::from_lit(PKGLIBDIR "/reuseport_kern.o"); } + + auto &http3conf = config->http3; + { + auto &upstreamconf = http3conf.upstream; + + upstreamconf.window_size = 256_k; + upstreamconf.connection_window_size = 1_m; + upstreamconf.max_window_size = 6_m; + upstreamconf.max_connection_window_size = 8_m; + } #endif // ENABLE_HTTP3 auto &loggingconf = config->logging; @@ -2901,6 +2911,34 @@ QUIC: Default: )" << config->quic.bpf.prog_file << R"( --no-bpf Disable eBPF. + --frontend-http3-window-size= + Sets the per-stream initial window size of HTTP/3 + frontend connection. + Default: )" + << util::utos_unit(config->http3.upstream.window_size) << R"( + --frontend-http3-connection-window-size= + Sets the per-connection window size of HTTP/3 frontend + connection. + Default: )" + << util::utos_unit(config->http3.upstream.connection_window_size) << R"( + --frontend-http3-max-window-size= + Sets the maximum per-stream window size of HTTP/3 + frontend connection. The window size is adjusted based + on the receiving rate of stream data. The initial value + is the value specified by --frontend-http3-window-size + and the window size grows up to bytes. + Default: )" + << util::utos_unit(config->http3.upstream.max_window_size) << R"( + --frontend-http3-max-connection-window-size= + Sets the maximum per-connection window size of HTTP/3 + frontend connection. The window size is adjusted based + on the receiving rate of stream data. The initial value + is the value specified by + --frontend-http3-connection-window-size and the window + size grows up to bytes. + Default: )" + << util::utos_unit(config->http3.upstream.max_connection_window_size) + << R"( )"; #endif // ENABLE_HTTP3 @@ -3612,6 +3650,14 @@ int main(int argc, char **argv) { {SHRPX_OPT_FRONTEND_QUIC_IDLE_TIMEOUT.c_str(), required_argument, &flag, 173}, {SHRPX_OPT_FRONTEND_QUIC_DEBUG_LOG.c_str(), no_argument, &flag, 174}, + {SHRPX_OPT_FRONTEND_HTTP3_WINDOW_SIZE.c_str(), required_argument, &flag, + 175}, + {SHRPX_OPT_FRONTEND_HTTP3_CONNECTION_WINDOW_SIZE.c_str(), + required_argument, &flag, 176}, + {SHRPX_OPT_FRONTEND_HTTP3_MAX_WINDOW_SIZE.c_str(), required_argument, + &flag, 177}, + {SHRPX_OPT_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE.c_str(), + required_argument, &flag, 178}, {nullptr, 0, nullptr, 0}}; int option_index = 0; @@ -4442,6 +4488,27 @@ int main(int argc, char **argv) { cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_DEBUG_LOG, StringRef::from_lit("yes")); break; + case 175: + // --frontend-http3-window-size + cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP3_WINDOW_SIZE, + StringRef{optarg}); + break; + case 176: + // --frontend-http3-connection-window-size + cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP3_CONNECTION_WINDOW_SIZE, + StringRef{optarg}); + break; + case 177: + // --frontend-http3-max-window-size + cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP3_MAX_WINDOW_SIZE, + StringRef{optarg}); + break; + case 178: + // --frontend-http3-max-connection-window-size + cmdcfgs.emplace_back( + SHRPX_OPT_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE, + StringRef{optarg}); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 0cfb62f0..3fb61021 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -2355,6 +2355,9 @@ int option_lookup_token(const char *name, size_t namelen) { if (util::strieq_l("frontend-http2-window-siz", name, 25)) { return SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_SIZE; } + if (util::strieq_l("frontend-http3-window-siz", name, 25)) { + return SHRPX_OPTID_FRONTEND_HTTP3_WINDOW_SIZE; + } break; case 's': if (util::strieq_l("frontend-http2-window-bit", name, 25)) { @@ -2449,6 +2452,11 @@ int option_lookup_token(const char *name, size_t namelen) { return SHRPX_OPTID_VERIFY_CLIENT_TOLERATE_EXPIRED; } break; + case 'e': + if (util::strieq_l("frontend-http3-max-window-siz", name, 29)) { + return SHRPX_OPTID_FRONTEND_HTTP3_MAX_WINDOW_SIZE; + } + break; case 'r': if (util::strieq_l("ignore-per-pattern-mruby-erro", name, 29)) { return SHRPX_OPTID_IGNORE_PER_PATTERN_MRUBY_ERROR; @@ -2578,6 +2586,9 @@ int option_lookup_token(const char *name, size_t namelen) { if (util::strieq_l("frontend-http2-connection-window-siz", name, 36)) { return SHRPX_OPTID_FRONTEND_HTTP2_CONNECTION_WINDOW_SIZE; } + if (util::strieq_l("frontend-http3-connection-window-siz", name, 36)) { + return SHRPX_OPTID_FRONTEND_HTTP3_CONNECTION_WINDOW_SIZE; + } if (util::strieq_l("tls-session-cache-memcached-cert-fil", name, 36)) { return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE; } @@ -2637,6 +2648,10 @@ int option_lookup_token(const char *name, size_t namelen) { 40)) { return SHRPX_OPTID_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE; } + if (util::strieq_l("frontend-http3-max-connection-window-siz", name, + 40)) { + return SHRPX_OPTID_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE; + } if (util::strieq_l("tls-ticket-key-memcached-private-key-fil", name, 40)) { return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE; @@ -3902,6 +3917,42 @@ int parse_config(Config *config, int optid, const StringRef &opt, config->quic.upstream.debug.log = util::strieq_l("yes", optarg); #endif // ENABLE_HTTP3 + return 0; + case SHRPX_OPTID_FRONTEND_HTTP3_WINDOW_SIZE: +#ifdef ENABLE_HTTP3 + if (parse_uint_with_unit(&config->http3.upstream.window_size, opt, + optarg) != 0) { + return -1; + } +#endif // ENABLE_HTTP3 + + return 0; + case SHRPX_OPTID_FRONTEND_HTTP3_CONNECTION_WINDOW_SIZE: +#ifdef ENABLE_HTTP3 + if (parse_uint_with_unit(&config->http3.upstream.connection_window_size, + opt, optarg) != 0) { + return -1; + } +#endif // ENABLE_HTTP3 + + return 0; + case SHRPX_OPTID_FRONTEND_HTTP3_MAX_WINDOW_SIZE: +#ifdef ENABLE_HTTP3 + if (parse_uint_with_unit(&config->http3.upstream.max_window_size, opt, + optarg) != 0) { + return -1; + } +#endif // ENABLE_HTTP3 + + return 0; + case SHRPX_OPTID_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE: +#ifdef ENABLE_HTTP3 + if (parse_uint_with_unit(&config->http3.upstream.max_connection_window_size, + opt, optarg) != 0) { + return -1; + } +#endif // ENABLE_HTTP3 + return 0; case SHRPX_OPTID_CONF: LOG(WARN) << "conf: ignored"; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 10b5b72c..08b903f8 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -373,6 +373,14 @@ constexpr auto SHRPX_OPT_FRONTEND_QUIC_IDLE_TIMEOUT = StringRef::from_lit("frontend-quic-idle-timeout"); constexpr auto SHRPX_OPT_FRONTEND_QUIC_DEBUG_LOG = StringRef::from_lit("frontend-quic-debug-log"); +constexpr auto SHRPX_OPT_FRONTEND_HTTP3_WINDOW_SIZE = + StringRef::from_lit("frontend-http3-window-size"); +constexpr auto SHRPX_OPT_FRONTEND_HTTP3_CONNECTION_WINDOW_SIZE = + StringRef::from_lit("frontend-http3-connection-window-size"); +constexpr auto SHRPX_OPT_FRONTEND_HTTP3_MAX_WINDOW_SIZE = + StringRef::from_lit("frontend-http3-max-window-size"); +constexpr auto SHRPX_OPT_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE = + StringRef::from_lit("frontend-http3-max-connection-window-size"); constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; @@ -742,6 +750,15 @@ struct QUICConfig { bool disabled; } bpf; }; + +struct Http3Config { + struct { + int32_t window_size; + int32_t connection_window_size; + int32_t max_window_size; + int32_t max_connection_window_size; + } upstream; +}; #endif // ENABLE_HTTP3 // custom error page @@ -1043,6 +1060,7 @@ struct Config { TLSConfig tls; #ifdef ENABLE_HTTP3 QUICConfig quic; + Http3Config http3; #endif // ENABLE_HTTP3 LoggingConfig logging; ConnectionConfig conn; @@ -1169,7 +1187,11 @@ enum { SHRPX_OPTID_FRONTEND_HTTP2_SETTINGS_TIMEOUT, SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_BITS, SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_SIZE, + SHRPX_OPTID_FRONTEND_HTTP3_CONNECTION_WINDOW_SIZE, + SHRPX_OPTID_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE, + SHRPX_OPTID_FRONTEND_HTTP3_MAX_WINDOW_SIZE, SHRPX_OPTID_FRONTEND_HTTP3_READ_TIMEOUT, + SHRPX_OPTID_FRONTEND_HTTP3_WINDOW_SIZE, SHRPX_OPTID_FRONTEND_KEEP_ALIVE_TIMEOUT, SHRPX_OPTID_FRONTEND_MAX_REQUESTS, SHRPX_OPTID_FRONTEND_NO_TLS, diff --git a/src/shrpx_http3_upstream.cc b/src/shrpx_http3_upstream.cc index 00f9c0d9..d5c649cd 100644 --- a/src/shrpx_http3_upstream.cc +++ b/src/shrpx_http3_upstream.cc @@ -496,6 +496,7 @@ int Http3Upstream::init(const UpstreamAddr *faddr, const Address &remote_addr, auto config = get_config(); auto &quicconf = config->quic; + auto &http3conf = config->http3; ngtcp2_settings settings; ngtcp2_settings_default(&settings); @@ -504,8 +505,8 @@ int Http3Upstream::init(const UpstreamAddr *faddr, const Address &remote_addr, } settings.initial_ts = quic_timestamp(); settings.cc_algo = NGTCP2_CC_ALGO_BBR; - settings.max_window = 6_m; - settings.max_stream_window = 6_m; + settings.max_window = http3conf.upstream.max_connection_window_size; + settings.max_stream_window = http3conf.upstream.max_window_size; settings.max_udp_payload_size = SHRPX_MAX_UDP_PAYLOAD_SIZE; settings.rand_ctx.native_handle = &worker->get_randgen(); settings.token = ngtcp2_vec{const_cast(token), tokenlen}; @@ -514,9 +515,9 @@ int Http3Upstream::init(const UpstreamAddr *faddr, const Address &remote_addr, ngtcp2_transport_params_default(¶ms); params.initial_max_streams_bidi = 100; params.initial_max_streams_uni = 3; - params.initial_max_data = 1_m; - params.initial_max_stream_data_bidi_remote = 256_k; - params.initial_max_stream_data_uni = 256_k; + params.initial_max_data = http3conf.upstream.connection_window_size; + params.initial_max_stream_data_bidi_remote = http3conf.upstream.window_size; + params.initial_max_stream_data_uni = http3conf.upstream.window_size; params.max_idle_timeout = static_cast( quicconf.upstream.timeout.idle * NGTCP2_SECONDS);