X86_64 network device naming

It's a pain to remap x86 network device names to their labeled names in OpenWrt -- for example, the on the Meraki MX100, all network ports are backed by PCIe devices, which are initialized in whatever order the machine wants them to be. The naming is consistent with itself, but inconsistent with the labeling of the device.

On platforms that boot using devicetrees, my understanding is that the device initialization process reads network device names from the device tree, which is always written to reflect the hardware, but our x86 bootloader, Grub v2.06, doesn't support device tree initialization on x86, nor would we really want it to (it'd replace ACPI).

I dug a bit into the device tree x86 analogue -- ACPI -- and found SSDTs. Unfortunately, SSDTs are not really anything like device trees -- they can help to overlay information about hardware onto the system for the Linux kernel, but are not useful for the rest of the things device trees do (making a more centralized and human-readable view of the state of the system).

So, where does that leave those of us that want device names encoded consistently?

What could be:

  • board.json currently encodes which devices belong on each default interface, through ucidef_set_interfaces_* (from /lib/functions/uci-defaults.sh).
    • For well-known x86 devices, board.json could be used to store a port name -> PCIe path mapping.

Here is a patch which solves the problem:

From 989a92758468f94214afb30504c72bf3534d4db0 Mon Sep 17 00:00:00 2001
From: Martin Kennedy <hurricos@gmail.com>
Date: Sun, 21 Aug 2022 20:37:18 -0400
Subject: [PATCH] [WIP] x86: rename ports on known boards

x86 lacks device trees with which to name network port interfaces. Use
board.json to store a mapping from ethernet port name to sysfs device
path; this allows us to reconfigure all network device names we know
about for a given board.

See also https://forum.openwrt.org/t/x86-64-network-device-naming/135154.

diff --git a/package/base-files/files/lib/functions/uci-defaults.sh b/package/base-files/files/lib/functions/uci-defaults.sh
index f96e645e73..a0d0209a65 100644
--- a/package/base-files/files/lib/functions/uci-defaults.sh
+++ b/package/base-files/files/lib/functions/uci-defaults.sh
@@ -107,13 +107,21 @@ ucidef_set_bridge_mac() {
 }
 
 ucidef_set_network_device_mac() {
-	json_select_object "network-device"
+	json_select_object "network_device"
 	json_select_object "${1}"
 	json_add_string macaddr "${2}"
 	json_select ..
 	json_select ..
 }
 
+ucidef_set_network_device_path() {
+	json_select_object "network_device"
+	json_select_object "${1}"
+	json_add_string path "${2}"
+	json_select ..
+	json_select ..
+}
+
 _ucidef_add_switch_port() {
 	# inherited: $num $device $need_tag $want_untag $role $index $prev_role
 	# inherited: $n_cpu $n_ports $n_vlan $cpu0 $cpu1 $cpu2 $cpu3 $cpu4 $cpu5
diff --git a/package/base-files/files/lib/preinit/10_indicate_preinit b/package/base-files/files/lib/preinit/10_indicate_preinit
index debb3d4480..b4b73fc3cf 100644
--- a/package/base-files/files/lib/preinit/10_indicate_preinit
+++ b/package/base-files/files/lib/preinit/10_indicate_preinit
@@ -63,6 +63,24 @@ preinit_config_switch() {
 	json_select ..
 }
 
+preinit_config_port() {
+	local original
+
+	local port=$1
+	local path=$2
+
+	[ -d "/sys/devices/$path/net" ] || return
+	original="$(ls /sys/devices/$path/net | head -1)"
+
+	[ "$port" = "$original" ] && return
+
+	if [ -h "/sys/class/net/$port" ]; then
+		ip l set $port down
+		ip l set $port name $(echo "$path" | md5sum | head -c 10)
+	fi
+	ip l set $original name $port
+}
+
 preinit_config_board() {
 	/bin/board_detect /tmp/board.json
 
@@ -73,6 +91,16 @@ preinit_config_board() {
 	json_init
 	json_load "$(cat /tmp/board.json)"
 
+	json_get_keys keys "network_device"
+	for key in $keys; do
+		json_select "network_device"
+			json_select $key
+				json_get_vars path path
+				[ -n "path" ] && preinit_config_port $key $path
+			json_select ..
+		json_select ..
+	done
+
 	json_select network
 		json_select "lan"
 			json_get_vars device
diff --git a/target/linux/x86/base-files/etc/board.d/02_network b/target/linux/x86/base-files/etc/board.d/02_network
index e4451461db..1e38b17f42 100644
--- a/target/linux/x86/base-files/etc/board.d/02_network
+++ b/target/linux/x86/base-files/etc/board.d/02_network
@@ -9,7 +9,19 @@ board_config_update
 
 case "$(board_name)" in
 cisco-mx100-hw)
-	ucidef_set_interfaces_lan_wan "eth0 eth1 eth2 eth3 eth4 eth5 eth7 eth8 eth9 eth10 eth11" "eth6"
+	ucidef_set_network_device_path "management" "pci0000:00/0000:00:01.2/0000:03:00.3"
+	ucidef_set_network_device_path "internet" "pci0000:00/0000:00:01.2/0000:03:00.2"
+	ucidef_set_network_device_path "eth2" "pci0000:00/0000:00:01.2/0000:03:00.1"
+	ucidef_set_network_device_path "eth3" "pci0000:00/0000:00:01.2/0000:03:00.0"
+	ucidef_set_network_device_path "eth4" "pci0000:00/0000:00:01.0/0000:01:00.2"
+	ucidef_set_network_device_path "eth5" "pci0000:00/0000:00:01.0/0000:01:00.1"
+	ucidef_set_network_device_path "eth6" "pci0000:00/0000:00:01.0/0000:01:00.4"
+	ucidef_set_network_device_path "eth7" "pci0000:00/0000:00:01.0/0000:01:00.3"
+	ucidef_set_network_device_path "eth8" "pci0000:00/0000:00:01.1/0000:02:00.1"
+	ucidef_set_network_device_path "eth9" "pci0000:00/0000:00:01.1/0000:02:00.0"
+	ucidef_set_network_device_path "eth10" "pci0000:00/0000:00:01.1/0000:02:00.3"
+	ucidef_set_network_device_path "eth11" "pci0000:00/0000:00:01.1/0000:02:00.2"
+	ucidef_set_interfaces_lan_wan "management eth1 eth2 eth3 eth4 eth5 eth7 eth8 eth9 eth10 eth11" "internet"
 	;;
 pc-engines-apu1|pc-engines-apu2|pc-engines-apu3)
 	ucidef_set_interfaces_lan_wan "eth1 eth2" "eth0"
-- 
2.36.1