QUIC: support BPF reload and binary upgrade
Some checks are pending
buildbot / buildbot (push) Waiting to run

The SO_COOKIE dependency is removed.  QUIC BPF dispatching now uses
separate sockets for new and established connections: listener sockets
handle new connections, while per-worker sockets handle established
ones.  Server connection IDs encode a random worker key, which BPF
uses to route established packets directly to the correct worker
socket.  New connections are routed through listen keys using a
dual slot scheme that enables both reload and binary upgrade.

On reload, new workers register new sockets and keys while old workers
continue receiving established connections through their encoded keys.
On binary upgrade, the new master uses the opposite slot, and exiting
masters clear their entries so traffic shifts to the surviving
instance.

Co-authored-by: Roman Arutyunyan <arut@nginx.com>
This commit is contained in:
Sai Krishna Kumar Reddy YADAMAKANTI 2026-09-29 15:07:24 +00:00 • committed by Roman Arutyunyan
parent ce6e7d6c12
commit 63af971a1e
17 changed files with 1079 additions and 283 deletions

View file

@ -1455,11 +1455,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=

View file

@ -178,8 +178,6 @@ USE_GEOIP=NO
NGX_GOOGLE_PERFTOOLS=NO
NGX_CPP_TEST=NO
SO_COOKIE_FOUND=NO
NGX_LIBATOMIC=NO
NGX_CPU_CACHE_LINE=

View file

@ -249,7 +249,10 @@ ngx_feature_test="union bpf_attr attr = { 0 };
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_ARRAY;
syscall(__NR_bpf, 0, &attr, 0);"
. auto/feature
@ -263,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>
$NGX_INCLUDE_INTTYPES_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"

View file

@ -7,7 +7,7 @@
#include <ngx_config.h>
#include <ngx_core.h>
#define NGX_BPF_LOGBUF_SIZE (16 * 1024)
#define NGX_BPF_LOGBUF_SIZE (32 * 1024)
static ngx_inline int

View file

