# HG changeset patch # User Roman Arutyunyan <a...@nginx.com> # Date 1670494771 0 # Thu Dec 08 10:19:31 2022 +0000 # Branch quic # Node ID afbac4ba4c75023e10e68bae39df5b1a0fdbd17b # Parent de8bcaea559d151f5945d0a2e06c61b56a26a52b QUIC: eBPF worker sockets.
For each nginx worker, a worker socket is created. Worker sockets process existing QUIC connections bound to the worker, while listen sockets handle new connections. When shutting down a worker, listen sockets are closed as uaual, while worker sockets keep handling existing connections. Reuseport eBPF program looks up a worker socket by packet DCID and, if not found, chooses a listen socket based on packet address hash. The mode is enabled by "quic_bpf on" directive and is only available on Linux. Reuseport listen parameter is requried to enable the feature on a QUIC listen. diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -1363,11 +1363,11 @@ if [ $USE_OPENSSL_QUIC = YES ]; then . auto/module - if [ $QUIC_BPF = YES -a $SO_COOKIE_FOUND = YES ]; then + if [ $QUIC_BPF = YES ]; then ngx_module_type=CORE ngx_module_name=ngx_quic_bpf_module ngx_module_incs= - ngx_module_deps= + ngx_module_deps=src/event/quic/ngx_event_quic_bpf.h ngx_module_srcs="src/event/quic/ngx_event_quic_bpf.c \ src/event/quic/ngx_event_quic_bpf_code.c" ngx_module_libs= diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -171,8 +171,6 @@ USE_GEOIP=NO NGX_GOOGLE_PERFTOOLS=NO NGX_CPP_TEST=NO -SO_COOKIE_FOUND=NO - NGX_LIBATOMIC=NO NGX_CPU_CACHE_LINE= diff --git a/auto/os/linux b/auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -234,7 +234,7 @@ ngx_include="sys/vfs.h"; . auto/incl # BPF sockhash -ngx_feature="BPF sockhash" +ngx_feature="BPF maps" ngx_feature_name="NGX_HAVE_BPF" ngx_feature_run=no ngx_feature_incs="#include <linux/bpf.h> @@ -245,7 +245,14 @@ ngx_feature_test="union bpf_attr attr = attr.map_flags = 0; attr.map_type = BPF_MAP_TYPE_SOCKHASH; + syscall(__NR_bpf, 0, &attr, 0); + attr.map_flags = 0; + attr.map_type = BPF_MAP_TYPE_SOCKMAP; + syscall(__NR_bpf, 0, &attr, 0); + + attr.map_flags = 0; + attr.map_type = BPF_MAP_TYPE_ARRAY; syscall(__NR_bpf, 0, &attr, 0);" . auto/feature @@ -259,23 +266,6 @@ if [ $ngx_found = yes ]; then fi -ngx_feature="SO_COOKIE" -ngx_feature_name="NGX_HAVE_SO_COOKIE" -ngx_feature_run=no -ngx_feature_incs="#include <sys/socket.h> - #include <stdint.h>" -ngx_feature_path= -ngx_feature_libs= -ngx_feature_test="socklen_t optlen = sizeof(uint64_t); - uint64_t cookie; - getsockopt(0, SOL_SOCKET, SO_COOKIE, &cookie, &optlen)" -. auto/feature - -if [ $ngx_found = yes ]; then - SO_COOKIE_FOUND=YES -fi - - # UDP segmentation offloading ngx_feature="UDP_SEGMENT" diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -1033,12 +1033,6 @@ ngx_close_listening_sockets(ngx_cycle_t ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { -#if (NGX_QUIC) - if (ls[i].quic) { - continue; - } -#endif - c = ls[i].connection; if (c) { diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -73,6 +73,7 @@ struct ngx_event_s { /* to test on worker exit */ unsigned channel:1; unsigned resolver:1; + unsigned quic:1; unsigned cancelable:1; diff --git a/src/event/quic/bpf/makefile b/src/event/quic/bpf/makefile --- a/src/event/quic/bpf/makefile +++ b/src/event/quic/bpf/makefile @@ -1,4 +1,4 @@ -CFLAGS=-O2 -Wall +CFLAGS=-O2 -Wall $(MAKE_CFLAGS) LICENSE=BSD diff --git a/src/event/quic/bpf/ngx_quic_reuseport_helper.c b/src/event/quic/bpf/ngx_quic_reuseport_helper.c --- a/src/event/quic/bpf/ngx_quic_reuseport_helper.c +++ b/src/event/quic/bpf/ngx_quic_reuseport_helper.c @@ -44,97 +44,93 @@ char _license[] SEC("license") = LICENSE #define NGX_QUIC_SERVER_CID_LEN 20 -#define advance_data(nbytes) \ - offset += nbytes; \ - if (start + offset > end) { \ - debugmsg("cannot read %ld bytes at offset %ld", nbytes, offset); \ - goto failed; \ - } \ - data = start + offset - 1; - - -#define ngx_quic_parse_uint64(p) \ - (((__u64)(p)[0] << 56) | \ - ((__u64)(p)[1] << 48) | \ - ((__u64)(p)[2] << 40) | \ - ((__u64)(p)[3] << 32) | \ - ((__u64)(p)[4] << 24) | \ - ((__u64)(p)[5] << 16) | \ - ((__u64)(p)[6] << 8) | \ - ((__u64)(p)[7])) - -/* - * actual map object is created by the "bpf" system call, - * all pointers to this variable are replaced by the bpf loader - */ -struct bpf_map_def SEC("maps") ngx_quic_sockmap; +struct bpf_map_def SEC("maps") ngx_quic_listen; +struct bpf_map_def SEC("maps") ngx_quic_worker; +struct bpf_map_def SEC("maps") ngx_quic_nlisten; SEC(PROGNAME) -int ngx_quic_select_socket_by_dcid(struct sk_reuseport_md *ctx) +int ngx_quic_select_socket_by_dcid(struct sk_reuseport_md *ctx) \ { - int rc; - __u64 key; + int rc, flags; + __u32 zero, *nsockets, ns; size_t len, offset; - unsigned char *start, *end, *data, *dcid; + unsigned char *start, *end, dcid[NGX_QUIC_SERVER_CID_LEN]; start = ctx->data; - end = (unsigned char *) ctx->data_end; - offset = 0; + end = ctx->data_end; - advance_data(sizeof(struct udphdr)); /* data at UDP header */ - advance_data(1); /* data at QUIC flags */ - - if (data[0] & NGX_QUIC_PKT_LONG) { + offset = sizeof(struct udphdr) + 1; /* UDP header + QUIC flags */ + if (start + offset > end) { + goto bad_dgram; + } - advance_data(4); /* data at QUIC version */ - advance_data(1); /* data at DCID len */ + flags = start[offset - 1]; + if (flags & NGX_QUIC_PKT_LONG) { - len = data[0]; /* read DCID length */ - - if (len < 8) { - /* it's useless to search for key in such short DCID */ - return SK_PASS; + offset += 5; /* QUIC version + DCID len */ + if (start + offset > end) { + goto bad_dgram; } - } else { - len = NGX_QUIC_SERVER_CID_LEN; + len = start[offset - 1]; + if (len != NGX_QUIC_SERVER_CID_LEN) { + goto new_conn; + } + } + + if (start + offset + NGX_QUIC_SERVER_CID_LEN > end) { + goto bad_dgram; + } + + memcpy(dcid, start + offset, NGX_QUIC_SERVER_CID_LEN); + + rc = bpf_sk_select_reuseport(ctx, &ngx_quic_worker, dcid, 0); + + if (rc == 0) { + debugmsg("nginx quic socket selected by dcid"); + return SK_PASS; } - dcid = &data[1]; - advance_data(len); /* we expect the packet to have full DCID */ + if (rc != -ENOENT) { + debugmsg("nginx quic bpf_sk_select_reuseport() failed:%d", rc); + return SK_DROP; + } + +new_conn: - /* make verifier happy */ - if (dcid + sizeof(__u64) > end) { - goto failed; + zero = 0; + + nsockets = bpf_map_lookup_elem(&ngx_quic_nlisten, &zero); + + if (nsockets == NULL) { + debugmsg("nginx quic nsockets undefined"); + return SK_DROP; } - key = ngx_quic_parse_uint64(dcid); - - rc = bpf_sk_select_reuseport(ctx, &ngx_quic_sockmap, &key, 0); + ns = ctx->hash % *nsockets; - switch (rc) { - case 0: - debugmsg("nginx quic socket selected by key 0x%llx", key); - return SK_PASS; + rc = bpf_sk_select_reuseport(ctx, &ngx_quic_listen, &ns, 0); - /* kernel returns positive error numbers, errno.h defines positive */ - case -ENOENT: - debugmsg("nginx quic default route for key 0x%llx", key); - /* let the default reuseport logic decide which socket to choose */ + if (rc == 0) { + debugmsg("nginx quic socket selected by hash:%d", (int) ns); return SK_PASS; - - default: - debugmsg("nginx quic bpf_sk_select_reuseport err: %d key 0x%llx", - rc, key); - goto failed; } -failed: - /* - * SK_DROP will generate ICMP, but we may want to process "invalid" packet - * in userspace quic to investigate further and finally react properly - * (maybe ignore, maybe send something in response or close connection) - */ - return SK_PASS; + if (rc != -ENOENT) { + debugmsg("nginx quic bpf_sk_select_reuseport() failed:%d", rc); + return SK_DROP; + } + + (void) bpf_map_update_elem(&ngx_quic_nlisten, &zero, &ns, BPF_ANY); + + debugmsg("nginx quic cut sockets array:%d", (int) ns); + + return SK_DROP; + +bad_dgram: + + debugmsg("nginx quic bad datagram"); + + return SK_DROP; } diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c --- a/src/event/quic/ngx_event_quic.c +++ b/src/event/quic/ngx_event_quic.c @@ -315,6 +315,10 @@ ngx_quic_new_connection(ngx_connection_t qc->congestion.ssthresh = (size_t) -1; qc->congestion.recovery_start = ngx_current_msec; + if (c->fd == c->listening->fd) { + qc->listen_bound = 1; + } + if (pkt->validated && pkt->retried) { qc->tp.retry_scid.len = pkt->dcid.len; qc->tp.retry_scid.data = ngx_pstrdup(c->pool, &pkt->dcid); @@ -422,6 +426,15 @@ ngx_quic_input_handler(ngx_event_t *rev) return; } + if (qc->listen_bound) { + c->fd = (ngx_socket_t) -1; + + qc->error = NGX_QUIC_ERR_NO_ERROR; + qc->error_reason = "graceful shutdown"; + ngx_quic_close_connection(c, NGX_ERROR); + return; + } + if (!qc->closing && qc->conf->shutdown) { qc->conf->shutdown(c); } @@ -894,14 +907,6 @@ ngx_quic_handle_packet(ngx_connection_t pkt->odcid = pkt->dcid; } - if (ngx_terminate || ngx_exiting) { - if (conf->retry) { - return ngx_quic_send_retry(c, conf, pkt); - } - - return NGX_ERROR; - } - c->log->action = "creating quic connection"; qc = ngx_quic_new_connection(c, conf, pkt); diff --git a/src/event/quic/ngx_event_quic_bpf.c b/src/event/quic/ngx_event_quic_bpf.c --- a/src/event/quic/ngx_event_quic_bpf.c +++ b/src/event/quic/ngx_event_quic_bpf.c @@ -6,6 +6,8 @@ #include <ngx_config.h> #include <ngx_core.h> +#include <ngx_event.h> +#include <ngx_event_quic_connection.h> #define NGX_QUIC_BPF_VARNAME "NGINX_BPF_MAPS" @@ -26,39 +28,57 @@ typedef struct { ngx_queue_t queue; - int map_fd; + + int listen_map; + int worker_map; + int nlisten_map; struct sockaddr *sockaddr; socklen_t socklen; - ngx_uint_t unused; /* unsigned unused:1; */ -} ngx_quic_sock_group_t; + + ngx_array_t listening; + + ngx_uint_t nlisten; + ngx_uint_t old_nlisten; +} ngx_quic_bpf_group_t; + + +typedef struct { + ngx_socket_t fd; + ngx_listening_t *listening; + ngx_connection_t *connection; +} ngx_quic_bpf_listening_t; typedef struct { ngx_flag_t enabled; - ngx_uint_t map_size; - ngx_queue_t groups; /* of ngx_quic_sock_group_t */ + ngx_uint_t max_connection_ids; + ngx_uint_t max_workers; + ngx_queue_t groups; } ngx_quic_bpf_conf_t; static void *ngx_quic_bpf_create_conf(ngx_cycle_t *cycle); +static char *ngx_quic_bpf_init_conf(ngx_cycle_t *cycle, void *conf); static ngx_int_t ngx_quic_bpf_module_init(ngx_cycle_t *cycle); static void ngx_quic_bpf_cleanup(void *data); static ngx_inline void ngx_quic_bpf_close(ngx_log_t *log, int fd, const char *name); -static ngx_quic_sock_group_t *ngx_quic_bpf_find_group(ngx_quic_bpf_conf_t *bcf, +static ngx_quic_bpf_group_t *ngx_quic_bpf_find_group(ngx_cycle_t *cycle, + ngx_listening_t *ls); +static ngx_quic_bpf_group_t *ngx_quic_bpf_alloc_group(ngx_cycle_t *cycle, ngx_listening_t *ls); -static ngx_quic_sock_group_t *ngx_quic_bpf_alloc_group(ngx_cycle_t *cycle, - struct sockaddr *sa, socklen_t socklen); -static ngx_quic_sock_group_t *ngx_quic_bpf_create_group(ngx_cycle_t *cycle, +static ngx_quic_bpf_group_t *ngx_quic_bpf_create_group(ngx_cycle_t *cycle, ngx_listening_t *ls); -static ngx_quic_sock_group_t *ngx_quic_bpf_get_group(ngx_cycle_t *cycle, +static ngx_int_t ngx_quic_bpf_inherit_fd(ngx_cycle_t *cycle, int fd); +static ngx_quic_bpf_group_t *ngx_quic_bpf_get_group(ngx_cycle_t *cycle, ngx_listening_t *ls); static ngx_int_t ngx_quic_bpf_group_add_socket(ngx_cycle_t *cycle, ngx_listening_t *ls); -static uint64_t ngx_quic_bpf_socket_key(ngx_fd_t fd, ngx_log_t *log); +static ngx_int_t ngx_quic_bpf_add_worker_socket(ngx_cycle_t *cycle, + ngx_quic_bpf_group_t *grp, ngx_listening_t *ls); static ngx_int_t ngx_quic_bpf_export_maps(ngx_cycle_t *cycle); static ngx_int_t ngx_quic_bpf_import_maps(ngx_cycle_t *cycle); @@ -82,7 +102,7 @@ static ngx_command_t ngx_quic_bpf_comma static ngx_core_module_t ngx_quic_bpf_module_ctx = { ngx_string("quic_bpf"), ngx_quic_bpf_create_conf, - NULL + ngx_quic_bpf_init_conf }; @@ -113,7 +133,6 @@ ngx_quic_bpf_create_conf(ngx_cycle_t *cy } bcf->enabled = NGX_CONF_UNSET; - bcf->map_size = NGX_CONF_UNSET_UINT; ngx_queue_init(&bcf->groups); @@ -121,12 +140,41 @@ ngx_quic_bpf_create_conf(ngx_cycle_t *cy } +static char * +ngx_quic_bpf_init_conf(ngx_cycle_t *cycle, void *conf) +{ + ngx_quic_bpf_conf_t *bcf = conf; + + ngx_quic_bpf_conf_t *obcf; + + ngx_conf_init_value(bcf->enabled, 0); + + if (cycle->old_cycle->conf_ctx == NULL) { + return NGX_CONF_OK; + } + + obcf = ngx_quic_bpf_get_conf(cycle->old_cycle); + if (obcf == NULL) { + return NGX_CONF_OK; + } + + if (obcf->enabled != bcf->enabled) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "cannot change \"quic_bpf\" after reload, ignoring"); + bcf->enabled = obcf->enabled; + } + + return NGX_CONF_OK; +} + + static ngx_int_t ngx_quic_bpf_module_init(ngx_cycle_t *cycle) { ngx_uint_t i; ngx_listening_t *ls; ngx_core_conf_t *ccf; + ngx_event_conf_t *ecf; ngx_pool_cleanup_t *cln; ngx_quic_bpf_conf_t *bcf; @@ -138,12 +186,16 @@ ngx_quic_bpf_module_init(ngx_cycle_t *cy return NGX_OK; } - ccf = ngx_core_get_conf(cycle); bcf = ngx_quic_bpf_get_conf(cycle); + if (!bcf->enabled) { + return NGX_OK; + } - ngx_conf_init_value(bcf->enabled, 0); + ccf = ngx_core_get_conf(cycle); + ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); - bcf->map_size = ccf->worker_processes * 4; + bcf->max_connection_ids = ecf->connections * NGX_QUIC_MAX_SERVER_IDS; + bcf->max_workers = ccf->worker_processes * 4; cln = ngx_pool_cleanup_add(cycle->pool, 0); if (cln == NULL) { @@ -153,6 +205,8 @@ ngx_quic_bpf_module_init(ngx_cycle_t *cy cln->data = bcf; cln->handler = ngx_quic_bpf_cleanup; + ls = cycle->listening.elts; + if (ngx_inherited && ngx_is_init_cycle(cycle->old_cycle)) { if (ngx_quic_bpf_import_maps(cycle) != NGX_OK) { goto failed; @@ -208,16 +262,32 @@ ngx_quic_bpf_cleanup(void *data) { ngx_quic_bpf_conf_t *bcf = (ngx_quic_bpf_conf_t *) data; - ngx_queue_t *q; - ngx_quic_sock_group_t *grp; + ngx_uint_t i; + ngx_queue_t *q; + ngx_quic_bpf_group_t *grp; + ngx_quic_bpf_listening_t *bls; for (q = ngx_queue_head(&bcf->groups); q != ngx_queue_sentinel(&bcf->groups); q = ngx_queue_next(q)) { - grp = ngx_queue_data(q, ngx_quic_sock_group_t, queue); + grp = ngx_queue_data(q, ngx_quic_bpf_group_t, queue); + + ngx_quic_bpf_close(ngx_cycle->log, grp->listen_map, "listen"); + ngx_quic_bpf_close(ngx_cycle->log, grp->worker_map, "worker"); + ngx_quic_bpf_close(ngx_cycle->log, grp->nlisten_map, "nlisten"); + + bls = grp->listening.elts; - ngx_quic_bpf_close(ngx_cycle->log, grp->map_fd, "map"); + for (i = 0; i < grp->listening.nelts; i++) { + if (bls[i].fd != (ngx_socket_t) -1) { + if (ngx_close_socket(bls[i].fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, + ngx_socket_errno, + ngx_close_socket_n " failed"); + } + } + } } } @@ -230,25 +300,32 @@ ngx_quic_bpf_close(ngx_log_t *log, int f } ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, - "quic bpf close %s fd:%d failed", name, fd); + "QUIC BPF close %s map fd:%d failed", name, fd); } -static ngx_quic_sock_group_t * -ngx_quic_bpf_find_group(ngx_quic_bpf_conf_t *bcf, ngx_listening_t *ls) +static ngx_quic_bpf_group_t * +ngx_quic_bpf_find_group(ngx_cycle_t *cycle, ngx_listening_t *ls) { - ngx_queue_t *q; - ngx_quic_sock_group_t *grp; + ngx_queue_t *q; + ngx_quic_bpf_conf_t *bcf; + ngx_quic_bpf_group_t *grp; + + bcf = ngx_quic_bpf_get_conf(cycle); + + if (!bcf->enabled || !ls->quic || !ls->reuseport) { + return NULL; + } for (q = ngx_queue_head(&bcf->groups); q != ngx_queue_sentinel(&bcf->groups); q = ngx_queue_next(q)) { - grp = ngx_queue_data(q, ngx_quic_sock_group_t, queue); + grp = ngx_queue_data(q, ngx_quic_bpf_group_t, queue); if (ngx_cmp_sockaddr(ls->sockaddr, ls->socklen, grp->sockaddr, grp->socklen, 1) - == NGX_OK) + == 0) { return grp; } @@ -258,26 +335,32 @@ ngx_quic_bpf_find_group(ngx_quic_bpf_con } -static ngx_quic_sock_group_t * -ngx_quic_bpf_alloc_group(ngx_cycle_t *cycle, struct sockaddr *sa, - socklen_t socklen) +static ngx_quic_bpf_group_t * +ngx_quic_bpf_alloc_group(ngx_cycle_t *cycle, ngx_listening_t *ls) { ngx_quic_bpf_conf_t *bcf; - ngx_quic_sock_group_t *grp; + ngx_quic_bpf_group_t *grp; bcf = ngx_quic_bpf_get_conf(cycle); - grp = ngx_pcalloc(cycle->pool, sizeof(ngx_quic_sock_group_t)); + grp = ngx_pcalloc(cycle->pool, sizeof(ngx_quic_bpf_group_t)); if (grp == NULL) { return NULL; } - grp->socklen = socklen; - grp->sockaddr = ngx_palloc(cycle->pool, socklen); - if (grp->sockaddr == NULL) { + grp->listen_map = -1; + grp->worker_map = -1; + grp->nlisten_map = -1; + + grp->sockaddr = ls->sockaddr; + grp->socklen = ls->socklen; + + if (ngx_array_init(&grp->listening, cycle->pool, 1, + sizeof(ngx_quic_bpf_listening_t)) + != NGX_OK) + { return NULL; } - ngx_memcpy(grp->sockaddr, sa, socklen); ngx_queue_insert_tail(&bcf->groups, &grp->queue); @@ -285,50 +368,72 @@ ngx_quic_bpf_alloc_group(ngx_cycle_t *cy } -static ngx_quic_sock_group_t * +static ngx_quic_bpf_group_t * ngx_quic_bpf_create_group(ngx_cycle_t *cycle, ngx_listening_t *ls) { - int progfd, failed, flags, rc; - ngx_quic_bpf_conf_t *bcf; - ngx_quic_sock_group_t *grp; + int progfd, failed; + ngx_quic_bpf_conf_t *bcf; + ngx_quic_bpf_group_t *grp; bcf = ngx_quic_bpf_get_conf(cycle); - if (!bcf->enabled) { - return NULL; - } - - grp = ngx_quic_bpf_alloc_group(cycle, ls->sockaddr, ls->socklen); + grp = ngx_quic_bpf_alloc_group(cycle, ls); if (grp == NULL) { return NULL; } - grp->map_fd = ngx_bpf_map_create(cycle->log, BPF_MAP_TYPE_SOCKHASH, - sizeof(uint64_t), sizeof(uint64_t), - bcf->map_size, 0); - if (grp->map_fd == -1) { + grp->listen_map = ngx_bpf_map_create(cycle->log, BPF_MAP_TYPE_SOCKMAP, + sizeof(uint32_t), sizeof(uint64_t), + bcf->max_workers, 0); + if (grp->listen_map == -1) { goto failed; } - flags = fcntl(grp->map_fd, F_GETFD); - if (flags == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, errno, - "quic bpf getfd failed"); - goto failed; - } - - /* need to inherit map during binary upgrade after exec */ - flags &= ~FD_CLOEXEC; - - rc = fcntl(grp->map_fd, F_SETFD, flags); - if (rc == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, errno, - "quic bpf setfd failed"); + if (ngx_quic_bpf_inherit_fd(cycle, grp->listen_map) != NGX_OK) { goto failed; } ngx_bpf_program_link(&ngx_quic_reuseport_helper, - "ngx_quic_sockmap", grp->map_fd); + "ngx_quic_listen", grp->listen_map); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "quic bpf listen map created fd:%d", grp->listen_map); + + + grp->worker_map = ngx_bpf_map_create(cycle->log, BPF_MAP_TYPE_SOCKHASH, + NGX_QUIC_SERVER_CID_LEN, sizeof(uint64_t), + bcf->max_connection_ids, 0); + if (grp->worker_map == -1) { + goto failed; + } + + if (ngx_quic_bpf_inherit_fd(cycle, grp->worker_map) != NGX_OK) { + goto failed; + } + + ngx_bpf_program_link(&ngx_quic_reuseport_helper, + "ngx_quic_worker", grp->worker_map); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "quic bpf worker map created fd:%d", grp->worker_map); + + + grp->nlisten_map = ngx_bpf_map_create(cycle->log, BPF_MAP_TYPE_ARRAY, + sizeof(uint32_t), sizeof(uint32_t), 1, 0); + if (grp->nlisten_map == -1) { + goto failed; + } + + if (ngx_quic_bpf_inherit_fd(cycle, grp->nlisten_map) != NGX_OK) { + goto failed; + } + + ngx_bpf_program_link(&ngx_quic_reuseport_helper, + "ngx_quic_nlisten", grp->nlisten_map); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "quic bpf nlisten map created fd:%d", grp->nlisten_map); + progfd = ngx_bpf_load_program(cycle->log, &ngx_quic_reuseport_helper); if (progfd < 0) { @@ -352,14 +457,116 @@ ngx_quic_bpf_create_group(ngx_cycle_t *c goto failed; } - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "quic bpf sockmap created fd:%d", grp->map_fd); return grp; failed: - if (grp->map_fd != -1) { - ngx_quic_bpf_close(cycle->log, grp->map_fd, "map"); + if (grp->listen_map != -1) { + ngx_quic_bpf_close(cycle->log, grp->listen_map, "listen"); + } + + if (grp->worker_map != -1) { + ngx_quic_bpf_close(cycle->log, grp->worker_map, "worker"); + } + + if (grp->nlisten_map != -1) { + ngx_quic_bpf_close(cycle->log, grp->nlisten_map, "nlisten"); + } + + ngx_queue_remove(&grp->queue); + + return NULL; +} + + +static ngx_int_t +ngx_quic_bpf_inherit_fd(ngx_cycle_t *cycle, int fd) +{ + int flags; + + flags = fcntl(fd, F_GETFD); + if (flags == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "fcntl(F_GETFD) failed"); + return NGX_ERROR; + } + + flags &= ~FD_CLOEXEC; + + if (fcntl(fd, F_SETFD, flags) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "fcntl(F_SETFD) failed"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_quic_bpf_group_t * +ngx_quic_bpf_get_group(ngx_cycle_t *cycle, ngx_listening_t *ls) +{ + ngx_quic_bpf_conf_t *old_bcf; + ngx_quic_bpf_group_t *grp, *ogrp; + + grp = ngx_quic_bpf_find_group(cycle, ls); + if (grp) { + return grp; + } + + old_bcf = ngx_quic_bpf_get_old_conf(cycle); + if (old_bcf == NULL) { + return ngx_quic_bpf_create_group(cycle, ls); + } + + ogrp = ngx_quic_bpf_find_group(cycle->old_cycle, ls); + if (ogrp == NULL) { + return ngx_quic_bpf_create_group(cycle, ls); + } + + grp = ngx_quic_bpf_alloc_group(cycle, ls); + if (grp == NULL) { + return NULL; + } + + grp->old_nlisten = ogrp->nlisten; + + grp->listen_map = dup(ogrp->listen_map); + if (grp->listen_map == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "failed to duplicate QUIC BPF listen map"); + + goto failed; + } + + grp->worker_map = dup(ogrp->worker_map); + if (grp->worker_map == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "failed to duplicate QUIC BPF worker map"); + goto failed; + } + + grp->nlisten_map = dup(ogrp->nlisten_map); + if (grp->nlisten_map == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "failed to duplicate QUIC BPF nlisten map"); + goto failed; + } + + return grp; + +failed: + + if (grp->listen_map != -1) { + ngx_quic_bpf_close(cycle->log, grp->listen_map, "listen"); + } + + if (grp->worker_map != -1) { + ngx_quic_bpf_close(cycle->log, grp->worker_map, "worker"); + } + + if (grp->nlisten_map != -1) { + ngx_quic_bpf_close(cycle->log, grp->nlisten_map, "nlisten"); } ngx_queue_remove(&grp->queue); @@ -368,129 +575,148 @@ failed: } -static ngx_quic_sock_group_t * -ngx_quic_bpf_get_group(ngx_cycle_t *cycle, ngx_listening_t *ls) -{ - ngx_quic_bpf_conf_t *bcf, *old_bcf; - ngx_quic_sock_group_t *grp, *ogrp; - - bcf = ngx_quic_bpf_get_conf(cycle); - - grp = ngx_quic_bpf_find_group(bcf, ls); - if (grp) { - return grp; - } - - old_bcf = ngx_quic_bpf_get_old_conf(cycle); - - if (old_bcf == NULL) { - return ngx_quic_bpf_create_group(cycle, ls); - } - - ogrp = ngx_quic_bpf_find_group(old_bcf, ls); - if (ogrp == NULL) { - return ngx_quic_bpf_create_group(cycle, ls); - } - - grp = ngx_quic_bpf_alloc_group(cycle, ls->sockaddr, ls->socklen); - if (grp == NULL) { - return NULL; - } - - grp->map_fd = dup(ogrp->map_fd); - if (grp->map_fd == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "quic bpf failed to duplicate bpf map descriptor"); - - ngx_queue_remove(&grp->queue); - - return NULL; - } - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "quic bpf sockmap fd duplicated old:%d new:%d", - ogrp->map_fd, grp->map_fd); - - return grp; -} - - static ngx_int_t ngx_quic_bpf_group_add_socket(ngx_cycle_t *cycle, ngx_listening_t *ls) { - uint64_t cookie; - ngx_quic_bpf_conf_t *bcf; - ngx_quic_sock_group_t *grp; - - bcf = ngx_quic_bpf_get_conf(cycle); + uint32_t zero, key; + ngx_quic_bpf_group_t *grp; grp = ngx_quic_bpf_get_group(cycle, ls); + if (grp == NULL) { + return NGX_ERROR; + } - if (grp == NULL) { - if (!bcf->enabled) { - return NGX_OK; - } - + if (ngx_quic_bpf_add_worker_socket(cycle, grp, ls) != NGX_OK) { return NGX_ERROR; } - grp->unused = 0; + key = ls->worker; - cookie = ngx_quic_bpf_socket_key(ls->fd, cycle->log); - if (cookie == (uint64_t) NGX_ERROR) { + if (ngx_bpf_map_update(grp->listen_map, &key, &ls->fd, BPF_ANY) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "failed to update QUIC BPF listen map"); return NGX_ERROR; } - /* map[cookie] = socket; for use in kernel helper */ - if (ngx_bpf_map_update(grp->map_fd, &cookie, &ls->fd, BPF_ANY) == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "quic bpf failed to update socket map key=%xL", cookie); - return NGX_ERROR; + if (grp->nlisten >= ls->worker + 1) { + return NGX_OK; } - ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "quic bpf sockmap fd:%d add socket:%d cookie:0x%xL worker:%ui", - grp->map_fd, ls->fd, cookie, ls->worker); + grp->nlisten = ls->worker + 1; + + if (grp->nlisten <= grp->old_nlisten) { + return NGX_OK; + } - /* do not inherit this socket */ - ls->ignore = 1; + zero = 0; + key = grp->nlisten; + + if (ngx_bpf_map_update(grp->nlisten_map, &zero, &key, BPF_ANY) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "failed to update QUIC BPF nlisten map"); + return NGX_ERROR; + } return NGX_OK; } -static uint64_t -ngx_quic_bpf_socket_key(ngx_fd_t fd, ngx_log_t *log) +static ngx_int_t +ngx_quic_bpf_add_worker_socket(ngx_cycle_t *cycle, ngx_quic_bpf_group_t *grp, + ngx_listening_t *ls) { - uint64_t cookie; - socklen_t optlen; + int value; + ngx_uint_t i, n; + ngx_socket_t s; + ngx_quic_bpf_listening_t *bls; + + s = ngx_socket(ls->sockaddr->sa_family, SOCK_DGRAM, 0); + if (s == (ngx_socket_t) -1) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_socket_errno, + ngx_socket_n " failed"); + return NGX_ERROR; + } - optlen = sizeof(cookie); + if (ngx_nonblocking(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_nonblocking_n " client socket failed"); + goto failed; + } + + value = 1; - if (getsockopt(fd, SOL_SOCKET, SO_COOKIE, &cookie, &optlen) == -1) { - ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - "quic bpf getsockopt(SO_COOKIE) failed"); - - return (ngx_uint_t) NGX_ERROR; + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + "setsockopt(SO_REUSEADDR) client socket failed"); + goto failed; } - return cookie; + if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + "setsockopt(SO_REUSEPORT) client socket failed"); + goto failed; + } + + if (bind(s, ls->sockaddr, ls->socklen) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + "bind() failed"); + goto failed; + } + + if (ls->worker >= grp->listening.nelts) { + n = ls->worker + 1 - grp->listening.nelts; + + bls = ngx_array_push_n(&grp->listening, n); + if (bls == NULL) { + goto failed; + } + + ngx_memzero(bls, n * sizeof(ngx_quic_bpf_listening_t)); + + for (i = 0; i < n; i++) { + bls[i].fd = (ngx_socket_t) -1; + } + } + + bls = grp->listening.elts; + bls[ls->worker].fd = s; + bls[ls->worker].listening = ls; + + return NGX_OK; + +failed: + + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + return NGX_ERROR; } - static ngx_int_t ngx_quic_bpf_export_maps(ngx_cycle_t *cycle) { - u_char *p, *buf; - size_t len; - ngx_str_t *var; - ngx_queue_t *q; - ngx_core_conf_t *ccf; - ngx_quic_bpf_conf_t *bcf; - ngx_quic_sock_group_t *grp; + u_char *p, *buf; + size_t len; + ngx_str_t *var; + ngx_queue_t *q; + ngx_core_conf_t *ccf; + ngx_quic_bpf_conf_t *bcf; + ngx_quic_bpf_group_t *grp; + + bcf = ngx_quic_bpf_get_conf(cycle); + if (!bcf->enabled) { + return NGX_OK; + } ccf = ngx_core_get_conf(cycle); - bcf = ngx_quic_bpf_get_conf(cycle); len = sizeof(NGX_QUIC_BPF_VARNAME) + 1; @@ -498,24 +724,26 @@ ngx_quic_bpf_export_maps(ngx_cycle_t *cy while (q != ngx_queue_sentinel(&bcf->groups)) { - grp = ngx_queue_data(q, ngx_quic_sock_group_t, queue); + grp = ngx_queue_data(q, ngx_quic_bpf_group_t, queue); q = ngx_queue_next(q); - if (grp->unused) { + if (grp->nlisten == 0) { /* * map was inherited, but it is not used in this configuration; * do not pass such map further and drop the group to prevent * interference with changes during reload */ - ngx_quic_bpf_close(cycle->log, grp->map_fd, "map"); + ngx_quic_bpf_close(cycle->log, grp->listen_map, "listen"); + ngx_quic_bpf_close(cycle->log, grp->worker_map, "worker"); + ngx_quic_bpf_close(cycle->log, grp->nlisten_map, "nlisten"); + ngx_queue_remove(&grp->queue); - continue; } - len += NGX_INT32_LEN + 1 + NGX_SOCKADDR_STRLEN + 1; + len += (NGX_INT32_LEN + 1) * 3 + NGX_SOCKADDR_STRLEN + 1; } len++; @@ -525,22 +753,23 @@ ngx_quic_bpf_export_maps(ngx_cycle_t *cy return NGX_ERROR; } - p = ngx_cpymem(buf, NGX_QUIC_BPF_VARNAME "=", - sizeof(NGX_QUIC_BPF_VARNAME)); + p = ngx_cpymem(buf, NGX_QUIC_BPF_VARNAME "=", sizeof(NGX_QUIC_BPF_VARNAME)); for (q = ngx_queue_head(&bcf->groups); q != ngx_queue_sentinel(&bcf->groups); q = ngx_queue_next(q)) { - grp = ngx_queue_data(q, ngx_quic_sock_group_t, queue); + grp = ngx_queue_data(q, ngx_quic_bpf_group_t, queue); - p = ngx_sprintf(p, "%ud", grp->map_fd); - + p = ngx_sprintf(p, "%ud", grp->listen_map); + *p++ = NGX_QUIC_BPF_ADDRSEP; + p = ngx_sprintf(p, "%ud", grp->worker_map); + *p++ = NGX_QUIC_BPF_ADDRSEP; + p = ngx_sprintf(p, "%ud", grp->nlisten_map); *p++ = NGX_QUIC_BPF_ADDRSEP; p += ngx_sock_ntop(grp->sockaddr, grp->socklen, p, NGX_SOCKADDR_STRLEN, 1); - *p++ = NGX_QUIC_BPF_VARSEP; } @@ -561,12 +790,14 @@ ngx_quic_bpf_export_maps(ngx_cycle_t *cy static ngx_int_t ngx_quic_bpf_import_maps(ngx_cycle_t *cycle) { - int s; - u_char *inherited, *p, *v; - ngx_uint_t in_fd; - ngx_addr_t tmp; - ngx_quic_bpf_conf_t *bcf; - ngx_quic_sock_group_t *grp; + int fds[3]; + u_char *inherited, *p, *v; + uint32_t zero, nlisten; + ngx_int_t fd; + ngx_uint_t nfd; + ngx_addr_t tmp; + ngx_quic_bpf_conf_t *bcf; + ngx_quic_bpf_group_t *grp; inherited = (u_char *) getenv(NGX_QUIC_BPF_VARNAME); @@ -574,13 +805,13 @@ ngx_quic_bpf_import_maps(ngx_cycle_t *cy return NGX_OK; } + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, + "using inherited QUIC BPF maps from \"%s\"", inherited); + bcf = ngx_quic_bpf_get_conf(cycle); -#if (NGX_SUPPRESS_WARN) - s = -1; -#endif - - in_fd = 1; + zero = 0; + nfd = 0; for (p = inherited, v = p; *p; p++) { @@ -588,63 +819,69 @@ ngx_quic_bpf_import_maps(ngx_cycle_t *cy case NGX_QUIC_BPF_ADDRSEP: - if (!in_fd) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "quic bpf failed to parse inherited env"); - return NGX_ERROR; - } - in_fd = 0; - - s = ngx_atoi(v, p - v); - if (s == NGX_ERROR) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "quic bpf failed to parse inherited map fd"); - return NGX_ERROR; + if (nfd > 2) { + goto failed; } + fd = ngx_atoi(v, p - v); + if (fd == NGX_ERROR) { + goto failed; + } + + fds[nfd++] = fd; v = p + 1; break; case NGX_QUIC_BPF_VARSEP: - if (in_fd) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "quic bpf failed to parse inherited env"); - return NGX_ERROR; + if (nfd != 3) { + goto failed; } - in_fd = 1; - grp = ngx_pcalloc(cycle->pool, - sizeof(ngx_quic_sock_group_t)); + grp = ngx_pcalloc(cycle->pool, sizeof(ngx_quic_bpf_group_t)); if (grp == NULL) { return NGX_ERROR; } - grp->map_fd = s; - - if (ngx_parse_addr_port(cycle->pool, &tmp, v, p - v) + if (ngx_array_init(&grp->listening, cycle->pool, 1, + sizeof(ngx_quic_bpf_listening_t)) != NGX_OK) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "quic bpf failed to parse inherited" - " address '%*s'", p - v , v); + return NGX_ERROR; + } + + grp->listen_map = fds[0]; + grp->worker_map = fds[1]; + grp->nlisten_map = fds[2]; - ngx_quic_bpf_close(cycle->log, s, "inherited map"); + if (ngx_parse_addr_port(cycle->pool, &tmp, v, p - v) != NGX_OK) { + goto failed; + } + grp->sockaddr = ngx_pcalloc(cycle->pool, tmp.socklen); + if (grp->sockaddr == NULL) { return NGX_ERROR; } - grp->sockaddr = tmp.sockaddr; + ngx_memcpy(grp->sockaddr, tmp.sockaddr, tmp.socklen); grp->socklen = tmp.socklen; - grp->unused = 1; + if (ngx_bpf_map_lookup(fds[2], &zero, &nlisten) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "failed to lookup QUIC BPF listen number"); + return NGX_ERROR; + } + + grp->old_nlisten = nlisten; ngx_queue_insert_tail(&bcf->groups, &grp->queue); - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + ngx_log_debug5(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "quic bpf sockmap inherited with " - "fd:%d address:%*s", - grp->map_fd, p - v, v); + "fds:%d/%d/%d address:%*s", + fds[0], fds[1], fds[2], p - v, v); + + nfd = 0; v = p + 1; break; @@ -654,4 +891,127 @@ ngx_quic_bpf_import_maps(ngx_cycle_t *cy } return NGX_OK; + +failed: + + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "failed to parse inherited QUIC BPF variable"); + + return NGX_ERROR; } + + +ngx_int_t +ngx_quic_bpf_get_client_connection(ngx_connection_t *lc, ngx_connection_t **pc) +{ + ngx_event_t *rev; + ngx_connection_t *c; + ngx_quic_bpf_group_t *grp; + ngx_quic_bpf_listening_t *bpf_listening, *bls; + + grp = ngx_quic_bpf_find_group((ngx_cycle_t *) ngx_cycle, lc->listening); + + if (grp == NULL || ngx_worker >= grp->listening.nelts) { + return NGX_OK; + } + + bpf_listening = grp->listening.elts; + bls = &bpf_listening[ngx_worker]; + + if (bls->fd == (ngx_socket_t) -1) { + return NGX_OK; + } + + if (bls->connection == NULL) { + c = ngx_get_connection(bls->fd, lc->log); + if (c == NULL) { + return NGX_ERROR; + } + + c->type = SOCK_DGRAM; + c->log = lc->log; + c->listening = bls->listening; + + rev = c->read; + rev->quic = 1; + rev->log = c->log; + rev->handler = ngx_quic_recvmsg; + + if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { + ngx_free_connection(c); + return NGX_ERROR; + } + + bls->connection = c; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, lc->log, 0, + "quic bpf worker socket connection fd:%d", bls->fd); + + } + + *pc = ngx_get_connection(bls->fd, lc->log); + if (*pc == NULL) { + return NGX_ERROR; + } + + (*pc)->shared = 1; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, lc->log, 0, + "quic bpf client connection fd:%d", bls->fd); + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_bpf_insert(ngx_connection_t *c, ngx_quic_connection_t *qc, + ngx_quic_socket_t *qsock) +{ + ngx_quic_bpf_group_t *grp; + + if (qsock->sid.len != NGX_QUIC_SERVER_CID_LEN) { + /* route by address */ + return NGX_OK; + } + + grp = ngx_quic_bpf_find_group((ngx_cycle_t *) ngx_cycle, c->listening); + if (grp == NULL) { + return NGX_OK; + } + + if (ngx_bpf_map_update(grp->worker_map, qsock->sid.id, &c->fd, BPF_ANY) + == -1) + { + ngx_log_error(NGX_LOG_EMERG, c->log, ngx_errno, + "failed to update QUIC BPF worker map"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_quic_bpf_delete(ngx_connection_t *c, ngx_quic_connection_t *qc, + ngx_quic_socket_t *qsock) +{ + ngx_quic_bpf_group_t *grp; + + if (qsock->sid.len != NGX_QUIC_SERVER_CID_LEN) { + /* route by address */ + return NGX_OK; + } + + grp = ngx_quic_bpf_find_group((ngx_cycle_t *) ngx_cycle, c->listening); + if (grp == NULL) { + return NGX_OK; + } + + if (ngx_bpf_map_delete(grp->worker_map, qsock->sid.id) == -1) { + ngx_log_error(NGX_LOG_EMERG, c->log, ngx_errno, + "failed to update QUIC BPF worker map"); + return NGX_ERROR; + } + + return NGX_OK; +} diff --git a/src/event/quic/ngx_event_quic_bpf.h b/src/event/quic/ngx_event_quic_bpf.h new file mode 100644 --- /dev/null +++ b/src/event/quic/ngx_event_quic_bpf.h @@ -0,0 +1,23 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_EVENT_QUIC_BPF_H_INCLUDED_ +#define _NGX_EVENT_QUIC_BPF_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +ngx_int_t ngx_quic_bpf_get_client_connection(ngx_connection_t *lc, + ngx_connection_t **pc); +ngx_int_t ngx_quic_bpf_insert(ngx_connection_t *c, ngx_quic_connection_t *qc, + ngx_quic_socket_t *qsock); +ngx_int_t ngx_quic_bpf_delete(ngx_connection_t *c, ngx_quic_connection_t *qc, + ngx_quic_socket_t *qsock); + + +#endif /* _NGX_EVENT_QUIC_BPF_H_INCLUDED_ */ diff --git a/src/event/quic/ngx_event_quic_bpf_code.c b/src/event/quic/ngx_event_quic_bpf_code.c --- a/src/event/quic/ngx_event_quic_bpf_code.c +++ b/src/event/quic/ngx_event_quic_bpf_code.c @@ -7,71 +7,146 @@ static ngx_bpf_reloc_t bpf_reloc_prog_ngx_quic_reuseport_helper[] = { - { "ngx_quic_sockmap", 55 }, + { "ngx_quic_worker", 82 }, + { "ngx_quic_nlisten", 99 }, + { "ngx_quic_listen", 110 }, + { "ngx_quic_nlisten", 127 }, }; static struct bpf_insn bpf_insn_prog_ngx_quic_reuseport_helper[] = { /* opcode dst src offset imm */ - { 0x79, BPF_REG_4, BPF_REG_1, (int16_t) 0, 0x0 }, - { 0x79, BPF_REG_3, BPF_REG_1, (int16_t) 8, 0x0 }, - { 0xbf, BPF_REG_2, BPF_REG_4, (int16_t) 0, 0x0 }, - { 0x7, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x8 }, - { 0x2d, BPF_REG_2, BPF_REG_3, (int16_t) 54, 0x0 }, - { 0xbf, BPF_REG_5, BPF_REG_4, (int16_t) 0, 0x0 }, - { 0x7, BPF_REG_5, BPF_REG_0, (int16_t) 0, 0x9 }, - { 0x2d, BPF_REG_5, BPF_REG_3, (int16_t) 51, 0x0 }, - { 0xb7, BPF_REG_5, BPF_REG_0, (int16_t) 0, 0x14 }, - { 0xb7, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x9 }, - { 0x71, BPF_REG_6, BPF_REG_2, (int16_t) 0, 0x0 }, - { 0x67, BPF_REG_6, BPF_REG_0, (int16_t) 0, 0x38 }, - { 0xc7, BPF_REG_6, BPF_REG_0, (int16_t) 0, 0x38 }, - { 0x65, BPF_REG_6, BPF_REG_0, (int16_t) 10, 0xffffffff }, - { 0xbf, BPF_REG_2, BPF_REG_4, (int16_t) 0, 0x0 }, - { 0x7, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0xd }, - { 0x2d, BPF_REG_2, BPF_REG_3, (int16_t) 42, 0x0 }, - { 0xbf, BPF_REG_5, BPF_REG_4, (int16_t) 0, 0x0 }, - { 0x7, BPF_REG_5, BPF_REG_0, (int16_t) 0, 0xe }, - { 0x2d, BPF_REG_5, BPF_REG_3, (int16_t) 39, 0x0 }, - { 0xb7, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0xe }, - { 0x71, BPF_REG_5, BPF_REG_2, (int16_t) 0, 0x0 }, - { 0xb7, BPF_REG_6, BPF_REG_0, (int16_t) 0, 0x8 }, - { 0x2d, BPF_REG_6, BPF_REG_5, (int16_t) 35, 0x0 }, - { 0xf, BPF_REG_5, BPF_REG_0, (int16_t) 0, 0x0 }, - { 0xf, BPF_REG_4, BPF_REG_5, (int16_t) 0, 0x0 }, - { 0x2d, BPF_REG_4, BPF_REG_3, (int16_t) 32, 0x0 }, - { 0xbf, BPF_REG_4, BPF_REG_2, (int16_t) 0, 0x0 }, - { 0x7, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x9 }, - { 0x2d, BPF_REG_4, BPF_REG_3, (int16_t) 29, 0x0 }, - { 0x71, BPF_REG_4, BPF_REG_2, (int16_t) 1, 0x0 }, + { 0xbf, BPF_REG_6, BPF_REG_1, (int16_t) 0, 0x0 }, + { 0xb7, BPF_REG_7, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x79, BPF_REG_2, BPF_REG_6, (int16_t) 8, 0x0 }, + { 0x79, BPF_REG_1, BPF_REG_6, (int16_t) 0, 0x0 }, + { 0xbf, BPF_REG_3, BPF_REG_1, (int16_t) 0, 0x0 }, + { 0x7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x9 }, + { 0x2d, BPF_REG_3, BPF_REG_2, (int16_t) 124, 0x0 }, + { 0xb7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x9 }, + { 0x71, BPF_REG_4, BPF_REG_1, (int16_t) 8, 0x0 }, { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x38 }, - { 0x71, BPF_REG_3, BPF_REG_2, (int16_t) 2, 0x0 }, - { 0x67, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x30 }, - { 0x4f, BPF_REG_3, BPF_REG_4, (int16_t) 0, 0x0 }, - { 0x71, BPF_REG_4, BPF_REG_2, (int16_t) 3, 0x0 }, - { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x28 }, - { 0x4f, BPF_REG_3, BPF_REG_4, (int16_t) 0, 0x0 }, - { 0x71, BPF_REG_4, BPF_REG_2, (int16_t) 4, 0x0 }, - { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x20 }, - { 0x4f, BPF_REG_3, BPF_REG_4, (int16_t) 0, 0x0 }, - { 0x71, BPF_REG_4, BPF_REG_2, (int16_t) 5, 0x0 }, - { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x18 }, + { 0xc7, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x38 }, + { 0x65, BPF_REG_4, BPF_REG_0, (int16_t) 6, 0xffffffff }, + { 0xbf, BPF_REG_3, BPF_REG_1, (int16_t) 0, 0x0 }, + { 0x7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0xe }, + { 0x2d, BPF_REG_3, BPF_REG_2, (int16_t) 116, 0x0 }, + { 0xb7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0xe }, + { 0x71, BPF_REG_4, BPF_REG_1, (int16_t) 13, 0x0 }, + { 0x55, BPF_REG_4, BPF_REG_0, (int16_t) 77, 0x14 }, + { 0xf, BPF_REG_1, BPF_REG_3, (int16_t) 0, 0x0 }, + { 0xbf, BPF_REG_3, BPF_REG_1, (int16_t) 0, 0x0 }, + { 0x7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x14 }, + { 0x2d, BPF_REG_3, BPF_REG_2, (int16_t) 109, 0x0 }, + { 0x71, BPF_REG_3, BPF_REG_1, (int16_t) 13, 0x0 }, + { 0x67, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x8 }, + { 0x71, BPF_REG_2, BPF_REG_1, (int16_t) 12, 0x0 }, + { 0x4f, BPF_REG_3, BPF_REG_2, (int16_t) 0, 0x0 }, + { 0x71, BPF_REG_2, BPF_REG_1, (int16_t) 15, 0x0 }, + { 0x67, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x8 }, + { 0x71, BPF_REG_4, BPF_REG_1, (int16_t) 14, 0x0 }, + { 0x4f, BPF_REG_2, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x71, BPF_REG_5, BPF_REG_1, (int16_t) 9, 0x0 }, + { 0x67, BPF_REG_5, BPF_REG_0, (int16_t) 0, 0x8 }, + { 0x71, BPF_REG_4, BPF_REG_1, (int16_t) 8, 0x0 }, + { 0x4f, BPF_REG_5, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x71, BPF_REG_4, BPF_REG_1, (int16_t) 11, 0x0 }, + { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x8 }, + { 0x71, BPF_REG_0, BPF_REG_1, (int16_t) 10, 0x0 }, + { 0x4f, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x10 }, + { 0x4f, BPF_REG_4, BPF_REG_5, (int16_t) 0, 0x0 }, + { 0x67, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x10 }, + { 0x4f, BPF_REG_2, BPF_REG_3, (int16_t) 0, 0x0 }, + { 0x71, BPF_REG_3, BPF_REG_1, (int16_t) 17, 0x0 }, + { 0x67, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x8 }, + { 0x71, BPF_REG_5, BPF_REG_1, (int16_t) 16, 0x0 }, + { 0x4f, BPF_REG_3, BPF_REG_5, (int16_t) 0, 0x0 }, + { 0x71, BPF_REG_5, BPF_REG_1, (int16_t) 19, 0x0 }, + { 0x67, BPF_REG_5, BPF_REG_0, (int16_t) 0, 0x8 }, + { 0x71, BPF_REG_0, BPF_REG_1, (int16_t) 18, 0x0 }, + { 0x4f, BPF_REG_5, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x67, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x20 }, + { 0x4f, BPF_REG_2, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x67, BPF_REG_5, BPF_REG_0, (int16_t) 0, 0x10 }, + { 0x4f, BPF_REG_5, BPF_REG_3, (int16_t) 0, 0x0 }, + { 0x71, BPF_REG_4, BPF_REG_1, (int16_t) 1, 0x0 }, + { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x8 }, + { 0x71, BPF_REG_3, BPF_REG_1, (int16_t) 0, 0x0 }, + { 0x4f, BPF_REG_4, BPF_REG_3, (int16_t) 0, 0x0 }, + { 0x71, BPF_REG_3, BPF_REG_1, (int16_t) 3, 0x0 }, + { 0x67, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x8 }, + { 0x71, BPF_REG_0, BPF_REG_1, (int16_t) 2, 0x0 }, + { 0x4f, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x63, BPF_REG_10, BPF_REG_5, (int16_t) 65520, 0x0 }, + { 0x7b, BPF_REG_10, BPF_REG_2, (int16_t) 65512, 0x0 }, + { 0x67, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x10 }, { 0x4f, BPF_REG_3, BPF_REG_4, (int16_t) 0, 0x0 }, - { 0x71, BPF_REG_4, BPF_REG_2, (int16_t) 6, 0x0 }, - { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x10 }, - { 0x4f, BPF_REG_3, BPF_REG_4, (int16_t) 0, 0x0 }, - { 0x71, BPF_REG_4, BPF_REG_2, (int16_t) 7, 0x0 }, - { 0x67, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x8 }, - { 0x4f, BPF_REG_3, BPF_REG_4, (int16_t) 0, 0x0 }, - { 0x71, BPF_REG_2, BPF_REG_2, (int16_t) 8, 0x0 }, - { 0x4f, BPF_REG_3, BPF_REG_2, (int16_t) 0, 0x0 }, - { 0x7b, BPF_REG_10, BPF_REG_3, (int16_t) 65528, 0x0 }, + { 0x71, BPF_REG_2, BPF_REG_1, (int16_t) 5, 0x0 }, + { 0x67, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x8 }, + { 0x71, BPF_REG_4, BPF_REG_1, (int16_t) 4, 0x0 }, + { 0x4f, BPF_REG_2, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x71, BPF_REG_4, BPF_REG_1, (int16_t) 6, 0x0 }, + { 0x71, BPF_REG_1, BPF_REG_1, (int16_t) 7, 0x0 }, + { 0x67, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x8 }, + { 0x4f, BPF_REG_1, BPF_REG_4, (int16_t) 0, 0x0 }, + { 0x67, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x10 }, + { 0x4f, BPF_REG_1, BPF_REG_2, (int16_t) 0, 0x0 }, + { 0x67, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x20 }, + { 0x4f, BPF_REG_1, BPF_REG_3, (int16_t) 0, 0x0 }, + { 0x7b, BPF_REG_10, BPF_REG_1, (int16_t) 65504, 0x0 }, { 0xbf, BPF_REG_3, BPF_REG_10, (int16_t) 0, 0x0 }, - { 0x7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0xfffffff8 }, + { 0x7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0xffffffe0 }, + { 0xbf, BPF_REG_1, BPF_REG_6, (int16_t) 0, 0x0 }, { 0x18, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x0 }, { 0x0, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x0 }, { 0xb7, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x0 }, { 0x85, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x52 }, - { 0xb7, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x1 }, + { 0xb7, BPF_REG_7, BPF_REG_0, (int16_t) 0, 0x1 }, + { 0x67, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x20 }, + { 0x77, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x20 }, + { 0x15, BPF_REG_0, BPF_REG_0, (int16_t) 41, 0x0 }, + { 0x18, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0xfffffffe }, + { 0x0, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x1d, BPF_REG_0, BPF_REG_1, (int16_t) 2, 0x0 }, + { 0xb7, BPF_REG_7, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x5, BPF_REG_0, BPF_REG_0, (int16_t) 36, 0x0 }, + { 0xb7, BPF_REG_7, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x63, BPF_REG_10, BPF_REG_7, (int16_t) 65532, 0x0 }, + { 0xbf, BPF_REG_2, BPF_REG_10, (int16_t) 0, 0x0 }, + { 0x7, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0xfffffffc }, + { 0x18, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x0, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x85, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x1 }, + { 0x15, BPF_REG_0, BPF_REG_0, (int16_t) 28, 0x0 }, + { 0x61, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x61, BPF_REG_2, BPF_REG_6, (int16_t) 32, 0x0 }, + { 0x9f, BPF_REG_2, BPF_REG_1, (int16_t) 0, 0x0 }, + { 0x63, BPF_REG_10, BPF_REG_2, (int16_t) 65528, 0x0 }, + { 0xbf, BPF_REG_3, BPF_REG_10, (int16_t) 0, 0x0 }, + { 0x7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0xfffffff8 }, + { 0xbf, BPF_REG_1, BPF_REG_6, (int16_t) 0, 0x0 }, + { 0x18, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x0, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0xb7, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x85, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x52 }, + { 0xb7, BPF_REG_7, BPF_REG_0, (int16_t) 0, 0x1 }, + { 0x67, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x20 }, + { 0x77, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x20 }, + { 0x15, BPF_REG_0, BPF_REG_0, (int16_t) 13, 0x0 }, + { 0x18, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0xfffffffe }, + { 0x0, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x1d, BPF_REG_0, BPF_REG_1, (int16_t) 1, 0x0 }, + { 0x5, BPF_REG_0, BPF_REG_0, (int16_t) 65507, 0x0 }, + { 0xbf, BPF_REG_2, BPF_REG_10, (int16_t) 0, 0x0 }, + { 0x7, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0xfffffffc }, + { 0xbf, BPF_REG_3, BPF_REG_10, (int16_t) 0, 0x0 }, + { 0x7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0xfffffff8 }, + { 0xb7, BPF_REG_7, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x18, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x0, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0xb7, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x0 }, + { 0x85, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x2 }, + { 0xbf, BPF_REG_0, BPF_REG_7, (int16_t) 0, 0x0 }, { 0x95, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x0 }, }; @@ -86,3 +161,4 @@ ngx_bpf_program_t ngx_quic_reuseport_hel .license = "BSD", .type = BPF_PROG_TYPE_SK_REUSEPORT, }; + diff --git a/src/event/quic/ngx_event_quic_connection.h b/src/event/quic/ngx_event_quic_connection.h --- a/src/event/quic/ngx_event_quic_connection.h +++ b/src/event/quic/ngx_event_quic_connection.h @@ -36,6 +36,9 @@ typedef struct ngx_quic_keys_s ng #include <ngx_event_quic_ack.h> #include <ngx_event_quic_output.h> #include <ngx_event_quic_socket.h> +#if (NGX_QUIC_BPF) +#include <ngx_event_quic_bpf.h> +#endif /* RFC 9002, 6.2.2. Handshakes and New Paths: kInitialRtt */ @@ -45,6 +48,8 @@ typedef struct ngx_quic_keys_s ng #define NGX_QUIC_SEND_CTX_LAST (NGX_QUIC_ENCRYPTION_LAST - 1) +#define NGX_QUIC_MAX_SERVER_IDS 8 + /* 0-RTT and 1-RTT data exist in the same packet number space, * so we have 3 packet number spaces: * @@ -257,6 +262,7 @@ struct ngx_quic_connection_s { unsigned key_phase:1; unsigned validated:1; unsigned client_tp_done:1; + unsigned listen_bound:1; }; diff --git a/src/event/quic/ngx_event_quic_connid.c b/src/event/quic/ngx_event_quic_connid.c --- a/src/event/quic/ngx_event_quic_connid.c +++ b/src/event/quic/ngx_event_quic_connid.c @@ -9,12 +9,7 @@ #include <ngx_event.h> #include <ngx_event_quic_connection.h> -#define NGX_QUIC_MAX_SERVER_IDS 8 - -#if (NGX_QUIC_BPF) -static ngx_int_t ngx_quic_bpf_attach_id(ngx_connection_t *c, u_char *id); -#endif static ngx_int_t ngx_quic_retire_client_id(ngx_connection_t *c, ngx_quic_client_id_t *cid); static ngx_quic_client_id_t *ngx_quic_alloc_client_id(ngx_connection_t *c, @@ -30,46 +25,10 @@ ngx_quic_create_server_id(ngx_connection return NGX_ERROR; } -#if (NGX_QUIC_BPF) - if (ngx_quic_bpf_attach_id(c, id) != NGX_OK) { - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "quic bpf failed to generate socket key"); - /* ignore error, things still may work */ - } -#endif - return NGX_OK; } -#if (NGX_QUIC_BPF) - -static ngx_int_t -ngx_quic_bpf_attach_id(ngx_connection_t *c, u_char *id) -{ - int fd; - uint64_t cookie; - socklen_t optlen; - - fd = c->listening->fd; - - optlen = sizeof(cookie); - - if (getsockopt(fd, SOL_SOCKET, SO_COOKIE, &cookie, &optlen) == -1) { - ngx_log_error(NGX_LOG_ERR, c->log, ngx_socket_errno, - "quic getsockopt(SO_COOKIE) failed"); - - return NGX_ERROR; - } - - ngx_quic_dcid_encode_key(id, cookie); - - return NGX_OK; -} - -#endif - - ngx_int_t ngx_quic_handle_new_connection_id_frame(ngx_connection_t *c, ngx_quic_new_conn_id_frame_t *f) diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c --- a/src/event/quic/ngx_event_quic_output.c +++ b/src/event/quic/ngx_event_quic_output.c @@ -84,6 +84,10 @@ ngx_quic_output(ngx_connection_t *c) ngx_quic_congestion_t *cg; ngx_quic_connection_t *qc; + if (c->fd == (ngx_socket_t) -1) { + return NGX_ERROR; + } + c->log->action = "sending frames"; qc = ngx_quic_get_connection(c); @@ -1031,7 +1035,6 @@ ngx_quic_send_retry(ngx_connection_t *c, pkt.odcid = inpkt->dcid; pkt.dcid = inpkt->scid; - /* TODO: generate routable dcid */ if (RAND_bytes(dcid, NGX_QUIC_SERVER_CID_LEN) != 1) { return NGX_ERROR; } diff --git a/src/event/quic/ngx_event_quic_socket.c b/src/event/quic/ngx_event_quic_socket.c --- a/src/event/quic/ngx_event_quic_socket.c +++ b/src/event/quic/ngx_event_quic_socket.c @@ -109,6 +109,13 @@ ngx_quic_open_sockets(ngx_connection_t * failed: ngx_rbtree_delete(&c->listening->rbtree, &qsock->udp.node); + +#if (NGX_QUIC_BPF) + if (ngx_quic_bpf_delete(c, qc, qsock) != NGX_OK) { + return NGX_ERROR; + } +#endif + c->udp = NULL; return NGX_ERROR; @@ -160,6 +167,13 @@ ngx_quic_close_socket(ngx_connection_t * ngx_queue_insert_head(&qc->free_sockets, &qsock->queue); ngx_rbtree_delete(&c->listening->rbtree, &qsock->udp.node); + +#if (NGX_QUIC_BPF) + if (ngx_quic_bpf_delete(c, qc, qsock) != NGX_OK) { + return; + } +#endif + qc->nsockets--; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, @@ -185,6 +199,12 @@ ngx_quic_listen(ngx_connection_t *c, ngx ngx_rbtree_insert(&c->listening->rbtree, &qsock->udp.node); +#if (NGX_QUIC_BPF) + if (ngx_quic_bpf_insert(c, qc, qsock) != NGX_OK) { + return NGX_ERROR; + } +#endif + ngx_queue_insert_tail(&qc->sockets, &qsock->queue); qc->nsockets++; diff --git a/src/event/quic/ngx_event_quic_udp.c b/src/event/quic/ngx_event_quic_udp.c --- a/src/event/quic/ngx_event_quic_udp.c +++ b/src/event/quic/ngx_event_quic_udp.c @@ -160,7 +160,7 @@ ngx_quic_recvmsg(ngx_event_t *ev) c->log->handler = NULL; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic recvmsg: fd:%d n:%z", c->fd, n); + "quic recvmsg: fd:%d n:%z", lc->fd, n); c->log->handler = handler; } @@ -193,12 +193,23 @@ ngx_quic_recvmsg(ngx_event_t *ev) ngx_accept_disabled = ngx_cycle->connection_n / 8 - ngx_cycle->free_connection_n; - c = ngx_get_connection(lc->fd, ev->log); - if (c == NULL) { + c = NULL; + +#if (NGX_QUIC_BPF) + if (ngx_quic_bpf_get_client_connection(lc, &c) != NGX_OK) { return; } +#endif - c->shared = 1; + if (c == NULL) { + c = ngx_get_connection(lc->fd, ev->log); + if (c == NULL) { + return; + } + + c->shared = 1; + } + c->type = SOCK_DGRAM; c->socklen = socklen; @@ -309,7 +320,7 @@ ngx_quic_recvmsg(ngx_event_t *ev) ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0, "*%uA quic recvmsg: %V fd:%d n:%z", - c->number, &addr, c->fd, n); + c->number, &addr, lc->fd, n); } } diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -964,7 +964,8 @@ ngx_worker_process_exit(ngx_cycle_t *cyc && c[i].read && !c[i].read->accept && !c[i].read->channel - && !c[i].read->resolver) + && !c[i].read->resolver + && !c[i].read->quic) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "*%uA open socket #%d left in connection %ui", _______________________________________________ nginx-devel mailing list -- nginx-devel@nginx.org To unsubscribe send an email to nginx-devel-le...@nginx.org