In nftables, both iifname
and iif
are meta expressions used for matching incoming network interfaces, but they operate at different levels of abstraction with distinct performance characteristics.
# iifname matches interface by name (string comparison)
iifname "eth0" accept
# iif matches interface by index (numeric comparison)
iif 2 accept
The primary technical distinctions:
iifname
performs string matching against the interface nameiif
uses the kernel's internal interface index (ifindex)iif
is generally faster as it avoids string comparisonsiifname
is more readable but potentially slower
Benchmarks show iif
can be 10-15% faster in high-throughput scenarios. This becomes significant when processing millions of packets per second. However, the difference is negligible for most use cases.
# Using iif with dynamic interfaces requires special handling
meta iif "ppp0" counter comment "This WON'T work - ppp0 might get new ifindex"
# Better approach for dynamic interfaces
define ppp_iface = "ppp0"
iifname $ppp_iface counter
Use iif
when:
- Working with static interfaces
- Performance is critical
- Ruleset is machine-generated
Prefer iifname
when:
- Dealing with dynamic interfaces (VPNs, PPP, etc.)
- Human readability is important
- Writing temporary debug rules
# Mixed approach combining both methods
define trusted_ifaces = { "eth0", "eth1" }
table inet filter {
chain input {
type filter hook input priority 0;
# Fast path for known static interfaces
iif { 2, 3 } accept comment "eth0 and eth1 by ifindex";
# Fallback to string matching for others
iifname $trusted_ifaces accept;
# Reject everything else
counter reject with icmp type host-unreachable
}
}
The fundamental difference between iif
and iifname
in nftables lies in how they reference network interfaces:
iifname "eth0" # String-based interface name matching
iif 2 # Numeric interface index matching
For optimal packet filtering performance:
iif
uses kernel-level interface indexes (faster resolution)iifname
requires string comparison (slightly more overhead)
When to use iifname
# Match traffic coming from specific interface names
iifname { "eth0", "wlan0" } accept
When to use iif
# First find interface index:
$ ip link show eth0 | grep -oP '(?<=eth0: <).*(?=>)'
# Then use in nftables:
iif 2 accept
Important behavioral differences:
iif
remains valid even if interface name changesiifname
breaks if interfaces are renamediif
persists across interface restarts (same index)
For most use cases, iifname
provides better readability and maintainability. Reserve iif
for:
- Performance-critical rulesets
- Dynamic interface environments
- Cases where interface names may change
Combining both approaches for maximum flexibility:
table inet filter {
set dynamic_ifaces {
type ifname
elements = { "eth0", "ppp0" }
}
chain input {
# Static interfaces by name
iifname { "lo", "vpn0" } accept
# Dynamic interface set
iifname @dynamic_ifaces accept
# Fallback to index for critical path
iif 2 tcp dport 22 accept
}
}
To debug interface matching issues:
nft --debug=netlink add rule inet filter input iif eth0 counter
nft monitor trace
This reveals whether the kernel is properly resolving interface references.