Skip to content

Commit

Permalink
Added support for acquiring DDP profile using devlink
Browse files Browse the repository at this point in the history
  • Loading branch information
ipatrykx committed Oct 26, 2022
1 parent fc8984c commit 1ea4df3
Show file tree
Hide file tree
Showing 4 changed files with 336 additions and 16 deletions.
46 changes: 32 additions & 14 deletions pkg/netdevice/pciNetDevice.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@ import (
// pciNetDevice extends pciDevice
type pciNetDevice struct {
types.PciDevice
ifName string
pfName string
linkSpeed string
rdmaSpec types.RdmaSpec
linkType string
vdpaDev types.VdpaDevice
ifName string
pfName string
linkSpeed string
rdmaSpec types.RdmaSpec
linkType string
vdpaDev types.VdpaDevice
getDDPProfile ddpProfileGetFunc
}

type ddpProfileGetFunc func(string) (string, error)

// NewPciNetDevice returns an instance of PciNetDevice interface
func NewPciNetDevice(dev *ghw.PCIDevice, rFactory types.ResourceFactory, rc *types.ResourceConfig) (types.PciNetDevice, error) {
var ifName string
Expand Down Expand Up @@ -99,14 +102,25 @@ func NewPciNetDevice(dev *ghw.PCIDevice, rFactory types.ResourceFactory, rc *typ
linkType = la.EncapType
}

var ddpFunc ddpProfileGetFunc

if utils.IsDevlinkDDPSupportedByPCIDevice(pciAddr) {
ddpFunc = utils.DevlinkGetDDPProfiles
} else if utils.IsDDPToolSupportedByDevice(pciAddr) {
ddpFunc = utils.GetDDPProfiles
} else {
ddpFunc = unsupportedDDP
}

return &pciNetDevice{
PciDevice: pciDev,
ifName: ifName,
pfName: pfName,
linkSpeed: "", // TO-DO: Get this using utils pkg
rdmaSpec: rdmaSpec,
linkType: linkType,
vdpaDev: vdpaDev,
PciDevice: pciDev,
ifName: ifName,
pfName: pfName,
linkSpeed: "", // TO-DO: Get this using utils pkg
rdmaSpec: rdmaSpec,
linkType: linkType,
vdpaDev: vdpaDev,
getDDPProfile: ddpFunc,
}, nil
}

Expand All @@ -130,9 +144,13 @@ func (nd *pciNetDevice) GetLinkType() string {
return nd.linkType
}

func unsupportedDDP(device string) (string, error) {
return "", utils.DDPNotSupportedError(device)
}

func (nd *pciNetDevice) GetDDPProfiles() string {
pciAddr := nd.GetPciAddr()
ddpProfile, err := utils.GetDDPProfiles(pciAddr)
ddpProfile, err := nd.getDDPProfile(pciAddr)
if err != nil {
glog.Infof("GetDDPProfiles(): unable to get ddp profiles for device %s : %q", pciAddr, err)
return ""
Expand Down
26 changes: 24 additions & 2 deletions pkg/utils/ddp.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package utils
import (
"bytes"
"encoding/json"
"fmt"
"os/exec"

"github.com/pkg/errors"
)

/*
Expand Down Expand Up @@ -47,8 +48,26 @@ type DDPpackage struct {
Name string `json:"name"`
}

// 8 is an exit code of ddptool when profile was not found
const ddpNoDDPProfile = 8

var ddpExecCommand = exec.Command

// IsDDPToolSupportedByDevice checks if DDPTool can be used with device
func IsDDPToolSupportedByDevice(dev string) bool {
if _, err := GetDDPProfiles(dev); err != nil && err != ErrProfileNameNotFound {
if exitError, ok := err.(*exec.ExitError); ok {
if exitError.ExitCode() == ddpNoDDPProfile {
return true
}
}

return false
}

return true
}

// GetDDPProfiles returns running DDP profile name if available
func GetDDPProfiles(dev string) (string, error) {
var stdout bytes.Buffer
Expand All @@ -61,14 +80,17 @@ func GetDDPProfiles(dev string) (string, error) {
return getDDPNameFromStdout(stdout.Bytes())
}

// ErrProfileNameNotFound error when DDPTool is supported, but package name is empty
var ErrProfileNameNotFound = errors.New("DDP profile name not found")

func getDDPNameFromStdout(in []byte) (string, error) {
ddpInfo := &DDPInfo{}
if err := json.Unmarshal(in, ddpInfo); err != nil {
return "", err
}

if ddpInfo.DDPInventory.DDPpackage.Name == "" {
return "", fmt.Errorf("DDP profile name not found")
return "", ErrProfileNameNotFound
}

return ddpInfo.DDPInventory.DDPpackage.Name, nil
Expand Down
96 changes: 96 additions & 0 deletions pkg/utils/devlink.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package utils

import (
"fmt"

"github.com/pkg/errors"
"github.com/vishvananda/netlink"
)

const (
// fwAppNameKey is a key to extract DDP name
fwAppNameKey = "fw.app.name"
pciBus = "pci"
)

// IsDevlinkDDPSupportedByPCIDevice checks if DDP of PCI device can be acquired with devlink info command
func IsDevlinkDDPSupportedByPCIDevice(device string) bool {
return IsDevlinkDDPSupportedByDevice(pciBus, device)
}

// IsDevlinkDDPSupportedByDevice checks if DDP of device can be acquired with devlink info command
func IsDevlinkDDPSupportedByDevice(bus, device string) bool {
if _, err := DevlinkGetDeviceInfoByNameAndKey(bus, device, fwAppNameKey); err != nil {
return false
}

return true
}

// DevlinkGetDDPProfiles returns DDP for selected device
func DevlinkGetDDPProfiles(device string) (string, error) {
return DevlinkGetDeviceInfoByNameAndKey(pciBus, device, fwAppNameKey)
}

// DevlinkGetDeviceInfoByNameAndKeys returns values for selected keys in device info
func DevlinkGetDeviceInfoByNameAndKeys(bus, device string,
keys []string) (map[string]string, error) {
data, err := netlink.DevlinkGetDeviceInfoByNameAsMap(bus, device)
if err != nil {
return nil, err
}

info := make(map[string]string)

for _, key := range keys {
if value, exists := data[key]; exists {
info[key] = value
} else {
return nil, KeyNotFoundError("DevlinkGetDeviceInfoByNameAndKeys", key)
}
}

return info, nil
}

// DevlinkGetDeviceInfoByNameAndKey returns values for selected key in device info
func DevlinkGetDeviceInfoByNameAndKey(bus, device, key string) (string, error) {
keys := []string{key}
info, err := DevlinkGetDeviceInfoByNameAndKeys(bus, device, keys)
if err != nil {
return "", err
}

if value, exists := info[key]; exists {
return value, nil
}

return "", KeyNotFoundError("DevlinkGetDeviceInfoByNameAndKey", key)
}

// ErrKeyNotFound error when key is not found in the parsed response
var ErrKeyNotFound = errors.New("key could not be found")

// ErrMessageTooShort error when netlink message is too short
var ErrMessageTooShort = errors.New("message too short")

// ErrReadAttributes error when netlink message attributes cannot be read
var ErrReadAttributes = errors.New("could not read attributes")

// ErrDDPNotSupported error when device does not support DDP
var ErrDDPNotSupported = errors.New("this device seems not to support DDP")

// KeyNotFoundError returns ErrKeyNotFound
func KeyNotFoundError(function, key string) error {
return fmt.Errorf("%s - %w: %s", function, ErrKeyNotFound, key)
}

// ReadAttributesError returns ErrReadAttributes
func ReadAttributesError(function, message string) error {
return fmt.Errorf("%s - %w: %s", function, ErrReadAttributes, message)
}

// DDPNotSupportedError returns ErrDDPNotSupported
func DDPNotSupportedError(device string) error {
return fmt.Errorf("%w: %s", ErrDDPNotSupported, device)
}
Loading

0 comments on commit 1ea4df3

Please sign in to comment.