Unfortunately I cant get it to accept the xtables (it occasionally happens but I reboot node and insert the iptables rules (from a file) and most of the time it doesnt work.
So I have looked at the code in
lxd/firewall/firewall_load.go
line 14 it checks if there is any issues with nft (via compat function) and if not it then on line 23 does an xtables compatible check running the Compat function
looking the the xtables driver the first thing it does is check if the iptables command is an nft shim and if so fails back therefore creating xtables rules wont work if your iptables command is an nft shim.
So to be honest I have no idea how it decided a couple of times to actually not use the nftables as iptables has always been a shim.
So improved detection for inserting a chain similar to what I entered is needed. I think it might be wise to include a flag to force one mode or the other as that would allow people to work around edge cases without the need to get new code changes inserted.
Im not a Go developer so not sure how to add switches to force this but I have made some changes to the drivers_nftables.go file to detect this edge case
func (d Nftables) Compat() (bool, error) {
// Get the kernel version.
uname, err := shared.Uname()
if err != nil {
return false, err
}
uname, er := shared.Uname()
if er != nil {
return false, er
}
the last 4 lines are new and used to run command but not loose previous error message
_, err = shared.RunCommandCLocale("nft", "create", "table", testTable)
if err != nil {
return false, fmt.Errorf("Failed to create a test table: %w", err)
}
// nft add rule inet testable5 prert.test ip saddr 192.168.24.0/24 ip daddr != 192.168.24.0/24 masquerade
_, err = shared.RunCommandCLocale("nft", "create", "table", "inet", testTable)
if err != nil {
return false, fmt.Errorf("Failed to create an inet test table: %w", err)
}
_, err = shared.RunCommandCLocale("nft", "add", "chain", "inet", testTable, "prert.test")
if err != nil {
return false, fmt.Errorf("Failed to create an inet test chain in table: %w", err)
}
_, err = shared.RunCommandCLocale("nft", "add", "rule", "inet", testTable, "prert.test", "ip", "saddr", "192.168.24.0/24", "ip", "daddr", "!=", "192.168.24.0/24", "masquerade")
if err != nil {
_, er = shared.RunCommandCLocale("nft", "delete", "chain", "inet", testTable, "prert.test")
_, er = shared.RunCommandCLocale("nft", "delete", "table", "inet", testTable)
_, er = shared.RunCommandCLocale("nft", "delete", "table", testTable)
return false, fmt.Errorf("Failed to create an inet test chain rule in table: %w", err)
}
_, err = shared.RunCommandCLocale("nft", "delete", "table", testTable)
if err != nil {
return false, fmt.Errorf("Failed to delete a test table: %w", err)
}
between the 2 existing tests I have added a new one (I cannot run the new lxd on the good server due to production but I did test the nft command failed on the 5.2.0 kernel without inet support in nftables, but sucessfully runs on a 5.15.x kernel so I assume its a good check and fails due to lack of inet support
the test I have added was very similar to what lxd itself inserts upon doing nat with nftables
With these changes my system doesnt automatically just use the nftables (as if nftables works and iptables uses the shim modules then logic to me says it will allways select nftables)
Simon