[PATCH v2 0/5] nwfilter: add nwfilter nftables driver

Dion Bosschieter posted 5 patches 1 month, 4 weeks ago
Failed in applying to current master (apply log)
po/POTFILES                                   |    3 +
src/conf/virnwfilterobj.h                     |   20 -
src/nwfilter/libvirtd_nwfilter.aug            |   37 +
src/nwfilter/meson.build                      |   39 +
src/nwfilter/nwfilter.conf.in                 |   26 +
src/nwfilter/nwfilter_driver.c                |   66 +-
src/nwfilter/nwfilter_driver_conf.c           |  210 +
src/nwfilter/nwfilter_driver_conf.h           |   66 +
src/nwfilter/nwfilter_ebiptables_driver.c     |  262 +-
src/nwfilter/nwfilter_ebiptables_driver.h     |    2 +-
src/nwfilter/nwfilter_gentech_driver.c        |   63 +-
src/nwfilter/nwfilter_gentech_driver.h        |    5 +-
src/nwfilter/nwfilter_nftables_driver.c       | 2374 +++++++++++
src/nwfilter/nwfilter_nftables_driver.h       |   28 +
src/nwfilter/nwfilter_tech_driver.c           |  249 ++
src/nwfilter/nwfilter_tech_driver.h           |   51 +-
src/nwfilter/test_libvirtd_nwfilter.aug.in    |    5 +
tests/meson.build                             |    4 +-
tests/nwfilternftablestest.c                  |  428 ++
...ltest.c => nwfilterxml2ebipfirewalltest.c} |    4 +-
...nux.args => ah-ipv6-linux.ebiptables.args} |    0
.../ah-ipv6-linux.nftables.args               |  304 ++
...ah-linux.args => ah-linux.ebiptables.args} |    0
.../ah-linux.nftables.args                    |  298 ++
...ux.args => all-ipv6-linux.ebiptables.args} |    0
.../all-ipv6-linux.nftables.args              |  286 ++
...l-linux.args => all-linux.ebiptables.args} |    0
.../all-linux.nftables.args                   |  280 ++
...p-linux.args => arp-linux.ebiptables.args} |    0
.../arp-linux.nftables.args                   |  215 +
.../nwfilterxml2firewalldata/arp.nftables.xml |   27 +
...nux.args => comment-linux.ebiptables.args} |    0
.../comment-linux.nftables.args               |  483 +++
...x.args => conntrack-linux.ebiptables.args} |    0
.../conntrack-linux.nftables.args             |  198 +
...ux.args => esp-ipv6-linux.ebiptables.args} |    0
.../esp-ipv6-linux.nftables.args              |  304 ++
...p-linux.args => esp-linux.ebiptables.args} |    0
.../esp-linux.nftables.args                   |  298 ++
...x.args => example-1-linux.ebiptables.args} |    0
.../example-1-linux.nftables.args             |  266 ++
...x.args => example-2-linux.ebiptables.args} |    0
.../example-2-linux.nftables.args             |  348 ++
...ux.args => hex-data-linux.ebiptables.args} |    0
.../hex-data-linux.nftables.args              |  357 ++
...s => icmp-direction-linux.ebiptables.args} |    0
.../icmp-direction-linux.nftables.args        |  238 ++
... => icmp-direction2-linux.ebiptables.args} |    0
.../icmp-direction2-linux.nftables.args       |  238 ++
... => icmp-direction3-linux.ebiptables.args} |    0
.../icmp-direction3-linux.nftables.args       |  184 +
...-linux.args => icmp-linux.ebiptables.args} |    0
.../icmp-linux.nftables.args                  |  252 ++
...inux.args => icmpv6-linux.ebiptables.args} |    0
.../icmpv6-linux.nftables.args                |  322 ++
...-linux.args => igmp-linux.ebiptables.args} |    0
.../igmp-linux.nftables.args                  |  298 ++
...ip-linux.args => ip-linux.ebiptables.args} |    0
.../ip-linux.nftables.args                    |  198 +
...linux.args => ipset-linux.ebiptables.args} |    0
... => ipt-no-macspoof-linux.ebiptables.args} |    0
.../ipt-no-macspoof-linux.nftables.args       |  169 +
...-linux.args => ipv6-linux.ebiptables.args} |    0
.../ipv6-linux.nftables.args                  |  474 +++
...linux.args => iter1-linux.ebiptables.args} |    0
.../iter1-linux.nftables.args                 |  298 ++
...linux.args => iter2-linux.ebiptables.args} |    0
.../iter2-linux.nftables.args                 | 3598 +++++++++++++++++
...linux.args => iter3-linux.ebiptables.args} |    0
.../iter3-linux.nftables.args                 |  418 ++
...c-linux.args => mac-linux.ebiptables.args} |    0
.../mac-linux.nftables.args                   |  180 +
...-linux.args => rarp-linux.ebiptables.args} |    0
.../rarp-linux.nftables.args                  |  215 +
...x.args => sctp-ipv6-linux.ebiptables.args} |    0
.../sctp-ipv6-linux.nftables.args             |  314 ++
...-linux.args => sctp-linux.ebiptables.args} |    0
.../sctp-linux.nftables.args                  |  314 ++
...p-linux.args => stp-linux.ebiptables.args} |    0
...inux.args => target-linux.ebiptables.args} |    0
.../target-linux.nftables.args                |  452 +++
...nux.args => target2-linux.ebiptables.args} |    0
.../target2-linux.nftables.args               |  316 ++
...ux.args => tcp-ipv6-linux.ebiptables.args} |    0
.../tcp-ipv6-linux.nftables.args              |  314 ++
...p-linux.args => tcp-linux.ebiptables.args} |    0
.../tcp-linux.nftables.args                   |  468 +++
...ux.args => udp-ipv6-linux.ebiptables.args} |    0
.../udp-ipv6-linux.nftables.args              |  314 ++
...p-linux.args => udp-linux.ebiptables.args} |    0
.../udp-linux.nftables.args                   |  314 ++
...rgs => udplite-ipv6-linux.ebiptables.args} |    0
.../udplite-ipv6-linux.nftables.args          |  304 ++
...nux.args => udplite-linux.ebiptables.args} |    0
.../udplite-linux.nftables.args               |  298 ++
...-linux.args => vlan-linux.ebiptables.args} |    0
.../vlan-linux.nftables.args                  |  264 ++
tests/nwfilterxml2nftfirewalltest.c           |  438 ++
98 files changed, 18433 insertions(+), 365 deletions(-)
create mode 100644 src/nwfilter/libvirtd_nwfilter.aug
create mode 100644 src/nwfilter/nwfilter.conf.in
create mode 100644 src/nwfilter/nwfilter_driver_conf.c
create mode 100644 src/nwfilter/nwfilter_driver_conf.h
create mode 100644 src/nwfilter/nwfilter_nftables_driver.c
create mode 100644 src/nwfilter/nwfilter_nftables_driver.h
create mode 100644 src/nwfilter/nwfilter_tech_driver.c
create mode 100644 src/nwfilter/test_libvirtd_nwfilter.aug.in
create mode 100644 tests/nwfilternftablestest.c
rename tests/{nwfilterxml2firewalltest.c => nwfilterxml2ebipfirewalltest.c} (99%)
rename tests/nwfilterxml2firewalldata/{ah-ipv6-linux.args => ah-ipv6-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/ah-ipv6-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{ah-linux.args => ah-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/ah-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{all-ipv6-linux.args => all-ipv6-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/all-ipv6-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{all-linux.args => all-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/all-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{arp-linux.args => arp-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/arp-linux.nftables.args
create mode 100644 tests/nwfilterxml2firewalldata/arp.nftables.xml
rename tests/nwfilterxml2firewalldata/{comment-linux.args => comment-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/comment-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{conntrack-linux.args => conntrack-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/conntrack-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{esp-ipv6-linux.args => esp-ipv6-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/esp-ipv6-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{esp-linux.args => esp-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/esp-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{example-1-linux.args => example-1-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/example-1-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{example-2-linux.args => example-2-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/example-2-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{hex-data-linux.args => hex-data-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/hex-data-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{icmp-direction-linux.args => icmp-direction-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/icmp-direction-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{icmp-direction2-linux.args => icmp-direction2-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/icmp-direction2-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{icmp-direction3-linux.args => icmp-direction3-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/icmp-direction3-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{icmp-linux.args => icmp-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/icmp-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{icmpv6-linux.args => icmpv6-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/icmpv6-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{igmp-linux.args => igmp-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/igmp-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{ip-linux.args => ip-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/ip-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{ipset-linux.args => ipset-linux.ebiptables.args} (100%)
rename tests/nwfilterxml2firewalldata/{ipt-no-macspoof-linux.args => ipt-no-macspoof-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/ipt-no-macspoof-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{ipv6-linux.args => ipv6-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/ipv6-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{iter1-linux.args => iter1-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/iter1-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{iter2-linux.args => iter2-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/iter2-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{iter3-linux.args => iter3-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/iter3-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{mac-linux.args => mac-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/mac-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{rarp-linux.args => rarp-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/rarp-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{sctp-ipv6-linux.args => sctp-ipv6-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/sctp-ipv6-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{sctp-linux.args => sctp-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/sctp-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{stp-linux.args => stp-linux.ebiptables.args} (100%)
rename tests/nwfilterxml2firewalldata/{target-linux.args => target-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/target-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{target2-linux.args => target2-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/target2-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{tcp-ipv6-linux.args => tcp-ipv6-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/tcp-ipv6-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{tcp-linux.args => tcp-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/tcp-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{udp-ipv6-linux.args => udp-ipv6-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/udp-ipv6-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{udp-linux.args => udp-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/udp-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{udplite-ipv6-linux.args => udplite-ipv6-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/udplite-ipv6-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{udplite-linux.args => udplite-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/udplite-linux.nftables.args
rename tests/nwfilterxml2firewalldata/{vlan-linux.args => vlan-linux.ebiptables.args} (100%)
create mode 100755 tests/nwfilterxml2firewalldata/vlan-linux.nftables.args
create mode 100644 tests/nwfilterxml2nftfirewalltest.c
[PATCH v2 0/5] nwfilter: add nwfilter nftables driver
Posted by Dion Bosschieter 1 month, 4 weeks ago
This series aims to implement nftables as a backend driver for
the nwfilter feature. The idea is that eventually it will replace
the ebiptables driver and provide an easy way for users to switch
from one driver to another.

The first 2 patches are moving of functions and renames, meant to decouple
nwfilter from the currently only existing ebiptables driver.

The 3rd patch introduces the new nwfilter driver. After which nwfilter allows
users to choose it in the 4th patch.

The last patch introduces unit testing of the new nftables driver.

- Implemented very basic nwfilter.conf reading and choosing a nwfilter
  driver based on the name of the drivers (nftables/ebiptables).
  Defaults to the nftables driver, based on the firewall_backend_priority
  meson option, following the bridge driver logic.
- Resolves issue https://gitlab.com/libvirt/libvirt/-/issues/603
  benchmarks showed that the amount of iifname jumps for each
  interface with 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-other" to preserve existing 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 prerouting and postrouting as hooks for input / output
  on the -ethernet and -other table. This makes it easier to merge
  the tables in the future. Saving management of two tables and
  decreasing the amount of tables a packet sees. Currently ebtables
  filtering happens via PREROUTING and POSTROUTING hooks, while
  ip/ip6tables filtering happens in the output/forward hooks.
- Stuck with 2 tables for compatibility reasons with eb iptables,
  unifying into 1 table will break users firewall definitions, which
  depend on being able to do accepts on ethernet rules
  (which currently get defined via ebtables) and additional filtering
  via the ip rules (which currently get defined via ip(6)tables).
  The nwfilter_nftables_driver keeps splitting the ethernet and
  non ethernet (other) rules in seperate tables
  "libvirt-nwfilter-ethernet" and "libvirt-nwfilter-other".
- 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 -other 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 use tmp names for atomic replacement.

Unsupported nwfilter features (for now):
- STP filtering
- Gratuitous ARP filtering
- IPSets (potential future support via nft sets)
- Reject due to filtering in pre/postrouting, using drop instead
  of reject, copying logic from existing ebiptables ebtables actions

Future improvements:
- Use `nft -f` for atomic rule application.
- Optional single-table mode via nwfilter.conf.
- Optimize boot phase with chain hash comparison.

---
Changes in v2:
- Rename {ebip,nf}tables specific test files in 1 directory instead of
  seperating them in different directories.
- Added default nwfilter.conf file in git, documented including augeas files
- Replaced hardcoding of default driver based on existing
  firewall_backend_priority meson option.
- Added nwfilter_driver_conf.{h,c} for configuration handling,
  to match the common pattern used in other drivers.

Dion Bosschieter (5):
  nwfilter: rename ebiptables unit tests and data files
  nwfilter: move shared nwfilter driver functions into nwfilter_tech_driver.c
  nwfilter: add nwfilter nftables driver
  nwfilter: allow use of nftables nwfilter driver via nwfilter.conf
  nwfilter: add unit tests and test data for nwfilter nftables driver

 po/POTFILES                                   |    3 +
 src/conf/virnwfilterobj.h                     |   20 -
 src/nwfilter/libvirtd_nwfilter.aug            |   37 +
 src/nwfilter/meson.build                      |   39 +
 src/nwfilter/nwfilter.conf.in                 |   26 +
 src/nwfilter/nwfilter_driver.c                |   66 +-
 src/nwfilter/nwfilter_driver_conf.c           |  210 +
 src/nwfilter/nwfilter_driver_conf.h           |   66 +
 src/nwfilter/nwfilter_ebiptables_driver.c     |  262 +-
 src/nwfilter/nwfilter_ebiptables_driver.h     |    2 +-
 src/nwfilter/nwfilter_gentech_driver.c        |   63 +-
 src/nwfilter/nwfilter_gentech_driver.h        |    5 +-
 src/nwfilter/nwfilter_nftables_driver.c       | 2374 +++++++++++
 src/nwfilter/nwfilter_nftables_driver.h       |   28 +
 src/nwfilter/nwfilter_tech_driver.c           |  249 ++
 src/nwfilter/nwfilter_tech_driver.h           |   51 +-
 src/nwfilter/test_libvirtd_nwfilter.aug.in    |    5 +
 tests/meson.build                             |    4 +-
 tests/nwfilternftablestest.c                  |  428 ++
 ...ltest.c => nwfilterxml2ebipfirewalltest.c} |    4 +-
 ...nux.args => ah-ipv6-linux.ebiptables.args} |    0
 .../ah-ipv6-linux.nftables.args               |  304 ++
 ...ah-linux.args => ah-linux.ebiptables.args} |    0
 .../ah-linux.nftables.args                    |  298 ++
 ...ux.args => all-ipv6-linux.ebiptables.args} |    0
 .../all-ipv6-linux.nftables.args              |  286 ++
 ...l-linux.args => all-linux.ebiptables.args} |    0
 .../all-linux.nftables.args                   |  280 ++
 ...p-linux.args => arp-linux.ebiptables.args} |    0
 .../arp-linux.nftables.args                   |  215 +
 .../nwfilterxml2firewalldata/arp.nftables.xml |   27 +
 ...nux.args => comment-linux.ebiptables.args} |    0
 .../comment-linux.nftables.args               |  483 +++
 ...x.args => conntrack-linux.ebiptables.args} |    0
 .../conntrack-linux.nftables.args             |  198 +
 ...ux.args => esp-ipv6-linux.ebiptables.args} |    0
 .../esp-ipv6-linux.nftables.args              |  304 ++
 ...p-linux.args => esp-linux.ebiptables.args} |    0
 .../esp-linux.nftables.args                   |  298 ++
 ...x.args => example-1-linux.ebiptables.args} |    0
 .../example-1-linux.nftables.args             |  266 ++
 ...x.args => example-2-linux.ebiptables.args} |    0
 .../example-2-linux.nftables.args             |  348 ++
 ...ux.args => hex-data-linux.ebiptables.args} |    0
 .../hex-data-linux.nftables.args              |  357 ++
 ...s => icmp-direction-linux.ebiptables.args} |    0
 .../icmp-direction-linux.nftables.args        |  238 ++
 ... => icmp-direction2-linux.ebiptables.args} |    0
 .../icmp-direction2-linux.nftables.args       |  238 ++
 ... => icmp-direction3-linux.ebiptables.args} |    0
 .../icmp-direction3-linux.nftables.args       |  184 +
 ...-linux.args => icmp-linux.ebiptables.args} |    0
 .../icmp-linux.nftables.args                  |  252 ++
 ...inux.args => icmpv6-linux.ebiptables.args} |    0
 .../icmpv6-linux.nftables.args                |  322 ++
 ...-linux.args => igmp-linux.ebiptables.args} |    0
 .../igmp-linux.nftables.args                  |  298 ++
 ...ip-linux.args => ip-linux.ebiptables.args} |    0
 .../ip-linux.nftables.args                    |  198 +
 ...linux.args => ipset-linux.ebiptables.args} |    0
 ... => ipt-no-macspoof-linux.ebiptables.args} |    0
 .../ipt-no-macspoof-linux.nftables.args       |  169 +
 ...-linux.args => ipv6-linux.ebiptables.args} |    0
 .../ipv6-linux.nftables.args                  |  474 +++
 ...linux.args => iter1-linux.ebiptables.args} |    0
 .../iter1-linux.nftables.args                 |  298 ++
 ...linux.args => iter2-linux.ebiptables.args} |    0
 .../iter2-linux.nftables.args                 | 3598 +++++++++++++++++
 ...linux.args => iter3-linux.ebiptables.args} |    0
 .../iter3-linux.nftables.args                 |  418 ++
 ...c-linux.args => mac-linux.ebiptables.args} |    0
 .../mac-linux.nftables.args                   |  180 +
 ...-linux.args => rarp-linux.ebiptables.args} |    0
 .../rarp-linux.nftables.args                  |  215 +
 ...x.args => sctp-ipv6-linux.ebiptables.args} |    0
 .../sctp-ipv6-linux.nftables.args             |  314 ++
 ...-linux.args => sctp-linux.ebiptables.args} |    0
 .../sctp-linux.nftables.args                  |  314 ++
 ...p-linux.args => stp-linux.ebiptables.args} |    0
 ...inux.args => target-linux.ebiptables.args} |    0
 .../target-linux.nftables.args                |  452 +++
 ...nux.args => target2-linux.ebiptables.args} |    0
 .../target2-linux.nftables.args               |  316 ++
 ...ux.args => tcp-ipv6-linux.ebiptables.args} |    0
 .../tcp-ipv6-linux.nftables.args              |  314 ++
 ...p-linux.args => tcp-linux.ebiptables.args} |    0
 .../tcp-linux.nftables.args                   |  468 +++
 ...ux.args => udp-ipv6-linux.ebiptables.args} |    0
 .../udp-ipv6-linux.nftables.args              |  314 ++
 ...p-linux.args => udp-linux.ebiptables.args} |    0
 .../udp-linux.nftables.args                   |  314 ++
 ...rgs => udplite-ipv6-linux.ebiptables.args} |    0
 .../udplite-ipv6-linux.nftables.args          |  304 ++
 ...nux.args => udplite-linux.ebiptables.args} |    0
 .../udplite-linux.nftables.args               |  298 ++
 ...-linux.args => vlan-linux.ebiptables.args} |    0
 .../vlan-linux.nftables.args                  |  264 ++
 tests/nwfilterxml2nftfirewalltest.c           |  438 ++
 98 files changed, 18433 insertions(+), 365 deletions(-)
 create mode 100644 src/nwfilter/libvirtd_nwfilter.aug
 create mode 100644 src/nwfilter/nwfilter.conf.in
 create mode 100644 src/nwfilter/nwfilter_driver_conf.c
 create mode 100644 src/nwfilter/nwfilter_driver_conf.h
 create mode 100644 src/nwfilter/nwfilter_nftables_driver.c
 create mode 100644 src/nwfilter/nwfilter_nftables_driver.h
 create mode 100644 src/nwfilter/nwfilter_tech_driver.c
 create mode 100644 src/nwfilter/test_libvirtd_nwfilter.aug.in
 create mode 100644 tests/nwfilternftablestest.c
 rename tests/{nwfilterxml2firewalltest.c => nwfilterxml2ebipfirewalltest.c} (99%)
 rename tests/nwfilterxml2firewalldata/{ah-ipv6-linux.args => ah-ipv6-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/ah-ipv6-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{ah-linux.args => ah-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/ah-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{all-ipv6-linux.args => all-ipv6-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/all-ipv6-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{all-linux.args => all-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/all-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{arp-linux.args => arp-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/arp-linux.nftables.args
 create mode 100644 tests/nwfilterxml2firewalldata/arp.nftables.xml
 rename tests/nwfilterxml2firewalldata/{comment-linux.args => comment-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/comment-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{conntrack-linux.args => conntrack-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/conntrack-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{esp-ipv6-linux.args => esp-ipv6-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/esp-ipv6-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{esp-linux.args => esp-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/esp-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{example-1-linux.args => example-1-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/example-1-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{example-2-linux.args => example-2-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/example-2-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{hex-data-linux.args => hex-data-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/hex-data-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{icmp-direction-linux.args => icmp-direction-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/icmp-direction-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{icmp-direction2-linux.args => icmp-direction2-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/icmp-direction2-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{icmp-direction3-linux.args => icmp-direction3-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/icmp-direction3-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{icmp-linux.args => icmp-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/icmp-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{icmpv6-linux.args => icmpv6-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/icmpv6-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{igmp-linux.args => igmp-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/igmp-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{ip-linux.args => ip-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/ip-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{ipset-linux.args => ipset-linux.ebiptables.args} (100%)
 rename tests/nwfilterxml2firewalldata/{ipt-no-macspoof-linux.args => ipt-no-macspoof-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/ipt-no-macspoof-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{ipv6-linux.args => ipv6-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/ipv6-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{iter1-linux.args => iter1-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/iter1-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{iter2-linux.args => iter2-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/iter2-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{iter3-linux.args => iter3-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/iter3-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{mac-linux.args => mac-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/mac-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{rarp-linux.args => rarp-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/rarp-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{sctp-ipv6-linux.args => sctp-ipv6-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/sctp-ipv6-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{sctp-linux.args => sctp-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/sctp-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{stp-linux.args => stp-linux.ebiptables.args} (100%)
 rename tests/nwfilterxml2firewalldata/{target-linux.args => target-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/target-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{target2-linux.args => target2-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/target2-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{tcp-ipv6-linux.args => tcp-ipv6-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/tcp-ipv6-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{tcp-linux.args => tcp-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/tcp-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{udp-ipv6-linux.args => udp-ipv6-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/udp-ipv6-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{udp-linux.args => udp-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/udp-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{udplite-ipv6-linux.args => udplite-ipv6-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/udplite-ipv6-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{udplite-linux.args => udplite-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/udplite-linux.nftables.args
 rename tests/nwfilterxml2firewalldata/{vlan-linux.args => vlan-linux.ebiptables.args} (100%)
 create mode 100755 tests/nwfilterxml2firewalldata/vlan-linux.nftables.args
 create mode 100644 tests/nwfilterxml2nftfirewalltest.c

-- 
2.43.0
Re: [PATCH v2 0/5] nwfilter: add nwfilter nftables driver
Posted by Daniel P. Berrangé via Devel 3 weeks, 1 day ago
On Thu, Dec 11, 2025 at 03:00:49PM +0100, Dion Bosschieter wrote:
> This series aims to implement nftables as a backend driver for
> the nwfilter feature. The idea is that eventually it will replace
> the ebiptables driver and provide an easy way for users to switch
> from one driver to another.
> 
> The first 2 patches are moving of functions and renames, meant to decouple
> nwfilter from the currently only existing ebiptables driver.
> 
> The 3rd patch introduces the new nwfilter driver. After which nwfilter allows
> users to choose it in the 4th patch.
> 
> The last patch introduces unit testing of the new nftables driver.
> 

> - Resolves issue https://gitlab.com/libvirt/libvirt/-/issues/603
>   benchmarks showed that the amount of iifname jumps for each
>   interface with 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.

That's good.

> - Split rules into separate tables: "libvirt-nwfilter-ethernet" and
>   "libvirt-nwfilter-other" to preserve existing firewall behavior.

> - Stuck with prerouting and postrouting as hooks for input / output
>   on the -ethernet and -other table. This makes it easier to merge
>   the tables in the future. Saving management of two tables and
>   decreasing the amount of tables a packet sees. Currently ebtables
>   filtering happens via PREROUTING and POSTROUTING hooks, while
>   ip/ip6tables filtering happens in the output/forward hooks.
> - Stuck with 2 tables for compatibility reasons with eb iptables,
>   unifying into 1 table will break users firewall definitions, which
>   depend on being able to do accepts on ethernet rules
>   (which currently get defined via ebtables) and additional filtering
>   via the ip rules (which currently get defined via ip(6)tables).
>   The nwfilter_nftables_driver keeps splitting the ethernet and
>   non ethernet (other) rules in seperate tables
>   "libvirt-nwfilter-ethernet" and "libvirt-nwfilter-other".

I guess with xtables, we would have effectively three - ebtables,
iptables and ip6tables. "other" here covers both iptables and
ip6tables which is fine because rules for those are mutually
exclusive for any single packet.  Perhaps call it "-inet" instead
of '-other'  ? 



> Unsupported nwfilter features (for now):
> - STP filtering
> - Gratuitous ARP filtering
> - IPSets (potential future support via nft sets)
> - Reject due to filtering in pre/postrouting, using drop instead
>   of reject, copying logic from existing ebiptables ebtables actions

I don't know if it is related, but when I tried this patch series
on an existing VM configured with the "clean-traffic" filter I
get a failure:


  2026-01-16 16:24:14.492+0000: 749946: error : virFirewallCmdNftablesApply:748 : internal error: Failed to apply firewall command 'nft add rule bridge libvirt-nwfilter-ethernet n-vnet0-rarp-out ether saddr == 52:54:00:5e:58:55 ether daddr == ff:ff:ff:ff:ff:ff ether type 0x8035 'arp operation' 3 arp saddr ip 0.0.0.0/32 arp daddr ip 0.0.0.0/32 'ether saddr' 52:54:00:5e:58:55 'ether daddr' 52:54:00:5e:58:55 accept comment '"priority=500"'': Error: conflicting statements


  nft add rule bridge libvirt-nwfilter-ethernet n-vnet0-rarp-out \
     ether saddr == 52:54:00:5e:58:55 \
     ether daddr == ff:ff:ff:ff:ff:ff \
     ether type 0x8035 \
     'arp operation' 3 \
     arp saddr ip 0.0.0.0/32 \
     arp daddr ip 0.0.0.0/32 \
     'ether saddr' 52:54:00:5e:58:55 \
     'ether daddr' 52:54:00:5e:58:55 \
     accept comment '"priority=500"'


We seem to have generated the MAC address matches twice resulting
in the 'conflicting statements' message.

Also those extra single quotes are a sign of a bug in passing the
args. Two nft args are being passed as a single argv element.

Interestingly that didn't seem to cause any problem, making me
think nft is munging all argv back to a single string and then
parsing it.

The following would fix it

diff --git a/src/nwfilter/nwfilter_nftables_driver.c b/src/nwfilter/nwfilter_nftables_driver.c
index 36a6c63f22..0ccb765a4e 100644
--- a/src/nwfilter/nwfilter_nftables_driver.c
+++ b/src/nwfilter/nwfilter_nftables_driver.c
@@ -460,7 +460,8 @@ insertRuleArg2Param(virFirewall *fw,
                     virNWFilterVarCombIter *vars,
                     nwItemDesc *itemLow,
                     nwItemDesc *itemHigh,
-                    const char *argument,
+                    const char *argument1,
+                    const char *argument2,
                     const char *seperator)
 {
     char field[VIR_INT64_STR_BUFLEN];
@@ -471,7 +472,8 @@ insertRuleArg2Param(virFirewall *fw,
                           field, sizeof(field),
                           itemLow) < 0)
             return -1;
-        virFirewallCmdAddArg(fw, fwrule, argument);
+        virFirewallCmdAddArg(fw, fwrule, argument1);
+        virFirewallCmdAddArg(fw, fwrule, argument2);
         if (ENTRY_WANT_NEG_SIGN(itemLow))
             virFirewallCmdAddArg(fw, fwrule, "!=");
         if (HAS_ENTRY_ITEM(itemHigh)) {
@@ -497,21 +499,15 @@ nftablesHandlePortData(virFirewall *fw,
                        portDataDef *portData,
                        bool reverseRule)
 {
-    char dport[VIR_INT64_STR_BUFLEN];
-    char sport[VIR_INT64_STR_BUFLEN];
-
-    g_snprintf(dport, sizeof(dport), reverseRule ? "%s sport" : "%s dport",
-               protocol);
-    g_snprintf(sport, sizeof(sport), reverseRule ? "%s dport": "%s sport",
-               protocol);
-
     if (insertRuleArg2Param(fw, fwrule, vars,
                             &portData->dataDstPortStart,
-                            &portData->dataDstPortEnd, dport, "-") < 0)
+                            &portData->dataDstPortEnd, protocol,
+                            reverseRule ? "sport" : "dport", "-") < 0)
         return -1;
     if (insertRuleArg2Param(fw, fwrule, vars,
                             &portData->dataSrcPortStart,
-                            &portData->dataSrcPortEnd, sport, "-") < 0)
+                            &portData->dataSrcPortEnd, protocol,
+                            reverseRule ? "dport" : "sport", "-") < 0)
         return -1;
 
     return 0;
@@ -522,7 +518,8 @@ nftablesHandleMacAddr(virFirewall *fw,
                       virFirewallCmd *fwrule,
                       virNWFilterVarCombIter *vars,
                       nwItemDesc *macaddr,
-                      const char *argument)
+                      const char *argument1,
+                      const char *argument2)
 {
     char macstr[VIR_MAC_STRING_BUFLEN];
 
@@ -532,7 +529,8 @@ nftablesHandleMacAddr(virFirewall *fw,
                           macaddr) < 0)
             return -1;
 
-        virFirewallCmdAddArg(fw, fwrule, argument);
+        virFirewallCmdAddArg(fw, fwrule, argument1);
+        virFirewallCmdAddArg(fw, fwrule, argument2);
         if (ENTRY_WANT_NEG_SIGN(macaddr))
             virFirewallCmdAddArg(fw, fwrule, "!=");
         virFirewallCmdAddArg(fw, fwrule, macstr);
@@ -547,7 +545,7 @@ nftablesHandleSrcMacAddr(virFirewall *fw,
                          virNWFilterVarCombIter *vars,
                          nwItemDesc *srcMacAddr)
 {
-    return nftablesHandleMacAddr(fw, fwrule, vars, srcMacAddr, "ether saddr");
+    return nftablesHandleMacAddr(fw, fwrule, vars, srcMacAddr, "ether", "saddr");
 }
 
 static void
@@ -893,7 +891,8 @@ insertRuleArgParam(virFirewall *fw,
                     virFirewallCmd *fwrule,
                     virNWFilterVarCombIter *vars,
                     nwItemDesc *item,
-                    const char *argument)
+                   const char *argument1,
+                   const char *argument2)
 {
     char field[VIR_INT64_STR_BUFLEN];
 
@@ -902,7 +901,8 @@ insertRuleArgParam(virFirewall *fw,
                           field, sizeof(field),
                           item) < 0)
             return -1;
-        virFirewallCmdAddArg(fw, fwrule, argument);
+        virFirewallCmdAddArg(fw, fwrule, argument1);
+        virFirewallCmdAddArg(fw, fwrule, argument2);
         if (ENTRY_WANT_NEG_SIGN(item))
             virFirewallCmdAddArg(fw, fwrule, "!=");
 
@@ -917,7 +917,8 @@ insertRuleArgParamHex(virFirewall *fw,
                       virFirewallCmd *fwrule,
                       virNWFilterVarCombIter *vars,
                       nwItemDesc *item,
-                      const char *argument)
+                      const char *argument1,
+                      const char *argument2)
 {
     char field[VIR_INT64_STR_BUFLEN];
 
@@ -926,7 +927,8 @@ insertRuleArgParamHex(virFirewall *fw,
                           field, sizeof(field),
                           item) < 0)
             return -1;
-        virFirewallCmdAddArg(fw, fwrule, argument);
+        virFirewallCmdAddArg(fw, fwrule, argument1);
+        virFirewallCmdAddArg(fw, fwrule, argument2);
         if (ENTRY_WANT_NEG_SIGN(item))
             virFirewallCmdAddArg(fw, fwrule, "!=");
 
@@ -971,7 +973,7 @@ nftablesHandleEthernetRule(virFirewall *fw,
 
         if (insertRuleArgParamHex(fw, fwrule, vars,
                                   &rule->p.ethHdrFilter.dataProtocolID,
-                                  "ether type") < 0)
+                                  "ether", "type") < 0)
             return -1;
         break;
     case VIR_NWFILTER_RULE_PROTOCOL_IP:
@@ -1031,21 +1033,21 @@ nftablesHandleEthernetRule(virFirewall *fw,
 
         if (insertRuleArgParam(fw, fwrule, vars,
                                &rule->p.ipHdrFilter.ipHdr.dataProtocolID,
-                               "ip protocol") < 0)
+                               "ip", "protocol") < 0)
             return -1;
         if (insertRuleArg2Param(fw, fwrule, vars,
                                 &rule->p.ipHdrFilter.portData.dataSrcPortStart,
                                 &rule->p.ipHdrFilter.portData.dataSrcPortEnd,
-                                reverseRule ? "th dport" : "th sport", "-") < 0)
+                                "th", reverseRule ? "dport" : "sport", "-") < 0)
             return -1;
         if (insertRuleArg2Param(fw, fwrule, vars,
                                 &rule->p.ipHdrFilter.portData.dataDstPortStart,
                                 &rule->p.ipHdrFilter.portData.dataDstPortEnd,
-                                reverseRule ? "th sport" : "th dport", "-") < 0)
+                                "th", reverseRule ? "sport" : "dport", "-") < 0)
             return -1;
         if (insertRuleArgParamHex(fw, fwrule, vars,
                                   &rule->p.ipHdrFilter.ipHdr.dataDSCP,
-                                  "ip dscp") < 0)
+                                  "ip", "dscp") < 0)
             return -1;
         break;
     case VIR_NWFILTER_RULE_PROTOCOL_ARP:
@@ -1063,15 +1065,15 @@ nftablesHandleEthernetRule(virFirewall *fw,
 
         if (insertRuleArgParam(fw, fwrule, vars,
                                &rule->p.arpHdrFilter.dataHWType,
-                               "arp htype") < 0)
+                               "arp", "htype") < 0)
             return -1;
         if (insertRuleArgParam(fw, fwrule, vars,
                                &rule->p.arpHdrFilter.dataOpcode,
-                               "arp operation") < 0)
+                               "arp", "operation") < 0)
             return -1;
         if (insertRuleArgParamHex(fw, fwrule, vars,
                                   &rule->p.arpHdrFilter.dataProtocolType,
-                                  "arp ptype") < 0)
+                                  "arp", "ptype") < 0)
             return -1;
 
         if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPSrcIPAddr)) {
@@ -1118,11 +1120,11 @@ nftablesHandleEthernetRule(virFirewall *fw,
 
         if (nftablesHandleMacAddr(fw, fwrule, vars,
                                   &rule->p.arpHdrFilter.dataARPSrcMACAddr,
-                                  reverseRule ? "ether daddr": "ether saddr") < 0)
+                                  "ether", reverseRule ? "addr": "saddr") < 0)
             return -1;
         if (nftablesHandleMacAddr(fw, fwrule, vars,
                                   &rule->p.arpHdrFilter.dataARPDstMACAddr,
-                                  reverseRule ? "ether saddr": "ether daddr") < 0)
+                                  "ether", reverseRule ? "saddr": "daddr") < 0)
             return -1;
 
         if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataGratuitousARP) &&
@@ -1187,28 +1189,28 @@ nftablesHandleEthernetRule(virFirewall *fw,
 
         if (insertRuleArgParam(fw, fwrule, vars,
                                &rule->p.ipv6HdrFilter.ipHdr.dataProtocolID,
-                               "ip6 nexthdr") < 0)
+                               "ip6", "nexthdr") < 0)
             return -1;
         if (insertRuleArg2Param(fw, fwrule, vars,
                                 &rule->p.ipv6HdrFilter.portData.dataSrcPortStart,
                                 &rule->p.ipv6HdrFilter.portData.dataSrcPortEnd,
-                                reverseRule ? "th dport" : "th sport", "-") < 0)
+                                "th", reverseRule ? "dport" : "sport", "-") < 0)
             return -1;
         if (insertRuleArg2Param(fw, fwrule, vars,
                                 &rule->p.ipv6HdrFilter.portData.dataDstPortStart,
                                 &rule->p.ipv6HdrFilter.portData.dataDstPortEnd,
-                                reverseRule ? "th sport" : "th dport", "-") < 0)
+                                "th", reverseRule ? "sport" : "dport", "-") < 0)
             return -1;
         if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPTypeStart)  ||
             HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPCodeStart)) {
 
             if (insertRuleArgParam(fw, fwrule, vars,
                                    &rule->p.ipv6HdrFilter.dataICMPTypeStart,
-                                   "icmpv6 type") < 0)
+                                   "icmpv6", "type") < 0)
                 return -1;
             if (insertRuleArgParam(fw, fwrule, vars,
                                    &rule->p.ipv6HdrFilter.dataICMPCodeStart,
-                                   "icmpv6 code") < 0)
+                                   "icmpv6", "code") < 0)
                 return -1;
         }
         break;
@@ -1222,11 +1224,11 @@ nftablesHandleEthernetRule(virFirewall *fw,
 
         if (insertRuleArgParam(fw, fwrule, vars,
                                &rule->p.vlanHdrFilter.dataVlanID,
-                               "vlan id") < 0)
+                               "vlan", "id") < 0)
             return -1;
         if (insertRuleArgParam(fw, fwrule, vars,
                                &rule->p.vlanHdrFilter.dataVlanEncap,
-                               "vlan type") < 0)
+                               "vlan", "type") < 0)
             return -1;
         break;
     case VIR_NWFILTER_RULE_PROTOCOL_STP:


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
Re: [PATCH v2 0/5] nwfilter: add nwfilter nftables driver
Posted by Daniel P. Berrangé via Devel 3 weeks, 1 day ago
On Fri, Jan 16, 2026 at 05:18:29PM +0000, Daniel P. Berrangé via Devel wrote:
> On Thu, Dec 11, 2025 at 03:00:49PM +0100, Dion Bosschieter wrote:
> > This series aims to implement nftables as a backend driver for
> > the nwfilter feature. The idea is that eventually it will replace
> > the ebiptables driver and provide an easy way for users to switch
> > from one driver to another.
> > 
> > The first 2 patches are moving of functions and renames, meant to decouple
> > nwfilter from the currently only existing ebiptables driver.
> > 
> > The 3rd patch introduces the new nwfilter driver. After which nwfilter allows
> > users to choose it in the 4th patch.
> > 
> > The last patch introduces unit testing of the new nftables driver.
> > 
> 
> > - Resolves issue https://gitlab.com/libvirt/libvirt/-/issues/603
> >   benchmarks showed that the amount of iifname jumps for each
> >   interface with 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.
> 
> That's good.
> 
> > - Split rules into separate tables: "libvirt-nwfilter-ethernet" and
> >   "libvirt-nwfilter-other" to preserve existing firewall behavior.
> 
> > - Stuck with prerouting and postrouting as hooks for input / output
> >   on the -ethernet and -other table. This makes it easier to merge
> >   the tables in the future. Saving management of two tables and
> >   decreasing the amount of tables a packet sees. Currently ebtables
> >   filtering happens via PREROUTING and POSTROUTING hooks, while
> >   ip/ip6tables filtering happens in the output/forward hooks.
> > - Stuck with 2 tables for compatibility reasons with eb iptables,
> >   unifying into 1 table will break users firewall definitions, which
> >   depend on being able to do accepts on ethernet rules
> >   (which currently get defined via ebtables) and additional filtering
> >   via the ip rules (which currently get defined via ip(6)tables).
> >   The nwfilter_nftables_driver keeps splitting the ethernet and
> >   non ethernet (other) rules in seperate tables
> >   "libvirt-nwfilter-ethernet" and "libvirt-nwfilter-other".
> 
> I guess with xtables, we would have effectively three - ebtables,
> iptables and ip6tables. "other" here covers both iptables and
> ip6tables which is fine because rules for those are mutually
> exclusive for any single packet.  Perhaps call it "-inet" instead
> of '-other'  ? 
> 
> 
> 
> > Unsupported nwfilter features (for now):
> > - STP filtering
> > - Gratuitous ARP filtering
> > - IPSets (potential future support via nft sets)
> > - Reject due to filtering in pre/postrouting, using drop instead
> >   of reject, copying logic from existing ebiptables ebtables actions
> 
> I don't know if it is related, but when I tried this patch series
> on an existing VM configured with the "clean-traffic" filter I
> get a failure:
> 
> 
>   2026-01-16 16:24:14.492+0000: 749946: error : virFirewallCmdNftablesApply:748 : internal error: Failed to apply firewall command 'nft add rule bridge libvirt-nwfilter-ethernet n-vnet0-rarp-out ether saddr == 52:54:00:5e:58:55 ether daddr == ff:ff:ff:ff:ff:ff ether type 0x8035 'arp operation' 3 arp saddr ip 0.0.0.0/32 arp daddr ip 0.0.0.0/32 'ether saddr' 52:54:00:5e:58:55 'ether daddr' 52:54:00:5e:58:55 accept comment '"priority=500"'': Error: conflicting statements

Also when this fails, the rollback code doesn't seem to work
either, as the tables get left with a bunch of stale rules


With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|