-
Notifications
You must be signed in to change notification settings - Fork 114
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add implementation of Infiniband interface
new package incapsulates the guid config file validation, guid pool implementation and host manipulations to set IB VF GUIDs
- Loading branch information
1 parent
7116dc0
commit 0022c10
Showing
14 changed files
with
871 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package infiniband | ||
|
||
import ( | ||
"fmt" | ||
"math/rand" | ||
"net" | ||
) | ||
|
||
// GUID address is an uint64 encapsulation for network hardware address | ||
type GUID uint64 | ||
|
||
const ( | ||
guidLength = 8 | ||
byteBitLen = 8 | ||
byteMask = 0xff | ||
) | ||
|
||
// ParseGUID parses string only as GUID 64 bit | ||
func ParseGUID(s string) (GUID, error) { | ||
ha, err := net.ParseMAC(s) | ||
if err != nil { | ||
return 0, err | ||
} | ||
if len(ha) != guidLength { | ||
return 0, fmt.Errorf("invalid GUID address %s", s) | ||
} | ||
var guid uint64 | ||
for idx, octet := range ha { | ||
guid |= uint64(octet) << uint(byteBitLen*(guidLength-1-idx)) | ||
} | ||
return GUID(guid), nil | ||
} | ||
|
||
// String returns the string representation of GUID | ||
func (g GUID) String() string { | ||
return g.HardwareAddr().String() | ||
} | ||
|
||
// HardwareAddr returns GUID representation as net.HardwareAddr | ||
func (g GUID) HardwareAddr() net.HardwareAddr { | ||
value := uint64(g) | ||
ha := make(net.HardwareAddr, guidLength) | ||
for idx := guidLength - 1; idx >= 0; idx-- { | ||
ha[idx] = byte(value & byteMask) | ||
value >>= byteBitLen | ||
} | ||
|
||
return ha | ||
} | ||
|
||
func generateRandomGUID() net.HardwareAddr { | ||
guid := make(net.HardwareAddr, 8) | ||
|
||
// First field is 0x01 - xfe to avoid all zero and all F invalid guids | ||
guid[0] = byte(1 + rand.Intn(0xfe)) | ||
|
||
for i := 1; i < len(guid); i++ { | ||
guid[i] = byte(rand.Intn(0x100)) | ||
} | ||
|
||
return guid | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package infiniband | ||
|
||
import ( | ||
"net" | ||
|
||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
var _ = Describe("GUID", func() { | ||
It("should parse and process GUIDs correctly", func() { | ||
guidStr := "00:01:02:03:04:05:06:08" | ||
nextGuidStr := "00:01:02:03:04:05:06:09" | ||
|
||
guid, err := ParseGUID(guidStr) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
Expect(guid.String()).To(Equal(guidStr)) | ||
Expect((guid + 1).String()).To(Equal(nextGuidStr)) | ||
}) | ||
It("should represent GUID as HW address", func() { | ||
guidStr := "00:01:02:03:04:05:06:08" | ||
|
||
guid, err := ParseGUID(guidStr) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
Expect(guid.HardwareAddr()).To(Equal(net.HardwareAddr{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08})) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
package infiniband | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/internal/lib/netlink" | ||
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/types" | ||
"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils" | ||
) | ||
|
||
type ibPfGUIDJSONConfig struct { | ||
PciAddress string `json:"pciAddress,omitempty"` | ||
PfGUID string `json:"pfGuid,omitempty"` | ||
GUIDs []string `json:"guids,omitempty"` | ||
GUIDsRange *GUIDRangeJSON `json:"guidsRange,omitempty"` | ||
} | ||
|
||
type GUIDRangeJSON struct { | ||
Start string `json:"start,omitempty"` | ||
End string `json:"end,omitempty"` | ||
} | ||
|
||
type ibPfGUIDConfig struct { | ||
GUIDs []GUID | ||
GUIDRange *GUIDRange | ||
} | ||
|
||
type GUIDRange struct { | ||
Start GUID | ||
End GUID | ||
} | ||
|
||
func getIbGUIDConfig(configPath string, netlinkLib netlink.NetlinkLib, networkHelper types.NetworkInterface) (map[string]ibPfGUIDConfig, error) { | ||
links, err := netlinkLib.LinkList() | ||
if err != nil { | ||
return nil, err | ||
} | ||
rawConfigs, err := readJSONConfig(configPath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
resultConfigs := map[string]ibPfGUIDConfig{} | ||
// Parse JSON config into an internal struct | ||
for _, rawConfig := range rawConfigs { | ||
pciAddress, err := getPfPciAddressFromRawConfig(rawConfig, links, networkHelper) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to extract pci address from ib guid config: %w", err) | ||
} | ||
if len(rawConfig.GUIDs) == 0 && (rawConfig.GUIDsRange == nil || (rawConfig.GUIDsRange.Start == "" || rawConfig.GUIDsRange.End == "")) { | ||
return nil, fmt.Errorf("either guid list or guid range should be provided, got none") | ||
} | ||
if len(rawConfig.GUIDs) != 0 && rawConfig.GUIDsRange != nil { | ||
return nil, fmt.Errorf("either guid list or guid range should be provided, got both") | ||
} | ||
if rawConfig.GUIDsRange != nil && ((rawConfig.GUIDsRange.Start != "" && rawConfig.GUIDsRange.End == "") || (rawConfig.GUIDsRange.Start == "" && rawConfig.GUIDsRange.End != "")) { | ||
return nil, fmt.Errorf("both guid rangeStart and rangeEnd should be provided, got one") | ||
} | ||
if len(rawConfig.GUIDs) != 0 { | ||
var guids []GUID | ||
for _, guidStr := range rawConfig.GUIDs { | ||
guid, err := ParseGUID(guidStr) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to parse ib guid %s: %w", guidStr, err) | ||
} | ||
guids = append(guids, guid) | ||
} | ||
resultConfigs[pciAddress] = ibPfGUIDConfig{ | ||
GUIDs: guids, | ||
} | ||
continue | ||
} | ||
|
||
rangeStart, err := ParseGUID(rawConfig.GUIDsRange.Start) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to parse ib guid range start: %w", err) | ||
} | ||
rangeEnd, err := ParseGUID(rawConfig.GUIDsRange.End) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to parse ib guid range end: %w", err) | ||
} | ||
if rangeEnd < rangeStart { | ||
return nil, fmt.Errorf("range end cannot be less then range start") | ||
} | ||
resultConfigs[pciAddress] = ibPfGUIDConfig{ | ||
GUIDRange: &GUIDRange{ | ||
Start: rangeStart, | ||
End: rangeEnd, | ||
}, | ||
} | ||
} | ||
return resultConfigs, nil | ||
} | ||
|
||
// readJSONConfig reads the file at the given path and unmarshals the contents into an array of ibPfGUIDJSONConfig structs | ||
func readJSONConfig(configPath string) ([]ibPfGUIDJSONConfig, error) { | ||
data, err := os.ReadFile(utils.GetHostExtensionPath(configPath)) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to read ib guid config: %w", err) | ||
} | ||
var configs []ibPfGUIDJSONConfig | ||
if err := json.Unmarshal(data, &configs); err != nil { | ||
return nil, fmt.Errorf("failed to unmarshal content of ib guid config: %w", err) | ||
} | ||
return configs, nil | ||
} | ||
|
||
func getPfPciAddressFromRawConfig(pfRawConfig ibPfGUIDJSONConfig, links []netlink.Link, networkHelper types.NetworkInterface) (string, error) { | ||
if pfRawConfig.PciAddress != "" && pfRawConfig.PfGUID != "" { | ||
return "", fmt.Errorf("either PCI address or PF GUID required to describe an interface, both provided") | ||
} | ||
if pfRawConfig.PciAddress == "" && pfRawConfig.PfGUID == "" { | ||
return "", fmt.Errorf("either PCI address or PF GUID required to describe an interface, none provided") | ||
} | ||
if pfRawConfig.PciAddress != "" { | ||
return pfRawConfig.PciAddress, nil | ||
} | ||
// PfGUID is provided, need to resolve the pci address | ||
for _, link := range links { | ||
if link.Attrs().HardwareAddr.String() == pfRawConfig.PfGUID { | ||
return networkHelper.GetPciAddressFromInterfaceName(link.Attrs().Name) | ||
} | ||
} | ||
return "", fmt.Errorf("no matching link found for pf guid: %s", pfRawConfig.PfGUID) | ||
} |
Oops, something went wrong.