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