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:
iifnameperforms string matching against the interface nameiifuses the kernel's internal interface index (ifindex)iifis generally faster as it avoids string comparisonsiifnameis 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:
iifuses kernel-level interface indexes (faster resolution)iifnamerequires 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:
iifremains valid even if interface name changesiifnamebreaks if interfaces are renamediifpersists 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.