I filed an issue upstream with libvirt (https://gitlab.com/libvirt/libvirt/-/issues/753) but I now think this is actually a problem with the nftables-restore service that Gentoo provides downstream. The problem is that libvirt creates interfaces and adds nftables rules, which when saved by nftables-restore on shutdown, cannot be restored by nftables-restore on boot, because libvirt has not yet created the interfaces. libvirt evidently has good reasons for operating this way. One of the recommendations from upstream (see https://gitlab.com/libvirt/libvirt/-/issues/753#note_2389490647) is that nftables-restore should only save and restore rules that it knows about. For now, not saving `table ip libvirt_network` and `table ip6 libvirt_network` would be sufficient.
Personally, I think the idea of automatically saving the active ruleset on system shutdown makes no sense. I think it makes more sense for the admin to configure their ruleset once and save it manually. If they need to update the ruleset they can resave it or edit the file. The systemd service should restore it only.
That makes sense to me and seems like a reasonable solution.
Also noteworthy: for iptables, we have the systemd service split into 2 units: iptables-restore.service iptables-store.service The sysadmin is able to enable/disable them independently. So, if I don't want the active ruleset to be saved on every reboot, I can make that decision. I would suggest we do the same for nftables, and discourage people from enabling nftables-store.service if they use other software that configures nftables.
So, the tl;dr is libvirt isn't doing anything wrong here. They could do defensive programming with iifname/oifname instead of iif/oif, but that's like asking the GNOME disk stat program to add a special case for /var/tmp/portage. To be specific there's some baggage in Gentoo's initscripts being held over from the ipchains/iptables era that needs to be let go of. nftables supports an unlimited number of tables, mostly independent of each other aside from priority numbering, and it's designed so they can be added and removed at runtime without interfering with each other. It's entirely reasonable for userspace network admin software to set up its own tables like this. miniupnpd also requires it and I'm sure there's others in tree. In future it's likely that *every* service/cgroup will get a table generated for it at runtime for basic filtering, and an init that calls "flush ruleset" and dumps/reloads entire rulesets with no coordination with anything else is completely incompatible with that. nftables.sh seems easy enough to fix. You replace the panic function with "table org.gentoo.panic [...] priority -999999", allow the system admin to specify an allowlist of extra tables it's permitted to touch in /etc/conf.d/nftables, and remove all global ruleset operations. If there's an existing /var/lib/nftables/rules-save then continue to load it at startup and nudge the user to migrate, otherwise there's no backcompat to worry about as Gentoo doesn't set up any rules by default.
(In reply to Enne Eziarc from comment #4) In my view, nftables.sh and the associated init script/unit is really meant to be a bare-bones solution for people to use when they don't want to mess with more robust firewall management packages. Adding more "smarts" to nftables.sh seems like a bad idea to me; it would probably make more sense to direct people to use something else. Implementing a whitelist in /etc/conf.d/nftables will not help the systemd users.
The solution seems to be - nftables-restore has to load rules at startup from some user-defined file, not from saved one at shutdown.
Just an idea, what if this is a service ordering problem? The default libvirt network is (usually) automatically started by libvirt, i.e. firewall rules are inserted when libvirt starts the network (on libvirtd/virtnetworkd startup). Moreover, that's the time when virbr0 is created. Now, if nftables-restore ran after libvirtd.service/virtnetworkd.service then the bridge would already exist. Sure, nftables-restrore would be overwriting libvirt rules, but hopefully with their 1:1 copy.
Actually, this is the problem of libvirt. It creates virbr* interfaces and nftables rules for them. So, by the logic, libvirt must initiate removing that rules, when they are not needed anymore (stopping libirtd / removing virbr* interfaces).
That's not really an option. It's explained in the linked upstream gitlab issue. Libvirt MUST NOT remove any bridge, kill any QEMU process when the daemon stops. I don't think you'd want your VMs to be killed simply by running 'systemctl stop libvirtd.service'.
(In reply to Michal Privoznik from comment #9) > That's not really an option. It's explained in the linked upstream gitlab > issue. Libvirt MUST NOT remove any bridge, kill any QEMU process when the > daemon stops. I don't think you'd want your VMs to be killed simply by > running 'systemctl stop libvirtd.service'. Alright, then nftables must be set to restore rules not from saved ones at previous shutdown, but from some another defined file.
> Now, if nftables-restore ran after libvirtd.service/virtnetworkd.service > then the bridge would already exist. Sure, nftables-restrore would > be overwriting libvirt rules, but hopefully with their 1:1 copy. Unfortunately (or fortunately depending on your situation :-)) adding a new nftables rule will never overwrite an existing identical rule - you'll just have 2 of the same rule. Logging an error and failing because libvirt uses ifindex-based comparisons rather than interface name was just a happy coincidence that pointed out the problem in a manner that couldn't be ignored. If not for that, then there would likely be lots of people silently accumulating more and more rules each time their host rebooted, and then eventually wondering why network performance was bad, or why a change in the other package's config didn't seem to take effect (would happen if, e.g. a new reject rule was appended *after* an existing accept rule that it should have overridden) This really can only be solved by nftables-restore "staying in its own lane"
The bug has been closed via the following commit(s): https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=96b47bf70929b78f8dc593c047b119fa88483403 commit 96b47bf70929b78f8dc593c047b119fa88483403 Author: Matt Turner <mattst88@gentoo.org> AuthorDate: 2025-03-12 03:15:52 +0000 Commit: Matt Turner <mattst88@gentoo.org> CommitDate: 2025-03-31 16:08:21 +0000 net-firewall/nftables: Split systemd service into separate load/store Closes: https://bugs.gentoo.org/951168 Signed-off-by: Matt Turner <mattst88@gentoo.org> .../nftables/files/systemd/nftables-load.service | 14 ++ .../nftables/files/systemd/nftables-store.service | 11 + net-firewall/nftables/nftables-1.1.1-r1.ebuild | 233 +++++++++++++++++++++ net-firewall/nftables/nftables-9999.ebuild | 23 +- 4 files changed, 272 insertions(+), 9 deletions(-)