devlink_linux.go 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175
  1. package netlink
  2. import (
  3. "errors"
  4. "fmt"
  5. "net"
  6. "strings"
  7. "syscall"
  8. "github.com/vishvananda/netlink/nl"
  9. "golang.org/x/sys/unix"
  10. )
  11. // DevlinkDevEswitchAttr represents device's eswitch attributes
  12. type DevlinkDevEswitchAttr struct {
  13. Mode string
  14. InlineMode string
  15. EncapMode string
  16. }
  17. // DevlinkDevAttrs represents device attributes
  18. type DevlinkDevAttrs struct {
  19. Eswitch DevlinkDevEswitchAttr
  20. }
  21. // DevlinkDevice represents device and its attributes
  22. type DevlinkDevice struct {
  23. BusName string
  24. DeviceName string
  25. Attrs DevlinkDevAttrs
  26. }
  27. // DevlinkPortFn represents port function and its attributes
  28. type DevlinkPortFn struct {
  29. HwAddr net.HardwareAddr
  30. State uint8
  31. OpState uint8
  32. }
  33. // DevlinkPortFnSetAttrs represents attributes to set
  34. type DevlinkPortFnSetAttrs struct {
  35. FnAttrs DevlinkPortFn
  36. HwAddrValid bool
  37. StateValid bool
  38. }
  39. // DevlinkPort represents port and its attributes
  40. type DevlinkPort struct {
  41. BusName string
  42. DeviceName string
  43. PortIndex uint32
  44. PortType uint16
  45. NetdeviceName string
  46. NetdevIfIndex uint32
  47. RdmaDeviceName string
  48. PortFlavour uint16
  49. Fn *DevlinkPortFn
  50. }
  51. type DevLinkPortAddAttrs struct {
  52. Controller uint32
  53. SfNumber uint32
  54. PortIndex uint32
  55. PfNumber uint16
  56. SfNumberValid bool
  57. PortIndexValid bool
  58. ControllerValid bool
  59. }
  60. // DevlinkDeviceInfo represents devlink info
  61. type DevlinkDeviceInfo struct {
  62. Driver string
  63. SerialNumber string
  64. BoardID string
  65. FwApp string
  66. FwAppBoundleID string
  67. FwAppName string
  68. FwBoundleID string
  69. FwMgmt string
  70. FwMgmtAPI string
  71. FwMgmtBuild string
  72. FwNetlist string
  73. FwNetlistBuild string
  74. FwPsidAPI string
  75. FwUndi string
  76. }
  77. // DevlinkResource represents a device resource
  78. type DevlinkResource struct {
  79. Name string
  80. ID uint64
  81. Size uint64
  82. SizeNew uint64
  83. SizeMin uint64
  84. SizeMax uint64
  85. SizeGranularity uint64
  86. PendingChange bool
  87. Unit uint8
  88. SizeValid bool
  89. OCCValid bool
  90. OCCSize uint64
  91. Parent *DevlinkResource
  92. Children []DevlinkResource
  93. }
  94. // parseAttributes parses provided Netlink Attributes and populates DevlinkResource, returns error if occured
  95. func (dlr *DevlinkResource) parseAttributes(attrs map[uint16]syscall.NetlinkRouteAttr) error {
  96. var attr syscall.NetlinkRouteAttr
  97. var ok bool
  98. // mandatory attributes
  99. attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_ID]
  100. if !ok {
  101. return fmt.Errorf("missing resource id")
  102. }
  103. dlr.ID = native.Uint64(attr.Value)
  104. attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_NAME]
  105. if !ok {
  106. return fmt.Errorf("missing resource name")
  107. }
  108. dlr.Name = nl.BytesToString(attr.Value)
  109. attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE]
  110. if !ok {
  111. return fmt.Errorf("missing resource size")
  112. }
  113. dlr.Size = native.Uint64(attr.Value)
  114. attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_GRAN]
  115. if !ok {
  116. return fmt.Errorf("missing resource size granularity")
  117. }
  118. dlr.SizeGranularity = native.Uint64(attr.Value)
  119. attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_UNIT]
  120. if !ok {
  121. return fmt.Errorf("missing resource unit")
  122. }
  123. dlr.Unit = uint8(attr.Value[0])
  124. attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_MIN]
  125. if !ok {
  126. return fmt.Errorf("missing resource size min")
  127. }
  128. dlr.SizeMin = native.Uint64(attr.Value)
  129. attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_MAX]
  130. if !ok {
  131. return fmt.Errorf("missing resource size max")
  132. }
  133. dlr.SizeMax = native.Uint64(attr.Value)
  134. // optional attributes
  135. attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_OCC]
  136. if ok {
  137. dlr.OCCSize = native.Uint64(attr.Value)
  138. dlr.OCCValid = true
  139. }
  140. attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_VALID]
  141. if ok {
  142. dlr.SizeValid = uint8(attr.Value[0]) != 0
  143. }
  144. dlr.SizeNew = dlr.Size
  145. attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_SIZE_NEW]
  146. if ok {
  147. dlr.SizeNew = native.Uint64(attr.Value)
  148. }
  149. dlr.PendingChange = dlr.Size != dlr.SizeNew
  150. attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_LIST]
  151. if ok {
  152. // handle nested resoruces recursively
  153. subResources, err := nl.ParseRouteAttr(attr.Value)
  154. if err != nil {
  155. return err
  156. }
  157. for _, subresource := range subResources {
  158. resource := DevlinkResource{Parent: dlr}
  159. attrs, err := nl.ParseRouteAttrAsMap(subresource.Value)
  160. if err != nil {
  161. return err
  162. }
  163. err = resource.parseAttributes(attrs)
  164. if err != nil {
  165. return fmt.Errorf("failed to parse child resource, parent:%s. %w", dlr.Name, err)
  166. }
  167. dlr.Children = append(dlr.Children, resource)
  168. }
  169. }
  170. return nil
  171. }
  172. // DevlinkResources represents all devlink resources of a devlink device
  173. type DevlinkResources struct {
  174. Bus string
  175. Device string
  176. Resources []DevlinkResource
  177. }
  178. // parseAttributes parses provided Netlink Attributes and populates DevlinkResources, returns error if occured
  179. func (dlrs *DevlinkResources) parseAttributes(attrs map[uint16]syscall.NetlinkRouteAttr) error {
  180. var attr syscall.NetlinkRouteAttr
  181. var ok bool
  182. // Bus
  183. attr, ok = attrs[nl.DEVLINK_ATTR_BUS_NAME]
  184. if !ok {
  185. return fmt.Errorf("missing bus name")
  186. }
  187. dlrs.Bus = nl.BytesToString(attr.Value)
  188. // Device
  189. attr, ok = attrs[nl.DEVLINK_ATTR_DEV_NAME]
  190. if !ok {
  191. return fmt.Errorf("missing device name")
  192. }
  193. dlrs.Device = nl.BytesToString(attr.Value)
  194. // Resource List
  195. attr, ok = attrs[nl.DEVLINK_ATTR_RESOURCE_LIST]
  196. if !ok {
  197. return fmt.Errorf("missing resource list")
  198. }
  199. resourceAttrs, err := nl.ParseRouteAttr(attr.Value)
  200. if err != nil {
  201. return err
  202. }
  203. for _, resourceAttr := range resourceAttrs {
  204. resource := DevlinkResource{}
  205. attrs, err := nl.ParseRouteAttrAsMap(resourceAttr.Value)
  206. if err != nil {
  207. return err
  208. }
  209. err = resource.parseAttributes(attrs)
  210. if err != nil {
  211. return fmt.Errorf("failed to parse root resoruces, %w", err)
  212. }
  213. dlrs.Resources = append(dlrs.Resources, resource)
  214. }
  215. return nil
  216. }
  217. // DevlinkParam represents parameter of the device
  218. type DevlinkParam struct {
  219. Name string
  220. IsGeneric bool
  221. Type uint8 // possible values are in nl.DEVLINK_PARAM_TYPE_* constants
  222. Values []DevlinkParamValue
  223. }
  224. // DevlinkParamValue contains values of the parameter
  225. // Data field contains specific type which can be casted by unsing info from the DevlinkParam.Type field
  226. type DevlinkParamValue struct {
  227. rawData []byte
  228. Data interface{}
  229. CMODE uint8 // possible values are in nl.DEVLINK_PARAM_CMODE_* constants
  230. }
  231. // parseAttributes parses provided Netlink Attributes and populates DevlinkParam, returns error if occured
  232. func (dlp *DevlinkParam) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
  233. var valuesList [][]syscall.NetlinkRouteAttr
  234. for _, attr := range attrs {
  235. switch attr.Attr.Type {
  236. case nl.DEVLINK_ATTR_PARAM:
  237. nattrs, err := nl.ParseRouteAttr(attr.Value)
  238. if err != nil {
  239. return err
  240. }
  241. for _, nattr := range nattrs {
  242. switch nattr.Attr.Type {
  243. case nl.DEVLINK_ATTR_PARAM_NAME:
  244. dlp.Name = nl.BytesToString(nattr.Value)
  245. case nl.DEVLINK_ATTR_PARAM_GENERIC:
  246. dlp.IsGeneric = true
  247. case nl.DEVLINK_ATTR_PARAM_TYPE:
  248. if len(nattr.Value) == 1 {
  249. dlp.Type = nattr.Value[0]
  250. }
  251. case nl.DEVLINK_ATTR_PARAM_VALUES_LIST:
  252. nnattrs, err := nl.ParseRouteAttr(nattr.Value)
  253. if err != nil {
  254. return err
  255. }
  256. valuesList = append(valuesList, nnattrs)
  257. }
  258. }
  259. }
  260. }
  261. for _, valAttr := range valuesList {
  262. v := DevlinkParamValue{}
  263. if err := v.parseAttributes(valAttr, dlp.Type); err != nil {
  264. return err
  265. }
  266. dlp.Values = append(dlp.Values, v)
  267. }
  268. return nil
  269. }
  270. func (dlpv *DevlinkParamValue) parseAttributes(attrs []syscall.NetlinkRouteAttr, paramType uint8) error {
  271. for _, attr := range attrs {
  272. nattrs, err := nl.ParseRouteAttr(attr.Value)
  273. if err != nil {
  274. return err
  275. }
  276. var rawData []byte
  277. for _, nattr := range nattrs {
  278. switch nattr.Attr.Type {
  279. case nl.DEVLINK_ATTR_PARAM_VALUE_DATA:
  280. rawData = nattr.Value
  281. case nl.DEVLINK_ATTR_PARAM_VALUE_CMODE:
  282. if len(nattr.Value) == 1 {
  283. dlpv.CMODE = nattr.Value[0]
  284. }
  285. }
  286. }
  287. switch paramType {
  288. case nl.DEVLINK_PARAM_TYPE_U8:
  289. dlpv.Data = uint8(0)
  290. if rawData != nil && len(rawData) == 1 {
  291. dlpv.Data = uint8(rawData[0])
  292. }
  293. case nl.DEVLINK_PARAM_TYPE_U16:
  294. dlpv.Data = uint16(0)
  295. if rawData != nil {
  296. dlpv.Data = native.Uint16(rawData)
  297. }
  298. case nl.DEVLINK_PARAM_TYPE_U32:
  299. dlpv.Data = uint32(0)
  300. if rawData != nil {
  301. dlpv.Data = native.Uint32(rawData)
  302. }
  303. case nl.DEVLINK_PARAM_TYPE_STRING:
  304. dlpv.Data = ""
  305. if rawData != nil {
  306. dlpv.Data = nl.BytesToString(rawData)
  307. }
  308. case nl.DEVLINK_PARAM_TYPE_BOOL:
  309. dlpv.Data = rawData != nil
  310. }
  311. }
  312. return nil
  313. }
  314. func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) {
  315. devices := make([]*DevlinkDevice, 0, len(msgs))
  316. for _, m := range msgs {
  317. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  318. if err != nil {
  319. return nil, err
  320. }
  321. dev := &DevlinkDevice{}
  322. if err = dev.parseAttributes(attrs); err != nil {
  323. return nil, err
  324. }
  325. devices = append(devices, dev)
  326. }
  327. return devices, nil
  328. }
  329. func eswitchStringToMode(modeName string) (uint16, error) {
  330. if modeName == "legacy" {
  331. return nl.DEVLINK_ESWITCH_MODE_LEGACY, nil
  332. } else if modeName == "switchdev" {
  333. return nl.DEVLINK_ESWITCH_MODE_SWITCHDEV, nil
  334. } else {
  335. return 0xffff, fmt.Errorf("invalid switchdev mode")
  336. }
  337. }
  338. func parseEswitchMode(mode uint16) string {
  339. var eswitchMode = map[uint16]string{
  340. nl.DEVLINK_ESWITCH_MODE_LEGACY: "legacy",
  341. nl.DEVLINK_ESWITCH_MODE_SWITCHDEV: "switchdev",
  342. }
  343. if eswitchMode[mode] == "" {
  344. return "unknown"
  345. } else {
  346. return eswitchMode[mode]
  347. }
  348. }
  349. func parseEswitchInlineMode(inlinemode uint8) string {
  350. var eswitchInlineMode = map[uint8]string{
  351. nl.DEVLINK_ESWITCH_INLINE_MODE_NONE: "none",
  352. nl.DEVLINK_ESWITCH_INLINE_MODE_LINK: "link",
  353. nl.DEVLINK_ESWITCH_INLINE_MODE_NETWORK: "network",
  354. nl.DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT: "transport",
  355. }
  356. if eswitchInlineMode[inlinemode] == "" {
  357. return "unknown"
  358. } else {
  359. return eswitchInlineMode[inlinemode]
  360. }
  361. }
  362. func parseEswitchEncapMode(encapmode uint8) string {
  363. var eswitchEncapMode = map[uint8]string{
  364. nl.DEVLINK_ESWITCH_ENCAP_MODE_NONE: "disable",
  365. nl.DEVLINK_ESWITCH_ENCAP_MODE_BASIC: "enable",
  366. }
  367. if eswitchEncapMode[encapmode] == "" {
  368. return "unknown"
  369. } else {
  370. return eswitchEncapMode[encapmode]
  371. }
  372. }
  373. func (d *DevlinkDevice) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
  374. for _, a := range attrs {
  375. switch a.Attr.Type {
  376. case nl.DEVLINK_ATTR_BUS_NAME:
  377. d.BusName = string(a.Value[:len(a.Value)-1])
  378. case nl.DEVLINK_ATTR_DEV_NAME:
  379. d.DeviceName = string(a.Value[:len(a.Value)-1])
  380. case nl.DEVLINK_ATTR_ESWITCH_MODE:
  381. d.Attrs.Eswitch.Mode = parseEswitchMode(native.Uint16(a.Value))
  382. case nl.DEVLINK_ATTR_ESWITCH_INLINE_MODE:
  383. d.Attrs.Eswitch.InlineMode = parseEswitchInlineMode(uint8(a.Value[0]))
  384. case nl.DEVLINK_ATTR_ESWITCH_ENCAP_MODE:
  385. d.Attrs.Eswitch.EncapMode = parseEswitchEncapMode(uint8(a.Value[0]))
  386. }
  387. }
  388. return nil
  389. }
  390. func (dev *DevlinkDevice) parseEswitchAttrs(msgs [][]byte) {
  391. m := msgs[0]
  392. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  393. if err != nil {
  394. return
  395. }
  396. dev.parseAttributes(attrs)
  397. }
  398. func (h *Handle) getEswitchAttrs(family *GenlFamily, dev *DevlinkDevice) {
  399. msg := &nl.Genlmsg{
  400. Command: nl.DEVLINK_CMD_ESWITCH_GET,
  401. Version: nl.GENL_DEVLINK_VERSION,
  402. }
  403. req := h.newNetlinkRequest(int(family.ID), unix.NLM_F_REQUEST|unix.NLM_F_ACK)
  404. req.AddData(msg)
  405. b := make([]byte, len(dev.BusName)+1)
  406. copy(b, dev.BusName)
  407. data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
  408. req.AddData(data)
  409. b = make([]byte, len(dev.DeviceName)+1)
  410. copy(b, dev.DeviceName)
  411. data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
  412. req.AddData(data)
  413. msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
  414. if err != nil {
  415. return
  416. }
  417. dev.parseEswitchAttrs(msgs)
  418. }
  419. // DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
  420. // otherwise returns an error code.
  421. // If the returned error is [ErrDumpInterrupted], results may be inconsistent
  422. // or incomplete.
  423. func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
  424. f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
  425. if err != nil {
  426. return nil, err
  427. }
  428. msg := &nl.Genlmsg{
  429. Command: nl.DEVLINK_CMD_GET,
  430. Version: nl.GENL_DEVLINK_VERSION,
  431. }
  432. req := h.newNetlinkRequest(int(f.ID),
  433. unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
  434. req.AddData(msg)
  435. msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
  436. if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
  437. return nil, executeErr
  438. }
  439. devices, err := parseDevLinkDeviceList(msgs)
  440. if err != nil {
  441. return nil, err
  442. }
  443. for _, d := range devices {
  444. h.getEswitchAttrs(f, d)
  445. }
  446. return devices, executeErr
  447. }
  448. // DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
  449. // otherwise returns an error code.
  450. //
  451. // If the returned error is [ErrDumpInterrupted], results may be inconsistent
  452. // or incomplete.
  453. func DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
  454. return pkgHandle.DevLinkGetDeviceList()
  455. }
  456. func parseDevlinkDevice(msgs [][]byte) (*DevlinkDevice, error) {
  457. m := msgs[0]
  458. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  459. if err != nil {
  460. return nil, err
  461. }
  462. dev := &DevlinkDevice{}
  463. if err = dev.parseAttributes(attrs); err != nil {
  464. return nil, err
  465. }
  466. return dev, nil
  467. }
  468. func (h *Handle) createCmdReq(cmd uint8, bus string, device string) (*GenlFamily, *nl.NetlinkRequest, error) {
  469. f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
  470. if err != nil {
  471. return nil, nil, err
  472. }
  473. msg := &nl.Genlmsg{
  474. Command: cmd,
  475. Version: nl.GENL_DEVLINK_VERSION,
  476. }
  477. req := h.newNetlinkRequest(int(f.ID),
  478. unix.NLM_F_REQUEST|unix.NLM_F_ACK)
  479. req.AddData(msg)
  480. b := make([]byte, len(bus)+1)
  481. copy(b, bus)
  482. data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
  483. req.AddData(data)
  484. b = make([]byte, len(device)+1)
  485. copy(b, device)
  486. data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
  487. req.AddData(data)
  488. return f, req, nil
  489. }
  490. // DevlinkGetDeviceByName provides a pointer to devlink device and nil error,
  491. // otherwise returns an error code.
  492. func (h *Handle) DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) {
  493. f, req, err := h.createCmdReq(nl.DEVLINK_CMD_GET, Bus, Device)
  494. if err != nil {
  495. return nil, err
  496. }
  497. respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
  498. if err != nil {
  499. return nil, err
  500. }
  501. dev, err := parseDevlinkDevice(respmsg)
  502. if err == nil {
  503. h.getEswitchAttrs(f, dev)
  504. }
  505. return dev, err
  506. }
  507. // DevlinkGetDeviceByName provides a pointer to devlink device and nil error,
  508. // otherwise returns an error code.
  509. func DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) {
  510. return pkgHandle.DevLinkGetDeviceByName(Bus, Device)
  511. }
  512. // DevLinkSetEswitchMode sets eswitch mode if able to set successfully or
  513. // returns an error code.
  514. // Equivalent to: `devlink dev eswitch set $dev mode switchdev`
  515. // Equivalent to: `devlink dev eswitch set $dev mode legacy`
  516. func (h *Handle) DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
  517. mode, err := eswitchStringToMode(NewMode)
  518. if err != nil {
  519. return err
  520. }
  521. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_ESWITCH_SET, Dev.BusName, Dev.DeviceName)
  522. if err != nil {
  523. return err
  524. }
  525. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_ESWITCH_MODE, nl.Uint16Attr(mode)))
  526. _, err = req.Execute(unix.NETLINK_GENERIC, 0)
  527. return err
  528. }
  529. // DevLinkSetEswitchMode sets eswitch mode if able to set successfully or
  530. // returns an error code.
  531. // Equivalent to: `devlink dev eswitch set $dev mode switchdev`
  532. // Equivalent to: `devlink dev eswitch set $dev mode legacy`
  533. func DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
  534. return pkgHandle.DevLinkSetEswitchMode(Dev, NewMode)
  535. }
  536. func (port *DevlinkPort) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
  537. for _, a := range attrs {
  538. switch a.Attr.Type {
  539. case nl.DEVLINK_ATTR_BUS_NAME:
  540. port.BusName = string(a.Value[:len(a.Value)-1])
  541. case nl.DEVLINK_ATTR_DEV_NAME:
  542. port.DeviceName = string(a.Value[:len(a.Value)-1])
  543. case nl.DEVLINK_ATTR_PORT_INDEX:
  544. port.PortIndex = native.Uint32(a.Value)
  545. case nl.DEVLINK_ATTR_PORT_TYPE:
  546. port.PortType = native.Uint16(a.Value)
  547. case nl.DEVLINK_ATTR_PORT_NETDEV_NAME:
  548. port.NetdeviceName = string(a.Value[:len(a.Value)-1])
  549. case nl.DEVLINK_ATTR_PORT_NETDEV_IFINDEX:
  550. port.NetdevIfIndex = native.Uint32(a.Value)
  551. case nl.DEVLINK_ATTR_PORT_IBDEV_NAME:
  552. port.RdmaDeviceName = string(a.Value[:len(a.Value)-1])
  553. case nl.DEVLINK_ATTR_PORT_FLAVOUR:
  554. port.PortFlavour = native.Uint16(a.Value)
  555. case nl.DEVLINK_ATTR_PORT_FUNCTION:
  556. port.Fn = &DevlinkPortFn{}
  557. for nested := range nl.ParseAttributes(a.Value) {
  558. switch nested.Type {
  559. case nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR:
  560. port.Fn.HwAddr = nested.Value[:]
  561. case nl.DEVLINK_PORT_FN_ATTR_STATE:
  562. port.Fn.State = uint8(nested.Value[0])
  563. case nl.DEVLINK_PORT_FN_ATTR_OPSTATE:
  564. port.Fn.OpState = uint8(nested.Value[0])
  565. }
  566. }
  567. }
  568. }
  569. return nil
  570. }
  571. func parseDevLinkAllPortList(msgs [][]byte) ([]*DevlinkPort, error) {
  572. ports := make([]*DevlinkPort, 0, len(msgs))
  573. for _, m := range msgs {
  574. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  575. if err != nil {
  576. return nil, err
  577. }
  578. port := &DevlinkPort{}
  579. if err = port.parseAttributes(attrs); err != nil {
  580. return nil, err
  581. }
  582. ports = append(ports, port)
  583. }
  584. return ports, nil
  585. }
  586. // DevLinkGetPortList provides a pointer to devlink ports and nil error,
  587. // otherwise returns an error code.
  588. // If the returned error is [ErrDumpInterrupted], results may be inconsistent
  589. // or incomplete.
  590. func (h *Handle) DevLinkGetAllPortList() ([]*DevlinkPort, error) {
  591. f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
  592. if err != nil {
  593. return nil, err
  594. }
  595. msg := &nl.Genlmsg{
  596. Command: nl.DEVLINK_CMD_PORT_GET,
  597. Version: nl.GENL_DEVLINK_VERSION,
  598. }
  599. req := h.newNetlinkRequest(int(f.ID),
  600. unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
  601. req.AddData(msg)
  602. msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
  603. if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
  604. return nil, executeErr
  605. }
  606. ports, err := parseDevLinkAllPortList(msgs)
  607. if err != nil {
  608. return nil, err
  609. }
  610. return ports, executeErr
  611. }
  612. // DevLinkGetPortList provides a pointer to devlink ports and nil error,
  613. // otherwise returns an error code.
  614. // If the returned error is [ErrDumpInterrupted], results may be inconsistent
  615. // or incomplete.
  616. func DevLinkGetAllPortList() ([]*DevlinkPort, error) {
  617. return pkgHandle.DevLinkGetAllPortList()
  618. }
  619. func parseDevlinkPortMsg(msgs [][]byte) (*DevlinkPort, error) {
  620. m := msgs[0]
  621. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  622. if err != nil {
  623. return nil, err
  624. }
  625. port := &DevlinkPort{}
  626. if err = port.parseAttributes(attrs); err != nil {
  627. return nil, err
  628. }
  629. return port, nil
  630. }
  631. // DevLinkGetPortByIndexprovides a pointer to devlink device and nil error,
  632. // otherwise returns an error code.
  633. func (h *Handle) DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
  634. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_GET, Bus, Device)
  635. if err != nil {
  636. return nil, err
  637. }
  638. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
  639. respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
  640. if err != nil {
  641. return nil, err
  642. }
  643. port, err := parseDevlinkPortMsg(respmsg)
  644. return port, err
  645. }
  646. // DevlinkGetDeviceResources returns devlink device resources
  647. func DevlinkGetDeviceResources(bus string, device string) (*DevlinkResources, error) {
  648. return pkgHandle.DevlinkGetDeviceResources(bus, device)
  649. }
  650. // DevlinkGetDeviceResources returns devlink device resources
  651. func (h *Handle) DevlinkGetDeviceResources(bus string, device string) (*DevlinkResources, error) {
  652. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_RESOURCE_DUMP, bus, device)
  653. if err != nil {
  654. return nil, err
  655. }
  656. respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
  657. if err != nil {
  658. return nil, err
  659. }
  660. var resources DevlinkResources
  661. for _, m := range respmsg {
  662. attrs, err := nl.ParseRouteAttrAsMap(m[nl.SizeofGenlmsg:])
  663. if err != nil {
  664. return nil, err
  665. }
  666. resources.parseAttributes(attrs)
  667. }
  668. return &resources, nil
  669. }
  670. // DevlinkGetDeviceParams returns parameters for devlink device
  671. // Equivalent to: `devlink dev param show <bus>/<device>`
  672. //
  673. // If the returned error is [ErrDumpInterrupted], results may be inconsistent
  674. // or incomplete.
  675. func (h *Handle) DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkParam, error) {
  676. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PARAM_GET, bus, device)
  677. if err != nil {
  678. return nil, err
  679. }
  680. req.Flags |= unix.NLM_F_DUMP
  681. respmsg, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
  682. if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
  683. return nil, executeErr
  684. }
  685. var params []*DevlinkParam
  686. for _, m := range respmsg {
  687. attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
  688. if err != nil {
  689. return nil, err
  690. }
  691. p := &DevlinkParam{}
  692. if err := p.parseAttributes(attrs); err != nil {
  693. return nil, err
  694. }
  695. params = append(params, p)
  696. }
  697. return params, executeErr
  698. }
  699. // DevlinkGetDeviceParams returns parameters for devlink device
  700. // Equivalent to: `devlink dev param show <bus>/<device>`
  701. //
  702. // If the returned error is [ErrDumpInterrupted], results may be inconsistent
  703. // or incomplete.
  704. func DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkParam, error) {
  705. return pkgHandle.DevlinkGetDeviceParams(bus, device)
  706. }
  707. // DevlinkGetDeviceParamByName returns specific parameter for devlink device
  708. // Equivalent to: `devlink dev param show <bus>/<device> name <param>`
  709. func (h *Handle) DevlinkGetDeviceParamByName(bus string, device string, param string) (*DevlinkParam, error) {
  710. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PARAM_GET, bus, device)
  711. if err != nil {
  712. return nil, err
  713. }
  714. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_NAME, nl.ZeroTerminated(param)))
  715. respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
  716. if err != nil {
  717. return nil, err
  718. }
  719. if len(respmsg) == 0 {
  720. return nil, fmt.Errorf("unexpected response")
  721. }
  722. attrs, err := nl.ParseRouteAttr(respmsg[0][nl.SizeofGenlmsg:])
  723. if err != nil {
  724. return nil, err
  725. }
  726. p := &DevlinkParam{}
  727. if err := p.parseAttributes(attrs); err != nil {
  728. return nil, err
  729. }
  730. return p, nil
  731. }
  732. // DevlinkGetDeviceParamByName returns specific parameter for devlink device
  733. // Equivalent to: `devlink dev param show <bus>/<device> name <param>`
  734. func DevlinkGetDeviceParamByName(bus string, device string, param string) (*DevlinkParam, error) {
  735. return pkgHandle.DevlinkGetDeviceParamByName(bus, device, param)
  736. }
  737. // DevlinkSetDeviceParam set specific parameter for devlink device
  738. // Equivalent to: `devlink dev param set <bus>/<device> name <param> cmode <cmode> value <value>`
  739. // cmode argument should contain valid cmode value as uint8, modes are define in nl.DEVLINK_PARAM_CMODE_* constants
  740. // value argument should have one of the following types: uint8, uint16, uint32, string, bool
  741. func (h *Handle) DevlinkSetDeviceParam(bus string, device string, param string, cmode uint8, value interface{}) error {
  742. // retrive the param type
  743. p, err := h.DevlinkGetDeviceParamByName(bus, device, param)
  744. if err != nil {
  745. return fmt.Errorf("failed to get device param: %v", err)
  746. }
  747. paramType := p.Type
  748. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PARAM_SET, bus, device)
  749. if err != nil {
  750. return err
  751. }
  752. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_TYPE, nl.Uint8Attr(paramType)))
  753. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_NAME, nl.ZeroTerminated(param)))
  754. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_VALUE_CMODE, nl.Uint8Attr(cmode)))
  755. var valueAsBytes []byte
  756. switch paramType {
  757. case nl.DEVLINK_PARAM_TYPE_U8:
  758. v, ok := value.(uint8)
  759. if !ok {
  760. return fmt.Errorf("unepected value type required: uint8, actual: %T", value)
  761. }
  762. valueAsBytes = nl.Uint8Attr(v)
  763. case nl.DEVLINK_PARAM_TYPE_U16:
  764. v, ok := value.(uint16)
  765. if !ok {
  766. return fmt.Errorf("unepected value type required: uint16, actual: %T", value)
  767. }
  768. valueAsBytes = nl.Uint16Attr(v)
  769. case nl.DEVLINK_PARAM_TYPE_U32:
  770. v, ok := value.(uint32)
  771. if !ok {
  772. return fmt.Errorf("unepected value type required: uint32, actual: %T", value)
  773. }
  774. valueAsBytes = nl.Uint32Attr(v)
  775. case nl.DEVLINK_PARAM_TYPE_STRING:
  776. v, ok := value.(string)
  777. if !ok {
  778. return fmt.Errorf("unepected value type required: string, actual: %T", value)
  779. }
  780. valueAsBytes = nl.ZeroTerminated(v)
  781. case nl.DEVLINK_PARAM_TYPE_BOOL:
  782. v, ok := value.(bool)
  783. if !ok {
  784. return fmt.Errorf("unepected value type required: bool, actual: %T", value)
  785. }
  786. if v {
  787. valueAsBytes = []byte{}
  788. }
  789. default:
  790. return fmt.Errorf("unsupported parameter type: %d", paramType)
  791. }
  792. if valueAsBytes != nil {
  793. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PARAM_VALUE_DATA, valueAsBytes))
  794. }
  795. _, err = req.Execute(unix.NETLINK_GENERIC, 0)
  796. return err
  797. }
  798. // DevlinkSetDeviceParam set specific parameter for devlink device
  799. // Equivalent to: `devlink dev param set <bus>/<device> name <param> cmode <cmode> value <value>`
  800. // cmode argument should contain valid cmode value as uint8, modes are define in nl.DEVLINK_PARAM_CMODE_* constants
  801. // value argument should have one of the following types: uint8, uint16, uint32, string, bool
  802. func DevlinkSetDeviceParam(bus string, device string, param string, cmode uint8, value interface{}) error {
  803. return pkgHandle.DevlinkSetDeviceParam(bus, device, param, cmode, value)
  804. }
  805. // DevLinkGetPortByIndex provides a pointer to devlink portand nil error,
  806. // otherwise returns an error code.
  807. func DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
  808. return pkgHandle.DevLinkGetPortByIndex(Bus, Device, PortIndex)
  809. }
  810. // DevLinkPortAdd adds a devlink port and returns a port on success
  811. // otherwise returns nil port and an error code.
  812. func (h *Handle) DevLinkPortAdd(Bus string, Device string, Flavour uint16, Attrs DevLinkPortAddAttrs) (*DevlinkPort, error) {
  813. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_NEW, Bus, Device)
  814. if err != nil {
  815. return nil, err
  816. }
  817. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FLAVOUR, nl.Uint16Attr(Flavour)))
  818. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_PF_NUMBER, nl.Uint16Attr(Attrs.PfNumber)))
  819. if Flavour == nl.DEVLINK_PORT_FLAVOUR_PCI_SF && Attrs.SfNumberValid {
  820. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_SF_NUMBER, nl.Uint32Attr(Attrs.SfNumber)))
  821. }
  822. if Attrs.PortIndexValid {
  823. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(Attrs.PortIndex)))
  824. }
  825. if Attrs.ControllerValid {
  826. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_CONTROLLER_NUMBER, nl.Uint32Attr(Attrs.Controller)))
  827. }
  828. respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
  829. if err != nil {
  830. return nil, err
  831. }
  832. port, err := parseDevlinkPortMsg(respmsg)
  833. return port, err
  834. }
  835. // DevLinkPortAdd adds a devlink port and returns a port on success
  836. // otherwise returns nil port and an error code.
  837. func DevLinkPortAdd(Bus string, Device string, Flavour uint16, Attrs DevLinkPortAddAttrs) (*DevlinkPort, error) {
  838. return pkgHandle.DevLinkPortAdd(Bus, Device, Flavour, Attrs)
  839. }
  840. // DevLinkPortDel deletes a devlink port and returns success or error code.
  841. func (h *Handle) DevLinkPortDel(Bus string, Device string, PortIndex uint32) error {
  842. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_DEL, Bus, Device)
  843. if err != nil {
  844. return err
  845. }
  846. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
  847. _, err = req.Execute(unix.NETLINK_GENERIC, 0)
  848. return err
  849. }
  850. // DevLinkPortDel deletes a devlink port and returns success or error code.
  851. func DevLinkPortDel(Bus string, Device string, PortIndex uint32) error {
  852. return pkgHandle.DevLinkPortDel(Bus, Device, PortIndex)
  853. }
  854. // DevlinkPortFnSet sets one or more port function attributes specified by the attribute mask.
  855. // It returns 0 on success or error code.
  856. func (h *Handle) DevlinkPortFnSet(Bus string, Device string, PortIndex uint32, FnAttrs DevlinkPortFnSetAttrs) error {
  857. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_SET, Bus, Device)
  858. if err != nil {
  859. return err
  860. }
  861. req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
  862. fnAttr := nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FUNCTION|unix.NLA_F_NESTED, nil)
  863. if FnAttrs.HwAddrValid {
  864. fnAttr.AddRtAttr(nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, []byte(FnAttrs.FnAttrs.HwAddr))
  865. }
  866. if FnAttrs.StateValid {
  867. fnAttr.AddRtAttr(nl.DEVLINK_PORT_FN_ATTR_STATE, nl.Uint8Attr(FnAttrs.FnAttrs.State))
  868. }
  869. req.AddData(fnAttr)
  870. _, err = req.Execute(unix.NETLINK_GENERIC, 0)
  871. return err
  872. }
  873. // DevlinkPortFnSet sets one or more port function attributes specified by the attribute mask.
  874. // It returns 0 on success or error code.
  875. func DevlinkPortFnSet(Bus string, Device string, PortIndex uint32, FnAttrs DevlinkPortFnSetAttrs) error {
  876. return pkgHandle.DevlinkPortFnSet(Bus, Device, PortIndex, FnAttrs)
  877. }
  878. // devlinkInfoGetter is function that is responsible for getting devlink info message
  879. // this is introduced for test purpose
  880. type devlinkInfoGetter func(bus, device string) ([]byte, error)
  881. // DevlinkGetDeviceInfoByName returns devlink info for selected device,
  882. // otherwise returns an error code.
  883. // Equivalent to: `devlink dev info $dev`
  884. func (h *Handle) DevlinkGetDeviceInfoByName(Bus string, Device string, getInfoMsg devlinkInfoGetter) (*DevlinkDeviceInfo, error) {
  885. info, err := h.DevlinkGetDeviceInfoByNameAsMap(Bus, Device, getInfoMsg)
  886. if err != nil {
  887. return nil, err
  888. }
  889. return parseInfoData(info), nil
  890. }
  891. // DevlinkGetDeviceInfoByName returns devlink info for selected device,
  892. // otherwise returns an error code.
  893. // Equivalent to: `devlink dev info $dev`
  894. func DevlinkGetDeviceInfoByName(Bus string, Device string) (*DevlinkDeviceInfo, error) {
  895. return pkgHandle.DevlinkGetDeviceInfoByName(Bus, Device, pkgHandle.getDevlinkInfoMsg)
  896. }
  897. // DevlinkGetDeviceInfoByNameAsMap returns devlink info for selected device as a map,
  898. // otherwise returns an error code.
  899. // Equivalent to: `devlink dev info $dev`
  900. func (h *Handle) DevlinkGetDeviceInfoByNameAsMap(Bus string, Device string, getInfoMsg devlinkInfoGetter) (map[string]string, error) {
  901. response, err := getInfoMsg(Bus, Device)
  902. if err != nil {
  903. return nil, err
  904. }
  905. info, err := parseInfoMsg(response)
  906. if err != nil {
  907. return nil, err
  908. }
  909. return info, nil
  910. }
  911. // DevlinkGetDeviceInfoByNameAsMap returns devlink info for selected device as a map,
  912. // otherwise returns an error code.
  913. // Equivalent to: `devlink dev info $dev`
  914. func DevlinkGetDeviceInfoByNameAsMap(Bus string, Device string) (map[string]string, error) {
  915. return pkgHandle.DevlinkGetDeviceInfoByNameAsMap(Bus, Device, pkgHandle.getDevlinkInfoMsg)
  916. }
  917. // GetDevlinkInfo returns devlink info for target device,
  918. // otherwise returns an error code.
  919. func (d *DevlinkDevice) GetDevlinkInfo() (*DevlinkDeviceInfo, error) {
  920. return pkgHandle.DevlinkGetDeviceInfoByName(d.BusName, d.DeviceName, pkgHandle.getDevlinkInfoMsg)
  921. }
  922. // GetDevlinkInfoAsMap returns devlink info for target device as a map,
  923. // otherwise returns an error code.
  924. func (d *DevlinkDevice) GetDevlinkInfoAsMap() (map[string]string, error) {
  925. return pkgHandle.DevlinkGetDeviceInfoByNameAsMap(d.BusName, d.DeviceName, pkgHandle.getDevlinkInfoMsg)
  926. }
  927. func (h *Handle) getDevlinkInfoMsg(bus, device string) ([]byte, error) {
  928. _, req, err := h.createCmdReq(nl.DEVLINK_CMD_INFO_GET, bus, device)
  929. if err != nil {
  930. return nil, err
  931. }
  932. response, err := req.Execute(unix.NETLINK_GENERIC, 0)
  933. if err != nil {
  934. return nil, err
  935. }
  936. if len(response) < 1 {
  937. return nil, fmt.Errorf("getDevlinkInfoMsg: message too short")
  938. }
  939. return response[0], nil
  940. }
  941. func parseInfoMsg(msg []byte) (map[string]string, error) {
  942. if len(msg) < nl.SizeofGenlmsg {
  943. return nil, fmt.Errorf("parseInfoMsg: message too short")
  944. }
  945. info := make(map[string]string)
  946. err := collectInfoData(msg[nl.SizeofGenlmsg:], info)
  947. if err != nil {
  948. return nil, err
  949. }
  950. return info, nil
  951. }
  952. func collectInfoData(msg []byte, data map[string]string) error {
  953. attrs, err := nl.ParseRouteAttr(msg)
  954. if err != nil {
  955. return err
  956. }
  957. for _, attr := range attrs {
  958. switch attr.Attr.Type {
  959. case nl.DEVLINK_ATTR_INFO_DRIVER_NAME:
  960. data["driver"] = parseInfoValue(attr.Value)
  961. case nl.DEVLINK_ATTR_INFO_SERIAL_NUMBER:
  962. data["serialNumber"] = parseInfoValue(attr.Value)
  963. case nl.DEVLINK_ATTR_INFO_VERSION_RUNNING, nl.DEVLINK_ATTR_INFO_VERSION_FIXED,
  964. nl.DEVLINK_ATTR_INFO_VERSION_STORED:
  965. key, value, err := getNestedInfoData(attr.Value)
  966. if err != nil {
  967. return err
  968. }
  969. data[key] = value
  970. }
  971. }
  972. if len(data) == 0 {
  973. return fmt.Errorf("collectInfoData: could not read attributes")
  974. }
  975. return nil
  976. }
  977. func getNestedInfoData(msg []byte) (string, string, error) {
  978. nestedAttrs, err := nl.ParseRouteAttr(msg)
  979. var key, value string
  980. if err != nil {
  981. return "", "", err
  982. }
  983. if len(nestedAttrs) != 2 {
  984. return "", "", fmt.Errorf("getNestedInfoData: too few attributes in nested structure")
  985. }
  986. for _, nestedAttr := range nestedAttrs {
  987. switch nestedAttr.Attr.Type {
  988. case nl.DEVLINK_ATTR_INFO_VERSION_NAME:
  989. key = parseInfoValue(nestedAttr.Value)
  990. case nl.DEVLINK_ATTR_INFO_VERSION_VALUE:
  991. value = parseInfoValue(nestedAttr.Value)
  992. }
  993. }
  994. if key == "" {
  995. return "", "", fmt.Errorf("getNestedInfoData: key not found")
  996. }
  997. if value == "" {
  998. return "", "", fmt.Errorf("getNestedInfoData: value not found")
  999. }
  1000. return key, value, nil
  1001. }
  1002. func parseInfoData(data map[string]string) *DevlinkDeviceInfo {
  1003. info := new(DevlinkDeviceInfo)
  1004. for key, value := range data {
  1005. switch key {
  1006. case "driver":
  1007. info.Driver = value
  1008. case "serialNumber":
  1009. info.SerialNumber = value
  1010. case "board.id":
  1011. info.BoardID = value
  1012. case "fw.app":
  1013. info.FwApp = value
  1014. case "fw.app.bundle_id":
  1015. info.FwAppBoundleID = value
  1016. case "fw.app.name":
  1017. info.FwAppName = value
  1018. case "fw.bundle_id":
  1019. info.FwBoundleID = value
  1020. case "fw.mgmt":
  1021. info.FwMgmt = value
  1022. case "fw.mgmt.api":
  1023. info.FwMgmtAPI = value
  1024. case "fw.mgmt.build":
  1025. info.FwMgmtBuild = value
  1026. case "fw.netlist":
  1027. info.FwNetlist = value
  1028. case "fw.netlist.build":
  1029. info.FwNetlistBuild = value
  1030. case "fw.psid.api":
  1031. info.FwPsidAPI = value
  1032. case "fw.undi":
  1033. info.FwUndi = value
  1034. }
  1035. }
  1036. return info
  1037. }
  1038. func parseInfoValue(value []byte) string {
  1039. v := strings.ReplaceAll(string(value), "\x00", "")
  1040. return strings.TrimSpace(v)
  1041. }