What is the different between "iifname" and "iif" in nftables?
Solution 1:
iif
looks up and compares the interface index of the received packet, while iifname
does string comparison with the interface name. Both have advantages and drawbacks.
So iif
is using less ressources, because the interface index is a simple number already stored in the packet traversing the network stack and nftables and thus immediately available for comparison. But its drawback is that if the interface is deleted (and most probably recreated, but with a newer index value), then the corresponding rule in nftables won't match anymore. The only garanteed interface index at all times is the loopback interface (named lo
by default): it's always the first created in the namespace and can't be deleted (nor added a second time), so its index value is always 1
.
iifname
on the other hand, just like iptables' --in-interface
does a string comparison with the current interface's name. This uses more ressources, but allows to create a rule for a non-existing interface, in advance, with a deterministic name, which iif
won't do easily. iifname
can also do wildcard match, like in iifname "ppp*"
, which iif
can't do and can be handy when interfaces get created and deleted often, but keeping a naming convention (like starting with ppp
for PPP links).
Example (using nftables 0.9.2):
$ unshare -r -n
# ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# nft add table ip filter
# nft add chain ip filter input '{ type filter hook input priority 0; policy accept; }'
# nft add rule ip filter input iif lo counter
# nft add rule ip filter input iif dummy0 counter
Error: Interface does not exist
add rule ip filter input iif dummy0 counter
^^^^^^
# nft add rule ip filter input iifname dummy0 counter
# ip link add name dummy0 type dummy
# ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 4a:09:68:3a:34:91 brd ff:ff:ff:ff:ff:ff
# nft add rule ip filter input iif dummy0 counter
# nft list ruleset
table ip filter {
chain input {
type filter hook input priority filter; policy accept;
iif "lo" counter packets 0 bytes 0
iifname "dummy0" counter packets 0 bytes 0
iif "dummy0" counter packets 0 bytes 0
}
}
# ip link delete dev dummy0
# nft list ruleset
table ip filter {
chain input {
type filter hook input priority filter; policy accept;
iif "lo" counter packets 0 bytes 0
iifname "dummy0" counter packets 0 bytes 0
iif 2 counter packets 0 bytes 0
}
}
The interface being gone, its index value is displayed instead. Likewise, an index value can be used, even in advance, when adding a rule:
# nft add rule ip filter input iif 3 counter
# nft list ruleset
table ip filter {
chain input {
type filter hook input priority filter; policy accept;
iif "lo" counter packets 0 bytes 0
iifname "dummy0" counter packets 0 bytes 0
iif 2 counter packets 0 bytes 0
iif 3 counter packets 0 bytes 0
}
}
# ip link add name dummy4 type dummy
# ip link add name dummy0 type dummy
# nft list ruleset
table ip filter {
chain input {
type filter hook input priority filter; policy accept;
iif "lo" counter packets 0 bytes 0
iifname "dummy0" counter packets 0 bytes 0
iif 2 counter packets 0 bytes 0
iif "dummy4" counter packets 0 bytes 0
}
}
Because interface index values are not recycled within the namespace but only increasing, the rule about index 2 is "lost" (it will never have a chance to match anymore). The next created interface, dummy4 got assigned index 3, which now resolves into dummy4
in the ruleset. dummy0 received index value 4, which is not referenced in any iif
rule but will still match with the iifname
rule.
What is recommended?
My advice:
You should use iif
for "stable" interfaces that won't change once created, like physical ethernet interfaces available at boot, before the rule is applied (if using the newer physical interface stable naming convention, that won't change if enumeration order changes), and of course the lo interface. It wasn't shown in the example, but you can still match a list of interfaces with iif
too, like iif { lo, dummy4 }
. So you still can have a single iif
statement matching multiple interfaces.
You should use iifname
for dynamic interfaces not known at boot (and at rules creation) but expected to appear later, or to match a group of interfaces with a naming convention when using a wildcard match.
Not very known, to optimize, instead of using wildcards, you could assign a group to each newly created interface, (eg using ip link set dev interface group 99
) and then match the interface group with iifgroup
rather than iifname
+ wildcard. But this requires some extra mechanism to group tag newly created interfaces.
You can also use interface named sets, thus keeping generic rules using iif
and iifname
and changing the contents of the named sets, rather than the rules themselves. Note that the previous wiki link doesn't tell about using interfaces in sets, but it's simply not up to date. More informations about this in my UL SE answer to this question: How do I create a named set of strings in nftables (for interface names)?.
Solution 2:
This is not an answer, just a comment on a previous answer. (My bad reputation won't let me comment.)
But this requires some extra mechanism to group tag newly created interfaces.
I use systemd-networkd
to do this^^^. It has a [Link]
section where you can set the interface group for each interface. (This is the [Link]
section read from .network
files by systemd-networkd
, not the [Link]
section read from .link
files by systemd-udevd
.)
So I'd set something like this in /etc/systemd/network/something.network
…
[Match]
MACAddress=my:in:te:rf:ac:e0
...
[Link]
Group=99
...
…and then ip link show group 99
can be used to check that interfaces are (indeed) tagged correctly. (Those without a group are in group 0
.) (Also ip link show
prints the group numbers.)
This makes it possible to use iifgroup
and oifgroup
in nftables.conf
.