github.com/vishvananda/netlink@v1.3.0/devlink_linux.go (about) 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 // DevlinkDevEswitchAttr represents device's eswitch attributes 14 type DevlinkDevEswitchAttr struct { 15 Mode string 16 InlineMode string 17 EncapMode string 18 } 19 20 // DevlinkDevAttrs represents device attributes 21 type DevlinkDevAttrs struct { 22 Eswitch DevlinkDevEswitchAttr 23 } 24 25 // DevlinkDevice represents device and its attributes 26 type DevlinkDevice struct { 27 BusName string 28 DeviceName string 29 Attrs DevlinkDevAttrs 30 } 31 32 // DevlinkPortFn represents port function and its attributes 33 type DevlinkPortFn struct { 34 HwAddr net.HardwareAddr 35 State uint8 36 OpState uint8 37 } 38 39 // DevlinkPortFnSetAttrs represents attributes to set 40 type DevlinkPortFnSetAttrs struct { 41 FnAttrs DevlinkPortFn 42 HwAddrValid bool 43 StateValid bool 44 } 45 46 // DevlinkPort represents port and its attributes 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 // DevlinkDeviceInfo represents devlink info 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 // DevlinkResource represents a device resource 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 // parseAttributes parses provided Netlink Attributes and populates DevlinkResource, returns error if occured 106 func (dlr *DevlinkResource) parseAttributes(attrs map[uint16]syscall.NetlinkRouteAttr) error { 107 var attr syscall.NetlinkRouteAttr 108 var ok bool 109 110 // mandatory attributes 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 // optional attributes 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 // handle nested resoruces recursively 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 // DevlinkResources represents all devlink resources of a devlink device 198 type DevlinkResources struct { 199 Bus string 200 Device string 201 Resources []DevlinkResource 202 } 203 204 // parseAttributes parses provided Netlink Attributes and populates DevlinkResources, returns error if occured 205 func (dlrs *DevlinkResources) parseAttributes(attrs map[uint16]syscall.NetlinkRouteAttr) error { 206 var attr syscall.NetlinkRouteAttr 207 var ok bool 208 209 // Bus 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 // Device 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 // Resource List 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 // DevlinkParam represents parameter of the device 251 type DevlinkParam struct { 252 Name string 253 IsGeneric bool 254 Type uint8 // possible values are in nl.DEVLINK_PARAM_TYPE_* constants 255 Values []DevlinkParamValue 256 } 257 258 // DevlinkParamValue contains values of the parameter 259 // Data field contains specific type which can be casted by unsing info from the DevlinkParam.Type field 260 type DevlinkParamValue struct { 261 rawData []byte 262 Data interface{} 263 CMODE uint8 // possible values are in nl.DEVLINK_PARAM_CMODE_* constants 264 } 265 266 // parseAttributes parses provided Netlink Attributes and populates DevlinkParam, returns error if occured 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 // DevLinkGetDeviceList provides a pointer to devlink devices and nil error, 468 // otherwise returns an error code. 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 // DevLinkGetDeviceList provides a pointer to devlink devices and nil error, 496 // otherwise returns an error code. 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 // DevlinkGetDeviceByName provides a pointer to devlink device and nil error, 542 // otherwise returns an error code. 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 // DevlinkGetDeviceByName provides a pointer to devlink device and nil error, 561 // otherwise returns an error code. 562 func DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) { 563 return pkgHandle.DevLinkGetDeviceByName(Bus, Device) 564 } 565 566 // DevLinkSetEswitchMode sets eswitch mode if able to set successfully or 567 // returns an error code. 568 // Equivalent to: `devlink dev eswitch set $dev mode switchdev` 569 // Equivalent to: `devlink dev eswitch set $dev mode legacy` 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 // DevLinkSetEswitchMode sets eswitch mode if able to set successfully or 588 // returns an error code. 589 // Equivalent to: `devlink dev eswitch set $dev mode switchdev` 590 // Equivalent to: `devlink dev eswitch set $dev mode legacy` 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 // DevLinkGetPortList provides a pointer to devlink ports and nil error, 648 // otherwise returns an error code. 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 // DevLinkGetPortList provides a pointer to devlink ports and nil error, 673 // otherwise returns an error code. 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 // DevLinkGetPortByIndexprovides a pointer to devlink device and nil error, 692 // otherwise returns an error code. 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 // DevlinkGetDeviceResources returns devlink device resources 711 func DevlinkGetDeviceResources(bus string, device string) (*DevlinkResources, error) { 712 return pkgHandle.DevlinkGetDeviceResources(bus, device) 713 } 714 715 // DevlinkGetDeviceResources returns devlink device resources 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 // DevlinkGetDeviceParams returns parameters for devlink device 740 // Equivalent to: `devlink dev param show <bus>/<device>` 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 // DevlinkGetDeviceParams returns parameters for devlink device 768 // Equivalent to: `devlink dev param show <bus>/<device>` 769 func DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkParam, error) { 770 return pkgHandle.DevlinkGetDeviceParams(bus, device) 771 } 772 773 // DevlinkGetDeviceParamByName returns specific parameter for devlink device 774 // Equivalent to: `devlink dev param show <bus>/<device> name <param>` 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 // DevlinkGetDeviceParamByName returns specific parameter for devlink device 800 // Equivalent to: `devlink dev param show <bus>/<device> name <param>` 801 func DevlinkGetDeviceParamByName(bus string, device string, param string) (*DevlinkParam, error) { 802 return pkgHandle.DevlinkGetDeviceParamByName(bus, device, param) 803 } 804 805 // DevlinkSetDeviceParam set specific parameter for devlink device 806 // Equivalent to: `devlink dev param set <bus>/<device> name <param> cmode <cmode> value <value>` 807 // cmode argument should contain valid cmode value as uint8, modes are define in nl.DEVLINK_PARAM_CMODE_* constants 808 // value argument should have one of the following types: uint8, uint16, uint32, string, bool 809 func (h *Handle) DevlinkSetDeviceParam(bus string, device string, param string, cmode uint8, value interface{}) error { 810 // retrive the param type 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 // DevlinkSetDeviceParam set specific parameter for devlink device 870 // Equivalent to: `devlink dev param set <bus>/<device> name <param> cmode <cmode> value <value>` 871 // cmode argument should contain valid cmode value as uint8, modes are define in nl.DEVLINK_PARAM_CMODE_* constants 872 // value argument should have one of the following types: uint8, uint16, uint32, string, bool 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 // DevLinkGetPortByIndex provides a pointer to devlink portand nil error, 878 // otherwise returns an error code. 879 func DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) { 880 return pkgHandle.DevLinkGetPortByIndex(Bus, Device, PortIndex) 881 } 882 883 // DevLinkPortAdd adds a devlink port and returns a port on success 884 // otherwise returns nil port and an error code. 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 // DevLinkPortAdd adds a devlink port and returns a port on success 912 // otherwise returns nil port and an error code. 913 func DevLinkPortAdd(Bus string, Device string, Flavour uint16, Attrs DevLinkPortAddAttrs) (*DevlinkPort, error) { 914 return pkgHandle.DevLinkPortAdd(Bus, Device, Flavour, Attrs) 915 } 916 917 // DevLinkPortDel deletes a devlink port and returns success or error code. 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 // DevLinkPortDel deletes a devlink port and returns success or error code. 930 func DevLinkPortDel(Bus string, Device string, PortIndex uint32) error { 931 return pkgHandle.DevLinkPortDel(Bus, Device, PortIndex) 932 } 933 934 // DevlinkPortFnSet sets one or more port function attributes specified by the attribute mask. 935 // It returns 0 on success or error code. 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 // DevlinkPortFnSet sets one or more port function attributes specified by the attribute mask. 960 // It returns 0 on success or error code. 961 func DevlinkPortFnSet(Bus string, Device string, PortIndex uint32, FnAttrs DevlinkPortFnSetAttrs) error { 962 return pkgHandle.DevlinkPortFnSet(Bus, Device, PortIndex, FnAttrs) 963 } 964 965 // devlinkInfoGetter is function that is responsible for getting devlink info message 966 // this is introduced for test purpose 967 type devlinkInfoGetter func(bus, device string) ([]byte, error) 968 969 // DevlinkGetDeviceInfoByName returns devlink info for selected device, 970 // otherwise returns an error code. 971 // Equivalent to: `devlink dev info $dev` 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 // DevlinkGetDeviceInfoByName returns devlink info for selected device, 982 // otherwise returns an error code. 983 // Equivalent to: `devlink dev info $dev` 984 func DevlinkGetDeviceInfoByName(Bus string, Device string) (*DevlinkDeviceInfo, error) { 985 return pkgHandle.DevlinkGetDeviceInfoByName(Bus, Device, pkgHandle.getDevlinkInfoMsg) 986 } 987 988 // DevlinkGetDeviceInfoByNameAsMap returns devlink info for selected device as a map, 989 // otherwise returns an error code. 990 // Equivalent to: `devlink dev info $dev` 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 // DevlinkGetDeviceInfoByNameAsMap returns devlink info for selected device as a map, 1006 // otherwise returns an error code. 1007 // Equivalent to: `devlink dev info $dev` 1008 func DevlinkGetDeviceInfoByNameAsMap(Bus string, Device string) (map[string]string, error) { 1009 return pkgHandle.DevlinkGetDeviceInfoByNameAsMap(Bus, Device, pkgHandle.getDevlinkInfoMsg) 1010 } 1011 1012 // GetDevlinkInfo returns devlink info for target device, 1013 // otherwise returns an error code. 1014 func (d *DevlinkDevice) GetDevlinkInfo() (*DevlinkDeviceInfo, error) { 1015 return pkgHandle.DevlinkGetDeviceInfoByName(d.BusName, d.DeviceName, pkgHandle.getDevlinkInfoMsg) 1016 } 1017 1018 // GetDevlinkInfoAsMap returns devlink info for target device as a map, 1019 // otherwise returns an error code. 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 }