From 71d1089184fdb570c9e65fac09ee3e63a71e371f Mon Sep 17 00:00:00 2001 From: Peter Sprygada Date: Mon, 12 Oct 2026 20:16:29 -0400 Subject: [PATCH] fix(xdp): Skip bonding_masters when selecting the XDP mode galactic-gateway and galactic-nat crashloop at startup on every bonded edge host since #852: xdpmode: read device of bonding_masters: lstat /sys/class/net/bonding_masters/device: not a directory Select walks every entry in /sys/class/net. With the bonding module loaded, bonding_masters is a regular file there, so the Lstat of its device link fails with ENOTDIR, which interfaceDriver treats as fatal. Select now skips regular files; every interface in sysfs is a symlink. The test fixture adds bonding_masters to the bonded-host cases, which fail with the same error without this change. Related to #673 --- internal/plumbing/ebpf/xdpmode/mode.go | 6 +++++- internal/plumbing/ebpf/xdpmode/mode_test.go | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/internal/plumbing/ebpf/xdpmode/mode.go b/internal/plumbing/ebpf/xdpmode/mode.go index 4fa614d8..74f93414 100644 --- a/internal/plumbing/ebpf/xdpmode/mode.go +++ b/internal/plumbing/ebpf/xdpmode/mode.go @@ -116,7 +116,8 @@ var sysClassNet = "/sys/class/net" // target and has no driver link at all, as while its driver unbinds, carries // no driver traffic; it is left out and listed in Skipped. An interface with // no device link, such as a bond master, a veth or a VLAN, is virtual and has -// no driver of its own to consider. +// no driver of its own to consider. A regular file, such as the bonding +// driver's bonding_masters, is not an interface. func Select(required ...string) (Decision, error) { entries, err := os.ReadDir(sysClassNet) if err != nil { @@ -129,6 +130,9 @@ func Select(required ...string) (Decision, error) { skipped []string ) for _, e := range entries { + if e.Type().IsRegular() { + continue + } name := e.Name() present[name] = true driver, physical, err := interfaceDriver(name) diff --git a/internal/plumbing/ebpf/xdpmode/mode_test.go b/internal/plumbing/ebpf/xdpmode/mode_test.go index 247a4861..3d554264 100644 --- a/internal/plumbing/ebpf/xdpmode/mode_test.go +++ b/internal/plumbing/ebpf/xdpmode/mode_test.go @@ -82,6 +82,15 @@ func (f *fakeSysfs) virtual(name string) { } } +// file adds a regular file, the way the bonding driver adds bonding_masters +// beside the interfaces. +func (f *fakeSysfs) file(name string) { + f.t.Helper() + if err := os.WriteFile(filepath.Join(sysClassNet, name), []byte("bond0 bond1\n"), 0o644); err != nil { + f.t.Fatal(err) + } +} + func TestSelect(t *testing.T) { tests := []struct { name string @@ -97,6 +106,7 @@ func TestSelect(t *testing.T) { f.physical(testNIC2, "ice") f.virtual("lo") f.virtual("bond0") + f.file("bonding_masters") }, required: []string{testNIC1, testNIC2}, want: Native, @@ -107,6 +117,7 @@ func TestSelect(t *testing.T) { f.physical("ens1f0np0", "bnxt_en") f.physical("ens3f0np0", "bnxt_en") f.virtual("bond1") + f.file("bonding_masters") }, required: []string{"ens1f0np0", "ens3f0np0"}, want: Generic,