fix(host): usb device passthrough use hostport (#24708)

This commit is contained in:
wanyaoqi
2026-04-23 13:52:49 +08:00
committed by GitHub
parent 7e5f5cff5e
commit 52bbe7c9a7
4 changed files with 77 additions and 8 deletions
+1 -1
View File
@@ -120,7 +120,7 @@ type SIsolatedDevice struct {
// guest disk index
DiskIndex int8 `nullable:"true" default:"-1" list:"user" update:"user"`
// # pci address of `Bus:Device.Function` format, or usb bus address of `bus.addr`
// # pci address of `Bus:Device.Function` format, or usb bus address of `bus:addr:port`
Addr string `width:"16" charset:"ascii" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
DevicePath string `width:"128" charset:"ascii" nullable:"true" list:"domain" update:"domain" create:"optional"`
@@ -562,6 +562,21 @@ func (man *isolatedDeviceManager) CheckDevIsNeedUpdate(dev IDevice, devInfo *Clo
func (man *isolatedDeviceManager) GetDeviceByIdent(vendorDevId, addr, mdevId string) IDevice {
for _, dev := range man.devices {
if dev.GetDeviceType() == api.USB_TYPE && dev.GetVendorDeviceId() == vendorDevId {
raddrSplit := strings.Split(addr, ":")
saddrSplit := strings.Split(dev.GetAddr(), ":")
// first update, same bus and dev
if len(raddrSplit) == 2 && raddrSplit[0] == saddrSplit[0] && raddrSplit[1] == saddrSplit[1] {
return dev
}
// same bus and port
if len(raddrSplit) == 3 && raddrSplit[0] == saddrSplit[0] && raddrSplit[2] == saddrSplit[2] {
return dev
}
}
if dev.GetVendorDeviceId() == vendorDevId && dev.GetAddr() == addr && dev.GetMdevId() == mdevId {
return dev
}
+60 -6
View File
@@ -32,6 +32,8 @@ import (
type sUSBDevice struct {
*SBaseDevice
lsusbLine *sLsusbLine
PortPath string
}
// TODO: rename PCIDevice
@@ -42,6 +44,13 @@ func newUSBDevice(dev *PCIDevice, lsusbLine *sLsusbLine) *sUSBDevice {
}
}
func (dev *sUSBDevice) SetPortPath(portPath string) {
dev.PortPath = portPath
if len(dev.PortPath) > 0 {
dev.dev.Addr = fmt.Sprintf("%s:%s", dev.dev.Addr, portPath)
}
}
func (dev *sUSBDevice) GetCPUCmd() string {
return ""
}
@@ -59,7 +68,7 @@ func GetUSBDevId(vendorId, devId, bus, addr string) string {
return fmt.Sprintf("dev_%s_%s-%s_%s", vendorId, devId, bus, addr)
}
func getUSBDevQemuOptions(vendorId, deviceId string, bus, addr string) (map[string]string, error) {
func getUSBDevQemuOptions(vendorId, deviceId string, bus, addr, port string) (map[string]string, error) {
// id := GetUSBDevId(vendorId, deviceId, bus, addr)
busI, err := strconv.Atoi(bus)
if err != nil {
@@ -69,6 +78,13 @@ func getUSBDevQemuOptions(vendorId, deviceId string, bus, addr string) (map[stri
if err != nil {
return nil, errors.Wrapf(err, "parse addr to int %q", bus)
}
if len(port) > 0 {
return map[string]string{
"hostbus": fmt.Sprintf("%d", busI),
"hostport": port,
}, nil
}
return map[string]string{
// "id": id,
// "bus": "usb.0",
@@ -88,13 +104,17 @@ func GetUSBDevQemuOptions(vendorDevId string, addr string) (map[string]string, e
productId := parts[1]
addrParts := strings.Split(addr, ":")
if len(addrParts) != 2 {
if len(addrParts) != 2 && len(addrParts) != 3 {
return nil, fmt.Errorf("invalid addr %q", addr)
}
hostBus := addrParts[0]
hostAddr := addrParts[1]
hostPort := ""
if len(addrParts) == 3 {
hostPort = addrParts[2]
}
return getUSBDevQemuOptions(vendorId, productId, hostBus, hostAddr)
return getUSBDevQemuOptions(vendorId, productId, hostBus, hostAddr, hostPort)
}
func (dev *sUSBDevice) GetKernelDriver() (string, error) {
@@ -177,7 +197,7 @@ func getPassthroughUSBs() ([]*sUSBDevice, error) {
}
// check by trees
isHubClass, err := isUSBHubClass(dev, trees)
isHubClass, err := checkIsUSBHubClassAndSetPortPath(dev, trees)
if err != nil {
return nil, errors.Wrap(err, "check isUSBHubClass")
}
@@ -197,7 +217,7 @@ func isUSBLinuxRootHub(vendorId string, deviceId string) bool {
return false
}
func isUSBHubClass(dev *sUSBDevice, trees *sLsusbTrees) (bool, error) {
func checkIsUSBHubClassAndSetPortPath(dev *sUSBDevice, trees *sLsusbTrees) (bool, error) {
busNum, err := dev.lsusbLine.GetBusNumber()
if err != nil {
return false, errors.Wrapf(err, "GetBusNumber of dev %#v", dev.lsusbLine)
@@ -214,8 +234,12 @@ func isUSBHubClass(dev *sUSBDevice, trees *sLsusbTrees) (bool, error) {
if treeDev == nil {
return false, errors.Errorf("not found dev %#v by bus %d, dev %d", dev.lsusbLine, busNum, devNum)
}
if utils.IsInStringArray(treeDev.Class, []string{"root_hub", "Hub"}) {
return true, nil
}
return utils.IsInStringArray(treeDev.Class, []string{"root_hub", "Hub"}), nil
dev.SetPortPath(tree.GetPortPath(devNum))
return false, nil
}
func parseLsusb(lines []string) ([]*sUSBDevice, error) {
@@ -516,6 +540,36 @@ func (t *sLsusbTree) GetContents() []string {
return ret
}
func (t *sLsusbTree) GetPortPath(devNum int) string {
portPath, found := t.GetDevicePortPath("", devNum)
if !found {
return ""
}
return portPath
}
func (t *sLsusbTree) GetDevicePortPath(portPath string, devNum int) (string, bool) {
if !t.IsRootBus {
if len(portPath) > 0 {
portPath = fmt.Sprintf("%s.%d", portPath, t.Port)
} else {
portPath = strconv.Itoa(t.Port)
}
}
if t.Dev == devNum {
return portPath, true
}
for _, node := range t.Nodes {
devPortPath, found := node.GetDevicePortPath(portPath, devNum)
if found {
return devPortPath, true
}
}
return "", false
}
func (t *sLsusbTree) GetDevice(devNum int) *sLsusbTree {
// should check self firstly
if t.Dev == devNum {
+1 -1
View File
@@ -178,7 +178,7 @@ func Test_getUSBDevQemuOptions(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got, _ := getUSBDevQemuOptions(tt.args.vendorId, tt.args.deviceId, tt.args.bus, tt.args.addr); !reflect.DeepEqual(got, tt.want) {
if got, _ := getUSBDevQemuOptions(tt.args.vendorId, tt.args.deviceId, tt.args.bus, tt.args.addr, ""); !reflect.DeepEqual(got, tt.want) {
t.Errorf("getUSBDevQemuOptions() = %v, want %v", got, tt.want)
}
})