From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id 113F41FF09C for ; Mon, 02 Nov 2026 16:21:30 +0100 (CET) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id BC55A21A8C; Mon, 02 Nov 2026 16:20:20 +0100 (CET) Message-ID: <671e4d12-6245-4a09-b9e6-31b1fd4c61c7@proxmox.com> Date: Mon, 2 Nov 2026 16:19:29 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: superseded: [PATCH container/docs/manager/network/proxmox{-ebpf,-perl-rs,-ve-rs}/qemu-server v4 00/20] sdn: implement DHCP for all zones using eBPF To: pve-devel@lists.proxmox.com References: <20261021084445.462195-1-h.laimer@proxmox.com> From: Hannes Laimer Content-Language: en-US In-Reply-To: <20261021084445.462195-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: 1793632769215 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.189 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) POISEN_SPAM_PILL 0.1 Meta: its spam POISEN_SPAM_PILL_1 0.1 random spam to be learned in bayes POISEN_SPAM_PILL_3 0.1 random spam to be learned in bayes 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: DQQP6ZZPFA42EWLUQRM7LVZYQA3JTTXE X-Message-ID-Hash: DQQP6ZZPFA42EWLUQRM7LVZYQA3JTTXE 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/20261102151842.1605234-1-h.laimer@proxmox.com On 2026-10-21 10:45, Hannes Laimer wrote: > This series adds a second DHCP backend, ebpf, next to dnsmasq. A zone > picks its backend. dnsmasq stays limited to simple zones, while ebpf > answers on the guest's own interface and works on every zone type. A > guest on a zone with the ebpf backend gets the address its NIC has in > the IPAM. There is no daemon per zone and no lease file. The answers > are held in the kernel and do not depend on the IPAM being reachable. > > The responder is a BPF program on the ingress of each guest interface > of a zone with the ebpf backend. It answers a request from the record > of that interface, and the exchange never reaches the bridge. A > request whose client MAC is not the interface's own passes on > unanswered. So a guest cannot read another guest's record, and a > nested client does not get the outer guest's address. > > An edit through /cluster/sdn/vnets/{vnet}/ips is proxied to the > guest's node and updates the backend there. The guest sees the change > at its next renewal, so the lease time bounds how long an old answer > survives. Subnets get a dhcp-lease-time property for both backends. > Without it dnsmasq hands out infinite leases and the responder ten > minutes. An apply attaches the responder to running guests, so a zone > switched to ebpf serves them without a restart. > > Changes reach the kernel in the order they read their input. So no > change overwrites a newer one with older input. A hotplug moves the > interface before the guest config names the new bridge. An apply or an > edit that read the older config in between leaves the moved interface > as its plug left it. A change that fails only warns, and what was > served stays served. Nothing of the responder survives a reboot, so it > is loaded again at boot before the guests start. > > Only DHCPv4 is answered. A request the guest tagged itself passes > unanswered as well, so a trunk port keeps working as before. The > request is answered on the guest interface, so the guest's firewall > rules, its DHCP firewall option and its rate limit do not apply to it. > The reply leaves through the interface's egress, where the rate limit > shapes it. A request the responder does not answer passes on to the > bridge and through the firewall as before. Mappings changed directly > in an external IPAM are not picked up, as with dnsmasq. > > In patch order, the series adds > - proxmox-ebpf, the dhcp subsystem, a tc program answering on the > guest interface and the per-interface map it answers from > - pve-rs, the bindings > - pve-network, the ebpf backend, the hooks that keep a backend current > when a guest interface or a mapping changes, dhcp on every zone > type, and fixes to the dnsmasq reservations and the MAC cache > - qemu-server and pve-container, the reports of a guest NIC coming, > going or moving, and for VMs the push at a migration's resume > - pve-manager, the backend and subnet options in the UI, and the > backends brought up at boot ahead of the guests > - proxmox-ve-rs, the ebpf variant of the dhcp backend type > - pve-docs, documentation > > - proxmox-ebpf applies on top of the v4 of its own series [1] > - pve-rs needs proxmox-ebpf with the dhcp feature > - pve-network needs pve-rs, at build and run time > - qemu-server, pve-container and pve-manager need pve-network > - proxmox-ve-config needs nothing, and proxmox-firewall needs its > dependency on it bumped, since an older one fails to parse a zone > with the ebpf backend and the firewall then cannot load its config > An older pve-network fails its apply on the unknown backend, so every > node needs the new one before a zone gets ebpf. > > Changes since v3, thanks @Stefan!: > * a mapping edit runs on the guest's node instead of being pushed to > it, the node endpoint is gone > * the MAC cache is read and written with lower-case keys, and its > three fixes are three commits > * the guest NIC list is keyed by MAC > * add the missing proxmox-ve-rs patch, the ebpf variant of the dhcp > backend type > * reword log lines and warnings > * (notes on patches with changes) > > Changes since v2: > * drop the generation counter. Every change takes the responder's > lock before it reads its input instead. An edit takes it > exclusively > * the resume at the end of a live migration pushes the guest's > mappings again on the target, so an edit made during the migration > reaches it > * new first pve-network commit, a dnsmasq fix that replaces a stale > reservation of another MAC instead of dropping it > * no MTU option for a zone without an MTU, where v2 handed out 1500 > * a mapping edit without a MAC no longer reaches the backends > * rewrite commit messages, cover letter and parts of the docs > * rebase onto current master > > (pre-build packages on sani) > > [1] https://lore.proxmox.com/pve-devel/20261019142413.2255644-1-h.laimer@proxmox.com/ > > > proxmox-ebpf: > > Hannes Laimer (2): > dhcp: add the per-tap DHCPv4 responder program > dhcp: add the subsystem that loads the responder and keeps its records > > Cargo.toml | 5 + > debian/control | 6 +- > src/bpf-shim/bpf/bpf_helpers.h | 3 + > src/bpf-shim/vmlinux.h | 1 + > src/dhcp/bpf/dhcp.bpf.c | 401 ++++++++++++ > src/dhcp/bpf/types.h | 24 + > src/dhcp/mod.rs | 1037 ++++++++++++++++++++++++++++++++ > src/dhcp/types.rs | 64 ++ > src/lib.rs | 3 + > src/subsystem.rs | 2 +- > tests/common/mod.rs | 63 +- > tests/dhcp.rs | 825 +++++++++++++++++++++++++ > 12 files changed, 2428 insertions(+), 6 deletions(-) > create mode 100644 src/dhcp/bpf/dhcp.bpf.c > create mode 100644 src/dhcp/bpf/types.h > create mode 100644 src/dhcp/mod.rs > create mode 100644 src/dhcp/types.rs > create mode 100644 tests/dhcp.rs > > > proxmox-perl-rs: > > Hannes Laimer (1): > pve-rs: sdn: add bindings for the eBPF DHCP responder > > pve-rs/Cargo.toml | 2 + > pve-rs/Makefile | 3 + > pve-rs/debian/control | 2 + > pve-rs/src/bindings/sdn/dhcp.rs | 229 ++++++++++++++++++++++++++++++++ > pve-rs/src/bindings/sdn/mod.rs | 1 + > 5 files changed, 237 insertions(+) > create mode 100644 pve-rs/src/bindings/sdn/dhcp.rs > > > pve-network: > > Hannes Laimer (11): > sdn: ipam: stop caching IPAM misses > sdn: ipam: write the lookup's cache entry under the cluster lock > sdn: ipam: key the MAC cache by lower-case MAC > sdn: dhcp: replace a stale dnsmasq reservation instead of dropping it > sdn: dhcp: update reservations when ip mappings change > sdn: dhcp: make the lease time configurable per subnet > sdn: dhcp: require a backend only if a zone on this node uses it > sdn: dhcp: add an eBPF backend answering on each guest interface > sdn: zones: report interface plugs and unplugs to the DHCP backends > sdn: dhcp: run IP mapping edits on the guest's node > sdn: zones: allow the ebpf DHCP backend on every zone type > > debian/libpve-network-perl.prerm | 13 + > src/PVE/API2/Network/SDN/Ips.pm | 23 + > src/PVE/API2/Network/SDN/Zones.pm | 11 +- > src/PVE/Network/SDN/Dhcp.pm | 139 +- > src/PVE/Network/SDN/Dhcp/Dnsmasq.pm | 106 +- > src/PVE/Network/SDN/Dhcp/Ebpf.pm | 295 +++++ > src/PVE/Network/SDN/Dhcp/Makefile | 2 +- > src/PVE/Network/SDN/Dhcp/Plugin.pm | 26 +- > src/PVE/Network/SDN/Ipams.pm | 50 +- > src/PVE/Network/SDN/SubnetPlugin.pm | 11 + > src/PVE/Network/SDN/Vnets.pm | 5 +- > src/PVE/Network/SDN/Zones.pm | 29 +- > src/PVE/Network/SDN/Zones/EvpnPlugin.pm | 32 + > src/PVE/Network/SDN/Zones/FaucetPlugin.pm | 1 + > src/PVE/Network/SDN/Zones/QinQPlugin.pm | 7 + > src/PVE/Network/SDN/Zones/SimplePlugin.pm | 2 +- > src/PVE/Network/SDN/Zones/VlanPlugin.pm | 7 + > src/PVE/Network/SDN/Zones/VxlanPlugin.pm | 25 + > src/test/run_test_vnets_blackbox.pl | 1464 ++++++++++++++++++++- > 19 files changed, 2169 insertions(+), 79 deletions(-) > create mode 100755 debian/libpve-network-perl.prerm > create mode 100644 src/PVE/Network/SDN/Dhcp/Ebpf.pm > > > qemu-server: > > Hannes Laimer (1): > network: sdn: keep the DHCP backends current on guest NICs > > src/PVE/CLI/qm.pm | 4 ++-- > src/PVE/QemuServer.pm | 4 ++++ > src/PVE/QemuServer/Network.pm | 19 +++++++++++++++++-- > src/PVE/QemuServer/RunState.pm | 2 ++ > src/usr/pve-bridge | 8 +++++++- > src/usr/pve-bridgedown | 4 ++-- > 6 files changed, 34 insertions(+), 7 deletions(-) > > > pve-container: > > Hannes Laimer (1): > net: report NIC plugs and removals to the SDN DHCP backends > > src/PVE/LXC.pm | 13 +++++++++++-- > src/PVE/LXC/Config.pm | 3 ++- > src/lxc-pve-poststop-hook | 6 +++--- > 3 files changed, 16 insertions(+), 6 deletions(-) > > > pve-manager: > > Hannes Laimer (2): > ui: sdn: add zone DHCP backend selector and subnet DHCP options > sdn: bring up the DHCP backends at boot before the guests start > > bin/pve-sdn-commit | 4 ++++ > services/pve-sdn-commit.service | 1 + > www/manager6/sdn/SubnetEdit.js | 23 +++++++++++++++++++++++ > www/manager6/sdn/zones/Base.js | 17 +++++++++++++++++ > www/manager6/sdn/zones/SimpleEdit.js | 11 ----------- > 5 files changed, 45 insertions(+), 11 deletions(-) > > > proxmox-ve-rs: > > Hannes Laimer (1): > ve-config: sdn: add the ebpf dhcp backend > > proxmox-ve-config/src/sdn/config.rs | 3 +++ > 1 file changed, 3 insertions(+) > > > pve-docs: > > Hannes Laimer (1): > sdn: dhcp: add eBPF backend section > > pvesdn.adoc | 101 ++++++++++++++++++++++++++++++++++++++++++---------- > 1 file changed, 83 insertions(+), 18 deletions(-) > > > Summary over all repositories: > 52 files changed, 5015 insertions(+), 127 deletions(-) >