summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Estabrook <jestabro@vyos.io>2026-08-20 09:24:38 -0500
committerGitHub <noreply@github.com>2026-08-20 09:24:38 -0500
commitb30ccbf4a5fdcc2240664d9b6d3814c90f7b1868 (patch)
treef893994eb0116893021d272705dd65231c11a186 /src
parent79e70fbfe0c4b5b33c5c707f0b0fee904fedd79f (diff)
parenta1360d645df8a82cd593d55ca592a8a1d60b34b3 (diff)
downloadvyos-1x-b30ccbf4a5fdcc2240664d9b6d3814c90f7b1868.tar.gz
vyos-1x-b30ccbf4a5fdcc2240664d9b6d3814c90f7b1868.zip
Merge pull request #5338 from ritika0313/T8329-azure-interface-naming-fix
T8329: Fix interface naming for Azure VF interfaces with Accelerated Networking enabled
Diffstat (limited to 'src')
-rw-r--r--src/etc/udev/rules.d/63-hyperv-vf-net.rules6
-rw-r--r--src/etc/udev/rules.d/65-vyos-net.rules18
-rwxr-xr-xsrc/system/vyos-net-name-resolve.py13
-rwxr-xr-xsrc/udev/vyos_vf_name88
4 files changed, 124 insertions, 1 deletions
diff --git a/src/etc/udev/rules.d/63-hyperv-vf-net.rules b/src/etc/udev/rules.d/63-hyperv-vf-net.rules
index b4dcb5a39..e5ecb4ede 100644
--- a/src/etc/udev/rules.d/63-hyperv-vf-net.rules
+++ b/src/etc/udev/rules.d/63-hyperv-vf-net.rules
@@ -1,5 +1,9 @@
ATTR{[dmi/id]sys_vendor}!="Microsoft Corporation", GOTO="end_hyperv_nic"
-ACTION=="add", SUBSYSTEM=="net", DRIVERS=="hv_pci", NAME="vf_%k"
+# Primary rename path for Azure VF.
+# Use helper-based naming so the VFs that reuse eth0,eth1,.. names do not
+# collide with already assigned vf_ethN names. Also, prevent renaming of
+# the interfaces already renamed to vf_ethN
+ACTION=="add", SUBSYSTEM=="net", DRIVERS=="hv_pci", KERNEL=="eth*", PROGRAM="vyos_vf_name %k", NAME="%c"
LABEL="end_hyperv_nic"
diff --git a/src/etc/udev/rules.d/65-vyos-net.rules b/src/etc/udev/rules.d/65-vyos-net.rules
index 32ae352de..0e7567cf8 100644
--- a/src/etc/udev/rules.d/65-vyos-net.rules
+++ b/src/etc/udev/rules.d/65-vyos-net.rules
@@ -4,6 +4,24 @@
ACTION!="add", GOTO="vyos_net_end"
SUBSYSTEM!="net", GOTO="vyos_net_end"
+# Fallback path for Azure VF interfaces: if a VF still appears as plain ethN,
+# rename it to vf_ethX before persistent synthetic interface naming runs to
+# prevent it from incorrectly being considered as a synthetic interface.
+ATTR{[dmi/id]sys_vendor}=="Microsoft Corporation", DRIVERS=="mlx*_core", KERNEL=="eth*", PROGRAM="vyos_vf_name %k", NAME="%c", GOTO="vyos_net_end"
+ATTR{[dmi/id]sys_vendor}=="Microsoft Corporation", DRIVERS=="mana", KERNEL=="eth*", PROGRAM="vyos_vf_name %k", NAME="%c", GOTO="vyos_net_end"
+
+# VF interfaces are not handled by vyos_net_name, so skip them.
+# KERNEL=="vf_*" catches already-renamed Mellanox and MANA VFs.
+# DRIVERS=="mlx*_core" and DRIVERS=="mana" on Azure catch VF interfaces
+# in an unexpected intermediate state (still named ethN/eN) that must not
+# be remapped by vyos_net_name.
+# This guard is intentionally scoped to Microsoft Azure to
+# avoid excluding bare-metal Mellanox NICs on physical hardware, which do
+# need persistent naming via vyos_net_name.
+KERNEL=="vf_*", GOTO="vyos_net_end"
+ATTR{[dmi/id]sys_vendor}=="Microsoft Corporation", DRIVERS=="mlx*_core", GOTO="vyos_net_end"
+ATTR{[dmi/id]sys_vendor}=="Microsoft Corporation", DRIVERS=="mana", GOTO="vyos_net_end"
+
# Do name change for ethernet and wireless devices only
KERNEL!="eth*|wlan*|e*", GOTO="vyos_net_end"
diff --git a/src/system/vyos-net-name-resolve.py b/src/system/vyos-net-name-resolve.py
index ca8ce02ea..5b1f36533 100755
--- a/src/system/vyos-net-name-resolve.py
+++ b/src/system/vyos-net-name-resolve.py
@@ -178,6 +178,11 @@ def discover_physical_interfaces(sys_class_net: str = '/sys/class/net') -> dict:
"""Return {kernel_name: mac} for every interface backed by a real bus
device - excludes lo, bridges, bonds, VLANs, veth, tunnels, etc.
+ Also excludes interfaces enslaved to another netdev (master symlink
+ present), which covers Azure VF datapath interfaces bound under their
+ synthetic parent. Those are acceleration children, not independent
+ primary interfaces, and must not be candidates for hw-id naming.
+
sys_class_net is overridable for testing against a fake sysfs tree.
"""
interfaces = {}
@@ -187,6 +192,14 @@ def discover_physical_interfaces(sys_class_net: str = '/sys/class/net') -> dict:
for entry in net_dir.iterdir():
if not (entry / 'device').exists():
+ logger.debug(
+ f"skipping '{entry.name}': no backing device in sysfs"
+ )
+ continue
+ if (entry / 'master').exists():
+ logger.debug(
+ f"skipping '{entry.name}': interface is enslaved via master link"
+ )
continue
mac = get_permanent_mac(entry.name, sys_class_net)
if mac:
diff --git a/src/udev/vyos_vf_name b/src/udev/vyos_vf_name
new file mode 100755
index 000000000..bd6c9d0cd
--- /dev/null
+++ b/src/udev/vyos_vf_name
@@ -0,0 +1,88 @@
+#!/bin/sh
+# vyos_vf_name - pick a non-colliding VF interface name.
+# Called by udev rules for VF devices that still have plain ethN names.
+#
+# Written as a POSIX shell script so it works in both initramfs (no Python3)
+# and the normal rootfs udev context.
+#
+# Usage: vyos_vf_name <current_ifname>
+# Prints the target vf_ethN name to stdout.
+
+set -e
+
+if [ -z "$1" ]; then
+ exit 1
+fi
+
+IFNAME="$1"
+LOCK_DIR="/run/udev"
+LOCK_PATH="${LOCK_DIR}/vyos_vf_name.lock"
+
+# Already normalized - return as-is.
+case "$IFNAME" in
+ vf_*)
+ echo "$IFNAME"
+ exit 0
+ ;;
+esac
+
+mkdir -p "$LOCK_DIR"
+
+# Acquire a lock to avoid race conditions when multiple VF devices are being
+# renamed concurrently.
+LOCK_ACQUIRED=0
+I=0
+while [ "$I" -lt 200 ]; do
+ if mkdir "$LOCK_PATH" 2>/dev/null; then
+ LOCK_ACQUIRED=1
+ break
+ fi
+ I=$((I + 1))
+ sleep 0.01
+done
+
+[ "$LOCK_ACQUIRED" -eq 1 ] || exit 1
+
+cleanup() {
+ rmdir "$LOCK_PATH" 2>/dev/null || true
+}
+trap cleanup EXIT INT TERM
+
+# Preferred: preserve the original ethN index when vf_ethN is not yet taken.
+case "$IFNAME" in
+ eth*)
+ PREFERRED="${IFNAME#eth}"
+ # Validate it is a pure integer.
+ case "$PREFERRED" in
+ *[!0-9]*)
+ ;;
+ *)
+ if ! [ -d "/sys/class/net/vf_eth${PREFERRED}" ]; then
+ echo "vf_eth${PREFERRED}"
+ exit 0
+ fi
+ ;;
+ esac
+ ;;
+esac
+
+# Fallback: allocate just above the highest ethN synthetic index present to
+# avoid collisions.
+MAX=-1
+for D in /sys/class/net/eth*; do
+ [ -d "$D" ] || continue
+ N="${D##*/eth}"
+ # Skip if not a pure integer (e.g. no match expands to literal path).
+ case "$N" in *[!0-9]*) continue;; esac
+ [ "$N" -gt "$MAX" ] && MAX="$N"
+done
+
+IDX=$((MAX + 1))
+[ "$IDX" -lt 0 ] && IDX=0
+
+# Skip any indices already occupied by existing vf_ethN interfaces.
+while [ -d "/sys/class/net/vf_eth${IDX}" ]; do
+ IDX=$((IDX + 1))
+done
+
+echo "vf_eth${IDX}"