From 6bef4b8f541ef469acc84cb602268c772700f1ed Mon Sep 17 00:00:00 2001 From: Miod Vallat Date: Fri, 7 Nov 2025 17:56:25 +0100 Subject: [PATCH] Alter the qname bpf filter to make it const. This program needs to use a runtime value (a file descriptor), so in its current form it is a non-const HUGE initializer, and causes the compiler to emit a lot of code to initialize the local variable with the program data, eating a lot of memory while there. By changing the program to use a value of zero for the file descriptor, the initializer becomes const; we need however to search for that instruction and pach it before using the program, and this is not the code I am most proud of... but when life gives you lemons, etc. Signed-off-by: Miod Vallat --- pdns/dnsdistdist/bpf-filter.cc | 39 +++++++++++++++++++++++++- pdns/dnsdistdist/bpf-filter.qname.ebpf | 4 ++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/pdns/dnsdistdist/bpf-filter.cc b/pdns/dnsdistdist/bpf-filter.cc index afe9ff6021..0a7161c80c 100644 --- a/pdns/dnsdistdist/bpf-filter.cc +++ b/pdns/dnsdistdist/bpf-filter.cc @@ -398,10 +398,47 @@ BPFFilter::BPFFilter(std::unordered_map& configs, #include "bpf-filter.main.ebpf" }; - const struct bpf_insn qname_filter[] = { + // ABANDON EVERY HOPE - SCARY CODE STARTS HERE + + // This EBF program is huge, and unfortunately not constant; this causes + // the compiler to emit a lot of code (and eat a lot of memory to do so). + // Therefore we include an incomplete but constant version of the program + // and patch it locally, relying upon the fact that there is only one place + // to change. + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays) + struct bpf_insn qname_filter[] = { #include "bpf-filter.qname.ebpf" }; + // The program above contains + // BPF_LD_MAP_FD(BPF_REG_1,0) + // instead of + // BPF_LD_MAP_FD(BPF_REG_1,maps->d_qnames.d_fd.getHandle()) + // and this is the only use of BPF_LD_MAP_FD in the program. + // We will search for that instruction, relying upon the fact that, + // in that particular program, there is only one such instruction. + { + unsigned int pos{0}; + unsigned int limit{sizeof(qname_filter) / sizeof(struct bpf_insn)}; + for (; pos < limit; ++pos) { + if (qname_filter[pos].code == (BPF_LD | BPF_DW | BPF_IMM)) { // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) + // We have found our instruction. + break; + } + } + // BPF_LD_MAP_FP actually is a sequence of two bpf instructions, + // because it loads a 64-bit value. So it can't be the last + // instruction either... + if (pos >= limit - 1) { + throw std::runtime_error("Assumption in the layout of the eBPF filter program no longer stands"); + } + auto data = static_cast<__u64>(maps->d_qnames.d_fd.getHandle()); + qname_filter[pos].imm = static_cast<__s32>(data); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) + qname_filter[pos + 1].imm = static_cast<__s32>(data >> 32); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) + } + + // SCARY CODE ENDS HERE + try { d_mainfilter = loadProgram(main_filter, sizeof(main_filter)); diff --git a/pdns/dnsdistdist/bpf-filter.qname.ebpf b/pdns/dnsdistdist/bpf-filter.qname.ebpf index 120e0620e2..c31b0540f7 100644 --- a/pdns/dnsdistdist/bpf-filter.qname.ebpf +++ b/pdns/dnsdistdist/bpf-filter.qname.ebpf @@ -4078,7 +4078,9 @@ BPF_MOV64_IMM(BPF_REG_9,255), BPF_ALU64_REG(BPF_ADD,BPF_REG_9,BPF_REG_7), BPF_RAW_INSN(BPF_LD|BPF_IND|BPF_H,BPF_REG_0,BPF_REG_9,0,0), BPF_MOV64_REG(BPF_REG_6,BPF_REG_0), -BPF_LD_MAP_FD(BPF_REG_1,maps->d_qnames.d_fd.getHandle()), +// This should be BPF_LD_MAP_FD(BPF_REG_1,maps->d_qnames.d_fd.getHandle()) +// but will be patched at runtime. +BPF_LD_MAP_FD(BPF_REG_1,0), BPF_MOV64_REG(BPF_REG_2,BPF_REG_10), BPF_ALU64_IMM(BPF_ADD,BPF_REG_2,-256), BPF_RAW_INSN(BPF_JMP|BPF_CALL,0,0,0,BPF_FUNC_map_lookup_elem), -- 2.47.3