Update max concurrent streams limit in HTTP listeners on reconfig

This commit ensures that HTTP listeners concurrent streams limit gets
updated properly on reconfiguration.

(cherry picked from commit e72962d5f1)
This commit is contained in:
Artem Boldariev 2022-06-22 16:45:28 +03:00
parent 1ccbb24078
commit bb8ba2c027
5 changed files with 93 additions and 9 deletions

View file

@ -121,6 +121,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__)
@ -645,6 +664,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

View file

@ -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, isc_sockaddr_t *iface, int backlog,
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);
@ -2955,6 +2951,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,

View file

@ -880,7 +880,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 */
@ -1833,6 +1833,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

View file

@ -3733,6 +3733,23 @@ isc_nm_verify_tls_peer_result_string(const isc_nmhandle_t *handle) {
return (NULL);
}
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);

View file

@ -941,13 +941,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,
@ -967,6 +980,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.
@ -974,6 +988,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);
}