@ -1142,7 +1142,9 @@ ngx_close_listening_sockets(ngx_cycle_t *cycle)
for (i = 0; i < cycle->listening.nelts; i++) {
#if (NGX_QUIC)
if (ls[i].quic) {
if (ls[i].quic
&& (!ls[i].reuseport || !ngx_quic_bpf_enabled(cycle)))
{
continue;
}
#endif

View file

@ -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;

View file

@ -1,4 +1,7 @@
CFLAGS=-O2 -Wall
# Copyright (C) Nginx, Inc.
CFLAGS=-O2 -Wall $(MAKE_CFLAGS)
LICENSE=BSD

View file

@ -54,17 +54,23 @@ char _license[] SEC("license") = LICENSE;
((__u64)(p)[6] << 8) | \
((__u64)(p)[7]))
#define ngx_quic_bpf_listen_key(worker) \
(((__u64) 0xFF << 56) | ((__u64) (worker) & 0xFFFFFFFFFFFFULL))
/*
* actual map object is created by the "bpf" system call,
* all pointers to this variable are replaced by the bpf loader
*/
extern int ngx_quic_sockmap;
struct {} ngx_quic_sockmap SEC(".maps");
struct {} ngx_quic_worker_counts SEC(".maps");
SEC(PROGNAME)
int ngx_quic_select_socket_by_dcid(struct sk_reuseport_md *ctx)
{
int rc;
int rc, worker_idx;
__u32 wc_key, *wc0, *wc1, n, m;
__u64 key;
size_t offset;
unsigned char *start, *end, *dcid, byte, buf[NGX_QUIC_SERVER_CID_LEN];
@ -98,7 +104,7 @@ int ngx_quic_select_socket_by_dcid(struct sk_reuseport_md *ctx)
}
if (byte != NGX_QUIC_SERVER_CID_LEN) {
return SK_PASS;
goto new;
}
}
@ -118,30 +124,84 @@ int ngx_quic_select_socket_by_dcid(struct sk_reuseport_md *ctx)
key = ngx_quic_parse_uint64(dcid);
rc = bpf_sk_select_reuseport(ctx, &ngx_quic_sockmap, &key, 0);
switch (rc) {
case 0:
debugmsg("nginx quic socket selected by key 0x%llx", key);
return SK_PASS;
/* 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 */
return SK_PASS;
default:
debugmsg("nginx quic bpf_sk_select_reuseport err: %d key 0x%llx",
rc, key);
goto failed;
if ((key >> 56) == 0xFF) {
goto new;
}
rc = bpf_sk_select_reuseport(ctx, &ngx_quic_sockmap, &key, 0);
if (rc == 0) {
debugmsg("nginx quic worker socket selected by dcid");
return SK_PASS;
}
if (rc != -ENOENT) {
debugmsg("nginx quic bpf_sk_select_reuseport() failed: %d", rc);
return SK_DROP;
}
new:
wc_key = 0;
wc0 = bpf_map_lookup_elem(&ngx_quic_worker_counts, &wc_key);
if (wc0 == NULL) {
debugmsg("nginx quic worker count 0 undefined");
return SK_DROP;
}
wc_key = 1;
wc1 = bpf_map_lookup_elem(&ngx_quic_worker_counts, &wc_key);
if (wc1 == NULL) {
debugmsg("nginx quic worker count 1 undefined");
return SK_DROP;
}
n = *wc0 > *wc1 ? *wc0 : *wc1;
if (n == 0) {
debugmsg("nginx quic no active workers");
return SK_DROP;
}
worker_idx = ctx->hash % n;
key = ngx_quic_bpf_listen_key(worker_idx);
rc = bpf_sk_select_reuseport(ctx, &ngx_quic_sockmap, &key, 0);
if (rc == 0) {
debugmsg("nginx quic listener socket selected worker index:%d",
worker_idx);
return SK_PASS;
}
if (rc != -ENOENT) {
debugmsg("nginx quic bpf_sk_select_reuseport() failed: %d", rc);
return SK_DROP;
}
m = *wc0 < *wc1 ? *wc0 : *wc1;
if (m && m != n) {
worker_idx = ctx->hash % m;
key = ngx_quic_bpf_listen_key(worker_idx);
rc = bpf_sk_select_reuseport(ctx, &ngx_quic_sockmap, &key, 0);
if (rc == 0) {
debugmsg("nginx quic listener socket selected "
"worker index:%d (fallback)", worker_idx);
return SK_PASS;
}
debugmsg("nginx quic bpf_sk_select_reuseport() fallback "
"failed: %d", rc);
}
return SK_DROP;
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;
debugmsg("nginx quic bad datagram");
return SK_DROP;
}

View file

