From 932841389b90eff16a3773293338ca6d0bcf482b Mon Sep 17 00:00:00 2001 From: Hakase Date: Fri, 12 May 2023 11:20:44 +0900 Subject: [PATCH] Latest update - 9089 --- README | 12 ---- auto/unix | 48 +++++++++++++++ src/core/ngx_connection.c | 72 +++++++++++++++++++++++ src/event/quic/ngx_event_quic.h | 1 - src/event/quic/ngx_event_quic_ack.c | 16 +++-- src/event/quic/ngx_event_quic_migration.c | 66 +++++++++++++++++---- src/event/quic/ngx_event_quic_streams.c | 32 +++++++++- src/event/quic/ngx_event_quic_transport.c | 2 +- src/event/quic/ngx_event_quic_udp.c | 2 +- src/http/v3/ngx_http_v3_module.c | 37 ------------ src/stream/ngx_stream_quic_module.c | 34 ----------- 11 files changed, 212 insertions(+), 110 deletions(-) diff --git a/README b/README index 7470457..cde316a 100644 --- a/README +++ b/README @@ -123,10 +123,6 @@ Experimental QUIC support for nginx quic_gso on; - To limit maximum UDP payload size on receive path: - - quic_mtu ; - To set host key for various tokens: quic_host_key ; @@ -209,14 +205,6 @@ Example configuration: Optimized sending is only supported on Linux featuring UDP_SEGMENT. - Syntax: quic_mtu size; - Default: quic_mtu 65527; - Context: http | stream, server - - Sets the QUIC max_udp_payload_size transport parameter value. - This is the maximum UDP payload that we are willing to receive. - - Syntax: quic_host_key file; Default: - Context: http | stream, server diff --git a/auto/unix b/auto/unix index 8671019..f29e69c 100644 --- a/auto/unix +++ b/auto/unix @@ -448,6 +448,54 @@ ngx_feature_test="setsockopt(0, IPPROTO_IPV6, IPV6_RECVPKTINFO, NULL, 0)" . auto/feature +# IP packet fragmentation + +ngx_feature="IP_MTU_DISCOVER" +ngx_feature_name="NGX_HAVE_IP_MTU_DISCOVER" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="(void) IP_PMTUDISC_DO; + setsockopt(0, IPPROTO_IP, IP_MTU_DISCOVER, NULL, 0)" +. auto/feature + + +ngx_feature="IPV6_MTU_DISCOVER" +ngx_feature_name="NGX_HAVE_IPV6_MTU_DISCOVER" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="(void) IPV6_PMTUDISC_DO; + setsockopt(0, IPPROTO_IPV6, IPV6_MTU_DISCOVER, NULL, 0)" +. auto/feature + + +ngx_feature="IP_DONTFRAG" +ngx_feature_name="NGX_HAVE_IP_DONTFRAG" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, IPPROTO_IP, IP_DONTFRAG, NULL, 0)" +. auto/feature + + +ngx_feature="IPV6_DONTFRAG" +ngx_feature_name="NGX_HAVE_IPV6_DONTFRAG" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, IPPROTO_IP, IPV6_DONTFRAG, NULL, 0)" +. auto/feature + + ngx_feature="TCP_DEFER_ACCEPT" ngx_feature_name="NGX_HAVE_DEFERRED_ACCEPT" ngx_feature_run=no diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 57c5a8a..5e56839 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -1009,6 +1009,78 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) } } +#endif + +#if (NGX_HAVE_IP_MTU_DISCOVER) + + if (ls[i].quic && ls[i].sockaddr->sa_family == AF_INET) { + value = IP_PMTUDISC_DO; + + if (setsockopt(ls[i].fd, IPPROTO_IP, IP_MTU_DISCOVER, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(IP_MTU_DISCOVER) " + "for %V failed, ignored", + &ls[i].addr_text); + } + } + +#elif (NGX_HAVE_IP_DONTFRAG) + + if (ls[i].quic && ls[i].sockaddr->sa_family == AF_INET) { + value = 1; + + if (setsockopt(ls[i].fd, IPPROTO_IP, IP_DONTFRAG, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(IP_DONTFRAG) " + "for %V failed, ignored", + &ls[i].addr_text); + } + } + +#endif + +#if (NGX_HAVE_INET6) + +#if (NGX_HAVE_IPV6_MTU_DISCOVER) + + if (ls[i].quic && ls[i].sockaddr->sa_family == AF_INET6) { + value = IPV6_PMTUDISC_DO; + + if (setsockopt(ls[i].fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(IPV6_MTU_DISCOVER) " + "for %V failed, ignored", + &ls[i].addr_text); + } + } + +#elif (NGX_HAVE_IP_DONTFRAG) + + if (ls[i].quic && ls[i].sockaddr->sa_family == AF_INET6) { + value = 1; + + if (setsockopt(ls[i].fd, IPPROTO_IPV6, IPV6_DONTFRAG, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(IPV6_DONTFRAG) " + "for %V failed, ignored", + &ls[i].addr_text); + } + } + +#endif + #endif } diff --git a/src/event/quic/ngx_event_quic.h b/src/event/quic/ngx_event_quic.h index 56713ec..0c68d68 100644 --- a/src/event/quic/ngx_event_quic.h +++ b/src/event/quic/ngx_event_quic.h @@ -69,7 +69,6 @@ typedef struct { ngx_flag_t disable_active_migration; ngx_msec_t timeout; ngx_str_t host_key; - size_t mtu; size_t stream_buffer_size; ngx_uint_t max_concurrent_streams_bidi; ngx_uint_t max_concurrent_streams_uni; diff --git a/src/event/quic/ngx_event_quic_ack.c b/src/event/quic/ngx_event_quic_ack.c index d236deb..062b065 100644 --- a/src/event/quic/ngx_event_quic_ack.c +++ b/src/event/quic/ngx_event_quic_ack.c @@ -736,7 +736,8 @@ ngx_quic_set_lost_timer(ngx_connection_t *c) q = ngx_queue_last(&ctx->sent); f = ngx_queue_data(q, ngx_quic_frame_t, queue); - w = (ngx_msec_int_t) (f->last + ngx_quic_pto(c, ctx) - now); + w = (ngx_msec_int_t) (f->last + (ngx_quic_pto(c, ctx) << qc->pto_count) + - now); if (w < 0) { w = 0; @@ -782,17 +783,12 @@ ngx_quic_pto(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) qc = ngx_quic_get_connection(c); /* RFC 9002, Appendix A.8. Setting the Loss Detection Timer */ + duration = qc->avg_rtt; - duration += ngx_max(4 * qc->rttvar, NGX_QUIC_TIME_GRANULARITY); - duration <<= qc->pto_count; - - if (qc->congestion.in_flight == 0) { /* no in-flight packets */ - return duration; - } if (ctx->level == ssl_encryption_application && c->ssl->handshaked) { - duration += qc->ctp.max_ack_delay << qc->pto_count; + duration += qc->ctp.max_ack_delay; } return duration; @@ -850,7 +846,9 @@ ngx_quic_pto_handler(ngx_event_t *ev) continue; } - if ((ngx_msec_int_t) (f->last + ngx_quic_pto(c, ctx) - now) > 0) { + if ((ngx_msec_int_t) (f->last + (ngx_quic_pto(c, ctx) << qc->pto_count) + - now) > 0) + { continue; } diff --git a/src/event/quic/ngx_event_quic_migration.c b/src/event/quic/ngx_event_quic_migration.c index 37c7b86..cf0438f 100644 --- a/src/event/quic/ngx_event_quic_migration.c +++ b/src/event/quic/ngx_event_quic_migration.c @@ -16,6 +16,7 @@ static ngx_int_t ngx_quic_validate_path(ngx_connection_t *c, ngx_quic_path_t *path); static ngx_int_t ngx_quic_send_path_challenge(ngx_connection_t *c, ngx_quic_path_t *path); +static void ngx_quic_set_path_timer(ngx_connection_t *c); static ngx_quic_path_t *ngx_quic_get_path(ngx_connection_t *c, ngx_uint_t tag); @@ -169,6 +170,8 @@ valid: path->validating = 0; path->limited = 0; + ngx_quic_set_path_timer(c); + return NGX_OK; } @@ -384,16 +387,13 @@ ngx_quic_free_path(ngx_connection_t *c, ngx_quic_path_t *path) static void ngx_quic_set_connection_path(ngx_connection_t *c, ngx_quic_path_t *path) { - size_t len; - ngx_memcpy(c->sockaddr, path->sockaddr, path->socklen); c->socklen = path->socklen; if (c->addr_text.data) { - len = ngx_min(c->addr_text.len, path->addr_text.len); - - ngx_memcpy(c->addr_text.data, path->addr_text.data, len); - c->addr_text.len = len; + c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen, + c->addr_text.data, + c->listening->addr_text_max_len, 0); } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, @@ -496,6 +496,7 @@ ngx_quic_validate_path(ngx_connection_t *c, ngx_quic_path_t *path) "quic initiated validation of path seq:%uL", path->seqnum); path->validating = 1; + path->tries = 0; if (RAND_bytes(path->challenge1, 8) != 1) { return NGX_ERROR; @@ -510,14 +511,11 @@ ngx_quic_validate_path(ngx_connection_t *c, ngx_quic_path_t *path) } ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application); - pto = ngx_quic_pto(c, ctx); + pto = ngx_max(ngx_quic_pto(c, ctx), 1000); path->expires = ngx_current_msec + pto; - path->tries = NGX_QUIC_PATH_RETRIES; - if (!qc->path_validation.timer_set) { - ngx_add_timer(&qc->path_validation, pto); - } + ngx_quic_set_path_timer(c); return NGX_OK; } @@ -563,6 +561,47 @@ ngx_quic_send_path_challenge(ngx_connection_t *c, ngx_quic_path_t *path) } +static void +ngx_quic_set_path_timer(ngx_connection_t *c) +{ + ngx_msec_t now; + ngx_queue_t *q; + ngx_msec_int_t left, next; + ngx_quic_path_t *path; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(c); + + now = ngx_current_msec; + next = -1; + + for (q = ngx_queue_head(&qc->paths); + q != ngx_queue_sentinel(&qc->paths); + q = ngx_queue_next(q)) + { + path = ngx_queue_data(q, ngx_quic_path_t, queue); + + if (!path->validating) { + continue; + } + + left = path->expires - now; + left = ngx_max(left, 1); + + if (next == -1 || left < next) { + next = left; + } + } + + if (next != -1) { + ngx_add_timer(&qc->path_validation, next); + + } else if (qc->path_validation.timer_set) { + ngx_del_timer(&qc->path_validation); + } +} + + void ngx_quic_path_validation_handler(ngx_event_t *ev) { @@ -578,7 +617,6 @@ ngx_quic_path_validation_handler(ngx_event_t *ev) qc = ngx_quic_get_connection(c); ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application); - pto = ngx_quic_pto(c, ctx); next = -1; now = ngx_current_msec; @@ -605,7 +643,9 @@ ngx_quic_path_validation_handler(ngx_event_t *ev) continue; } - if (--path->tries) { + if (++path->tries < NGX_QUIC_PATH_RETRIES) { + pto = ngx_max(ngx_quic_pto(c, ctx), 1000) << path->tries; + path->expires = ngx_current_msec + pto; if (next == -1 || pto < next) { diff --git a/src/event/quic/ngx_event_quic_streams.c b/src/event/quic/ngx_event_quic_streams.c index 3b72f83..6664dfd 100644 --- a/src/event/quic/ngx_event_quic_streams.c +++ b/src/event/quic/ngx_event_quic_streams.c @@ -637,10 +637,12 @@ ngx_quic_do_init_streams(ngx_connection_t *c) static ngx_quic_stream_t * ngx_quic_create_stream(ngx_connection_t *c, uint64_t id) { + ngx_str_t addr_text; ngx_log_t *log; ngx_pool_t *pool; ngx_uint_t reusable; ngx_queue_t *q; + struct sockaddr *sockaddr; ngx_connection_t *sc; ngx_quic_stream_t *qs; ngx_pool_cleanup_t *cln; @@ -692,6 +694,31 @@ ngx_quic_create_stream(ngx_connection_t *c, uint64_t id) *log = *c->log; pool->log = log; + sockaddr = ngx_palloc(pool, c->socklen); + if (sockaddr == NULL) { + ngx_destroy_pool(pool); + ngx_queue_insert_tail(&qc->streams.free, &qs->queue); + return NULL; + } + + ngx_memcpy(sockaddr, c->sockaddr, c->socklen); + + if (c->addr_text.data) { + addr_text.data = ngx_pnalloc(pool, c->addr_text.len); + if (addr_text.data == NULL) { + ngx_destroy_pool(pool); + ngx_queue_insert_tail(&qc->streams.free, &qs->queue); + return NULL; + } + + ngx_memcpy(addr_text.data, c->addr_text.data, c->addr_text.len); + addr_text.len = c->addr_text.len; + + } else { + addr_text.len = 0; + addr_text.data = NULL; + } + reusable = c->reusable; ngx_reusable_connection(c, 0); @@ -710,9 +737,10 @@ ngx_quic_create_stream(ngx_connection_t *c, uint64_t id) sc->type = SOCK_STREAM; sc->pool = pool; sc->ssl = c->ssl; - sc->sockaddr = c->sockaddr; + sc->sockaddr = sockaddr; + sc->socklen = c->socklen; sc->listening = c->listening; - sc->addr_text = c->addr_text; + sc->addr_text = addr_text; sc->local_sockaddr = c->local_sockaddr; sc->local_socklen = c->local_socklen; sc->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); diff --git a/src/event/quic/ngx_event_quic_transport.c b/src/event/quic/ngx_event_quic_transport.c index 46456db..b663efb 100644 --- a/src/event/quic/ngx_event_quic_transport.c +++ b/src/event/quic/ngx_event_quic_transport.c @@ -1987,7 +1987,7 @@ ngx_quic_init_transport_params(ngx_quic_tp_t *tp, ngx_quic_conf_t *qcf) tp->max_idle_timeout = qcf->timeout; - tp->max_udp_payload_size = qcf->mtu; + tp->max_udp_payload_size = NGX_QUIC_MAX_UDP_PAYLOAD_SIZE; nstreams = qcf->max_concurrent_streams_bidi + qcf->max_concurrent_streams_uni; diff --git a/src/event/quic/ngx_event_quic_udp.c b/src/event/quic/ngx_event_quic_udp.c index f7253a2..0721ca8 100644 --- a/src/event/quic/ngx_event_quic_udp.c +++ b/src/event/quic/ngx_event_quic_udp.c @@ -34,7 +34,7 @@ ngx_quic_recvmsg(ngx_event_t *ev) ngx_event_conf_t *ecf; ngx_connection_t *c, *lc; ngx_quic_socket_t *qsock; - static u_char buffer[65535]; + static u_char buffer[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; #if (NGX_HAVE_ADDRINFO_CMSG) u_char msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))]; diff --git a/src/http/v3/ngx_http_v3_module.c b/src/http/v3/ngx_http_v3_module.c index 02b88b4..8569f07 100644 --- a/src/http/v3/ngx_http_v3_module.c +++ b/src/http/v3/ngx_http_v3_module.c @@ -16,8 +16,6 @@ static ngx_int_t ngx_http_v3_add_variables(ngx_conf_t *cf); static void *ngx_http_v3_create_srv_conf(ngx_conf_t *cf); static char *ngx_http_v3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); -static char *ngx_http_quic_mtu(ngx_conf_t *cf, void *post, - void *data); static char *ngx_http_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void *ngx_http_v3_create_loc_conf(ngx_conf_t *cf); @@ -26,10 +24,6 @@ static char *ngx_http_v3_merge_loc_conf(ngx_conf_t *cf, void *parent, static char *ngx_http_v3_push(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static ngx_conf_post_t ngx_http_quic_mtu_post = - { ngx_http_quic_mtu }; - - static ngx_command_t ngx_http_v3_commands[] = { { ngx_string("http3"), @@ -95,13 +89,6 @@ static ngx_command_t ngx_http_v3_commands[] = { offsetof(ngx_http_v3_srv_conf_t, quic.gso_enabled), NULL }, - { ngx_string("quic_mtu"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v3_srv_conf_t, quic.mtu), - &ngx_http_quic_mtu_post }, - { ngx_string("quic_host_key"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_http_quic_host_key, @@ -240,7 +227,6 @@ ngx_http_v3_create_srv_conf(ngx_conf_t *cf) h3scf->max_concurrent_pushes = NGX_CONF_UNSET_UINT; h3scf->max_concurrent_streams = NGX_CONF_UNSET_UINT; - h3scf->quic.mtu = NGX_CONF_UNSET_SIZE; h3scf->quic.stream_buffer_size = NGX_CONF_UNSET_SIZE; h3scf->quic.max_concurrent_streams_bidi = NGX_CONF_UNSET_UINT; h3scf->quic.max_concurrent_streams_uni = NGX_HTTP_V3_MAX_UNI_STREAMS; @@ -277,9 +263,6 @@ ngx_http_v3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) conf->max_blocked_streams = conf->max_concurrent_streams; - ngx_conf_merge_size_value(conf->quic.mtu, prev->quic.mtu, - NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); - ngx_conf_merge_size_value(conf->quic.stream_buffer_size, prev->quic.stream_buffer_size, 65536); @@ -334,26 +317,6 @@ ngx_http_v3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) } -static char * -ngx_http_quic_mtu(ngx_conf_t *cf, void *post, void *data) -{ - size_t *sp = data; - - if (*sp < NGX_QUIC_MIN_INITIAL_SIZE - || *sp > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"quic_mtu\" must be between %d and %d", - NGX_QUIC_MIN_INITIAL_SIZE, - NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); - - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; -} - - static char * ngx_http_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/stream/ngx_stream_quic_module.c b/src/stream/ngx_stream_quic_module.c index 644fa03..42f5fe0 100644 --- a/src/stream/ngx_stream_quic_module.c +++ b/src/stream/ngx_stream_quic_module.c @@ -16,12 +16,9 @@ static ngx_int_t ngx_stream_quic_add_variables(ngx_conf_t *cf); static void *ngx_stream_quic_create_srv_conf(ngx_conf_t *cf); static char *ngx_stream_quic_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); -static char *ngx_stream_quic_mtu(ngx_conf_t *cf, void *post, void *data); static char *ngx_stream_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static ngx_conf_post_t ngx_stream_quic_mtu_post = - { ngx_stream_quic_mtu }; static ngx_command_t ngx_stream_quic_commands[] = { @@ -32,13 +29,6 @@ static ngx_command_t ngx_stream_quic_commands[] = { offsetof(ngx_quic_conf_t, timeout), NULL }, - { ngx_string("quic_mtu"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_STREAM_SRV_CONF_OFFSET, - offsetof(ngx_quic_conf_t, mtu), - &ngx_stream_quic_mtu_post }, - { ngx_string("quic_stream_buffer_size"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -175,7 +165,6 @@ ngx_stream_quic_create_srv_conf(ngx_conf_t *cf) */ conf->timeout = NGX_CONF_UNSET_MSEC; - conf->mtu = NGX_CONF_UNSET_SIZE; conf->stream_buffer_size = NGX_CONF_UNSET_SIZE; conf->max_concurrent_streams_bidi = NGX_CONF_UNSET_UINT; conf->max_concurrent_streams_uni = NGX_CONF_UNSET_UINT; @@ -199,9 +188,6 @@ ngx_stream_quic_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); - ngx_conf_merge_size_value(conf->mtu, prev->mtu, - NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); - ngx_conf_merge_size_value(conf->stream_buffer_size, prev->stream_buffer_size, 65536); @@ -259,26 +245,6 @@ ngx_stream_quic_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) } -static char * -ngx_stream_quic_mtu(ngx_conf_t *cf, void *post, void *data) -{ - size_t *sp = data; - - if (*sp < NGX_QUIC_MIN_INITIAL_SIZE - || *sp > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"quic_mtu\" must be between %d and %d", - NGX_QUIC_MIN_INITIAL_SIZE, - NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); - - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; -} - - static char * ngx_stream_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {