devlink_linux.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. package netlink
  2. import (
  3. "fmt"
  4. "net"
  5. "strings"
  6. "syscall"
  7. "github.com/vishvananda/netlink/nl"
  8. "golang.org/x/sys/unix"
  9. )
  10. // DevlinkDevEswitchAttr represents device's eswitch attributes
  11. type DevlinkDevEswitchAttr struct {
  12. Mode string
  13. InlineMode string
  14. EncapMode string
  15. }
  16. // DevlinkDevAttrs represents device attributes
  17. type DevlinkDevAttrs struct {
  18. Eswitch DevlinkDevEswitchAttr
  19. }
  20. // DevlinkDevice represents device and its attributes
  21. type DevlinkDevice struct {
  22. BusName string
  23. DeviceName string
  24. Attrs DevlinkDevAttrs
  25. }
  26. // DevlinkPortFn represents port function and its attributes
  27. type DevlinkPortFn struct {
  28. HwAddr net.HardwareAddr
  29. State uint8
  30. OpState uint8
  31. }
  32. // DevlinkPortFnSetAttrs represents attributes to set
  33. type DevlinkPortFnSetAttrs struct {
  34. FnAttrs DevlinkPortFn
  35. HwAddrValid bool
  36. StateValid bool
  37. }
  38. // DevlinkPort represents port and its attributes
  39. type DevlinkPort struct {
  40. BusName string
  41. DeviceName string
  42. PortIndex uint32
  43. PortType uint16
  44. NetdeviceName string
  45. NetdevIfIndex uint32
  46. RdmaDeviceName string
  47. PortFlavour uint16
  48. Fn *DevlinkPortFn
  49. }
  50. type DevLinkPortAddAttrs struct {
  51. Controller uint32
  52. SfNumber uint32
  53. PortIndex uint32
  54. PfNumber uint16
  55. SfNumberValid bool
  56. PortIndexValid bool
  57. ControllerValid bool
  58. }
  59. // DevlinkDeviceInfo represents devlink info
  60. type DevlinkDeviceInfo struct {
  61. Driver string
  62. SerialNumber string
  63. BoardID string
  64. FwApp string
  65. FwAppBoundleID string
  66. FwAppName string
  67. FwBoundleID string
  68. FwMgmt string
  69. FwMgmtAPI string
  70. FwMgmtBuild string
  71. FwNetlist string
  72. FwNetlistBuild string
  73. FwPsidAPI string
  74. FwUndi string
  75. }
  76. func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) {
  77. devices := make([]*DevlinkDevice, 0, len(msgs))
  78. for _, m := range msgs {
  79. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  80. if err != nil {
  81. return nil, err
  82. }
  83. dev := &DevlinkDevice{}
  84. if err = dev.parseAttributes(attrs); err != nil {
  85. return nil, err
  86. }
  87. devices = append(devices, dev)
  88. }
  89. return devices, nil
  90. }
  91. func eswitchStringToMode(modeName string) (uint16, error) {
  92. if modeName == "legacy" {
  93. return nl.DEVLINK_ESWITCH_MODE_LEGACY, nil
  94. } else if modeName == "switchdev" {
  95. return nl.DEVLINK_ESWITCH_MODE_SWITCHDEV, nil
  96. } else {
  97. return 0xffff, fmt.Errorf("invalid switchdev mode")
  98. }
  99. }
  100. func parseEswitchMode(mode uint16) string {
  101. var eswitchMode = map[uint16]string{
  102. nl.DEVLINK_ESWITCH_MODE_LEGACY: "legacy",
  103. nl.DEVLINK_ESWITCH_MODE_SWITCHDEV: "switchdev",
  104. }
  105. if eswitchMode[mode] == "" {
  106. return "unknown"
  107. } else {
  108. return eswitchMode[mode]
  109. }
  110. }
  111. func parseEswitchInlineMode(inlinemode uint8) string {
  112. var eswitchInlineMode = map[uint8]string{
  113. nl.DEVLINK_ESWITCH_INLINE_MODE_NONE: "none",
  114. nl.DEVLINK_ESWITCH_INLINE_MODE_LINK: "link",
  115. nl.DEVLINK_ESWITCH_INLINE_MODE_NETWORK: "network",
  116. nl.DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT: "transport",
  117. }
  118. if eswitchInlineMode[inlinemode] == "" {
  119. return "unknown"
  120. } else {
  121. return eswitchInlineMode[inlinemode]
  122. }
  123. }
  124. func parseEswitchEncapMode(encapmode uint8) string {
  125. var eswitchEncapMode = map[uint8]string{
  126. nl.DEVLINK_ESWITCH_ENCAP_MODE_NONE: "disable",
  127. nl.DEVLINK_ESWITCH_ENCAP_MODE_BASIC: "enable",
  128. }
  129. if eswitchEncapMode[encapmode] == "" {
  130. return "unknown"
  131. } else {
  132. return eswitchEncapMode[encapmode]
  133. }
  134. }
  135. func (d *DevlinkDevice) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
  136. for _, a := range attrs {
  137. switch a.Attr.Type {
  138. case nl.DEVLINK_ATTR_BUS_NAME:
  139. d.BusName = string(a.Value[:len(a.Value)-1])
  140. case nl.DEVLINK_ATTR_DEV_NAME:
  141. d.DeviceName = string(a.Value[:len(a.Value)-1])
  142. case nl.DEVLINK_ATTR_ESWITCH_MODE:
  143. d.Attrs.Eswitch.Mode = parseEswitchMode(native.Uint16(a.Value))
  144. case nl.DEVLINK_ATTR_ESWITCH_INLINE_MODE:
  145. d.Attrs.Eswitch.InlineMode = parseEswitchInlineMode(uint8(a.Value[0]))
  146. case nl.DEVLINK_ATTR_ESWITCH_ENCAP_MODE:
  147. d.Attrs.Eswitch.EncapMode = parseEswitchEncapMode(uint8(a.Value[0]))
  148. }
  149. }
  150. return nil
  151. }
  152. func (dev *DevlinkDevice) parseEswitchAttrs(msgs [][]byte) {
  153. m := msgs[0]
  154. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  155. if err != nil {
  156. return
  157. }
  158. dev.parseAttributes(attrs)
  159. }
  160. func (h *Handle) getEswitchAttrs(family *GenlFamily, dev *DevlinkDevice) {
  161. msg := &nl.Genlmsg{
  162. Command: nl.DEVLINK_CMD_ESWITCH_GET,
  163. Version: nl.GENL_DEVLINK_VERSION,
  164. }
  165. req := h.newNetlinkRequest(int(family.ID), unix.NLM_F_REQUEST|unix.NLM_F_ACK)
  166. req.AddData(msg)
  167. b := make([]byte, len(dev.BusName)+1)
  168. copy(b, dev.BusName)
  169. data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
  170. req.AddData(data)
  171. b = make([]byte, len(dev.DeviceName)+1)
  172. copy(b, dev.DeviceName)
  173. data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
  174. req.AddData(data)
  175. msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
  176. if err != nil {
  177. return
  178. }
  179. dev.parseEswitchAttrs(msgs)
  180. }
  181. // DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
  182. // otherwise returns an error code.
  183. func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
  184. f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
  185. if err != nil {
  186. return nil, err
  187. }
  188. msg := &nl.Genlmsg{
  189. Command: nl.DEVLINK_CMD_GET,
  190. Version: nl.GENL_DEVLINK_VERSION,
  191. }
  192. req := h.newNetlinkRequest(int(f.ID),
  193. unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
  194. req.AddData(msg)
  195. msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
  196. if err != nil {
  197. return nil, err
  198. }
  199. devices, err := parseDevLinkDeviceList(msgs)
  200. if err != nil {
  201. return nil, err
  202. }
  203. for _, d := range devices {
  204. h.getEswitchAttrs(f, d)
  205. }
  206. return devices, nil
  207. }
  208. // DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
  209. // otherwise returns an error code.
  210. func DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
  211. return pkgHandle.DevLinkGetDeviceList()
  212. }
  213. func parseDevlinkDevice(msgs [][]byte) (*DevlinkDevice, error) {
  214. m := msgs[0]
  215. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  216. if err != nil {
  217. return nil, err
  218. }
  219. dev := &DevlinkDevice{}
  220. if err = dev.parseAttributes(attrs); err != nil {
  221. return nil, err
  222. }
  223. return dev, nil
  224. }
  225. func (h *Handle) createCmdReq(cmd uint8, bus string, device string) (*GenlFamily, *nl.NetlinkRequest, error) {
  226. f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
  227. if err != nil {
  228. return nil, nil, err
  229. }
  230. msg := &nl.Genlmsg{
  231. Command: cmd,
  232. Version: nl.GENL_DEVLINK_VERSION,
  233. }
  234. req := h.newNetlinkRequest(int(f.ID),
  235. unix.NLM_F_REQUEST|unix.NLM_F_ACK)
  236. req.AddData(msg)
  237. b := make([]byte, len(bus)+1)
  238. copy(b, bus)
  239. data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
  240. req.AddData(data)
  241. b = make([]byte, len(device)+1)
  242. copy(b, device)
  243. data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
  244. req.AddData(data)
  245. return f, req, nil
  246. }
  247. // DevlinkGetDeviceByName provides a pointer to devlink device and nil error,
  248. // otherwise returns an error code.
  249. func (h *Handle) DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) {
  250. f, req, err := h.createCmdReq(nl.DEVLINK_CMD_GET, Bus, Device)
  251. if err != nil {
  252. return nil, err
  253. }
  254. respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
  255. if err != nil {
  256. return nil, err
  257. }
  258. dev, err := parseDevlinkDevice(respmsg)
  259. if err == nil {
  260. h.getEswitchAttrs(f, dev)
  261. }
  262. return dev, err
  263. }
  264. // DevlinkGetDeviceByName provides a pointer to devlink device and nil error,
  265. // otherwise returns an error code.
  266. func DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) {
  267. return pkgHandle.DevLinkGetDeviceByName(Bus, Device)
  268. }
  269. // DevLinkSetEswitchMode sets eswitch mode if able to set successfully or
  270. // returns an error code.
  271. // Equivalent to: `devlink dev eswitch set $dev mode switchdev`
  272. // Equivalent to: `devlink dev eswitch set $dev mode legacy`
  273. func (h *Handle) DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
  274. mode, err := eswitchStringToMode(NewMode)
  275. if err != nil {
  276. return err
  277. }
  278. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_ESWITCH_SET, Dev.BusName, Dev.DeviceName)
  279. if err != nil {
  280. return err
  281. }
  282. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_ESWITCH_MODE, nl.Uint16Attr(mode)))
  283. _, err = req.Execute(unix.NETLINK_GENERIC, 0)
  284. return err
  285. }
  286. // DevLinkSetEswitchMode sets eswitch mode if able to set successfully or
  287. // returns an error code.
  288. // Equivalent to: `devlink dev eswitch set $dev mode switchdev`
  289. // Equivalent to: `devlink dev eswitch set $dev mode legacy`
  290. func DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
  291. return pkgHandle.DevLinkSetEswitchMode(Dev, NewMode)
  292. }
  293. func (port *DevlinkPort) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
  294. for _, a := range attrs {
  295. switch a.Attr.Type {
  296. case nl.DEVLINK_ATTR_BUS_NAME:
  297. port.BusName = string(a.Value[:len(a.Value)-1])
  298. case nl.DEVLINK_ATTR_DEV_NAME:
  299. port.DeviceName = string(a.Value[:len(a.Value)-1])
  300. case nl.DEVLINK_ATTR_PORT_INDEX:
  301. port.PortIndex = native.Uint32(a.Value)
  302. case nl.DEVLINK_ATTR_PORT_TYPE:
  303. port.PortType = native.Uint16(a.Value)
  304. case nl.DEVLINK_ATTR_PORT_NETDEV_NAME:
  305. port.NetdeviceName = string(a.Value[:len(a.Value)-1])
  306. case nl.DEVLINK_ATTR_PORT_NETDEV_IFINDEX:
  307. port.NetdevIfIndex = native.Uint32(a.Value)
  308. case nl.DEVLINK_ATTR_PORT_IBDEV_NAME:
  309. port.RdmaDeviceName = string(a.Value[:len(a.Value)-1])
  310. case nl.DEVLINK_ATTR_PORT_FLAVOUR:
  311. port.PortFlavour = native.Uint16(a.Value)
  312. case nl.DEVLINK_ATTR_PORT_FUNCTION:
  313. port.Fn = &DevlinkPortFn{}
  314. for nested := range nl.ParseAttributes(a.Value) {
  315. switch nested.Type {
  316. case nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR:
  317. port.Fn.HwAddr = nested.Value[:]
  318. case nl.DEVLINK_PORT_FN_ATTR_STATE:
  319. port.Fn.State = uint8(nested.Value[0])
  320. case nl.DEVLINK_PORT_FN_ATTR_OPSTATE:
  321. port.Fn.OpState = uint8(nested.Value[0])
  322. }
  323. }
  324. }
  325. }
  326. return nil
  327. }
  328. func parseDevLinkAllPortList(msgs [][]byte) ([]*DevlinkPort, error) {
  329. ports := make([]*DevlinkPort, 0, len(msgs))
  330. for _, m := range msgs {
  331. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  332. if err != nil {
  333. return nil, err
  334. }
  335. port := &DevlinkPort{}
  336. if err = port.parseAttributes(attrs); err != nil {
  337. return nil, err
  338. }
  339. ports = append(ports, port)
  340. }
  341. return ports, nil
  342. }
  343. // DevLinkGetPortList provides a pointer to devlink ports and nil error,
  344. // otherwise returns an error code.
  345. func (h *Handle) DevLinkGetAllPortList() ([]*DevlinkPort, error) {
  346. f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
  347. if err != nil {
  348. return nil, err
  349. }
  350. msg := &nl.Genlmsg{
  351. Command: nl.DEVLINK_CMD_PORT_GET,
  352. Version: nl.GENL_DEVLINK_VERSION,
  353. }
  354. req := h.newNetlinkRequest(int(f.ID),
  355. unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
  356. req.AddData(msg)
  357. msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
  358. if err != nil {
  359. return nil, err
  360. }
  361. ports, err := parseDevLinkAllPortList(msgs)
  362. if err != nil {
  363. return nil, err
  364. }
  365. return ports, nil
  366. }
  367. // DevLinkGetPortList provides a pointer to devlink ports and nil error,
  368. // otherwise returns an error code.
  369. func DevLinkGetAllPortList() ([]*DevlinkPort, error) {
  370. return pkgHandle.DevLinkGetAllPortList()
  371. }
  372. func parseDevlinkPortMsg(msgs [][]byte) (*DevlinkPort, error) {
  373. m := msgs[0]
  374. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  375. if err != nil {
  376. return nil, err
  377. }
  378. port := &DevlinkPort{}
  379. if err = port.parseAttributes(attrs); err != nil {
  380. return nil, err
  381. }
  382. return port, nil
  383. }
  384. // DevLinkGetPortByIndexprovides a pointer to devlink device and nil error,
  385. // otherwise returns an error code.
  386. func (h *Handle) DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
  387. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_GET, Bus, Device)
  388. if err != nil {
  389. return nil, err
  390. }
  391. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
  392. respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
  393. if err != nil {
  394. return nil, err
  395. }
  396. port, err := parseDevlinkPortMsg(respmsg)
  397. return port, err
  398. }
  399. // DevLinkGetPortByIndex provides a pointer to devlink portand nil error,
  400. // otherwise returns an error code.
  401. func DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
  402. return pkgHandle.DevLinkGetPortByIndex(Bus, Device, PortIndex)
  403. }
  404. // DevLinkPortAdd adds a devlink port and returns a port on success
  405. // otherwise returns nil port and an error code.
  406. func (h *Handle) DevLinkPortAdd(Bus string, Device string, Flavour uint16, Attrs DevLinkPortAddAttrs) (*DevlinkPort, error) {
  407. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_NEW, Bus, Device)
  408. if err != nil {
  409. return nil, err
  410. }
  411. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FLAVOUR, nl.Uint16Attr(Flavour)))
  412. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_PF_NUMBER, nl.Uint16Attr(Attrs.PfNumber)))
  413. if Flavour == nl.DEVLINK_PORT_FLAVOUR_PCI_SF && Attrs.SfNumberValid {
  414. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_SF_NUMBER, nl.Uint32Attr(Attrs.SfNumber)))
  415. }
  416. if Attrs.PortIndexValid {
  417. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(Attrs.PortIndex)))
  418. }
  419. if Attrs.ControllerValid {
  420. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_CONTROLLER_NUMBER, nl.Uint32Attr(Attrs.Controller)))
  421. }
  422. respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
  423. if err != nil {
  424. return nil, err
  425. }
  426. port, err := parseDevlinkPortMsg(respmsg)
  427. return port, err
  428. }
  429. // DevLinkPortAdd adds a devlink port and returns a port on success
  430. // otherwise returns nil port and an error code.
  431. func DevLinkPortAdd(Bus string, Device string, Flavour uint16, Attrs DevLinkPortAddAttrs) (*DevlinkPort, error) {
  432. return pkgHandle.DevLinkPortAdd(Bus, Device, Flavour, Attrs)
  433. }
  434. // DevLinkPortDel deletes a devlink port and returns success or error code.
  435. func (h *Handle) DevLinkPortDel(Bus string, Device string, PortIndex uint32) error {
  436. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_DEL, Bus, Device)
  437. if err != nil {
  438. return err
  439. }
  440. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
  441. _, err = req.Execute(unix.NETLINK_GENERIC, 0)
  442. return err
  443. }
  444. // DevLinkPortDel deletes a devlink port and returns success or error code.
  445. func DevLinkPortDel(Bus string, Device string, PortIndex uint32) error {
  446. return pkgHandle.DevLinkPortDel(Bus, Device, PortIndex)
  447. }
  448. // DevlinkPortFnSet sets one or more port function attributes specified by the attribute mask.
  449. // It returns 0 on success or error code.
  450. func (h *Handle) DevlinkPortFnSet(Bus string, Device string, PortIndex uint32, FnAttrs DevlinkPortFnSetAttrs) error {
  451. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_SET, Bus, Device)
  452. if err != nil {
  453. return err
  454. }
  455. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
  456. fnAttr := nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FUNCTION|unix.NLA_F_NESTED, nil)
  457. if FnAttrs.HwAddrValid {
  458. fnAttr.AddRtAttr(nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, []byte(FnAttrs.FnAttrs.HwAddr))
  459. }
  460. if FnAttrs.StateValid {
  461. fnAttr.AddRtAttr(nl.DEVLINK_PORT_FN_ATTR_STATE, nl.Uint8Attr(FnAttrs.FnAttrs.State))
  462. }
  463. req.AddData(fnAttr)
  464. _, err = req.Execute(unix.NETLINK_GENERIC, 0)
  465. return err
  466. }
  467. // DevlinkPortFnSet sets one or more port function attributes specified by the attribute mask.
  468. // It returns 0 on success or error code.
  469. func DevlinkPortFnSet(Bus string, Device string, PortIndex uint32, FnAttrs DevlinkPortFnSetAttrs) error {
  470. return pkgHandle.DevlinkPortFnSet(Bus, Device, PortIndex, FnAttrs)
  471. }
  472. // devlinkInfoGetter is function that is responsible for getting devlink info message
  473. // this is introduced for test purpose
  474. type devlinkInfoGetter func(bus, device string) ([]byte, error)
  475. // DevlinkGetDeviceInfoByName returns devlink info for selected device,
  476. // otherwise returns an error code.
  477. // Equivalent to: `devlink dev info $dev`
  478. func (h *Handle) DevlinkGetDeviceInfoByName(Bus string, Device string, getInfoMsg devlinkInfoGetter) (*DevlinkDeviceInfo, error) {
  479. info, err := h.DevlinkGetDeviceInfoByNameAsMap(Bus, Device, getInfoMsg)
  480. if err != nil {
  481. return nil, err
  482. }
  483. return parseInfoData(info), nil
  484. }
  485. // DevlinkGetDeviceInfoByName returns devlink info for selected device,
  486. // otherwise returns an error code.
  487. // Equivalent to: `devlink dev info $dev`
  488. func DevlinkGetDeviceInfoByName(Bus string, Device string) (*DevlinkDeviceInfo, error) {
  489. return pkgHandle.DevlinkGetDeviceInfoByName(Bus, Device, pkgHandle.getDevlinkInfoMsg)
  490. }
  491. // DevlinkGetDeviceInfoByNameAsMap returns devlink info for selected device as a map,
  492. // otherwise returns an error code.
  493. // Equivalent to: `devlink dev info $dev`
  494. func (h *Handle) DevlinkGetDeviceInfoByNameAsMap(Bus string, Device string, getInfoMsg devlinkInfoGetter) (map[string]string, error) {
  495. response, err := getInfoMsg(Bus, Device)
  496. if err != nil {
  497. return nil, err
  498. }
  499. info, err := parseInfoMsg(response)
  500. if err != nil {
  501. return nil, err
  502. }
  503. return info, nil
  504. }
  505. // DevlinkGetDeviceInfoByNameAsMap returns devlink info for selected device as a map,
  506. // otherwise returns an error code.
  507. // Equivalent to: `devlink dev info $dev`
  508. func DevlinkGetDeviceInfoByNameAsMap(Bus string, Device string) (map[string]string, error) {
  509. return pkgHandle.DevlinkGetDeviceInfoByNameAsMap(Bus, Device, pkgHandle.getDevlinkInfoMsg)
  510. }
  511. // GetDevlinkInfo returns devlink info for target device,
  512. // otherwise returns an error code.
  513. func (d *DevlinkDevice) GetDevlinkInfo() (*DevlinkDeviceInfo, error) {
  514. return pkgHandle.DevlinkGetDeviceInfoByName(d.BusName, d.DeviceName, pkgHandle.getDevlinkInfoMsg)
  515. }
  516. // GetDevlinkInfoAsMap returns devlink info for target device as a map,
  517. // otherwise returns an error code.
  518. func (d *DevlinkDevice) GetDevlinkInfoAsMap() (map[string]string, error) {
  519. return pkgHandle.DevlinkGetDeviceInfoByNameAsMap(d.BusName, d.DeviceName, pkgHandle.getDevlinkInfoMsg)
  520. }
  521. func (h *Handle) getDevlinkInfoMsg(bus, device string) ([]byte, error) {
  522. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_INFO_GET, bus, device)
  523. if err != nil {
  524. return nil, err
  525. }
  526. response, err := req.Execute(unix.NETLINK_GENERIC, 0)
  527. if err != nil {
  528. return nil, err
  529. }
  530. if len(response) < 1 {
  531. return nil, fmt.Errorf("getDevlinkInfoMsg: message too short")
  532. }
  533. return response[0], nil
  534. }
  535. func parseInfoMsg(msg []byte) (map[string]string, error) {
  536. if len(msg) < nl.SizeofGenlmsg {
  537. return nil, fmt.Errorf("parseInfoMsg: message too short")
  538. }
  539. info := make(map[string]string)
  540. err := collectInfoData(msg[nl.SizeofGenlmsg:], info)
  541. if err != nil {
  542. return nil, err
  543. }
  544. return info, nil
  545. }
  546. func collectInfoData(msg []byte, data map[string]string) error {
  547. attrs, err := nl.ParseRouteAttr(msg)
  548. if err != nil {
  549. return err
  550. }
  551. for _, attr := range attrs {
  552. switch attr.Attr.Type {
  553. case nl.DEVLINK_ATTR_INFO_DRIVER_NAME:
  554. data["driver"] = parseInfoValue(attr.Value)
  555. case nl.DEVLINK_ATTR_INFO_SERIAL_NUMBER:
  556. data["serialNumber"] = parseInfoValue(attr.Value)
  557. case nl.DEVLINK_ATTR_INFO_VERSION_RUNNING, nl.DEVLINK_ATTR_INFO_VERSION_FIXED,
  558. nl.DEVLINK_ATTR_INFO_VERSION_STORED:
  559. key, value, err := getNestedInfoData(attr.Value)
  560. if err != nil {
  561. return err
  562. }
  563. data[key] = value
  564. }
  565. }
  566. if len(data) == 0 {
  567. return fmt.Errorf("collectInfoData: could not read attributes")
  568. }
  569. return nil
  570. }
  571. func getNestedInfoData(msg []byte) (string, string, error) {
  572. nestedAttrs, err := nl.ParseRouteAttr(msg)
  573. var key, value string
  574. if err != nil {
  575. return "", "", err
  576. }
  577. if len(nestedAttrs) != 2 {
  578. return "", "", fmt.Errorf("getNestedInfoData: too few attributes in nested structure")
  579. }
  580. for _, nestedAttr := range nestedAttrs {
  581. switch nestedAttr.Attr.Type {
  582. case nl.DEVLINK_ATTR_INFO_VERSION_NAME:
  583. key = parseInfoValue(nestedAttr.Value)
  584. case nl.DEVLINK_ATTR_INFO_VERSION_VALUE:
  585. value = parseInfoValue(nestedAttr.Value)
  586. }
  587. }
  588. if key == "" {
  589. return "", "", fmt.Errorf("getNestedInfoData: key not found")
  590. }
  591. if value == "" {
  592. return "", "", fmt.Errorf("getNestedInfoData: value not found")
  593. }
  594. return key, value, nil
  595. }
  596. func parseInfoData(data map[string]string) *DevlinkDeviceInfo {
  597. info := new(DevlinkDeviceInfo)
  598. for key, value := range data {
  599. switch key {
  600. case "driver":
  601. info.Driver = value
  602. case "serialNumber":
  603. info.SerialNumber = value
  604. case "board.id":
  605. info.BoardID = value
  606. case "fw.app":
  607. info.FwApp = value
  608. case "fw.app.bundle_id":
  609. info.FwAppBoundleID = value
  610. case "fw.app.name":
  611. info.FwAppName = value
  612. case "fw.bundle_id":
  613. info.FwBoundleID = value
  614. case "fw.mgmt":
  615. info.FwMgmt = value
  616. case "fw.mgmt.api":
  617. info.FwMgmtAPI = value
  618. case "fw.mgmt.build":
  619. info.FwMgmtBuild = value
  620. case "fw.netlist":
  621. info.FwNetlist = value
  622. case "fw.netlist.build":
  623. info.FwNetlistBuild = value
  624. case "fw.psid.api":
  625. info.FwPsidAPI = value
  626. case "fw.undi":
  627. info.FwUndi = value
  628. }
  629. }
  630. return info
  631. }
  632. func parseInfoValue(value []byte) string {
  633. v := strings.ReplaceAll(string(value), "\x00", "")
  634. return strings.TrimSpace(v)
  635. }