Bug 2064412

Summary: altname interface property not recognized within ifname datatype
Product: Red Hat Enterprise Linux 9 Reporter: Tomas Dolezal <todoleza>
Component: nftablesAssignee: Phil Sutter <psutter>
Status: ASSIGNED --- QA Contact: qe-baseos-daemons
Severity: medium Docs Contact:
Priority: unspecified    
Version: 9.0CC: todoleza
Target Milestone: rc   
Target Release: ---   
Hardware: Unspecified   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of:
: 2064414 2064419 (view as bug list) Environment:
Last Closed: Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 2064419    

Description Tomas Dolezal 2022-03-15 18:54:22 UTC
Description of problem:
kernel allows use of so-called altname(s) property for interfaces that is different to actual interface name. nftables (and iptables-nft) do not recognize altnames in rules, they simply never match.
There is no documentation of this ifname limitation in nft(8) nor iptables(8) manpages.

nftables affected:
iifname / oifname

iptables-nft affected:
--in-interface / --out-interface

Version-Release number of selected component (if applicable):
kernel-5.14.0-70.1.1.el9.x86_64
nftables-0.9.8-12.el9.x86_64
iptables-nft-1.8.7-28.el9.x86_64

How reproducible:
always

Steps to Reproduce:
test.sh:
#!/bin/bash

DEFAULT_IFACE="$(ip route list default | sed -ne '1 {s/^.*dev //; s/ .*// }; p')"
ALT_IFACE="enother"

ip link property add $DEFAULT_IFACE altname $ALT_IFACE
nft -f - <<EOF
flush ruleset
table ip filter {
	chain OUTPUT {
		type filter hook output priority filter; policy accept;
		oifname "$ALT_IFACE" counter
		oifname "$DEFAULT_IFACE" counter
	}
}
EOF

ping -w 1 -c 4 192.0.2.42

nft list ruleset
iptables -L -v -n

ip link property del $DEFAULT_IFACE altname $ALT_IFACE

echo finished!

Actual results:
zero counter for altname interface (enother)
./test.sh 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether fa:16:3e:04:ed:04 brd ff:ff:ff:ff:ff:ff
    altname enp0s3
    altname ens3
    altname enother
PING 192.0.2.42 (192.0.2.42) 56(84) bytes of data.

--- 192.0.2.42 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

table ip filter {
	chain OUTPUT {
		type filter hook output priority filter; policy accept;
		oifname "enother" counter packets 0 bytes 0
		oifname "eth0" counter packets 8 bytes 1108
	}
}
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0            all  --  *      enother  0.0.0.0/0            0.0.0.0/0           
   12  1492            all  --  *      eth0    0.0.0.0/0            0.0.0.0/0           
finished!

Expected results:
documentation updated for both components or issue overcome/fixed.

Additional info:
$ nft describe ifname
datatype ifname (network interface name) (basetype string), 128 bits
$ nft describe iifname
meta expression, datatype ifname (network interface name) (basetype string), 16 characters

Comment 1 Phil Sutter 2022-05-31 11:20:19 UTC
Supporting this is a bit problematic:

In kernel, altnames are organized in a list struct net_device::name_node::list
points at.

Standard 'meta iifname' merely copies the struct net_device::name value into
destination register for a following 'cmp' expression to compare it against
user-provided value.

We obviously can't follow this approach with altnames but instead will have to
perform an "opposite direction" lookup of user-provided value in the
interface's altname list.

Maybe one could turn meta+cmp expressions into a statement "under the hood" to
perform the lookup, thereby allowing free choice of real- or altname when
matching on interface names.

Comment 2 Phil Sutter 2022-05-31 17:37:00 UTC
Adding to my previous comment:

Something like 'meta iifname { "eth0", "eth1" }' might still work as "hidden"
statement, but e.g. 'mark set meta iifname map { "eth0" : 1, "eth1" : 2 }'
probably kills it.