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 AE1411FF0AA for ; Tue, 20 Oct 2026 15:11:15 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id A07D7216DB; Tue, 20 Oct 2026 15:11:10 +0200 (CEST) Message-ID: <10d049a5-09ab-4b06-8efb-5de7629df91f@proxmox.com> Date: Tue, 20 Oct 2026 15:11:00 +0200 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH container/docs/manager/network/proxmox{-ebpf,-perl-rs}/qemu-server v3 00/17] sdn: implement DHCP for all zones using eBPF To: pve-devel@lists.proxmox.com References: <20261020080005.470757-1-h.laimer@proxmox.com> Content-Language: en-US From: Stefan Hanreich In-Reply-To: <20261020080005.470757-1-h.laimer@proxmox.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.233 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: YXMPUKNUO2CRRPBN2IW66UAJNHOX42PR X-Message-ID-Hash: YXMPUKNUO2CRRPBN2IW66UAJNHOX42PR X-MailFrom: s.hanreich@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: Did some testing: * PVE IPAM / All zones / eBPF backend * PVE IPAM / Simple zone / dnsmasq backend * Netbox IPAM / All zones / eBPF backend * Netbox IPAM / Simple zone / dnsmasq backend * switching from dnsmasq -> eBPF and vice-versa -> pre-existing: dnsmasq doesn't clean its config folder * changing bridge on network devices * changing subnets on the vnet and then reacquiring a lease Everything worked really well, also the pre-existing dnsmasq zone. This revision seems a lot nicer already without the generation counter, which seemed a bit clunky. This is a more elegant solution imo. One thing I found: The new DHCP backend type needs to be added to proxmox-ve-rs as well, otherwise the config fails to parse (firewall). We should add fallback variants there... for code-related stuff see the respective patches. On 10/20/26 10:00 AM, 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 reaches the guest's node > by a detached call to a new node endpoint, POST > /nodes/{node}/sdn/dhcp-mapping. 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. A > failed push is logged in the journal, and the responder on the guest's > node catches up at the node's next apply or the guest's next start. An > apply also 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 > - 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 > 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 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 | 1031 ++++++++++++++++++++++++++++++++ > 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, 2422 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 (9): > sdn: dhcp: replace a stale dnsmasq reservation instead of dropping it > sdn: dhcp: update reservations when ip mappings change > sdn: ipam: key the MAC cache by lower-case MAC, stop caching misses > 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: push IP mapping edits to 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 | 10 + > src/PVE/API2/Network/SDN/Nodes/Status.pm | 37 + > src/PVE/API2/Network/SDN/Zones.pm | 11 +- > src/PVE/Network/SDN/Dhcp.pm | 200 ++- > src/PVE/Network/SDN/Dhcp/Dnsmasq.pm | 114 +- > src/PVE/Network/SDN/Dhcp/Ebpf.pm | 308 +++++ > src/PVE/Network/SDN/Dhcp/Makefile | 2 +- > src/PVE/Network/SDN/Dhcp/Plugin.pm | 26 +- > src/PVE/Network/SDN/Ipams.pm | 61 +- > 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 | 1442 ++++++++++++++++++++- > 20 files changed, 2263 insertions(+), 80 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 | 3 +++ > 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, 44 insertions(+), 11 deletions(-) > > > 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, 5099 insertions(+), 128 deletions(-) >