On Fri, Mar 27, 2026 at 04:40:34PM +0100, Dion Bosschieter wrote:
On 3/27/26 13:06, Daniel P. Berrangé wrote:
On Mon, Feb 16, 2026 at 11:42:37AM +0100, Dion Bosschieter wrote:
Resolves issue: https://gitlab.com/libvirt/libvirt/-/issues/603 Benchmarks showed that the amount of iifname jumps for each interface is the cause for this. Switched the nftables driver towards a vmap (verdict map) so we can have 1 rule that jumps to the correct root input/output chain per interface. Which improves throughput as when the number of interface check and jump rules increases the throughput decreases. The issue describes the interface matching works using the interface name and the majority of the effort is the strncpy, this commit also switches nftables to an interface_index compare instead. However, just using the interface_index is not enough, the amount of oif and iif jump rules causes quite a performance issue, the vmap instead solves this.
Split rules into separate tables: "libvirt_nwfilter_ethernet" and "libvirt_nwfilter_inet" to preserve existing ebip firewall behavior.
Reworked chain logic for clarity with root -input/-output chains per interface. input in the VM interface is filtered in the -input chain(s), output out of the VM inteface is filtered in the -output chain(s).
Stuck with two tables for compatibility reasons with ebiptables. Unifying into a single table would break users’ firewall definitions, which depend on being able to accept traffic at the Ethernet layer (currently defined via ebtables) and apply additional filtering via IP rules (currently defined via ip(6)tables). The nwfilter_nftables_driver splits the ethernet and non ethernet (inet) rules in seperate tables, for above mentioned compatibility reasons. “libvirt_nwfilter_ethernet” and “libvirt_nwfilter_inet”.
Rewrote chain logic, so it is easier to understand, input in the VM interface is filtered in the -input chain(s), output out of the VM inteface is filtered in the -output chain(s). _ethernet and _inet table follow the same style and hook in the same way.
Simplified conntrack handling: rules with accept+conntrack are duplicated to the opposite chain for symmetric behavior, to support the existing ebiptables logic.
Firewall updates continue to use tmp names for atomic replacement.
Unsupported nwfilter features (for now): - STP filtering - Gratuitous ARP filtering - IPSets (potential future support via nft sets)
Signed-off-by: Dion Bosschieter <dionbosschieter@gmail.com> --- po/POTFILES | 1 + src/nwfilter/meson.build | 1 + src/nwfilter/nwfilter_nftables_driver.c | 2667 +++++++++++++++++++++++ src/nwfilter/nwfilter_nftables_driver.h | 28 + 4 files changed, 2697 insertions(+) create mode 100644 src/nwfilter/nwfilter_nftables_driver.c create mode 100644 src/nwfilter/nwfilter_nftables_driver.h
+ /* process rule comment */ + virFirewallCmdAddArg(fw, fwrule, "comment"); + + /* ethernet rules don't have the allHdrFilter */ + if (HAS_ENTRY_ITEM(&rule->p.allHdrFilter.ipHdr.dataComment) && + !virNWFilterRuleIsProtocolEthernet(rule)) { + nftablesAddCmdUserComment(fw, fwrule, rule); + } else { + virFirewallCmdAddArgFormat(fw, fwrule, "\"priority=%d\"", rule->priority); + }
I'm wondering why we need to include "priority=NNN" in a comment against every rule ?
We don't need to, I found it easier to read the nftables rules when comparing them to the nwfilter source.
I'll remove them in a v6.
FYI, if you post a v6 I think we've got enough working here that we can look to merge it. I have WIP for libvirt-tck testing coverage at https://gitlab.com/libvirt/libvirt-tck/-/merge_requests/79 With regards, Daniel -- |: https://berrange.com ~~ https://hachyderm.io/@berrange :| |: https://libvirt.org ~~ https://entangle-photo.org :| |: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|