@ -142,4 +142,10 @@ ngx_int_t ngx_quic_get_packet_dcid(ngx_log_t *log, u_char *data, size_t len,
ngx_int_t ngx_quic_derive_key(ngx_log_t *log, const char *label,
ngx_str_t *secret, ngx_str_t *salt, u_char *out, size_t len);
#if (NGX_QUIC_BPF)
ngx_uint_t ngx_quic_bpf_enabled(ngx_cycle_t *cycle);
#else
#define ngx_quic_bpf_enabled(c) 0
#endif
#endif /* _NGX_EVENT_QUIC_H_INCLUDED_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,20 @@
/*
* 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_worker_fd(ngx_connection_t *lc,
ngx_socket_t *fd);
ngx_int_t ngx_quic_bpf_get_worker_key(ngx_connection_t *c, uint64_t *key);
#endif /* _NGX_EVENT_QUIC_BPF_H_INCLUDED_ */

View file

@ -7,93 +7,194 @@
static ngx_bpf_reloc_t bpf_reloc_prog_ngx_quic_reuseport_helper[] = {
{ "ngx_quic_sockmap", 77 },
{ "ngx_quic_sockmap", 81 },
{ "ngx_quic_worker_counts", 97 },
{ "ngx_quic_worker_counts", 106 },
{ "ngx_quic_sockmap", 133 },
{ "ngx_quic_sockmap", 170 },
};
static struct bpf_insn bpf_insn_prog_ngx_quic_reuseport_helper[] = {
/* opcode dst src offset imm */
{ 0xbf, BPF_REG_6, BPF_REG_1, (int16_t) 0, 0x0 },
{ 0x79, BPF_REG_8, BPF_REG_6, (int16_t) 8, 0x0 },
{ 0x79, BPF_REG_7, BPF_REG_6, (int16_t) 0, 0x0 },
{ 0xbf, BPF_REG_1, BPF_REG_7, (int16_t) 0, 0x0 },
{ 0x79, BPF_REG_9, BPF_REG_6, (int16_t) 8, 0x0 },
{ 0x79, BPF_REG_8, BPF_REG_6, (int16_t) 0, 0x0 },
{ 0xbf, BPF_REG_1, BPF_REG_8, (int16_t) 0, 0x0 },
{ 0x7, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x8 },
{ 0x2d, BPF_REG_8, BPF_REG_1, (int16_t) 10, 0x0 },
{ 0x2d, BPF_REG_9, BPF_REG_1, (int16_t) 11, 0x0 },
{ 0xbf, BPF_REG_3, BPF_REG_10, (int16_t) 0, 0x0 },
{ 0x7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0xfffffff7 },
{ 0x7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0xffffffef },
{ 0xbf, BPF_REG_1, BPF_REG_6, (int16_t) 0, 0x0 },
{ 0xb7, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x8 },
{ 0xb7, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x1 },
{ 0x85, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x1a },
{ 0xb7, BPF_REG_7, BPF_REG_0, (int16_t) 0, 0x0 },
{ 0x15, BPF_REG_0, BPF_REG_0, (int16_t) 1, 0x0 },
{ 0x5, BPF_REG_0, BPF_REG_0, (int16_t) 67, 0x0 },
{ 0x71, BPF_REG_1, BPF_REG_10, (int16_t) 65527, 0x0 },
{ 0x5, BPF_REG_0, BPF_REG_0, (int16_t) 163, 0x0 },
{ 0x71, BPF_REG_1, BPF_REG_10, (int16_t) 65519, 0x0 },
{ 0x5, BPF_REG_0, BPF_REG_0, (int16_t) 2, 0x0 },
{ 0x71, BPF_REG_1, BPF_REG_1, (int16_t) 0, 0x0 },
{ 0x73, BPF_REG_10, BPF_REG_1, (int16_t) 65527, 0x0 },
{ 0x73, BPF_REG_10, BPF_REG_1, (int16_t) 65519, 0x0 },
{ 0xb7, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x9 },
{ 0x67, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x38 },
{ 0xc7, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x38 },
{ 0x65, BPF_REG_1, BPF_REG_0, (int16_t) 18, 0xffffffff },
{ 0xbf, BPF_REG_1, BPF_REG_7, (int16_t) 0, 0x0 },
{ 0xbf, BPF_REG_1, BPF_REG_8, (int16_t) 0, 0x0 },
{ 0x7, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0xd },
{ 0x2d, BPF_REG_8, BPF_REG_1, (int16_t) 11, 0x0 },
{ 0x2d, BPF_REG_9, BPF_REG_1, (int16_t) 11, 0x0 },
{ 0xbf, BPF_REG_3, BPF_REG_10, (int16_t) 0, 0x0 },
{ 0x7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0xfffffff7 },
{ 0x7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0xffffffef },
{ 0xbf, BPF_REG_1, BPF_REG_6, (int16_t) 0, 0x0 },
{ 0xb7, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0xd },
{ 0xb7, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x1 },
{ 0x85, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x1a },
{ 0x55, BPF_REG_0, BPF_REG_0, (int16_t) 49, 0x0 },
{ 0xb7, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0xe },
{ 0x71, BPF_REG_1, BPF_REG_10, (int16_t) 65527, 0x0 },
{ 0x15, BPF_REG_1, BPF_REG_0, (int16_t) 5, 0x14 },
{ 0x5, BPF_REG_0, BPF_REG_0, (int16_t) 45, 0x0 },
{ 0xb7, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0xe },
{ 0xb7, BPF_REG_7, BPF_REG_0, (int16_t) 0, 0x0 },
{ 0x15, BPF_REG_0, BPF_REG_0, (int16_t) 1, 0x0 },
{ 0x5, BPF_REG_0, BPF_REG_0, (int16_t) 143, 0x0 },
{ 0x71, BPF_REG_1, BPF_REG_10, (int16_t) 65519, 0x0 },
{ 0x5, BPF_REG_0, BPF_REG_0, (int16_t) 2, 0x0 },
{ 0x71, BPF_REG_1, BPF_REG_1, (int16_t) 0, 0x0 },
{ 0x73, BPF_REG_10, BPF_REG_1, (int16_t) 65527, 0x0 },
{ 0x55, BPF_REG_1, BPF_REG_0, (int16_t) 41, 0x14 },
{ 0xf, BPF_REG_7, BPF_REG_2, (int16_t) 0, 0x0 },
{ 0xbf, BPF_REG_1, BPF_REG_7, (int16_t) 0, 0x0 },
{ 0x73, BPF_REG_10, BPF_REG_1, (int16_t) 65519, 0x0 },
{ 0xb7, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0xe },
{ 0x55, BPF_REG_1, BPF_REG_0, (int16_t) 52, 0x14 },
{ 0xf, BPF_REG_8, BPF_REG_2, (int16_t) 0, 0x0 },
{ 0xbf, BPF_REG_1, BPF_REG_8, (int16_t) 0, 0x0 },
{ 0x7, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x14 },
{ 0x3d, BPF_REG_8, BPF_REG_1, (int16_t) 7, 0x0 },
{ 0xbf, BPF_REG_7, BPF_REG_10, (int16_t) 0, 0x0 },
{ 0x7, BPF_REG_7, BPF_REG_0, (int16_t) 0, 0xffffffe3 },
{ 0x3d, BPF_REG_9, BPF_REG_1, (int16_t) 8, 0x0 },
{ 0xbf, BPF_REG_8, BPF_REG_10, (int16_t) 0, 0x0 },
{ 0x7, BPF_REG_8, BPF_REG_0, (int16_t) 0, 0xffffffdb },
{ 0xbf, BPF_REG_1, BPF_REG_6, (int16_t) 0, 0x0 },
{ 0xbf, BPF_REG_3, BPF_REG_7, (int16_t) 0, 0x0 },
{ 0xbf, BPF_REG_3, BPF_REG_8, (int16_t) 0, 0x0 },
{ 0xb7, BPF_REG_4, BPF_REG_0, (int16_t) 0, 0x14 },
{ 0x85, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x1a },
{ 0x55, BPF_REG_0, BPF_REG_0, (int16_t) 30, 0x0 },
{ 0x71, BPF_REG_2, BPF_REG_7, (int16_t) 0, 0x0 },
{ 0x67, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x38 },
{ 0x71, BPF_REG_1, BPF_REG_7, (int16_t) 1, 0x0 },
{ 0xb7, BPF_REG_7, BPF_REG_0, (int16_t) 0, 0x0 },
{ 0x55, BPF_REG_0, BPF_REG_0, (int16_t) 125, 0x0 },
{ 0x71, BPF_REG_1, BPF_REG_8, (int16_t) 1, 0x0 },
{ 0x67, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x30 },
{ 0x4f, BPF_REG_1, BPF_REG_2, (int16_t) 0, 0x0 },
{ 0x71, BPF_REG_2, BPF_REG_7, (int16_t) 2, 0x0 },
{ 0x67, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x28 },
{ 0x4f, BPF_REG_1, BPF_REG_2, (int16_t) 0, 0x0 },
{ 0x71, BPF_REG_2, BPF_REG_7, (int16_t) 3, 0x0 },
{ 0x67, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x20 },
{ 0x4f, BPF_REG_1, BPF_REG_2, (int16_t) 0, 0x0 },
{ 0x71, BPF_REG_2, BPF_REG_7, (int16_t) 4, 0x0 },
{ 0x67, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x18 },
{ 0x4f, BPF_REG_1, BPF_REG_2, (int16_t) 0, 0x0 },
{ 0x71, BPF_REG_2, BPF_REG_7, (int16_t) 5, 0x0 },
{ 0x67, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x10 },
{ 0x4f, BPF_REG_1, BPF_REG_2, (int16_t) 0, 0x0 },
{ 0x71, BPF_REG_2, BPF_REG_7, (int16_t) 6, 0x0 },
{ 0x67, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x8 },
{ 0x4f, BPF_REG_1, BPF_REG_2, (int16_t) 0, 0x0 },
{ 0x71, BPF_REG_2, BPF_REG_7, (int16_t) 7, 0x0 },
{ 0x4f, BPF_REG_1, BPF_REG_2, (int16_t) 0, 0x0 },
{ 0x7b, BPF_REG_10, BPF_REG_1, (int16_t) 65528, 0x0 },
{ 0x71, BPF_REG_2, BPF_REG_8, (int16_t) 0, 0x0 },
{ 0xbf, BPF_REG_3, BPF_REG_2, (int16_t) 0, 0x0 },
{ 0x67, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x38 },
{ 0x4f, BPF_REG_1, BPF_REG_3, (int16_t) 0, 0x0 },
{ 0x71, BPF_REG_3, BPF_REG_8, (int16_t) 2, 0x0 },
{ 0x67, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x28 },
{ 0x4f, BPF_REG_1, BPF_REG_3, (int16_t) 0, 0x0 },
{ 0x71, BPF_REG_3, BPF_REG_8, (int16_t) 3, 0x0 },
{ 0x67, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x20 },
{ 0x4f, BPF_REG_1, BPF_REG_3, (int16_t) 0, 0x0 },
{ 0x71, BPF_REG_3, BPF_REG_8, (int16_t) 4, 0x0 },
{ 0x67, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x18 },
{ 0x4f, BPF_REG_1, BPF_REG_3, (int16_t) 0, 0x0 },
{ 0x71, BPF_REG_3, BPF_REG_8, (int16_t) 5, 0x0 },
{ 0x67, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x10 },
{ 0x4f, BPF_REG_1, BPF_REG_3, (int16_t) 0, 0x0 },
{ 0x71, BPF_REG_3, BPF_REG_8, (int16_t) 7, 0x0 },
{ 0x4f, BPF_REG_1, BPF_REG_3, (int16_t) 0, 0x0 },
{ 0x71, BPF_REG_3, BPF_REG_8, (int16_t) 6, 0x0 },
{ 0x67, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0x8 },
{ 0x4f, BPF_REG_1, BPF_REG_3, (int16_t) 0, 0x0 },
{ 0x7b, BPF_REG_10, BPF_REG_1, (int16_t) 65520, 0x0 },
{ 0x15, BPF_REG_2, BPF_REG_0, (int16_t) 15, 0xff },
{ 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, 0xfffffff0 },
{ 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) 89, 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) 84, 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 },
{ 0xbf, BPF_REG_8, BPF_REG_0, (int16_t) 0, 0x0 },
{ 0x15, BPF_REG_8, BPF_REG_0, (int16_t) 76, 0x0 },
{ 0xb7, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x1 },
{ 0x63, BPF_REG_10, BPF_REG_1, (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) 68, 0x0 },
{ 0x61, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x0 },
{ 0x61, BPF_REG_9, BPF_REG_8, (int16_t) 0, 0x0 },
{ 0x2d, BPF_REG_9, BPF_REG_1, (int16_t) 1, 0x0 },
{ 0xbf, BPF_REG_9, BPF_REG_1, (int16_t) 0, 0x0 },
{ 0x15, BPF_REG_9, BPF_REG_0, (int16_t) 63, 0x0 },
{ 0xbf, BPF_REG_1, BPF_REG_9, (int16_t) 0, 0x0 },
{ 0x67, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x20 },
{ 0x77, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x20 },
{ 0xbf, BPF_REG_7, 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 },
{ 0x67, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x20 },
{ 0xc7, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x20 },
{ 0x18, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0xffffffff },
{ 0x0, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0xffff },
{ 0x5f, BPF_REG_2, BPF_REG_1, (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, 0xff000000 },
{ 0x4f, BPF_REG_2, BPF_REG_1, (int16_t) 0, 0x0 },
{ 0x7b, BPF_REG_10, BPF_REG_2, (int16_t) 65520, 0x0 },
{ 0xbf, BPF_REG_3, BPF_REG_10, (int16_t) 0, 0x0 },
{ 0x7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0xfffffff0 },
{ 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 },
{ 0xbf, BPF_REG_2, BPF_REG_7, (int16_t) 0, 0x0 },
{ 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) 36, 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) 31, 0x0 },
{ 0x61, BPF_REG_1, BPF_REG_8, (int16_t) 0, 0x0 },
{ 0x61, BPF_REG_2, BPF_REG_2, (int16_t) 0, 0x0 },
{ 0x2d, BPF_REG_2, BPF_REG_1, (int16_t) 1, 0x0 },
{ 0xbf, BPF_REG_1, BPF_REG_2, (int16_t) 0, 0x0 },
{ 0x15, BPF_REG_1, BPF_REG_0, (int16_t) 26, 0x0 },
{ 0x67, BPF_REG_9, BPF_REG_0, (int16_t) 0, 0x20 },
{ 0x77, BPF_REG_9, BPF_REG_0, (int16_t) 0, 0x20 },
{ 0x67, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x20 },
{ 0x77, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0x20 },
{ 0x1d, BPF_REG_1, BPF_REG_9, (int16_t) 21, 0x0 },
{ 0x61, BPF_REG_2, BPF_REG_6, (int16_t) 32, 0x0 },
{ 0x9f, BPF_REG_2, BPF_REG_1, (int16_t) 0, 0x0 },
{ 0x67, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x20 },
{ 0xc7, BPF_REG_2, BPF_REG_0, (int16_t) 0, 0x20 },
{ 0x18, BPF_REG_1, BPF_REG_0, (int16_t) 0, 0xffffffff },
{ 0x0, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0xffff },
{ 0x5f, BPF_REG_2, BPF_REG_1, (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, 0xff000000 },
{ 0x4f, BPF_REG_2, BPF_REG_1, (int16_t) 0, 0x0 },
{ 0x7b, BPF_REG_10, BPF_REG_2, (int16_t) 65520, 0x0 },
{ 0xbf, BPF_REG_3, BPF_REG_10, (int16_t) 0, 0x0 },
{ 0x7, BPF_REG_3, BPF_REG_0, (int16_t) 0, 0xfffffff0 },
{ 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 },
{ 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) 1, 0x0 },
{ 0xb7, BPF_REG_7, BPF_REG_0, (int16_t) 0, 0x0 },
{ 0xbf, BPF_REG_0, BPF_REG_7, (int16_t) 0, 0x0 },
{ 0x95, BPF_REG_0, BPF_REG_0, (int16_t) 0, 0x0 },
};

