From e72962d5f1a4e157800519b5ac878cc72052c3a8 Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Wed, 22 Jun 2022 16:45:28 +0300 Subject: [PATCH] Update max concurrent streams limit in HTTP listeners on reconfig This commit ensures that HTTP listeners concurrent streams limit gets updated properly on reconfiguration. --- lib/isc/include/isc/netmgr.h | 34 ++++++++++++++++++++++++++++++++++ lib/isc/netmgr/http.c | 29 +++++++++++++++++++++-------- lib/isc/netmgr/netmgr-int.h | 6 +++++- lib/isc/netmgr/netmgr.c | 17 +++++++++++++++++ lib/ns/interfacemgr.c | 16 ++++++++++++++++ 5 files changed, 93 insertions(+), 9 deletions(-) diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index f7a15a0653..6333bfc569 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -129,6 +129,25 @@ isc_nmsocket_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx); * \li 'tlsctx' is a valid pointer to a TLS context object. */ +void +isc_nmsocket_set_max_streams(isc_nmsocket_t *listener, + const uint32_t max_streams); +/*%< + * Set the maximum allowed number of concurrent streams for accepted + * client connections. The implementation might be asynchronous + * depending on the listener socket type. + * + * The call is a no-op for any listener socket type that does not + * support concept of multiple sessions per a client + * connection. Currently, it works only for HTTP/2 listeners. + * + * Setting 'max_streams' to '0' instructs the listener that there is + * no limit for concurrent streams. + * + * Requires: + * \li 'listener' is a pointer to a valid network manager listener socket. + */ + #ifdef NETMGR_TRACE #define isc_nmhandle_attach(handle, dest) \ isc__nmhandle_attach(handle, dest, __FILE__, __LINE__, __func__) @@ -609,6 +628,21 @@ isc_nm_http_makeuri(const bool https, const isc_sockaddr_t *sa, * \li 'outbuf' is a valid pointer to a buffer which will get the result; * \li 'outbuf_len' is a size of the result buffer and is greater than zero. */ + +void +isc_nm_http_set_endpoints(isc_nmsocket_t *listener, + isc_nm_http_endpoints_t *eps); +/*%< + * Asynchronously replace the set of HTTP endpoints (paths) within + * the listener socket object. The function is intended to be used + * during reconfiguration. + * + * Requires: + * \li 'listener' is a pointer to a valid network manager listener socket + object with TLS support; + * \li 'eps' is a valid pointer to an HTTP endpoints set. + */ + #endif /* HAVE_LIBNGHTTP2 */ void diff --git a/lib/isc/netmgr/http.c b/lib/isc/netmgr/http.c index 4cde316236..8acc4baa99 100644 --- a/lib/isc/netmgr/http.c +++ b/lib/isc/netmgr/http.c @@ -2454,7 +2454,7 @@ httplisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) { new_session(httplistensock->mgr->mctx, NULL, &session); session->max_concurrent_streams = - httplistensock->h2.max_concurrent_streams; + atomic_load(&httplistensock->h2.max_concurrent_streams); initialize_nghttp2_server_session(session); handle->sock->h2.session = session; @@ -2481,14 +2481,10 @@ isc_nm_listenhttp(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface, sock = isc_mem_get(mgr->mctx, sizeof(*sock)); isc__nmsocket_init(sock, mgr, isc_nm_httplistener, iface); - sock->h2.max_concurrent_streams = - NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS; + atomic_init(&sock->h2.max_concurrent_streams, + NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS); - if (max_concurrent_streams > 0 && - max_concurrent_streams < NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS) - { - sock->h2.max_concurrent_streams = max_concurrent_streams; - } + isc_nmsocket_set_max_streams(sock, max_concurrent_streams); atomic_store(&eps->in_use, true); isc_nm_http_endpoints_attach(eps, &sock->h2.listener_endpoints); @@ -2953,6 +2949,23 @@ isc__nm_http_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx) { isc_nmsocket_set_tlsctx(listener->outer, tlsctx); } +void +isc__nm_http_set_max_streams(isc_nmsocket_t *listener, + const uint32_t max_concurrent_streams) { + uint32_t max_streams = NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS; + + REQUIRE(VALID_NMSOCK(listener)); + REQUIRE(listener->type == isc_nm_httplistener); + + if (max_concurrent_streams > 0 && + max_concurrent_streams < NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS) + { + max_streams = max_concurrent_streams; + } + + atomic_store(&listener->h2.max_concurrent_streams, max_streams); +} + static const bool base64url_validation_table[256] = { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index f1a6bce08e..6d5251bba3 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -872,7 +872,7 @@ typedef struct isc_nmsocket_h2 { isc_nmsocket_t *httpserver; /* maximum concurrent streams (server-side) */ - uint32_t max_concurrent_streams; + atomic_uint_fast32_t max_concurrent_streams; uint32_t min_ttl; /* used to set "max-age" in responses */ @@ -1817,6 +1817,10 @@ isc__nm_httpsession_detach(isc_nm_http_session_t **sessionp); void isc__nm_http_set_tlsctx(isc_nmsocket_t *sock, isc_tlsctx_t *tlsctx); +void +isc__nm_http_set_max_streams(isc_nmsocket_t *listener, + const uint32_t max_concurrent_streams); + #endif void diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index 6d73d0e288..3285adbe7d 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -3373,6 +3373,23 @@ isc_nmsocket_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx) { }; } +void +isc_nmsocket_set_max_streams(isc_nmsocket_t *listener, + const uint32_t max_streams) { + REQUIRE(VALID_NMSOCK(listener)); + switch (listener->type) { +#if HAVE_LIBNGHTTP2 + case isc_nm_httplistener: + isc__nm_http_set_max_streams(listener, max_streams); + break; +#endif /* HAVE_LIBNGHTTP2 */ + default: + UNUSED(max_streams); + break; + }; + return; +} + void isc__nmsocket_log_tls_session_reuse(isc_nmsocket_t *sock, isc_tls_t *tls) { const int log_level = ISC_LOG_DEBUG(1); diff --git a/lib/ns/interfacemgr.c b/lib/ns/interfacemgr.c index f52127cd8f..8604e62032 100644 --- a/lib/ns/interfacemgr.c +++ b/lib/ns/interfacemgr.c @@ -943,13 +943,26 @@ replace_listener_tlsctx(ns_interface_t *ifp, isc_tlsctx_t *newctx) { } } +#ifdef HAVE_LIBNGHTTP2 static void update_http_settings(ns_interface_t *ifp, ns_listenelt_t *le) { + isc_nmsocket_t *listener; + REQUIRE(le->is_http); INSIST(ifp->http_quota != NULL); isc_quota_max(ifp->http_quota, le->http_max_clients); + + if (ifp->http_secure_listensocket != NULL) { + listener = ifp->http_secure_listensocket; + } else { + INSIST(ifp->http_listensocket != NULL); + listener = ifp->http_listensocket; + } + + isc_nmsocket_set_max_streams(listener, le->max_concurrent_streams); } +#endif /* HAVE_LIBNGHTTP2 */ static void update_listener_configuration(ns_interfacemgr_t *mgr, ns_interface_t *ifp, @@ -969,6 +982,7 @@ update_listener_configuration(ns_interfacemgr_t *mgr, ns_interface_t *ifp, replace_listener_tlsctx(ifp, le->sslctx); } +#ifdef HAVE_LIBNGHTTP2 /* * Let's update HTTP listener settings * on reconfiguration. @@ -976,6 +990,8 @@ update_listener_configuration(ns_interfacemgr_t *mgr, ns_interface_t *ifp, if (le->is_http) { update_http_settings(ifp, le); } +#endif /* HAVE_LIBNGHTTP2 */ + UNLOCK(&mgr->lock); }