vdpa_linux.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. package netlink
  2. import (
  3. "errors"
  4. "fmt"
  5. "net"
  6. "syscall"
  7. "golang.org/x/sys/unix"
  8. "github.com/vishvananda/netlink/nl"
  9. )
  10. type vdpaDevID struct {
  11. Name string
  12. ID uint32
  13. }
  14. // VDPADev contains info about VDPA device
  15. type VDPADev struct {
  16. vdpaDevID
  17. VendorID uint32
  18. MaxVQS uint32
  19. MaxVQSize uint16
  20. MinVQSize uint16
  21. }
  22. // VDPADevConfig contains configuration of the VDPA device
  23. type VDPADevConfig struct {
  24. vdpaDevID
  25. Features uint64
  26. NegotiatedFeatures uint64
  27. Net VDPADevConfigNet
  28. }
  29. // VDPADevVStats conatins vStats for the VDPA device
  30. type VDPADevVStats struct {
  31. vdpaDevID
  32. QueueIndex uint32
  33. Vendor []VDPADevVStatsVendor
  34. NegotiatedFeatures uint64
  35. }
  36. // VDPADevVStatsVendor conatins name and value for vendor specific vstat option
  37. type VDPADevVStatsVendor struct {
  38. Name string
  39. Value uint64
  40. }
  41. // VDPADevConfigNet conatins status and net config for the VDPA device
  42. type VDPADevConfigNet struct {
  43. Status VDPADevConfigNetStatus
  44. Cfg VDPADevConfigNetCfg
  45. }
  46. // VDPADevConfigNetStatus contains info about net status
  47. type VDPADevConfigNetStatus struct {
  48. LinkUp bool
  49. Announce bool
  50. }
  51. // VDPADevConfigNetCfg contains net config for the VDPA device
  52. type VDPADevConfigNetCfg struct {
  53. MACAddr net.HardwareAddr
  54. MaxVQP uint16
  55. MTU uint16
  56. }
  57. // VDPAMGMTDev conatins info about VDPA management device
  58. type VDPAMGMTDev struct {
  59. BusName string
  60. DevName string
  61. SupportedClasses uint64
  62. SupportedFeatures uint64
  63. MaxVQS uint32
  64. }
  65. // VDPANewDevParams contains parameters for new VDPA device
  66. // use SetBits to configure requried features for the device
  67. // example:
  68. //
  69. // VDPANewDevParams{Features: SetBits(0, VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_MAC_ADDR)}
  70. type VDPANewDevParams struct {
  71. MACAddr net.HardwareAddr
  72. MaxVQP uint16
  73. MTU uint16
  74. Features uint64
  75. }
  76. // SetBits set provided bits in the uint64 input value
  77. // usage example:
  78. // features := SetBits(0, VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_MAC_ADDR)
  79. func SetBits(input uint64, pos ...int) uint64 {
  80. for _, p := range pos {
  81. input |= 1 << uint64(p)
  82. }
  83. return input
  84. }
  85. // IsBitSet check if specific bit is set in the uint64 input value
  86. // usage example:
  87. // hasNetClass := IsBitSet(mgmtDev, VIRTIO_ID_NET)
  88. func IsBitSet(input uint64, pos int) bool {
  89. val := input & (1 << uint64(pos))
  90. return val > 0
  91. }
  92. // VDPANewDev adds new VDPA device
  93. // Equivalent to: `vdpa dev add name <name> mgmtdev <mgmtBus>/mgmtName [params]`
  94. func VDPANewDev(name, mgmtBus, mgmtName string, params VDPANewDevParams) error {
  95. return pkgHandle.VDPANewDev(name, mgmtBus, mgmtName, params)
  96. }
  97. // VDPADelDev removes VDPA device
  98. // Equivalent to: `vdpa dev del <name>`
  99. func VDPADelDev(name string) error {
  100. return pkgHandle.VDPADelDev(name)
  101. }
  102. // VDPAGetDevList returns list of VDPA devices
  103. // Equivalent to: `vdpa dev show`
  104. //
  105. // If the returned error is [ErrDumpInterrupted], results may be inconsistent
  106. // or incomplete.
  107. func VDPAGetDevList() ([]*VDPADev, error) {
  108. return pkgHandle.VDPAGetDevList()
  109. }
  110. // VDPAGetDevByName returns VDPA device selected by name
  111. // Equivalent to: `vdpa dev show <name>`
  112. func VDPAGetDevByName(name string) (*VDPADev, error) {
  113. return pkgHandle.VDPAGetDevByName(name)
  114. }
  115. // VDPAGetDevConfigList returns list of VDPA devices configurations
  116. // Equivalent to: `vdpa dev config show`
  117. //
  118. // If the returned error is [ErrDumpInterrupted], results may be inconsistent
  119. // or incomplete.
  120. func VDPAGetDevConfigList() ([]*VDPADevConfig, error) {
  121. return pkgHandle.VDPAGetDevConfigList()
  122. }
  123. // VDPAGetDevConfigByName returns VDPA device configuration selected by name
  124. // Equivalent to: `vdpa dev config show <name>`
  125. func VDPAGetDevConfigByName(name string) (*VDPADevConfig, error) {
  126. return pkgHandle.VDPAGetDevConfigByName(name)
  127. }
  128. // VDPAGetDevVStats returns vstats for VDPA device
  129. // Equivalent to: `vdpa dev vstats show <name> qidx <queueIndex>`
  130. func VDPAGetDevVStats(name string, queueIndex uint32) (*VDPADevVStats, error) {
  131. return pkgHandle.VDPAGetDevVStats(name, queueIndex)
  132. }
  133. // VDPAGetMGMTDevList returns list of mgmt devices
  134. // Equivalent to: `vdpa mgmtdev show`
  135. //
  136. // If the returned error is [ErrDumpInterrupted], results may be inconsistent
  137. // or incomplete.
  138. func VDPAGetMGMTDevList() ([]*VDPAMGMTDev, error) {
  139. return pkgHandle.VDPAGetMGMTDevList()
  140. }
  141. // VDPAGetMGMTDevByBusAndName returns mgmt devices selected by bus and name
  142. // Equivalent to: `vdpa mgmtdev show <bus>/<name>`
  143. func VDPAGetMGMTDevByBusAndName(bus, name string) (*VDPAMGMTDev, error) {
  144. return pkgHandle.VDPAGetMGMTDevByBusAndName(bus, name)
  145. }
  146. type vdpaNetlinkMessage []syscall.NetlinkRouteAttr
  147. func (id *vdpaDevID) parseIDAttribute(attr syscall.NetlinkRouteAttr) {
  148. switch attr.Attr.Type {
  149. case nl.VDPA_ATTR_DEV_NAME:
  150. id.Name = nl.BytesToString(attr.Value)
  151. case nl.VDPA_ATTR_DEV_ID:
  152. id.ID = native.Uint32(attr.Value)
  153. }
  154. }
  155. func (netStatus *VDPADevConfigNetStatus) parseStatusAttribute(value []byte) {
  156. a := native.Uint16(value)
  157. netStatus.Announce = (a & VIRTIO_NET_S_ANNOUNCE) > 0
  158. netStatus.LinkUp = (a & VIRTIO_NET_S_LINK_UP) > 0
  159. }
  160. func (d *VDPADev) parseAttributes(attrs vdpaNetlinkMessage) {
  161. for _, a := range attrs {
  162. d.parseIDAttribute(a)
  163. switch a.Attr.Type {
  164. case nl.VDPA_ATTR_DEV_VENDOR_ID:
  165. d.VendorID = native.Uint32(a.Value)
  166. case nl.VDPA_ATTR_DEV_MAX_VQS:
  167. d.MaxVQS = native.Uint32(a.Value)
  168. case nl.VDPA_ATTR_DEV_MAX_VQ_SIZE:
  169. d.MaxVQSize = native.Uint16(a.Value)
  170. case nl.VDPA_ATTR_DEV_MIN_VQ_SIZE:
  171. d.MinVQSize = native.Uint16(a.Value)
  172. }
  173. }
  174. }
  175. func (c *VDPADevConfig) parseAttributes(attrs vdpaNetlinkMessage) {
  176. for _, a := range attrs {
  177. c.parseIDAttribute(a)
  178. switch a.Attr.Type {
  179. case nl.VDPA_ATTR_DEV_NET_CFG_MACADDR:
  180. c.Net.Cfg.MACAddr = a.Value
  181. case nl.VDPA_ATTR_DEV_NET_STATUS:
  182. c.Net.Status.parseStatusAttribute(a.Value)
  183. case nl.VDPA_ATTR_DEV_NET_CFG_MAX_VQP:
  184. c.Net.Cfg.MaxVQP = native.Uint16(a.Value)
  185. case nl.VDPA_ATTR_DEV_NET_CFG_MTU:
  186. c.Net.Cfg.MTU = native.Uint16(a.Value)
  187. case nl.VDPA_ATTR_DEV_FEATURES:
  188. c.Features = native.Uint64(a.Value)
  189. case nl.VDPA_ATTR_DEV_NEGOTIATED_FEATURES:
  190. c.NegotiatedFeatures = native.Uint64(a.Value)
  191. }
  192. }
  193. }
  194. func (s *VDPADevVStats) parseAttributes(attrs vdpaNetlinkMessage) {
  195. for _, a := range attrs {
  196. s.parseIDAttribute(a)
  197. switch a.Attr.Type {
  198. case nl.VDPA_ATTR_DEV_QUEUE_INDEX:
  199. s.QueueIndex = native.Uint32(a.Value)
  200. case nl.VDPA_ATTR_DEV_VENDOR_ATTR_NAME:
  201. s.Vendor = append(s.Vendor, VDPADevVStatsVendor{Name: nl.BytesToString(a.Value)})
  202. case nl.VDPA_ATTR_DEV_VENDOR_ATTR_VALUE:
  203. if len(s.Vendor) == 0 {
  204. break
  205. }
  206. s.Vendor[len(s.Vendor)-1].Value = native.Uint64(a.Value)
  207. case nl.VDPA_ATTR_DEV_NEGOTIATED_FEATURES:
  208. s.NegotiatedFeatures = native.Uint64(a.Value)
  209. }
  210. }
  211. }
  212. func (d *VDPAMGMTDev) parseAttributes(attrs vdpaNetlinkMessage) {
  213. for _, a := range attrs {
  214. switch a.Attr.Type {
  215. case nl.VDPA_ATTR_MGMTDEV_BUS_NAME:
  216. d.BusName = nl.BytesToString(a.Value)
  217. case nl.VDPA_ATTR_MGMTDEV_DEV_NAME:
  218. d.DevName = nl.BytesToString(a.Value)
  219. case nl.VDPA_ATTR_MGMTDEV_SUPPORTED_CLASSES:
  220. d.SupportedClasses = native.Uint64(a.Value)
  221. case nl.VDPA_ATTR_DEV_SUPPORTED_FEATURES:
  222. d.SupportedFeatures = native.Uint64(a.Value)
  223. case nl.VDPA_ATTR_DEV_MGMTDEV_MAX_VQS:
  224. d.MaxVQS = native.Uint32(a.Value)
  225. }
  226. }
  227. }
  228. func (h *Handle) vdpaRequest(command uint8, extraFlags int, attrs []*nl.RtAttr) ([]vdpaNetlinkMessage, error) {
  229. f, err := h.GenlFamilyGet(nl.VDPA_GENL_NAME)
  230. if err != nil {
  231. return nil, err
  232. }
  233. req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_ACK|extraFlags)
  234. req.AddData(&nl.Genlmsg{
  235. Command: command,
  236. Version: nl.VDPA_GENL_VERSION,
  237. })
  238. for _, a := range attrs {
  239. req.AddData(a)
  240. }
  241. resp, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
  242. if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
  243. return nil, executeErr
  244. }
  245. messages := make([]vdpaNetlinkMessage, 0, len(resp))
  246. for _, m := range resp {
  247. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  248. if err != nil {
  249. return nil, err
  250. }
  251. messages = append(messages, attrs)
  252. }
  253. return messages, executeErr
  254. }
  255. // dump all devices if dev is nil
  256. //
  257. // If dev is nil and the returned error is [ErrDumpInterrupted], results may be inconsistent
  258. // or incomplete.
  259. func (h *Handle) vdpaDevGet(dev *string) ([]*VDPADev, error) {
  260. var extraFlags int
  261. var attrs []*nl.RtAttr
  262. if dev != nil {
  263. attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(*dev)))
  264. } else {
  265. extraFlags = extraFlags | unix.NLM_F_DUMP
  266. }
  267. messages, executeErr := h.vdpaRequest(nl.VDPA_CMD_DEV_GET, extraFlags, attrs)
  268. if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
  269. return nil, executeErr
  270. }
  271. devs := make([]*VDPADev, 0, len(messages))
  272. for _, m := range messages {
  273. d := &VDPADev{}
  274. d.parseAttributes(m)
  275. devs = append(devs, d)
  276. }
  277. return devs, executeErr
  278. }
  279. // dump all devices if dev is nil
  280. //
  281. // If dev is nil, and the returned error is [ErrDumpInterrupted], results may be inconsistent
  282. // or incomplete.
  283. func (h *Handle) vdpaDevConfigGet(dev *string) ([]*VDPADevConfig, error) {
  284. var extraFlags int
  285. var attrs []*nl.RtAttr
  286. if dev != nil {
  287. attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(*dev)))
  288. } else {
  289. extraFlags = extraFlags | unix.NLM_F_DUMP
  290. }
  291. messages, executeErr := h.vdpaRequest(nl.VDPA_CMD_DEV_CONFIG_GET, extraFlags, attrs)
  292. if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
  293. return nil, executeErr
  294. }
  295. cfgs := make([]*VDPADevConfig, 0, len(messages))
  296. for _, m := range messages {
  297. cfg := &VDPADevConfig{}
  298. cfg.parseAttributes(m)
  299. cfgs = append(cfgs, cfg)
  300. }
  301. return cfgs, executeErr
  302. }
  303. // dump all devices if dev is nil
  304. //
  305. // If dev is nil and the returned error is [ErrDumpInterrupted], results may be inconsistent
  306. // or incomplete.
  307. func (h *Handle) vdpaMGMTDevGet(bus, dev *string) ([]*VDPAMGMTDev, error) {
  308. var extraFlags int
  309. var attrs []*nl.RtAttr
  310. if dev != nil {
  311. attrs = append(attrs,
  312. nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_DEV_NAME, nl.ZeroTerminated(*dev)),
  313. )
  314. if bus != nil {
  315. attrs = append(attrs,
  316. nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_BUS_NAME, nl.ZeroTerminated(*bus)),
  317. )
  318. }
  319. } else {
  320. extraFlags = extraFlags | unix.NLM_F_DUMP
  321. }
  322. messages, executeErr := h.vdpaRequest(nl.VDPA_CMD_MGMTDEV_GET, extraFlags, attrs)
  323. if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
  324. return nil, executeErr
  325. }
  326. cfgs := make([]*VDPAMGMTDev, 0, len(messages))
  327. for _, m := range messages {
  328. cfg := &VDPAMGMTDev{}
  329. cfg.parseAttributes(m)
  330. cfgs = append(cfgs, cfg)
  331. }
  332. return cfgs, executeErr
  333. }
  334. // VDPANewDev adds new VDPA device
  335. // Equivalent to: `vdpa dev add name <name> mgmtdev <mgmtBus>/mgmtName [params]`
  336. func (h *Handle) VDPANewDev(name, mgmtBus, mgmtName string, params VDPANewDevParams) error {
  337. attrs := []*nl.RtAttr{
  338. nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(name)),
  339. nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_DEV_NAME, nl.ZeroTerminated(mgmtName)),
  340. }
  341. if mgmtBus != "" {
  342. attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_MGMTDEV_BUS_NAME, nl.ZeroTerminated(mgmtBus)))
  343. }
  344. if len(params.MACAddr) != 0 {
  345. attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NET_CFG_MACADDR, params.MACAddr))
  346. }
  347. if params.MaxVQP > 0 {
  348. attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NET_CFG_MAX_VQP, nl.Uint16Attr(params.MaxVQP)))
  349. }
  350. if params.MTU > 0 {
  351. attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_NET_CFG_MTU, nl.Uint16Attr(params.MTU)))
  352. }
  353. if params.Features > 0 {
  354. attrs = append(attrs, nl.NewRtAttr(nl.VDPA_ATTR_DEV_FEATURES, nl.Uint64Attr(params.Features)))
  355. }
  356. _, err := h.vdpaRequest(nl.VDPA_CMD_DEV_NEW, 0, attrs)
  357. return err
  358. }
  359. // VDPADelDev removes VDPA device
  360. // Equivalent to: `vdpa dev del <name>`
  361. func (h *Handle) VDPADelDev(name string) error {
  362. _, err := h.vdpaRequest(nl.VDPA_CMD_DEV_DEL, 0, []*nl.RtAttr{
  363. nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(name))})
  364. return err
  365. }
  366. // VDPAGetDevList returns list of VDPA devices
  367. // Equivalent to: `vdpa dev show`
  368. //
  369. // If the returned error is [ErrDumpInterrupted], results may be inconsistent
  370. // or incomplete.
  371. func (h *Handle) VDPAGetDevList() ([]*VDPADev, error) {
  372. return h.vdpaDevGet(nil)
  373. }
  374. // VDPAGetDevByName returns VDPA device selected by name
  375. // Equivalent to: `vdpa dev show <name>`
  376. func (h *Handle) VDPAGetDevByName(name string) (*VDPADev, error) {
  377. devs, err := h.vdpaDevGet(&name)
  378. if err != nil {
  379. return nil, err
  380. }
  381. if len(devs) == 0 {
  382. return nil, fmt.Errorf("device not found")
  383. }
  384. return devs[0], nil
  385. }
  386. // VDPAGetDevConfigList returns list of VDPA devices configurations
  387. // Equivalent to: `vdpa dev config show`
  388. //
  389. // If the returned error is [ErrDumpInterrupted], results may be inconsistent
  390. // or incomplete.
  391. func (h *Handle) VDPAGetDevConfigList() ([]*VDPADevConfig, error) {
  392. return h.vdpaDevConfigGet(nil)
  393. }
  394. // VDPAGetDevConfigByName returns VDPA device configuration selected by name
  395. // Equivalent to: `vdpa dev config show <name>`
  396. func (h *Handle) VDPAGetDevConfigByName(name string) (*VDPADevConfig, error) {
  397. cfgs, err := h.vdpaDevConfigGet(&name)
  398. if err != nil {
  399. return nil, err
  400. }
  401. if len(cfgs) == 0 {
  402. return nil, fmt.Errorf("configuration not found")
  403. }
  404. return cfgs[0], nil
  405. }
  406. // VDPAGetDevVStats returns vstats for VDPA device
  407. // Equivalent to: `vdpa dev vstats show <name> qidx <queueIndex>`
  408. func (h *Handle) VDPAGetDevVStats(name string, queueIndex uint32) (*VDPADevVStats, error) {
  409. messages, err := h.vdpaRequest(nl.VDPA_CMD_DEV_VSTATS_GET, 0, []*nl.RtAttr{
  410. nl.NewRtAttr(nl.VDPA_ATTR_DEV_NAME, nl.ZeroTerminated(name)),
  411. nl.NewRtAttr(nl.VDPA_ATTR_DEV_QUEUE_INDEX, nl.Uint32Attr(queueIndex)),
  412. })
  413. if err != nil {
  414. return nil, err
  415. }
  416. if len(messages) == 0 {
  417. return nil, fmt.Errorf("stats not found")
  418. }
  419. stats := &VDPADevVStats{}
  420. stats.parseAttributes(messages[0])
  421. return stats, nil
  422. }
  423. // VDPAGetMGMTDevList returns list of mgmt devices
  424. // Equivalent to: `vdpa mgmtdev show`
  425. //
  426. // If the returned error is [ErrDumpInterrupted], results may be inconsistent
  427. // or incomplete.
  428. func (h *Handle) VDPAGetMGMTDevList() ([]*VDPAMGMTDev, error) {
  429. return h.vdpaMGMTDevGet(nil, nil)
  430. }
  431. // VDPAGetMGMTDevByBusAndName returns mgmt devices selected by bus and name
  432. // Equivalent to: `vdpa mgmtdev show <bus>/<name>`
  433. func (h *Handle) VDPAGetMGMTDevByBusAndName(bus, name string) (*VDPAMGMTDev, error) {
  434. var busPtr *string
  435. if bus != "" {
  436. busPtr = &bus
  437. }
  438. devs, err := h.vdpaMGMTDevGet(busPtr, &name)
  439. if err != nil {
  440. return nil, err
  441. }
  442. if len(devs) == 0 {
  443. return nil, fmt.Errorf("mgmtdev not found")
  444. }
  445. return devs[0], nil
  446. }