usb.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package isolated_device
  15. import (
  16. "fmt"
  17. "sort"
  18. "strconv"
  19. "strings"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/utils"
  23. api "yunion.io/x/onecloud/pkg/apis/compute"
  24. "yunion.io/x/onecloud/pkg/hostman/guestman/desc"
  25. "yunion.io/x/onecloud/pkg/util/regutils2"
  26. )
  27. type sUSBDevice struct {
  28. *SBaseDevice
  29. lsusbLine *sLsusbLine
  30. }
  31. // TODO: rename PCIDevice
  32. func newUSBDevice(dev *PCIDevice, lsusbLine *sLsusbLine) *sUSBDevice {
  33. return &sUSBDevice{
  34. SBaseDevice: NewBaseDevice(dev, api.USB_TYPE),
  35. lsusbLine: lsusbLine,
  36. }
  37. }
  38. func (dev *sUSBDevice) GetCPUCmd() string {
  39. return ""
  40. }
  41. func (dev *sUSBDevice) GetVGACmd() string {
  42. return ""
  43. }
  44. func (dev *sUSBDevice) CustomProbe(int) error {
  45. // do nothing
  46. return nil
  47. }
  48. func GetUSBDevId(vendorId, devId, bus, addr string) string {
  49. return fmt.Sprintf("dev_%s_%s-%s_%s", vendorId, devId, bus, addr)
  50. }
  51. func getUSBDevQemuOptions(vendorId, deviceId string, bus, addr string) (map[string]string, error) {
  52. // id := GetUSBDevId(vendorId, deviceId, bus, addr)
  53. busI, err := strconv.Atoi(bus)
  54. if err != nil {
  55. return nil, errors.Wrapf(err, "parse bus to int %q", bus)
  56. }
  57. addrI, err := strconv.Atoi(addr)
  58. if err != nil {
  59. return nil, errors.Wrapf(err, "parse addr to int %q", bus)
  60. }
  61. return map[string]string{
  62. // "id": id,
  63. // "bus": "usb.0",
  64. "vendorid": fmt.Sprintf("0x%s", vendorId),
  65. "productid": fmt.Sprintf("0x%s", deviceId),
  66. "hostbus": fmt.Sprintf("%d", busI),
  67. "hostaddr": fmt.Sprintf("%d", addrI),
  68. }, nil
  69. }
  70. func GetUSBDevQemuOptions(vendorDevId string, addr string) (map[string]string, error) {
  71. parts := strings.Split(vendorDevId, ":")
  72. if len(parts) != 2 {
  73. return nil, fmt.Errorf("invalid vendor_device_id %q", vendorDevId)
  74. }
  75. vendorId := parts[0]
  76. productId := parts[1]
  77. addrParts := strings.Split(addr, ":")
  78. if len(addrParts) != 2 {
  79. return nil, fmt.Errorf("invalid addr %q", addr)
  80. }
  81. hostBus := addrParts[0]
  82. hostAddr := addrParts[1]
  83. return getUSBDevQemuOptions(vendorId, productId, hostBus, hostAddr)
  84. }
  85. func (dev *sUSBDevice) GetKernelDriver() (string, error) {
  86. return "", nil
  87. }
  88. func (dev *sUSBDevice) GetQemuId() string {
  89. addrParts := strings.Split(dev.dev.Addr, ":")
  90. return GetUSBDevId(dev.dev.VendorId, dev.dev.DeviceId, addrParts[0], addrParts[1])
  91. }
  92. func (dev *sUSBDevice) GetPassthroughOptions() map[string]string {
  93. opts, _ := GetUSBDevQemuOptions(dev.dev.GetVendorDeviceId(), dev.dev.Addr)
  94. return opts
  95. }
  96. func (dev *sUSBDevice) GetPassthroughCmd(index int) string {
  97. opts, _ := GetUSBDevQemuOptions(dev.dev.GetVendorDeviceId(), dev.dev.Addr)
  98. optsStr := []string{}
  99. for k, v := range opts {
  100. optsStr = append(optsStr, fmt.Sprintf("%s=%s", k, v))
  101. }
  102. opt := fmt.Sprintf(" -device usb-host,%s", strings.Join(optsStr, ","))
  103. return opt
  104. }
  105. func (dev *sUSBDevice) GetHotPlugOptions(isolatedDev *desc.SGuestIsolatedDevice, guestDesc *desc.SGuestDesc) ([]*HotPlugOption, error) {
  106. opts, err := GetUSBDevQemuOptions(dev.dev.GetVendorDeviceId(), dev.dev.Addr)
  107. if err != nil {
  108. return nil, errors.Wrap(err, "GetUSBDevQemuOptions")
  109. }
  110. opts["id"] = isolatedDev.Usb.Id
  111. opts["bus"] = fmt.Sprintf("%s.0", guestDesc.Usb.Id)
  112. return []*HotPlugOption{
  113. {
  114. Device: "usb-host",
  115. Options: opts,
  116. },
  117. }, nil
  118. }
  119. func (dev *sUSBDevice) GetHotUnplugOptions(*desc.SGuestIsolatedDevice) ([]*HotUnplugOption, error) {
  120. return []*HotUnplugOption{
  121. {Id: dev.GetQemuId()},
  122. }, nil
  123. }
  124. func getPassthroughUSBs() ([]*sUSBDevice, error) {
  125. ret, err := bashOutput("lsusb")
  126. if err != nil {
  127. return nil, errors.Wrap(err, "execute lsusb")
  128. }
  129. lines := []string{}
  130. for _, l := range ret {
  131. if len(l) != 0 {
  132. lines = append(lines, l)
  133. }
  134. }
  135. devs, err := parseLsusb(lines)
  136. if err != nil {
  137. return nil, errors.Wrap(err, "parseLsusb")
  138. }
  139. treeRet, err := bashRawOutput("lsusb -t")
  140. if err != nil {
  141. return nil, errors.Wrap(err, "execute `lsusb -t`")
  142. }
  143. trees, err := parseLsusbTrees(treeRet)
  144. if err != nil {
  145. return nil, errors.Wrap(err, "parseLsusbTrees")
  146. }
  147. // fitler linux root hub
  148. retDev := make([]*sUSBDevice, 0)
  149. for _, dev := range devs {
  150. // REF: https://github.com/virt-manager/virt-manager/blob/0038d750c9056ddd63cb48b343e451f8db2746fa/virtinst/nodedev.py#L142
  151. if isUSBLinuxRootHub(dev.dev.VendorId, dev.dev.DeviceId) {
  152. continue
  153. }
  154. // check by trees
  155. isHubClass, err := isUSBHubClass(dev, trees)
  156. if err != nil {
  157. return nil, errors.Wrap(err, "check isUSBHubClass")
  158. }
  159. if isHubClass {
  160. continue
  161. }
  162. retDev = append(retDev, dev)
  163. }
  164. return retDev, nil
  165. }
  166. func isUSBLinuxRootHub(vendorId string, deviceId string) bool {
  167. if vendorId == "1d6b" && utils.IsInStringArray(deviceId, []string{"0001", "0002", "0003"}) {
  168. return true
  169. }
  170. return false
  171. }
  172. func isUSBHubClass(dev *sUSBDevice, trees *sLsusbTrees) (bool, error) {
  173. busNum, err := dev.lsusbLine.GetBusNumber()
  174. if err != nil {
  175. return false, errors.Wrapf(err, "GetBusNumber of dev %#v", dev.lsusbLine)
  176. }
  177. devNum, err := dev.lsusbLine.GetDeviceNumber()
  178. if err != nil {
  179. return false, errors.Wrapf(err, "GetDeviceNumber of dev %#v", dev.lsusbLine)
  180. }
  181. tree, ok := trees.GetBus(busNum)
  182. if !ok {
  183. return false, errors.Errorf("not found dev %#v by bus %d", dev.lsusbLine, busNum)
  184. }
  185. treeDev := tree.GetDevice(devNum)
  186. if treeDev == nil {
  187. return false, errors.Errorf("not found dev %#v by bus %d, dev %d", dev.lsusbLine, busNum, devNum)
  188. }
  189. return utils.IsInStringArray(treeDev.Class, []string{"root_hub", "Hub"}), nil
  190. }
  191. func parseLsusb(lines []string) ([]*sUSBDevice, error) {
  192. devs := make([]*sUSBDevice, 0)
  193. for _, line := range lines {
  194. if len(line) == 0 {
  195. continue
  196. }
  197. dev, err := parseLsusbLine(line)
  198. if err != nil {
  199. return nil, errors.Wrapf(err, "parseLsusbLine %q", line)
  200. }
  201. usbDev := newUSBDevice(dev.ToPCIDevice(), dev)
  202. devs = append(devs, usbDev)
  203. }
  204. return devs, nil
  205. }
  206. var (
  207. lsusbRegex = `^Bus (?P<bus_id>([0-9]{3})) Device (?P<device>([0-9]{3})): ID (?P<vendor_id>([0-9a-z]{4})):(?P<device_id>([0-9a-z]{4}))\s{0,1}(?P<name>(.*))`
  208. )
  209. type sLsusbLine struct {
  210. BusId string `json:"bus_id"`
  211. Device string `json:"device"`
  212. VendorId string `json:"vendor_id"`
  213. DeviceId string `json:"device_id"`
  214. Name string `json:"name"`
  215. }
  216. func parseLsusbLine(line string) (*sLsusbLine, error) {
  217. ret := regutils2.SubGroupMatch(lsusbRegex, line)
  218. dev := new(sLsusbLine)
  219. if err := jsonutils.Marshal(ret).Unmarshal(dev); err != nil {
  220. return nil, err
  221. }
  222. return dev, nil
  223. }
  224. func (dev *sLsusbLine) ToPCIDevice() *PCIDevice {
  225. return &PCIDevice{
  226. Addr: fmt.Sprintf("%s:%s", dev.BusId, dev.Device),
  227. VendorId: dev.VendorId,
  228. DeviceId: dev.DeviceId,
  229. ModelName: dev.Name,
  230. }
  231. }
  232. func (dev *sLsusbLine) GetBusNumber() (int, error) {
  233. return strconv.Atoi(dev.BusId)
  234. }
  235. func (dev *sLsusbLine) GetDeviceNumber() (int, error) {
  236. return strconv.Atoi(dev.Device)
  237. }
  238. type sLsusbTrees struct {
  239. Trees map[int]*sLsusbTree
  240. sorted bool
  241. sortedTrees sortLsusbTree
  242. }
  243. type sortLsusbTree []*sLsusbTree
  244. func (t sortLsusbTree) Len() int {
  245. return len(t)
  246. }
  247. func (t sortLsusbTree) Swap(i, j int) {
  248. t[i], t[j] = t[j], t[i]
  249. }
  250. func (t sortLsusbTree) Less(i, j int) bool {
  251. it := t[i]
  252. jt := t[j]
  253. return it.Bus < jt.Bus
  254. }
  255. func newLsusbTrees() *sLsusbTrees {
  256. return &sLsusbTrees{
  257. Trees: make(map[int]*sLsusbTree),
  258. sorted: false,
  259. sortedTrees: sortLsusbTree([]*sLsusbTree{}),
  260. }
  261. }
  262. func (ts *sLsusbTrees) Add(bus int, tree *sLsusbTree) *sLsusbTrees {
  263. ts.Trees[bus] = tree
  264. return ts
  265. }
  266. func (ts *sLsusbTrees) sortTrees() *sLsusbTrees {
  267. if ts.sorted {
  268. return ts
  269. }
  270. for _, t := range ts.Trees {
  271. ts.sortedTrees = append(ts.sortedTrees, t)
  272. }
  273. sort.Sort(ts.sortedTrees)
  274. return ts
  275. }
  276. func (ts *sLsusbTrees) GetContent() string {
  277. ts.sortTrees()
  278. ret := []string{}
  279. for _, t := range ts.sortedTrees {
  280. ret = append(ret, t.GetContents()...)
  281. }
  282. return strings.Join(ret, "\n")
  283. }
  284. func (ts *sLsusbTrees) GetBus(bus int) (*sLsusbTree, bool) {
  285. t, ok := ts.Trees[bus]
  286. return t, ok
  287. }
  288. // parseLsusbTrees parses `lsusb -t` output
  289. func parseLsusbTrees(lines []string) (*sLsusbTrees, error) {
  290. return _parseLsusbTrees(lines)
  291. }
  292. func _parseLsusbTrees(lines []string) (*sLsusbTrees, error) {
  293. trees := newLsusbTrees()
  294. var (
  295. prevTree *sLsusbTree
  296. )
  297. for idx, line := range lines {
  298. if len(strings.TrimSpace(line)) == 0 {
  299. continue
  300. }
  301. tree, err := newLsusbTreeByLine(line)
  302. if err != nil {
  303. return nil, errors.Wrapf(err, "by line %q, index %d", line, idx)
  304. }
  305. if tree.IsRootBus {
  306. tree.parentNode = nil
  307. trees.Add(tree.Bus, tree)
  308. prevTree = tree
  309. } else {
  310. if len(tree.LinePrefix) > len(prevTree.LinePrefix) {
  311. // child node should be added to previous node
  312. tree.parentNode = prevTree
  313. tree.parentNode.AddNode(tree)
  314. } else if len(tree.LinePrefix) == len(prevTree.LinePrefix) {
  315. // sibling node should be added to parent
  316. prevTree.parentNode.AddNode(tree)
  317. } else if len(tree.LinePrefix) < len(prevTree.LinePrefix) {
  318. // find current node's sibling node and added to it's parent
  319. parent := prevTree.FindParentByTree(tree)
  320. if parent == nil {
  321. return nil, errors.Errorf("can't found parent by tree %s, current line %q, prevTree %s", jsonutils.Marshal(tree), line, jsonutils.Marshal(prevTree))
  322. }
  323. parent.AddNode(tree)
  324. }
  325. prevTree = tree
  326. }
  327. }
  328. return trees, nil
  329. }
  330. const (
  331. busRootPrefix = "/: Bus"
  332. )
  333. var (
  334. lsusbTreeRootBusRegex = `(?P<prefix>(.*))Bus (?P<bus_id>([0-9]{2}))\.`
  335. lsusbTreeBusSuffixRegex = `Port (?P<port_id>([0-9]{1,2})): Dev (?P<device>([0-9]{1,2})), Class=(?P<class>(.*)), Driver=(?P<driver>(.*)),\s{0,1}(?P<speed>(.*))`
  336. lsusbTreeSuffixRegex = `Port (?P<port_id>([0-9]{1,2})): Dev (?P<device>([0-9]{1,2})), If (?P<interface>([0-9]{1,2})), Class=(?P<class>(.*)), Driver=(?P<driver>(.*)),\s{0,1}(?P<speed>(.*))`
  337. lsusbTreeRootBusLineRegex = lsusbTreeRootBusRegex + lsusbTreeBusSuffixRegex
  338. lsusbTreeLineRegex = `(?P<prefix>(.*))` + lsusbTreeSuffixRegex
  339. )
  340. type sLsusbTree struct {
  341. parentNode *sLsusbTree
  342. IsRootBus bool `json:"is_root_bus"`
  343. LinePrefix string `json:"line_prefix"`
  344. Bus int `json:"bus"`
  345. Port int `json:"port"`
  346. Dev int `json:"dev"`
  347. // If maybe nil
  348. If int `json:"if"`
  349. Class string `json:"class"`
  350. Driver string `json:"driver"`
  351. Content string `json:"content"`
  352. Nodes []*sLsusbTree `json:"nodes"`
  353. }
  354. func newLsusbTreeByLine(line string) (*sLsusbTree, error) {
  355. var (
  356. isRootBus = false
  357. regExp = lsusbTreeLineRegex
  358. )
  359. if strings.HasPrefix(line, busRootPrefix) {
  360. isRootBus = true
  361. }
  362. if isRootBus {
  363. regExp = lsusbTreeRootBusLineRegex
  364. }
  365. ret := regutils2.SubGroupMatch(regExp, line)
  366. linePrefix := ret["prefix"]
  367. if linePrefix == "" {
  368. return nil, errors.Errorf("not found prefix of line %q", line)
  369. }
  370. t := &sLsusbTree{
  371. IsRootBus: isRootBus,
  372. Content: line,
  373. LinePrefix: linePrefix,
  374. Nodes: make([]*sLsusbTree, 0),
  375. }
  376. if isRootBus {
  377. // parse bus
  378. busIdStr, ok := ret["bus_id"]
  379. if !ok {
  380. return nil, errors.Errorf("not found 'Bus' in %q", line)
  381. }
  382. busId, err := strconv.Atoi(busIdStr)
  383. if err != nil {
  384. return nil, errors.Errorf("invalid Bus string %q", busIdStr)
  385. }
  386. t.Bus = busId
  387. }
  388. // parse port
  389. portIdStr, ok := ret["port_id"]
  390. if !ok {
  391. return nil, errors.Errorf("not found 'Port' in %q", line)
  392. }
  393. portId, err := strconv.Atoi(portIdStr)
  394. if err != nil {
  395. return nil, errors.Errorf("invalid Port string %q", portIdStr)
  396. }
  397. t.Port = portId
  398. // parse dev
  399. devStr, ok := ret["device"]
  400. if !ok {
  401. return nil, errors.Errorf("not found 'Dev' in %q", line)
  402. }
  403. dev, err := strconv.Atoi(devStr)
  404. if err != nil {
  405. return nil, errors.Errorf("invalid Dev string %q", devStr)
  406. }
  407. t.Dev = dev
  408. // parse if when not root bus
  409. if !isRootBus {
  410. ifStr, ok := ret["interface"]
  411. if !ok {
  412. return nil, errors.Errorf("not found 'If' in %q", line)
  413. }
  414. ifN, err := strconv.Atoi(ifStr)
  415. if err != nil {
  416. return nil, errors.Errorf("invalid ifStr string %q", ifStr)
  417. }
  418. t.If = ifN
  419. }
  420. // parse class
  421. class, ok := ret["class"]
  422. if !ok {
  423. return nil, errors.Errorf("not found 'Class' in %q", line)
  424. }
  425. t.Class = class
  426. // parse driver
  427. driver := ret["driver"]
  428. t.Driver = driver
  429. return t, nil
  430. }
  431. func (t *sLsusbTree) AddNode(child *sLsusbTree) *sLsusbTree {
  432. child.Bus = t.Bus
  433. child.parentNode = t
  434. t.Nodes = append(t.Nodes, child)
  435. return t
  436. }
  437. func (t *sLsusbTree) FindParentByTree(it *sLsusbTree) *sLsusbTree {
  438. tl := len(t.LinePrefix)
  439. itl := len(it.LinePrefix)
  440. if tl == itl {
  441. return t.parentNode
  442. } else if tl > itl {
  443. return t
  444. } else {
  445. return t.parentNode.FindParentByTree(it)
  446. }
  447. }
  448. func (t *sLsusbTree) GetContents() []string {
  449. ret := []string{t.Content}
  450. for _, n := range t.Nodes {
  451. ret = append(ret, n.GetContents()...)
  452. }
  453. return ret
  454. }
  455. func (t *sLsusbTree) GetDevice(devNum int) *sLsusbTree {
  456. // should check self firstly
  457. if t.Dev == devNum {
  458. return t
  459. }
  460. // then check children
  461. for _, node := range t.Nodes {
  462. dev := node.GetDevice(devNum)
  463. if dev != nil {
  464. return dev
  465. }
  466. }
  467. return nil
  468. }