如何不依赖CLI工具通用获取网卡bus-info?含Go实现需求
通用获取网卡bus-info的方法(Go实现优先)
核心思路
兼容物理机(PM)和虚拟机(VM)环境,优先通过sysfs读取(无外部依赖),失败后降级调用系统工具:
- 先尝试读取网卡设备的
uevent文件,提取PCI_SLOT_NAME字段(物理机直接可用); - 若
uevent无对应字段,解析网卡设备目录的真实路径,提取其中符合PCI总线格式的段; - 若上述方法都失败,调用
ethtool命令解析输出(需系统预装ethtool)。
Go语言实现代码
package main import ( "bufio" "fmt" "os" "os/exec" "path/filepath" "regexp" "strings" ) // GetBusInfo 获取指定网卡的bus-info func GetBusInfo(iface string) (string, error) { // 步骤1:读取uevent文件的PCI_SLOT_NAME ueventPath := fmt.Sprintf("/sys/class/net/%s/device/uevent", iface) file, err := os.Open(ueventPath) if err == nil { defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() if strings.HasPrefix(line, "PCI_SLOT_NAME=") { return strings.TrimPrefix(line, "PCI_SLOT_NAME="), nil } } if err := scanner.Err(); err != nil { return "", err } } // 步骤2:解析device目录的真实路径,提取PCI总线信息 devicePath := fmt.Sprintf("/sys/class/net/%s/device", iface) realDevicePath, err := filepath.EvalSymlinks(devicePath) if err != nil { return "", err } // 匹配PCI总线格式:xxxx:xx:xx.x pciRegex := regexp.MustCompile(`[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}\.[0-9a-fA-F]`) matches := pciRegex.FindStringSubmatch(realDevicePath) if len(matches) > 0 { return matches[0], nil } // 步骤3:降级调用ethtool命令 cmd := exec.Command("ethtool", "-i", iface) output, err := cmd.Output() if err != nil { return "", fmt.Errorf("ethtool failed: %w", err) } scanner := bufio.NewScanner(strings.NewReader(string(output))) for scanner.Scan() { line := scanner.Text() if strings.HasPrefix(line, "bus-info:") { return strings.TrimSpace(strings.TrimPrefix(line, "bus-info:")), nil } } if err := scanner.Err(); err != nil { return "", err } return "", fmt.Errorf("failed to get bus-info for interface %s", iface) } func main() { if len(os.Args) != 2 { fmt.Printf("Usage: %s <interface>\n", os.Args[0]) os.Exit(1) } busInfo, err := GetBusInfo(os.Args[1]) if err != nil { fmt.Printf("Error: %v\n", err) os.Exit(1) } fmt.Printf("Bus-info for %s: %s\n", os.Args[1], busInfo) }
代码说明
- sysfs读取:直接访问Linux内核暴露的sysfs文件系统,无外部依赖,效率最高;
- 路径解析:利用
filepath.EvalSymlinks获取真实路径,通过正则匹配PCI总线格式,兼容VM环境下的多层路径; - ethtool降级:作为兜底方案,覆盖极少数特殊环境。
sysfs路径差异的原因
物理机和虚拟机的网卡sysfs路径差异,本质是设备虚拟化层的存在:
- 物理机:网卡是直接挂载在PCI总线下的物理设备,sysfs路径为
/sys/devices/pci<domain>:<bus>/<slot>:<func>.<dev>/net/<iface>,PCI总线信息直接位于net目录的父节点; - 虚拟机:网卡是虚拟化设备(如virtio、vmxnet3),这类设备会先映射为虚拟机内部的虚拟PCI设备,再通过虚拟化驱动(如virtio-net)暴露为网卡接口,因此sysfs路径多了一层虚拟化设备节点,比如
/sys/devices/pci<domain>:<bus>/<slot>:<func>.<dev>/virtio<X>/net/<iface>,PCI总线信息位于虚拟化节点的父节点。
这种差异是Linux内核对不同类型设备的sysfs组织规则导致的——物理设备直接关联总线,虚拟化设备则需要通过中间层关联到宿主机的物理设备。
内容的提问来源于stack exchange,提问作者DesistDaydream
相关产品推荐
相关产品推荐

