mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
fix(host): usb device passthrough use hostport (#24708)
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user