From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id 27A5F1FF0C0 for ; Wed, 04 Nov 2026 18:32:01 +0100 (CET) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 3FE8D21401; Wed, 04 Nov 2026 18:31:59 +0100 (CET) Message-ID: Date: Wed, 4 Nov 2026 18:31:31 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: superseded: [PATCH proxmox v7 0/6] add proxmox-ebpf library To: pve-devel@lists.proxmox.com References: <20261104160105.2184145-1-h.laimer@proxmox.com> From: Hannes Laimer Content-Language: en-US In-Reply-To: <20261104160105.2184145-1-h.laimer@proxmox.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1793813491212 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.296 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: WZFML4YD3CXB2JCFDSNBYD47XNHSO562 X-Message-ID-Hash: WZFML4YD3CXB2JCFDSNBYD47XNHSO562 X-MailFrom: h.laimer@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: superseded-by: https://lore.proxmox.com/pve-devel/20261104172918.2643810-1-h.laimer@proxmox.com/ On 2026-11-04 17:02, Hannes Laimer wrote: > proxmox-ebpf holds the eBPF programs and the code that loads, attaches > and updates them, grouped into subsystems. It is a library only, whoever > needs a subsystem pulls in just that one through a cargo feature and > calls it from their side. This series is the shared part, the actual > subsystems come as their own series on top. > > The core is the shared subsystem code. It takes care of everything from > loading and attaching per interface to pinning in bpffs and tearing down > again. So nothing has to keep running, and each call picks up where the > last one left off. The build records a hash of the compiled object, the > crate's version and a schema version per subsystem, so a call can tell > what changed and an older build leaves a newer one's state alone. A > changed program or map schema is swapped onto the existing links > without interrupting traffic. The new maps are filled before the links > move onto them. The BPF C code is also built natively against a small > shim, so the parsing and packet building logic can be tested without a > kernel. Packaging is debcargo like the other Rust crates. > > Every change runs under a lock per subsystem, a full apply takes it > exclusively and a single-interface step shared, like the pmxcfs domain > locks. The holder reads the input of its change under the lock and > writes before it lets go. So a change and a full apply reach the kernel > in the order they read their input, and nothing has to order them after > the fact. A holder that never returns makes the waiters time out instead > of hanging them. A subsystem can also hand over the whole content of its > maps. The programs then move onto the new content one link at a time and > never read a mix of old and new entries, and a write the kernel refuses > leaves the old content in place. The programs of different subsystems on > one interface run in a fixed order. An attach places its link relative > to the links the other subsystems already hold there, so the order holds > however the attaches are timed, and an update keeps every link in its > place. > > The crate goes into the proxmox workspace, as the first one there with a > build script. Building needs clang-21, libbpf-dev and > proxmox-kernel-libc-dev, the programs compile against the UAPI headers > from there. > > v7: > * include rust pkg version next to fingerprint, so we can avoid > flip-flopping the loaded programs in case a worker stays around > during/after an upgrade > * differentiate between a link swap failing on open or on the swap > itself > * replacing the maps and clearing take the lock guard mutably, so a map > ref opened before cannot be written after the exchange, it would hit > the retired map > * the repair after an interrupted replacement also detaches the links > of a direction the update dropped, a retry that failed afterwards > left them attached > * add context to io errors > * merge a run order change, don't blindly replace, this covers cases > where something was added and reordered in one > > v6: > * loop all links at the start of every replace, moving links to live/ > is done one-by-one, so it can fail. a failed pass then has some links > still on staging/, this makes sure we dont delete state that may > still be attached. the kernel checks if it already exists on a swap, > so this is a no-op, and at worst an atomic swap for links that still > has staging/ attached > * only allow adding to the run order, at least for live updates. > removal or re-orders are applied on the next reboot > * enforce that map refs live as long as the lock they were taken under > * a pin that cannot be opened stays and fails the step instead of > being unlinked, which under a descriptor shortage detached a working > link > * the harness tests run a C program of their own against the shim > * move the crate into the proxmox workspace, the vendored vmlinux.h is > gone, the programs build against the UAPI headers of > proxmox-kernel-libc-dev with a versioned clang > > v5: > * add a call that replaces the maps as a whole, it uses more space and > writes everything instead of only what changed, but leaves the old > content in place instead of a mix, in cases where the write fails > with ENOMEM. Subsystems choose which they need > * install/upgrade now also use this newly added replace path, this > simplifies the process and also closes a hole where attached programs > would read empty maps, shortly before they were filled after a schema > version bump > * the run order of the subsystems is written to > `/run/proxmox-ebpf/order` by a full apply and every attach places by > it, so a stale process running an older version attaches correctly > against subsystems added by a process running a newer version > * set correct permissions on `/run/..` > * a build whose schema is older than the pinned one no longer counts > its state as current, so its single steps back off as well > * add `interrupted()` on the lock guard, true when a replacement left > its staged set or an old schema directory behind, a full pass > replaces then > * an attach checks after attaching that the interface still has the > index of its pin, one recreated under the same name in between is > reported as gone > * a map missing from a pinned set is reported by name > > v4, thanks @Stefan!: > * drop the generation counter, a change takes the apply lock before it > reads its input instead, so the lock order is the input order > * new, the links of different subsystems on an interface are now > ordered > * the tc link plumbing is its own commit ahead of the subsystem code > * subsystem programs are now a list of direction and name pairs > * add short note for why not proxmox-sys's locking > * improve tc error handling > * fix smaller spacing and code stuff > > > proxmox: > > Hannes Laimer (6): > ebpf: add the crate with its BPF build > ebpf: tc: add the link plumbing > ebpf: subsystem: add the shared tc program handling > ebpf: subsystem: place subsystem links in a fixed order > ebpf: tests: add a native harness for the BPF C programs > ebpf: debian: package the crate as a Rust library > > Cargo.toml | 2 + > proxmox-ebpf/Cargo.toml | 22 + > proxmox-ebpf/build.rs | 190 +++ > proxmox-ebpf/debian/changelog | 5 + > proxmox-ebpf/debian/control | 50 + > proxmox-ebpf/debian/copyright | 18 + > proxmox-ebpf/debian/debcargo.toml | 13 + > proxmox-ebpf/include/bpf_debug.h | 12 + > proxmox-ebpf/src/bpf-shim/bpf/bpf_helpers.h | 34 + > proxmox-ebpf/src/bpf-shim/bpf_debug.h | 10 + > proxmox-ebpf/src/bpf-shim/linux/bpf.h | 25 + > proxmox-ebpf/src/lib.rs | 6 + > proxmox-ebpf/src/subsystem.rs | 1373 +++++++++++++++++++ > proxmox-ebpf/src/tc.rs | 326 +++++ > proxmox-ebpf/tests/bpf/fixture.bpf.c | 37 + > proxmox-ebpf/tests/common/mod.rs | 211 +++ > proxmox-ebpf/tests/harness.rs | 84 ++ > 17 files changed, 2418 insertions(+) > create mode 100644 proxmox-ebpf/Cargo.toml > create mode 100644 proxmox-ebpf/build.rs > create mode 100644 proxmox-ebpf/debian/changelog > create mode 100644 proxmox-ebpf/debian/control > create mode 100644 proxmox-ebpf/debian/copyright > create mode 100644 proxmox-ebpf/debian/debcargo.toml > create mode 100644 proxmox-ebpf/include/bpf_debug.h > create mode 100644 proxmox-ebpf/src/bpf-shim/bpf/bpf_helpers.h > create mode 100644 proxmox-ebpf/src/bpf-shim/bpf_debug.h > create mode 100644 proxmox-ebpf/src/bpf-shim/linux/bpf.h > create mode 100644 proxmox-ebpf/src/lib.rs > create mode 100644 proxmox-ebpf/src/subsystem.rs > create mode 100644 proxmox-ebpf/src/tc.rs > create mode 100644 proxmox-ebpf/tests/bpf/fixture.bpf.c > create mode 100644 proxmox-ebpf/tests/common/mod.rs > create mode 100644 proxmox-ebpf/tests/harness.rs > > > Summary over all repositories: > 17 files changed, 2418 insertions(+), 0 deletions(-) >