Repository: trafficserver Updated Branches: refs/heads/master 1e9c9484c -> 0e6e5c151
TS-4087: Reduce SETTINGS_MAX_CONCURRENT_STREAMS when too many streams Add below variables in records.config - proxy.config.http2.min_concurrent_streams_in - proxy.config.http2.max_active_streams_in When connection wide active stream are larger than proxy.config.http2.max_active_streams_in, SETTINGS_MAX_CONCURRENT_STREAMS is reduced to proxy.config.http2.min_concurrent_streams_in in new connections. If the value of proxy.config.http2.max_active_streams_in is 0, there is no limit. This closes #485 Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/0e6e5c15 Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/0e6e5c15 Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/0e6e5c15 Branch: refs/heads/master Commit: 0e6e5c151cde5f06c15e295f663a98b2b7d37a6d Parents: 1e9c948 Author: Masaori Koshiba <[email protected]> Authored: Mon Feb 15 20:57:25 2016 +0900 Committer: Masaori Koshiba <[email protected]> Committed: Tue Mar 22 10:52:37 2016 +0900 ---------------------------------------------------------------------- mgmt/RecordsConfig.cc | 4 ++++ proxy/http2/HTTP2.cc | 12 ++++++++--- proxy/http2/HTTP2.h | 5 ++++- proxy/http2/Http2ConnectionState.cc | 35 ++++++++++++++++++++++++++++++++ proxy/http2/Http2ConnectionState.h | 4 +++- 5 files changed, 55 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0e6e5c15/mgmt/RecordsConfig.cc ---------------------------------------------------------------------- diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 0e963c9..b0e0e6a 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1977,6 +1977,10 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.http2.max_concurrent_streams_in", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} , + {RECT_CONFIG, "proxy.config.http2.min_concurrent_streams_in", RECD_INT, "10", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.http2.max_active_streams_in", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} + , {RECT_CONFIG, "proxy.config.http2.initial_window_size_in", RECD_INT, "1048576", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} , {RECT_CONFIG, "proxy.config.http2.max_frame_size", RECD_INT, "16384", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0e6e5c15/proxy/http2/HTTP2.cc ---------------------------------------------------------------------- diff --git a/proxy/http2/HTTP2.cc b/proxy/http2/HTTP2.cc index 5cb9d79..c9ea2bc 100644 --- a/proxy/http2/HTTP2.cc +++ b/proxy/http2/HTTP2.cc @@ -727,7 +727,10 @@ http2_decode_header_blocks(HTTPHdr *hdr, const uint8_t *buf_start, const uint8_t } // Initialize this subsystem with librecords configs (for now) -uint32_t Http2::max_concurrent_streams = 100; +uint32_t Http2::max_concurrent_streams_in = 100; +uint32_t Http2::min_concurrent_streams_in = 10; +uint32_t Http2::max_active_streams_in = 0; +bool Http2::throttling = false; uint32_t Http2::initial_window_size = 1048576; uint32_t Http2::max_frame_size = 16384; uint32_t Http2::header_table_size = 4096; @@ -740,7 +743,9 @@ uint32_t Http2::active_timeout_in = 0; void Http2::init() { - REC_EstablishStaticConfigInt32U(max_concurrent_streams, "proxy.config.http2.max_concurrent_streams_in"); + REC_EstablishStaticConfigInt32U(max_concurrent_streams_in, "proxy.config.http2.max_concurrent_streams_in"); + REC_EstablishStaticConfigInt32U(min_concurrent_streams_in, "proxy.config.http2.min_concurrent_streams_in"); + REC_EstablishStaticConfigInt32U(max_active_streams_in, "proxy.config.http2.max_active_streams_in"); REC_EstablishStaticConfigInt32U(initial_window_size, "proxy.config.http2.initial_window_size_in"); REC_EstablishStaticConfigInt32U(max_frame_size, "proxy.config.http2.max_frame_size"); REC_EstablishStaticConfigInt32U(header_table_size, "proxy.config.http2.header_table_size"); @@ -751,7 +756,8 @@ Http2::init() REC_EstablishStaticConfigInt32U(active_timeout_in, "proxy.config.http2.active_timeout_in"); // If any settings is broken, ATS should not start - ink_release_assert(http2_settings_parameter_is_valid({HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, max_concurrent_streams}) && + ink_release_assert(http2_settings_parameter_is_valid({HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, max_concurrent_streams_in}) && + http2_settings_parameter_is_valid({HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, min_concurrent_streams_in}) && http2_settings_parameter_is_valid({HTTP2_SETTINGS_INITIAL_WINDOW_SIZE, initial_window_size}) && http2_settings_parameter_is_valid({HTTP2_SETTINGS_MAX_FRAME_SIZE, max_frame_size}) && http2_settings_parameter_is_valid({HTTP2_SETTINGS_HEADER_TABLE_SIZE, header_table_size}) && http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0e6e5c15/proxy/http2/HTTP2.h ---------------------------------------------------------------------- diff --git a/proxy/http2/HTTP2.h b/proxy/http2/HTTP2.h index 10e22e3..9b62b17 100644 --- a/proxy/http2/HTTP2.h +++ b/proxy/http2/HTTP2.h @@ -342,7 +342,10 @@ int64_t http2_write_header_fragment(HTTPHdr *, MIMEFieldIter &, uint8_t *, uint6 class Http2 { public: - static uint32_t max_concurrent_streams; + static uint32_t max_concurrent_streams_in; + static uint32_t min_concurrent_streams_in; + static uint32_t max_active_streams_in; + static bool throttling; static uint32_t initial_window_size; static uint32_t max_frame_size; static uint32_t header_table_size; http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0e6e5c15/proxy/http2/Http2ConnectionState.cc ---------------------------------------------------------------------- diff --git a/proxy/http2/Http2ConnectionState.cc b/proxy/http2/Http2ConnectionState.cc index 077f8ea..5180b3f 100644 --- a/proxy/http2/Http2ConnectionState.cc +++ b/proxy/http2/Http2ConnectionState.cc @@ -727,6 +727,8 @@ Http2ConnectionState::main_event_handler(int event, void *edata) // settings. Http2ConnectionSettings configured_settings; configured_settings.settings_from_configs(); + configured_settings.set(HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, _adjust_concurrent_stream()); + send_settings_frame(configured_settings); if (server_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE) > HTTP2_INITIAL_WINDOW_SIZE) { @@ -1167,3 +1169,36 @@ Http2ConnectionState::send_window_update_frame(Http2StreamId id, uint32_t size) SCOPED_MUTEX_LOCK(lock, this->ua_session->mutex, this_ethread()); this->ua_session->handleEvent(HTTP2_SESSION_EVENT_XMIT, &window_update); } + +// Return min_concurrent_streams_in when current client streams number is larger than max_active_streams_in. +// Main purpose of this is preventing DDoS Attacks. +unsigned +Http2ConnectionState::_adjust_concurrent_stream() +{ + if (Http2::max_active_streams_in == 0) { + // Throttling down is disabled. + return Http2::max_concurrent_streams_in; + } + + int64_t current_client_streams = 0; + RecGetRawStatSum(http2_rsb, HTTP2_STAT_CURRENT_CLIENT_STREAM_COUNT, ¤t_client_streams); + + DebugHttp2Con(ua_session, "current client streams: %" PRId64, current_client_streams); + + if (current_client_streams >= Http2::max_active_streams_in) { + if (!Http2::throttling) { + Warning("too many streams: %" PRId64 ", reduce SETTINGS_MAX_CONCURRENT_STREAMS to %d", current_client_streams, + Http2::min_concurrent_streams_in); + Http2::throttling = true; + } + + return Http2::min_concurrent_streams_in; + } else { + if (Http2::throttling) { + Note("revert SETTINGS_MAX_CONCURRENT_STREAMS to %d", Http2::max_concurrent_streams_in); + Http2::throttling = false; + } + } + + return Http2::max_concurrent_streams_in; +} http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0e6e5c15/proxy/http2/Http2ConnectionState.h ---------------------------------------------------------------------- diff --git a/proxy/http2/Http2ConnectionState.h b/proxy/http2/Http2ConnectionState.h index 9423c4e..afd0cf2 100644 --- a/proxy/http2/Http2ConnectionState.h +++ b/proxy/http2/Http2ConnectionState.h @@ -51,7 +51,7 @@ public: void settings_from_configs() { - settings[indexof(HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS)] = Http2::max_concurrent_streams; + settings[indexof(HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS)] = Http2::max_concurrent_streams_in; settings[indexof(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE)] = Http2::initial_window_size; settings[indexof(HTTP2_SETTINGS_MAX_FRAME_SIZE)] = Http2::max_frame_size; settings[indexof(HTTP2_SETTINGS_HEADER_TABLE_SIZE)] = Http2::header_table_size; @@ -199,6 +199,8 @@ private: Http2ConnectionState(const Http2ConnectionState &); // noncopyable Http2ConnectionState &operator=(const Http2ConnectionState &); // noncopyable + unsigned _adjust_concurrent_stream(); + // NOTE: 'stream_list' has only active streams. // If given Stream Identifier is not found in stream_list and it is less // than or equal to latest_streamid, the state of Stream
