In ebtables a subchain was created with a default accept When converted to nftables, this resulted in an "accept" at the end of each subchain: chain O-v100562794-mac { ether daddr 52:54:00:a3:13:87 counter packets 9 bytes 1145 return ether daddr 33:33:00:00:00:00/16 counter packets 48 bytes 3712 return ether daddr ff:ff:ff:ff:ff:ff counter packets 22 bytes 924 return counter packets 3 bytes 384 drop
counter packets 0 bytes 0 accept }
In order to mimick this behavior we add an "accept" for each subchain by calling nftablesCreateSubChainAccept after having created all of the fw rules Signed-off-by: Dion Bosschieter <dionbosschieter@gmail.com> --- src/nwfilter/nwfilter_nftables_driver.c | 60 +++++++++++++++++-- .../stp-linux.nftables.args | 14 +++++ 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/nwfilter/nwfilter_nftables_driver.c b/src/nwfilter/nwfilter_nftables_driver.c index a72c51472f..79bd987325 100644 --- a/src/nwfilter/nwfilter_nftables_driver.c +++ b/src/nwfilter/nwfilter_nftables_driver.c @@ -80,9 +80,9 @@ static bool trace_enabled; #define SAME_IP_SET_NAME "same-ip-set" -#define ROOT_CHAINSETTINGS(chain, defaultPolicy) \ +#define ROOT_CHAINSETTINGS(chain) \ "{ type filter hook "chain" priority %d;" \ - " policy "defaultPolicy"; %s }" + " policy "DEFAULT_POLICY"; %s }" VIR_LOG_INIT("nwfilter.nwfilter_nftables_driver"); @@ -183,12 +183,12 @@ static void nftablesCreateTable(virFirewall *fw, fwrule = virFirewallAddCmd(fw, layer, "add", "chain", "bridge", tableName, IN_CHAIN, NULL); virFirewallCmdAddArgFormat(fw, fwrule, - ROOT_CHAINSETTINGS(IN_CHAIN, DEFAULT_POLICY), + ROOT_CHAINSETTINGS(IN_CHAIN), tablePriority, traceSetting); fwrule = virFirewallAddCmd(fw, layer, "add", "chain", "bridge", tableName, OUT_CHAIN, NULL); virFirewallCmdAddArgFormat(fw, fwrule, - ROOT_CHAINSETTINGS(OUT_CHAIN, DEFAULT_POLICY), + ROOT_CHAINSETTINGS(OUT_CHAIN), tablePriority, traceSetting); /* add the one jump rule based on the vmap */ @@ -1825,7 +1825,7 @@ nftablesRuleInstCommand(virFirewall *fw, * nftablesCreateSubChain: * @fw: the firewall ruleset instance * @layer: the firewall layer - * @ifname : The name of the interface to apply the chain to + * @nftablesTableName : The name of the table to create the chain on * @chainPrefix: The prefix to put on the beginning of the name of the chain * @protoidx: Protocol id for conditional jump * @rootChain: The chain to define the jump on @@ -1871,6 +1871,41 @@ nftablesCreateSubChain(virFirewall *fw, virFirewallCmdAddArgList(fw, fwrule, "jump", chain, NULL); } +/* + * nftablesCreateSubChainAccept: + * @fw: the firewall ruleset instance + * @layer: the firewall layer + * @nftablesTableName : The name of the table to create the chain on + * @chainPrefix: The prefix to put on the beginning of the name of the chain + * @chainPostfix: The postfix to put at the end of the name of the chain + * + * To comply with what nwfilter ipebtables was doing for ethernet subchains + * we need to end with an accept on a subchain, to follow the nwfilter ipebtables logic + * on ebtables, subchains have an ACCEPT, which means, that if the end of the chain + * is reached, the packet will be accepted, not returned + * Ebtables chains look as follows if translated to nftables: + * chain O-v100562794-ipv6 { + * ether type ip6 icmpv6 type 133 counter packets 0 bytes 0 drop + * ether type ip6 ether type ip6 meta l4proto ipv6-icmp counter packets 54 bytes 4368 accept + * ether type ip6 ip6 daddr 2a01:7c8:fffe:3::/64 counter packets 0 bytes 0 accept + * counter packets 3 bytes 489 accept + * } + * + * The accept at the bottom has not been provided by the user, it got added by translating ebtables to nftables + */ +static void nftablesCreateSubChainAccept(virFirewall *fw, + virFirewallLayer layer, + const char *nftablesTableName, + const char *chainPrefix, + const char *chainPostfix) +{ + char chain[MAX_NF_CHAINNAME_LENGTH]; + g_snprintf(chain, sizeof(chain), "%s-%s", chainPrefix, chainPostfix); + + virFirewallAddCmd(fw, layer, "add", "rule", "bridge", + nftablesTableName, chain, "accept", NULL); +} + static void nftablesCreateRootChainJump(virFirewall *fw, virFirewallLayer layer, @@ -2165,6 +2200,21 @@ nftablesHandleCreateChains(virFirewall *fw, goto cleanup; } + /* create subchain accepts */ + /* to comply with what nwfilter ipebtables was doing for ethernet subchains + * we need to finally accept on a subchain, to follow the nwfilter ipebtables logic + * on ebtables, subchains have an ACCEPT, which means, that if the end of the chain + * is reached, the packet will be accepted, not returned + */ + for (i = 0; i < nchains; i++) { + if (chains[i]->ethernetInChain) + nftablesCreateSubChainAccept(fw, layer, NF_ETHERNET_TABLE, + chains[i]->prefix, "in"); + if (chains[i]->ethernetOutChain) + nftablesCreateSubChainAccept(fw, layer, NF_ETHERNET_TABLE, + chains[i]->prefix, "out"); + } + /* creation of temp jumps is done as libvirt doesn't execute * atomic nft changes (yet) */ nftablesCreateRootChainJump(fw, layer, cbdata->ifname, IN_IFMATCH, diff --git a/tests/nwfilterxml2firewalldata/stp-linux.nftables.args b/tests/nwfilterxml2firewalldata/stp-linux.nftables.args index 4dabd3cbc2..85ee588a16 100644 --- a/tests/nwfilterxml2firewalldata/stp-linux.nftables.args +++ b/tests/nwfilterxml2firewalldata/stp-linux.nftables.args @@ -111,6 +111,20 @@ nft \ add \ rule \ bridge \ +libvirt_nwfilter_ethernet \ +n-vnet0-stp-xyz-in \ +accept +nft \ +add \ +rule \ +bridge \ +libvirt_nwfilter_ethernet \ +n-vnet0-stp-xyz-out \ +accept +nft \ +add \ +rule \ +bridge \ libvirt_nwfilter_inet \ postrouting \ oif \ -- 2.53.0