Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/etc/udev/rules.d/63-hyperv-vf-net.rules
Original file line number Diff line number Diff line change
@@ -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"
18 changes: 18 additions & 0 deletions src/etc/udev/rules.d/65-vyos-net.rules
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
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"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
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"

Expand Down
13 changes: 13 additions & 0 deletions src/system/vyos-net-name-resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}
Expand All @@ -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:
Expand Down
88 changes: 88 additions & 0 deletions src/udev/vyos_vf_name
Original file line number Diff line number Diff line change
@@ -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
Comment thread
coderabbitai[bot] marked this conversation as resolved.
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}"
Loading