View file

@ -48,6 +48,9 @@ typedef struct ngx_quic_keys_s ngx_quic_keys_t;
#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 */

View file

@ -34,7 +34,7 @@ ngx_quic_create_server_id(ngx_connection_t *c, u_char *id)
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 */
return NGX_ERROR;
}
#endif
@ -47,22 +47,21 @@ ngx_quic_create_server_id(ngx_connection_t *c, u_char *id)
static ngx_int_t
ngx_quic_bpf_attach_id(ngx_connection_t *c, u_char *id)
{
int fd;
uint64_t cookie;
socklen_t optlen;
uint64_t key;
ngx_int_t rc;
fd = c->listening->fd;
rc = ngx_quic_bpf_get_worker_key(c, &key);
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");
if (rc == NGX_DECLINED) {
/* BPF not applicable for this listener, leave DCID as random */
return NGX_OK;
}
if (rc != NGX_OK) {
return NGX_ERROR;
}
ngx_quic_dcid_encode_key(id, cookie);
ngx_quic_dcid_encode_key(id, key);
return NGX_OK;
}

View file

@ -1085,7 +1085,6 @@ ngx_quic_send_retry(ngx_connection_t *c, ngx_quic_conf_t *conf,
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;
}

View file

@ -26,6 +26,7 @@ ngx_quic_recvmsg(ngx_event_t *ev)
ngx_err_t err;
socklen_t socklen, local_socklen;
ngx_event_t *rev, *wev;
ngx_socket_t cfd;
struct iovec iov[1];
struct msghdr msg;
ngx_sockaddr_t sa, lsa;
@ -168,7 +169,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;
}
@ -204,6 +205,14 @@ ngx_quic_recvmsg(ngx_event_t *ev)
goto next;
}
#if (NGX_QUIC_BPF)
if (lc->read->quic) {
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
"quic new connection on worker socket, dropped");
goto next;
}
#endif
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_accepted, 1);
#endif
@ -211,7 +220,15 @@ 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);
cfd = lc->fd;
#if (NGX_QUIC_BPF)
if (ngx_quic_bpf_get_worker_fd(lc, &cfd) != NGX_OK) {
return;
}
#endif
c = ngx_get_connection(cfd, ev->log);
if (c == NULL) {
return;
}
@ -327,7 +344,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);
}
}

View file

@ -989,7 +989,8 @@ ngx_worker_process_exit(ngx_cycle_t *cycle)
&& 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",