Mercurial > hg > nginx
view src/event/quic/bpf/ngx_quic_reuseport_helper.c @ 8888:6d1488b62dc5 quic
QUIC: style.
author | Sergey Kandaurov <pluknet@nginx.com> |
---|---|
date | Tue, 26 Oct 2021 18:05:57 +0300 |
parents | 1a489587e1c8 |
children | a2fbae359828 |
line wrap: on
line source
#include <errno.h> #include <linux/string.h> #include <linux/udp.h> #include <linux/bpf.h> /* * the bpf_helpers.h is not included into linux-headers, only available * with kernel sources in "tools/lib/bpf/bpf_helpers.h" or in libbpf. */ #include <bpf/bpf_helpers.h> #if !defined(SEC) #define SEC(NAME) __attribute__((section(NAME), used)) #endif #if defined(LICENSE_GPL) /* * To see debug: * * echo 1 > /sys/kernel/debug/tracing/events/bpf_trace/enable * cat /sys/kernel/debug/tracing/trace_pipe * echo 0 > /sys/kernel/debug/tracing/events/bpf_trace/enable */ #define debugmsg(fmt, ...) \ do { \ char __buf[] = fmt; \ bpf_trace_printk(__buf, sizeof(__buf), ##__VA_ARGS__); \ } while (0) #else #define debugmsg(fmt, ...) #endif char _license[] SEC("license") = LICENSE; /*****************************************************************************/ #define NGX_QUIC_PKT_LONG 0x80 /* header form */ #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; SEC(PROGNAME) int ngx_quic_select_socket_by_dcid(struct sk_reuseport_md *ctx) { int rc; __u64 key; size_t len, offset; unsigned char *start, *end, *data, *dcid; start = ctx->data; end = (unsigned char *) ctx->data_end; offset = 0; advance_data(sizeof(struct udphdr)); /* data at UDP header */ advance_data(1); /* data at QUIC flags */ if (data[0] & NGX_QUIC_PKT_LONG) { advance_data(4); /* data at QUIC version */ advance_data(1); /* data at DCID len */ len = data[0]; /* read DCID length */ if (len < 8) { /* it's useless to search for key in such short DCID */ return SK_PASS; } } else { len = NGX_QUIC_SERVER_CID_LEN; } dcid = &data[1]; advance_data(len); /* we expect the packet to have full DCID */ /* make verifier happy */ if (dcid + sizeof(__u64) > end) { goto failed; } 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; } 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; }