diff --git a/README.md b/README.md index 00348d05f..4b4d841db 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ which are available on a Kubernetes host - Handles SR-IOV capable/not-capable devices (NICs and Accelerators alike) - Handles PCI backed Auxiliary network devices (**at the moment SFs only**) - Supports devices with both Kernel and userspace (UIO and VFIO) drivers -- Allows resource grouping using "Selector" +- Allows resource grouping using "selector(s)" - User configurable resourceName - Detects Kubelet restarts and auto-re-register - Detects Link status (for Linux network devices) and updates associated VFs health accordingly @@ -180,81 +180,89 @@ This plugin creates device plugin endpoints based on the configurations given in { "resourceList": [{ "resourceName": "intel_sriov_netdevice", - "selectors": { + "selectors": [{ "vendors": ["8086"], "devices": ["154c", "10ed", "1889"], "drivers": ["i40evf", "ixgbevf", "iavf"] - } + }] }, { "resourceName": "intel_sriov_dpdk", "resourcePrefix": "intel.com", - "selectors": { + "selectors": [{ "vendors": ["8086"], "devices": ["154c", "10ed", "1889"], "drivers": ["vfio-pci"], "pfNames": ["enp0s0f0","enp2s2f1"], "needVhostNet": true - } + }] }, { "resourceName": "mlnx_sriov_rdma", "resourcePrefix": "mellanox.com", - "selectors": { + "selectors": [{ "vendors": ["15b3"], "devices": ["1018"], "drivers": ["mlx5_ib"], "isRdma": true - } + }] }, { "resourceName": "infiniband_rdma_netdevs", - "selectors": { + "selectors": [{ "linkTypes": ["infiniband"], "isRdma": true - } + }] }, { "resourceName": "ct6dx_vdpa_vhost", - "selectors": { + "selectors": [{ "vendors": ["15b3"], "devices": ["101e"], "drivers": ["mlx5_core"], "vdpaType": "vhost" - } + }] }, { "resourceName": "intel_fpga", "deviceType": "accelerator", - "selectors": { + "selectors": [{ "vendors": ["8086"], "devices": ["0d90"] - } + }] }, { "resourceName": "bf2_sf", "resourcePrefix": "nvidia.com", "deviceType": "auxNetDevice", - "selectors": { + "selectors": [{ "vendors": ["15b3"], "devices": ["a2d6"], "pfNames": ["p0#1-5"], "auxTypes": ["sf"] - } + }] }, { "resourceName": "intel_sriov_netdevice_additional_env", - "selectors": { + "selectors": [{ "vendors": ["8086"], "devices": ["154c", "10ed", "1889"], "drivers": ["i40evf", "ixgbevf", "iavf"] - }, + }], "additionalInfo": { "*": { "token": "3e49019f-412f-4f02-824e-4cd195944205" } } - } + }, + { + "resourceName": "old_selectors_syntax_example", + "selectors": { + "vendors": ["8086"], + "devices": ["154c", "10ed", "1889"], + "drivers": ["i40evf", "ixgbevf", "iavf"] + } + } ] } ``` @@ -267,17 +275,32 @@ This plugin creates device plugin endpoints based on the configurations given in | "resourcePrefix" | N | Endpoint resource prefix name override. Should not contain special characters | string Default : "intel.com" | "yourcompany.com" | | "deviceType" | N | Device Type for a resource pool. | string value of supported types. Default: "netDevice" | Currently supported values: "accelerator", "netDevice", "auxNetDevice" | | "excludeTopology" | N | Exclude advertising of device's NUMA topology | bool Default: "false" | "excludeTopology": true | -| "selectors" | N | A map of device selectors. The "deviceType" value determines the "selectors" options. | json object as string Default: null | Example: "selectors": {"vendors": ["8086"],"devices": ["154c"]} | +| "selectors" | N | Either a single device selector map or a list of maps. The list syntax is preferred. The "deviceType" value determines the device selector options. | json list of objects or json object. Default: null | Example: "selectors": [{"vendors": ["8086"],"devices": ["154c"]}] | | "additionalInfo" | N | A map of map to add additional information to the pod via environment variables to devices | json object as string Default: null | Example: "additionalInfo": {"*": {"token": "3e49019f-412f-4f02-824e-4cd195944205"}} | Note: "resourceName" must be unique only in the scope of a given prefix, including the one specified globally in the CLI params, e.g. "example.com/10G", "acme.com/10G" and "acme.com/40G" are perfectly valid names. #### Device selectors -The "deviceType" value determines which selectors are supported for that device. Each selector evaluated in order as listed in selector tables below. +The "selectors" field accepts both a single object and a list of selector objects. While both formats are supported, the list syntax is preferred. When using the list syntax, each selector object is evaluated in the order present in the list. For example, a single object would look like: +```json +"selectors": {"vendors": ["8086"],"devices": ["154c"]} +``` +and the list syntax would look like: +```json +"selectors": [{"vendors": ["8086"],"devices": ["154c"]}, {"vendors": ["8086"], "needVhostNet": true}] +``` + +The list syntax example specifies two selector objects in the list. In this example, all devices specified by the first selector object have vendor ID 8086 and device ID 154c. The second selector object specifies all devices with vendor ID 8086. Since the selector objects are processed in the specified order, devices with vendor ID 8086 and device ID 154c would not have the `needVhostNet: true` applied to them. Contrast this with another similar looking example: +```json +"selectors": [{"vendors": ["8086"], "needVhostNet": true}, {"vendors": ["8086"],"devices": ["154c"]}] +``` +In this latter example, the order of the selector objects has been switched. Since all devices that are specified by the second object are also specified by the first object, this makes the second selector object ineffective. + +A given selector object comprises of "selectors". The "deviceType" value determines which selectors are supported for that device. Each selector is evaluated in order as listed in selector tables below. #### Accelerator devices selectors -This selectors are applicable when "deviceType" is "accelerator". +These selectors are applicable when "deviceType" is "accelerator". | Field | Required | Description | Type/Defaults | Example/Accepted values | |----------------|----------|-------------------------------------------|-------------------------------|-------------------------------------| @@ -287,8 +310,8 @@ This selectors are applicable when "deviceType" is "accelerator". | "pciAddresses" | N | Target device's pci address as string | `string` list Default: `null` | "pciAddresses": ["0000:03:02.0"] | -#### Network devices selector -This selector is applicable when "deviceType" is "netDevice"(note: this is default) +#### Network devices selectors +These selectors are applicable when "deviceType" is "netDevice" (note: this is default) | Field | Required | Description | Type/Defaults | Example/Accepted values | @@ -300,14 +323,14 @@ This selector is applicable when "deviceType" is "netDevice"(note: this is defau | "pfNames" | N | functions from PF matches list of PF names | `string` list Default: `null` | "pfNames": ["enp2s2f0"] (See follow-up sections for some advance usage of "pfNames") | | "rootDevices" | N | functions from PF matches list of PF PCI addresses | `string` list Default: `null` | "rootDevices": ["0000:86:00.0"] (See follow-up sections for some advance usage of "rootDevices") | | "linkTypes" | N | The link type of the net device associated with the PCI device | `string` list Default: `null` | "linkTypes": ["ether"] | -| "isRdma" | N | Mount RDMA resources. Incompatible with vdpaType | `bool` values `true` or `false` Default: `false` | "isRdma": `true` | | "ddpProfiles" | N | A map of device selectors | `string` list Default: `null` | "ddpProfiles": ["GTPv1-C/U IPv4/IPv6 payload"] | +| "isRdma" | N | Mount RDMA resources. Incompatible with vdpaType | `bool` values `true` or `false` Default: `false` | "isRdma": `true` | | "needVhostNet" | N | Share /dev/vhost-net and /dev/net/tun | `bool` values `true` or `false` Default: `false` | "needVhostNet": `true` | | "vdpaType" | N | The type of vDPA device (virtio, vhost). Incompatible with isRdma = true | `string` values `vhost` or `virtio` Default: `null` | "vdpaType": "vhost" | #### Auxiliary network devices selectors -This selector is applicable when "deviceType" is "auxNetDevice". +These selectors are applicable when "deviceType" is "auxNetDevice". | Field | Required | Description | Type/Defaults | Example/Accepted values | |---------------|----------|----------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------|--------------------------------------------------------------------------------------------------| @@ -405,13 +428,13 @@ Usage of ./sriovdp: ### Assumptions -This plugin does not bind or unbind any driver to any device whether it's PFs or VFs. It also doesn't create Virtual functions either. Usually, the virtual functions are created at boot time when kernel module for the device is loaded. Same with a SFs. Required device drivers could be loaded on system boot-up time by allow-listing/deny-listing the right modules. But plugin needs to be aware of the driver type of the resources (i.e. devices) that it is registering as K8s extended resource so that it's able to create appropriate Device Specs for the requested resource. +This plugin does not bind or unbind any driver to any device whether it's PFs or VFs. It also doesn't create virtual functions either. Usually, the virtual functions are created at boot time when kernel module for the device is loaded. Same with SFs. Required device drivers could be loaded on system boot-up time by allow-listing/deny-listing the right modules. But plugin needs to be aware of the driver type of the resources (i.e. devices) that it is registering as K8s extended resource so that it's able to create appropriate Device Specs for the requested resource. For example, if the driver type is uio (i.e. igb_uio.ko) then there are specific device files to add in Device Spec. For vfio-pci, device files are different. And if it is Linux kernel network driver then there is no device file to be added. -The idea here is, user creates a resource config for each resource pool as shown in [Config parameters](#config-parameters) by specifying the resource name, a list resource "selectors". +The idea here is, user creates a resource config for each resource pool as shown in [Config parameters](#config-parameters) by specifying the resource name and a "selector object" or list of "selector objects". Each "selector object" contains "selector(s)". -The device plugin will initially discover all PCI network resources in the host and populate an initial "device list". If device type is Auxiliary network device (auxNetDevice), then for each discovered PCI device of type Netdevice plugin discovers auxiliry devices. Each "resource pool" then applies its selectors on this list and add devices that satisfies the selector's constraints. Each selector narrows down the list of devices for the resource pool. Currently, the selectors are applied in following order: +The device plugin will initially discover all PCI network resources in the host and populate an initial "device list". If device type is Auxiliary network device (auxNetDevice), then for each discovered PCI device of type Netdevice the plugin discovers auxiliary devices. Each "resource pool" then applies its selector object(s) in order to the list of discovered devices. The plugin will add devices that satisfy the selector object's constraints to the resource pool. Each "selector" specified in the selector object narrows down the list of devices for the resource pool. Currently, the selectors are applied in following order: 1. "vendors" - The vendor hex code of device 2. "devices" - The device hex code of device @@ -422,6 +445,8 @@ The device plugin will initially discover all PCI network resources in the host 7. "rootDevices" - The Physical function PCI address 8. "linkTypes" - The link type of the net device associated with the PCI device +If a single device matches multiple selector objects, it will only be allocated to the first one. + The "pfNames" and "rootDevices" selectors can be used to specify a list and/or range of VFs/SFs for a pool in the below format ```` "#,-,,,-" diff --git a/cmd/sriovdp/manager.go b/cmd/sriovdp/manager.go index 096492143..1a3003a38 100644 --- a/cmd/sriovdp/manager.go +++ b/cmd/sriovdp/manager.go @@ -89,7 +89,7 @@ func (rm *resourceManager) readConfig() error { } else if _, ok := types.SupportedDevices[conf.DeviceType]; !ok { return fmt.Errorf("unsupported deviceType: \"%s\"", conf.DeviceType) } - if conf.SelectorObj, err = rm.rFactory.GetDeviceFilter(conf); err == nil { + if conf.SelectorObjs, err = rm.rFactory.GetDeviceFilter(conf); err == nil { rm.configList = append(rm.configList, &resources.ResourceList[i]) } else { glog.Warningf("unable to get SelectorObj from selectors list:'%s' for deviceType: %s error: %s", @@ -115,12 +115,18 @@ func (rm *resourceManager) initServers() error { return fmt.Errorf("error getting device provider") } - devices := dp.GetDevices(rc) - filteredDevices, err := dp.GetFilteredDevices(devices, rc) - if err != nil { - glog.Errorf("initServers(): error getting filtered devices for config %+v: %q", rc, err) + filteredDevices := make([]types.HostDevice, 0) + + for index := range rc.SelectorObjs { + devices := dp.GetDevices(rc, index) + partialFilteredDevices, err := dp.GetFilteredDevices(devices, rc, index) + if err != nil { + glog.Errorf("initServers(): error getting filtered devices for config %+v: %q", rc, err) + } + partialFilteredDevices = rm.excludeAllocatedDevices(partialFilteredDevices, deviceAllocated) + glog.Infof("initServers(): selector index %d will register %d devices", index, len(partialFilteredDevices)) + filteredDevices = append(filteredDevices, partialFilteredDevices...) } - filteredDevices = rm.excludeAllocatedDevices(filteredDevices, deviceAllocated) if len(filteredDevices) < 1 { glog.Infof("no devices in device pool, skipping creating resource server for %s", rc.ResourceName) continue diff --git a/cmd/sriovdp/manager_test.go b/cmd/sriovdp/manager_test.go index dc8288d8d..c24c2fdb8 100644 --- a/cmd/sriovdp/manager_test.go +++ b/cmd/sriovdp/manager_test.go @@ -127,6 +127,63 @@ var _ = Describe("Resource manager", func() { Expect(len(rm.configList)).To(Equal(2)) }) }) + Context("when the multi-selector config reading is successful", func() { + var err error + BeforeEach(func() { + // add err handling + testErr := os.MkdirAll("/tmp/sriovdp", 0755) + if testErr != nil { + panic(testErr) + } + testErr = os.WriteFile("/tmp/sriovdp/test_config", []byte(`{ + "resourceList": [{ + "resourceName": "intel_sriov_netdevice", + "selectors": { + "isRdma": false, + "vendors": ["8086"], + "devices": ["154c", "10ed"], + "drivers": ["i40evf", "ixgbevf"] + } + }, + { + "resourceName": "dpdk", + "selectors": [{ + "vendors": ["8086"], + "devices": ["154c", "10ed"], + "drivers": ["vfio-pci"] + }, { + "vendors": ["15b3"], + "devices": ["1018"], + "drivers": ["mlx5_core"], + "isRdma": true + }] + } + ] + }`), 0644) + if testErr != nil { + panic(testErr) + } + err = rm.readConfig() + }) + AfterEach(func() { + testErr := os.RemoveAll("/tmp/sriovdp") + if testErr != nil { + panic(testErr) + } + rm = nil + cp = nil + }) + It("shouldn't fail", func() { + Expect(err).NotTo(HaveOccurred()) + }) + It("should load resources list", func() { + Expect(rm.configList).To(HaveLen(2)) + }) + It("should load all selector objects", func() { + Expect(rm.configList[0].SelectorObjs).To(HaveLen(1)) + Expect(rm.configList[1].SelectorObjs).To(HaveLen(2)) + }) + }) }) Describe("validating configuration", func() { var fs *utils.FakeFilesystem @@ -242,6 +299,73 @@ var _ = Describe("Resource manager", func() { Expect(rm.validConfigs()).To(Equal(false)) }) }) + Context("when isRdma and vdpaType are configured in separate selectors", func() { + BeforeEach(func() { + err := os.MkdirAll("/tmp/sriovdp", 0755) + if err != nil { + panic(err) + } + err = os.WriteFile("/tmp/sriovdp/test_config", []byte(`{ + "resourceList": [{ + "resourceName": "correct_config", + "selectors": [{ + "vdpaType": "virtio", + "vendors": ["8086"], + "devices": ["154c", "10ed"], + "drivers": ["i40evf", "ixgbevf"] + }, { + "isRdma": true, + "vendors": ["8086"], + "devices": ["154c", "10ed"], + "drivers": ["i40evf", "ixgbevf"] + }] + }] + }`), 0644) + if err != nil { + panic(err) + } + _ = rm.readConfig() + + }) + It("should return true", func() { + defer fs.Use()() + Expect(rm.validConfigs()).To(Equal(true)) + }) + }) + Context("when isRdma and vdpaType are configured in a second selector", func() { + BeforeEach(func() { + err := os.MkdirAll("/tmp/sriovdp", 0755) + if err != nil { + panic(err) + } + err = os.WriteFile("/tmp/sriovdp/test_config", []byte(`{ + "resourceList": [{ + "resourceName": "mixed_config", + "selectors": [{ + "vdpaType": "virtio", + "vendors": ["8086"], + "devices": ["154c", "10ed"], + "drivers": ["i40evf", "ixgbevf"] + }, { + "isRdma": true, + "vdpaType": "virtio", + "vendors": ["8086"], + "devices": ["154c", "10ed"], + "drivers": ["i40evf", "ixgbevf"] + }] + }] + }`), 0644) + if err != nil { + panic(err) + } + _ = rm.readConfig() + + }) + It("should return false", func() { + defer fs.Use()() + Expect(rm.validConfigs()).To(Equal(false)) + }) + }) Describe("managing resources servers", func() { Describe("initializing servers", func() { Context("when initializing server fails", func() { @@ -273,10 +397,10 @@ var _ = Describe("Resource manager", func() { rc := &types.ResourceConfig{ ResourceName: "fake", DeviceType: types.NetDeviceType, - SelectorObj: types.NetDeviceSelectors{}, + SelectorObjs: []interface{}{types.NetDeviceSelectors{}}, } dp := &mocks.DeviceProvider{} - dp.On("GetFilteredDevices", devs, rc).Return(devs, nil) + dp.On("GetFilteredDevices", devs, rc, 0).Return(devs, nil) rp := &mocks.ResourcePool{} @@ -284,7 +408,7 @@ var _ = Describe("Resource manager", func() { mockedRf.On("GetResourcePool", rc, devs).Return(rp, nil). On("GetResourceServer", rp).Return(mockedServer, nil) dev.On("GetDeviceID").Return("0000:01:10.0") - dp.On("GetDevices", rc).Return(devs) + dp.On("GetDevices", rc, 0).Return(devs) rm := &resourceManager{ rFactory: mockedRf, configList: []*types.ResourceConfig{rc}, diff --git a/docs/ddp/README.md b/docs/ddp/README.md index 6529456e9..38dc46163 100644 --- a/docs/ddp/README.md +++ b/docs/ddp/README.md @@ -88,35 +88,35 @@ data: "resourceList": [ { "resourceName": "e800_default", - "selectors": { + "selectors": [{ "vendors": ["8086"], "devices": ["1889"], "ddpProfiles": ["ICE OS Default Package"] - } + }] }, { "resourceName": "e800_comms", - "selectors": { + "selectors": [{ "vendors": ["8086"], "devices": ["1889"], "ddpProfiles": ["ICE COMMS Package"] - } + }] }, { "resourceName": "x700_gtp", - "selectors": { + "selectors": [{ "vendors": ["8086"], "devices": ["154c"], "ddpProfiles": ["GTPv1-C/U IPv4/IPv6 payload"] - } + }] }, { "resourceName": "x700_pppoe", - "selectors": { + "selectors": [{ "vendors": ["8086"], "devices": ["154c"], "ddpProfiles": ["E710 PPPoE and PPPoL2TPv2"] - } + }] } ] } diff --git a/docs/ddp/e800/configMap.yaml b/docs/ddp/e800/configMap.yaml index f8d770bcd..b84b8393d 100644 --- a/docs/ddp/e800/configMap.yaml +++ b/docs/ddp/e800/configMap.yaml @@ -9,20 +9,20 @@ data: "resourceList": [{ "resourceName": "e800_default", "resourcePrefix": "intel.com", - "selectors": { + "selectors": [{ "vendors": ["8086"], "devices": ["1889"], "ddpProfiles": ["ICE OS Default Package"] - } + }] }, { "resourceName": "e800_comms", "resourcePrefix": "intel.com", - "selectors": { + "selectors": [{ "vendors": ["8086"], "devices": ["1889"], "ddpProfiles": ["ICE COMMS Package"] - } + }] } ] } diff --git a/docs/ddp/x700/configMap.yaml b/docs/ddp/x700/configMap.yaml index 0b3203288..7a33fdc16 100644 --- a/docs/ddp/x700/configMap.yaml +++ b/docs/ddp/x700/configMap.yaml @@ -9,20 +9,20 @@ data: "resourceList": [{ "resourceName": "x700_gtp", "resourcePrefix": "intel.com", - "selectors": { + "selectors": [{ "vendors": ["8086"], "devices": ["154c"], "ddpProfiles": ["GTPv1-C/U IPv4/IPv6 payload"] - } + }] }, { "resourceName": "x700_pppoe", "resourcePrefix": "intel.com", - "selectors": { + "selectors": [{ "vendors": ["8086"], "devices": ["154c"], "ddpProfiles": ["E710 PPPoE and PPPoL2TPv2"] - } + }] } ] } diff --git a/docs/dpdk/configMap-all-nics.yaml b/docs/dpdk/configMap-all-nics.yaml new file mode 100644 index 000000000..103971856 --- /dev/null +++ b/docs/dpdk/configMap-all-nics.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: sriovdp-config + namespace: kube-system +data: + config.json: | + { + "resourceList": [ + { + "resourcePrefix": "dpdk.org", + "resourceName": "nic", + "selectors": [{ + "vendors": ["15b3"], + "devices": ["1016"], + "drivers": ["mlx5_core"], + "isRdma": true + }, { + "vendors": ["15b3"], + "devices": ["1018"], + "drivers": ["mlx5_core"], + "isRdma": true + }, { + "vendors": ["8086"], + "devices": ["154c"], + "drivers": ["vfio-pci"] + }] + } + ] + } diff --git a/docs/dpdk/configMap-virt.yaml b/docs/dpdk/configMap-virt.yaml index e8af43c33..8081ad95c 100644 --- a/docs/dpdk/configMap-virt.yaml +++ b/docs/dpdk/configMap-virt.yaml @@ -9,7 +9,7 @@ data: "resourceList": [ { "resourceName": "intelnics_radio_downlink", - "selectors": { + "selectors": [{ "drivers": [ "vfio-pci" ], @@ -17,11 +17,11 @@ data: "0000:00:09.0", "0000:00:0a.0" ], - }, + }], }, { "resourceName": "intelnics_radio_uplink", - "selectors": { + "selectors": [{ "drivers": [ "vfio-pci" ], @@ -29,7 +29,7 @@ data: "0000:00:07.0", "0000:00:08.0" ], - }, + }], } ] } diff --git a/docs/dpdk/configMap.yaml b/docs/dpdk/configMap.yaml index c60be5e3b..0faf314f0 100644 --- a/docs/dpdk/configMap.yaml +++ b/docs/dpdk/configMap.yaml @@ -9,11 +9,11 @@ data: "resourceList": [ { "resourceName": "intel_x710vfio", - "selectors": { + "selectors": [{ "vendors": ["8086"], "devices": ["154c"], "drivers": ["vfio-pci"] - } + }] } ] } diff --git a/docs/rdma/configMap.yaml b/docs/rdma/configMap.yaml index f2cc72ba2..ebc8b2dc9 100644 --- a/docs/rdma/configMap.yaml +++ b/docs/rdma/configMap.yaml @@ -10,12 +10,12 @@ data: { "resourceName": "mlnx_rdma", "resourcePrefix": "mellanox.com", - "selectors": { + "selectors": [{ "vendors": ["15b3"], "devices": ["1016", "1018"], "drivers": ["mlx5_core"], "isRdma": true - } + }] }, { "resourceName": "intel_rdma", diff --git a/docs/subfunctions/README.md b/docs/subfunctions/README.md index 4fb6a1127..df8ccb829 100644 --- a/docs/subfunctions/README.md +++ b/docs/subfunctions/README.md @@ -38,12 +38,12 @@ For BlueField-2® NIC: "resourceName": "bf2_sf", "resourcePrefix": "nvidia.com", "deviceType": "auxNetDevice", - "selectors": { + "selectors": [{ "vendors": ["15b3"], "devices": ["a2d6"], "pfNames": ["p0#1-5"], "auxTypes": ["sf"] - } + }] } ] } @@ -57,20 +57,20 @@ For ConnectX-6® Dx NIC for SFs and VFs: { "resourceName": "cx6dx_vf", "resourcePrefix": "nvidia.com", - "selectors": { + "selectors": [{ "vendors": ["15b3"], "devices": ["101e"], - } + }] }, { "resourceName": "cx6dx_sf", "resourcePrefix": "nvidia.com", "deviceType": "auxNetDevice", - "selectors": { + "selectors": [{ "vendors": ["15b3"], "devices": ["101e"], "auxTypes": ["sf"] - } + }] } ] } diff --git a/docs/vdpa/configMap.yaml b/docs/vdpa/configMap.yaml index 70e99444f..df221e532 100644 --- a/docs/vdpa/configMap.yaml +++ b/docs/vdpa/configMap.yaml @@ -9,21 +9,21 @@ data: "resourceList": [{ { "resourceName": "vdpa_mlx_virtio", - "selectors": { + "selectors": [{ "vendors": ["15b3"], "devices": ["101e"], "drivers": ["mlx5_core"], "vdpaType": "virtio" - } + }] }, { "resourceName": "vdpa_mlx_vhost", - "selectors": { + "selectors": [{ "vendors": ["15b3"], "devices": ["101e"], "drivers": ["mlx5_core"], "vdpaType": "vhost" - } + }] } ] } diff --git a/pkg/accelerator/accelDeviceProvider.go b/pkg/accelerator/accelDeviceProvider.go index 360ddbbf1..299a71f65 100644 --- a/pkg/accelerator/accelDeviceProvider.go +++ b/pkg/accelerator/accelDeviceProvider.go @@ -41,7 +41,7 @@ func (ap *accelDeviceProvider) GetDiscoveredDevices() []*ghw.PCIDevice { return ap.deviceList } -func (ap *accelDeviceProvider) GetDevices(rc *types.ResourceConfig) []types.HostDevice { +func (ap *accelDeviceProvider) GetDevices(rc *types.ResourceConfig, selectorIndex int) []types.HostDevice { newHostDevices := make([]types.HostDevice, 0) for _, device := range ap.deviceList { if newDevice, err := NewAccelDevice(device, ap.rFactory, rc); err == nil { @@ -73,9 +73,15 @@ func (ap *accelDeviceProvider) AddTargetDevices(devices []*ghw.PCIDevice, device return nil } -func (ap *accelDeviceProvider) GetFilteredDevices(devices []types.HostDevice, rc *types.ResourceConfig) ([]types.HostDevice, error) { +//nolint:gocyclo +func (ap *accelDeviceProvider) GetFilteredDevices(devices []types.HostDevice, + rc *types.ResourceConfig, selectorIndex int) ([]types.HostDevice, error) { filteredDevice := devices - af, ok := rc.SelectorObj.(*types.AccelDeviceSelectors) + if selectorIndex < 0 || selectorIndex >= len(rc.SelectorObjs) { + return filteredDevice, fmt.Errorf("invalid selectorIndex %d, resource config only has %d selector objects", + selectorIndex, len(rc.SelectorObjs)) + } + af, ok := rc.SelectorObjs[selectorIndex].(*types.AccelDeviceSelectors) if !ok { return filteredDevice, fmt.Errorf("unable to convert SelectorObj to AccelDeviceSelectors") } @@ -113,10 +119,12 @@ func (ap *accelDeviceProvider) GetFilteredDevices(devices []types.HostDevice, rc } func (ap *accelDeviceProvider) ValidConfig(rc *types.ResourceConfig) bool { - _, ok := rc.SelectorObj.(*types.AccelDeviceSelectors) - if !ok { - glog.Errorf("unable to convert SelectorObj to AccelDeviceSelectors") - return false + for _, selector := range rc.SelectorObjs { + _, ok := selector.(*types.AccelDeviceSelectors) + if !ok { + glog.Errorf("unable to convert SelectorObjs to AccelDeviceSelectors") + return false + } } return true } diff --git a/pkg/accelerator/accelDeviceProvider_test.go b/pkg/accelerator/accelDeviceProvider_test.go index 00fd42d60..b1e23c28e 100644 --- a/pkg/accelerator/accelDeviceProvider_test.go +++ b/pkg/accelerator/accelDeviceProvider_test.go @@ -44,12 +44,32 @@ var _ = Describe("AcceleratorProvider", func() { p := accelerator.NewAccelDeviceProvider(rf) config := &types.ResourceConfig{} dDevs := p.GetDiscoveredDevices() - devs := p.GetDevices(config) + devs := p.GetDevices(config, 0) It("should return empty slice", func() { Expect(dDevs).To(BeEmpty()) Expect(devs).To(BeEmpty()) }) }) + Context("when the selector index is invalid", func() { + rf := &mocks.ResourceFactory{} + p := accelerator.NewAccelDeviceProvider(rf) + config := &types.ResourceConfig{} + dDevs := p.GetDiscoveredDevices() + devs := p.GetDevices(config, 0) + It("should return empty slice when SelectorObjs is nil", func() { + Expect(dDevs).To(BeEmpty()) + Expect(devs).To(BeEmpty()) + }) + + It("should return empty slice when selector index is out of range", func() { + accelDeviceSelector := types.AccelDeviceSelectors{} + config = &types.ResourceConfig{SelectorObjs: []interface{}{&accelDeviceSelector}} + devs = p.GetDevices(config, 1) + + Expect(dDevs).To(BeEmpty()) + Expect(devs).To(BeEmpty()) + }) + }) }) Describe("adding 4 target devices", func() { Context("when 2 are valid devices, but 2 are not", func() { @@ -76,9 +96,9 @@ var _ = Describe("AcceleratorProvider", func() { p := accelerator.NewAccelDeviceProvider(rf) config := &types.ResourceConfig{ DeviceType: types.AcceleratorType, - SelectorObj: types.AccelDeviceSelectors{ + SelectorObjs: []interface{}{types.AccelDeviceSelectors{ DeviceSelectors: types.DeviceSelectors{}, - }, + }}, } dev1 := &ghw.PCIDevice{ @@ -113,7 +133,7 @@ var _ = Describe("AcceleratorProvider", func() { err := p.AddTargetDevices(devsToAdd, 0x1024) dDevs := p.GetDiscoveredDevices() - devs := p.GetDevices(config) + devs := p.GetDevices(config, 0) It("shouldn't return an error", func() { Expect(err).NotTo(HaveOccurred()) }) @@ -162,12 +182,60 @@ var _ = Describe("AcceleratorProvider", func() { for _, tc := range testCases { By(tc.name) - config := &types.ResourceConfig{SelectorObj: tc.sel} - actual, err := p.GetFilteredDevices(all, config) + config := &types.ResourceConfig{SelectorObjs: []interface{}{tc.sel}} + actual, err := p.GetFilteredDevices(all, config, 0) Expect(err).NotTo(HaveOccurred()) Expect(actual).To(HaveLen(len(tc.expected))) Expect(actual).To(ConsistOf(tc.expected)) } + By("GetFilteredDevices uses the specified selector index") + selectors := []*types.AccelDeviceSelectors{ + { + DeviceSelectors: types.DeviceSelectors{ + Vendors: []string{"None"}, + }, + }, { + DeviceSelectors: types.DeviceSelectors{ + Vendors: []string{"8086"}, + }, + }, + } + matchingDevices := []types.HostDevice{all[0], all[1]} + + selectorObjs := make([]interface{}, len(selectors)) + for index := range selectors { + selectorObjs[index] = selectors[index] + } + config := &types.ResourceConfig{SelectorObjs: selectorObjs} + + actual, err := p.GetFilteredDevices(all, config, 0) + Expect(err).NotTo(HaveOccurred()) + Expect(actual).To(BeEmpty()) + + actual, err = p.GetFilteredDevices(all, config, 1) + Expect(err).NotTo(HaveOccurred()) + Expect(actual).To(HaveLen(len(matchingDevices))) + Expect(actual).To(ConsistOf(matchingDevices)) + }) + It("should error if the selector index is out of bounds", func() { + rf := factory.NewResourceFactory("fake", "fake", false) + p := accelerator.NewAccelDeviceProvider(rf) + devs := make([]types.HostDevice, 0) + + rc := &types.ResourceConfig{} + + _, err := p.GetFilteredDevices(devs, rc, 0) + + Expect(err).To(HaveOccurred()) + + rc = &types.ResourceConfig{ + SelectorObjs: []interface{}{ + &types.AccelDeviceSelectors{}, + }, + } + _, err = p.GetFilteredDevices(devs, rc, 1) + + Expect(err).To(HaveOccurred()) }) }) }) diff --git a/pkg/auxnetdevice/auxNetDevice.go b/pkg/auxnetdevice/auxNetDevice.go index f526b195c..4c815be40 100644 --- a/pkg/auxnetdevice/auxNetDevice.go +++ b/pkg/auxnetdevice/auxNetDevice.go @@ -38,7 +38,8 @@ type auxNetDevice struct { // NewAuxNetDevice returns an instance of AciNetDevice interface func NewAuxNetDevice(dev *ghw.PCIDevice, deviceID string, rFactory types.ResourceFactory, - rc *types.ResourceConfig) (types.AuxNetDevice, error) { + rc *types.ResourceConfig, selectorIndex int) (types.AuxNetDevice, error) { + var nf *types.AuxNetDeviceSelectors driverName, err := utils.GetDriverName(dev.Address) if err != nil { return nil, err @@ -46,7 +47,10 @@ func NewAuxNetDevice(dev *ghw.PCIDevice, deviceID string, rFactory types.Resourc infoProviders := rFactory.GetDefaultInfoProvider(deviceID, driverName) isRdma := false - nf, ok := rc.SelectorObj.(*types.AuxNetDeviceSelectors) + ok := false + if selectorIndex >= 0 && selectorIndex < len(rc.SelectorObjs) { + nf, ok = rc.SelectorObjs[selectorIndex].(*types.AuxNetDeviceSelectors) + } if ok { if nf.IsRdma { rdmaSpec := rFactory.GetRdmaSpec(types.AuxNetDeviceType, deviceID) diff --git a/pkg/auxnetdevice/auxNetDeviceProvider.go b/pkg/auxnetdevice/auxNetDeviceProvider.go index b093707fe..993bffa89 100644 --- a/pkg/auxnetdevice/auxNetDeviceProvider.go +++ b/pkg/auxnetdevice/auxNetDeviceProvider.go @@ -44,7 +44,7 @@ func (ap *auxNetDeviceProvider) GetDiscoveredDevices() []*ghw.PCIDevice { return ap.deviceList } -func (ap *auxNetDeviceProvider) GetDevices(rc *types.ResourceConfig) []types.HostDevice { +func (ap *auxNetDeviceProvider) GetDevices(rc *types.ResourceConfig, selectorIndex int) []types.HostDevice { newAuxDevices := make([]types.HostDevice, 0) for _, device := range ap.deviceList { // discover auxiliary device names @@ -55,7 +55,7 @@ func (ap *auxNetDeviceProvider) GetDevices(rc *types.ResourceConfig) []types.Hos continue } for _, auxDev := range auxDevs { - if newDevice, err := NewAuxNetDevice(device, auxDev, ap.rFactory, rc); err == nil { + if newDevice, err := NewAuxNetDevice(device, auxDev, ap.rFactory, rc, selectorIndex); err == nil { newAuxDevices = append(newAuxDevices, newDevice) } else { glog.Warningf("auxnetdevice GetDevices(): error creating new device %s PCI %s: %q", @@ -90,9 +90,14 @@ func (ap *auxNetDeviceProvider) AddTargetDevices(devices []*ghw.PCIDevice, devic } //nolint:gocyclo -func (ap *auxNetDeviceProvider) GetFilteredDevices(devices []types.HostDevice, rc *types.ResourceConfig) ([]types.HostDevice, error) { +func (ap *auxNetDeviceProvider) GetFilteredDevices(devices []types.HostDevice, rc *types.ResourceConfig, + selectorIndex int) ([]types.HostDevice, error) { filteredDevice := devices - nf, ok := rc.SelectorObj.(*types.AuxNetDeviceSelectors) + if selectorIndex < 0 || selectorIndex >= len(rc.SelectorObjs) { + return filteredDevice, fmt.Errorf("invalid selectorIndex %d, resource config only has %d selector objects", + selectorIndex, len(rc.SelectorObjs)) + } + nf, ok := rc.SelectorObjs[selectorIndex].(*types.AuxNetDeviceSelectors) if !ok { return filteredDevice, fmt.Errorf("unable to convert SelectorObj to AuxNetDeviceSelectors") } @@ -166,22 +171,24 @@ func (ap *auxNetDeviceProvider) GetFilteredDevices(devices []types.HostDevice, r // ValidConfig performs validation of AuxNetDeviceSelectors func (ap *auxNetDeviceProvider) ValidConfig(rc *types.ResourceConfig) bool { - nf, ok := rc.SelectorObj.(*types.AuxNetDeviceSelectors) - if !ok { - glog.Errorf("unable to convert SelectorObj to AuxNetDeviceSelectors") - return false - } - if len(nf.AuxTypes) == 0 { - glog.Errorf("AuxTypes are not specified") - return false - } - // Check that only supported auxiliary device types are specified - // TODO ATM only SFs are supported; review this in the future if new types are added - for _, auxType := range nf.AuxTypes { - if auxType != "sf" { - glog.Errorf("Only \"sf\" auxiliary device type currently supported") + for _, selector := range rc.SelectorObjs { + nf, ok := selector.(*types.AuxNetDeviceSelectors) + if !ok { + glog.Errorf("unable to convert SelectorObj to AuxNetDeviceSelectors") return false } + if len(nf.AuxTypes) == 0 { + glog.Errorf("AuxTypes are not specified") + return false + } + // Check that only supported auxiliary device types are specified + // TODO ATM only SFs are supported; review this in the future if new types are added + for _, auxType := range nf.AuxTypes { + if auxType != "sf" { + glog.Errorf("Only \"sf\" auxiliary device type currently supported") + return false + } + } } return true } diff --git a/pkg/auxnetdevice/auxNetDeviceProvider_test.go b/pkg/auxnetdevice/auxNetDeviceProvider_test.go index a5da2eea1..6a9c50c4c 100644 --- a/pkg/auxnetdevice/auxNetDeviceProvider_test.go +++ b/pkg/auxnetdevice/auxNetDeviceProvider_test.go @@ -43,16 +43,22 @@ var _ = Describe("AuxNetDeviceProvider", func() { Expect(actual).To(Equal(expected)) }, Entry("invalid selector in config passed", - &types.ResourceConfig{SelectorObj: &types.NetDeviceSelectors{DeviceSelectors: types.DeviceSelectors{}}}, + &types.ResourceConfig{SelectorObjs: []interface{}{&types.NetDeviceSelectors{DeviceSelectors: types.DeviceSelectors{}}}}, false), Entry("auxTypes list is empty", - &types.ResourceConfig{SelectorObj: &types.AuxNetDeviceSelectors{AuxTypes: []string{}}}, + &types.ResourceConfig{SelectorObjs: []interface{}{&types.AuxNetDeviceSelectors{AuxTypes: []string{}}}}, + false), + Entry("auxTypes list is empty in second selector", + &types.ResourceConfig{SelectorObjs: []interface{}{&types.AuxNetDeviceSelectors{AuxTypes: []string{"sf"}}, &types.AuxNetDeviceSelectors{AuxTypes: []string{}}}}, false), Entry("unsupported auxiliary device types specified", - &types.ResourceConfig{SelectorObj: &types.AuxNetDeviceSelectors{AuxTypes: []string{"sf", "eth", "rdma"}}}, + &types.ResourceConfig{SelectorObjs: []interface{}{&types.AuxNetDeviceSelectors{AuxTypes: []string{"sf", "eth", "rdma"}}}}, + false), + Entry("unsupported auxiliary device types specified in second selector", + &types.ResourceConfig{SelectorObjs: []interface{}{&types.AuxNetDeviceSelectors{AuxTypes: []string{"sf"}}, &types.AuxNetDeviceSelectors{AuxTypes: []string{"sf", "eth", "rdma"}}}}, false), Entry("supported auxiliary device types", - &types.ResourceConfig{SelectorObj: &types.AuxNetDeviceSelectors{AuxTypes: []string{"sf", "sf"}}}, + &types.ResourceConfig{SelectorObjs: []interface{}{&types.AuxNetDeviceSelectors{AuxTypes: []string{"sf", "sf"}}}}, true), ) Describe("getting new instance of auxNetDeviceProvider", func() { @@ -70,12 +76,32 @@ var _ = Describe("AuxNetDeviceProvider", func() { p := auxnetdevice.NewAuxNetDeviceProvider(rf) config := &types.ResourceConfig{} dDevs := p.GetDiscoveredDevices() - devs := p.GetDevices(config) + devs := p.GetDevices(config, 0) It("should return empty slice", func() { Expect(dDevs).To(BeEmpty()) Expect(devs).To(BeEmpty()) }) }) + Context("with an invalid selector index", func() { + rf := &tmocks.ResourceFactory{} + p := auxnetdevice.NewAuxNetDeviceProvider(rf) + config := &types.ResourceConfig{} + dDevs := p.GetDiscoveredDevices() + devs := p.GetDevices(config, 0) + It("should return empty slice when SelectorObjs is nil", func() { + Expect(dDevs).To(BeEmpty()) + Expect(devs).To(BeEmpty()) + }) + + It("should return empty slice when selector index is out of range", func() { + auxNetDeviceSelector := types.AuxNetDeviceSelectors{} + config = &types.ResourceConfig{SelectorObjs: []interface{}{&auxNetDeviceSelector}} + devs = p.GetDevices(config, 1) + + Expect(dDevs).To(BeEmpty()) + Expect(devs).To(BeEmpty()) + }) + }) }) Describe("adding 3 target devices", func() { Context("when 2 are valid devices, but only one have auxiliary devices", func() { @@ -111,10 +137,10 @@ var _ = Describe("AuxNetDeviceProvider", func() { p := auxnetdevice.NewAuxNetDeviceProvider(rf) config := &types.ResourceConfig{ DeviceType: types.AuxNetDeviceType, - SelectorObj: &types.AuxNetDeviceSelectors{ + SelectorObjs: []interface{}{&types.AuxNetDeviceSelectors{ DeviceSelectors: types.DeviceSelectors{}, }, - } + }} vendor := &pcidb.Vendor{Name: "Mellanox Technologies"} devsToAdd := []*ghw.PCIDevice{ @@ -140,7 +166,7 @@ var _ = Describe("AuxNetDeviceProvider", func() { err := p.AddTargetDevices(devsToAdd, 0x2) dDevs := p.GetDiscoveredDevices() - devs := p.GetDevices(config) + devs := p.GetDevices(config, 0) It("shouldn't return an error", func() { Expect(err).NotTo(HaveOccurred()) }) @@ -202,12 +228,61 @@ var _ = Describe("AuxNetDeviceProvider", func() { for _, tc := range testCases { By(tc.name) - config := &types.ResourceConfig{SelectorObj: tc.sel} - actual, err := p.GetFilteredDevices(all, config) + config := &types.ResourceConfig{SelectorObjs: []interface{}{tc.sel}} + actual, err := p.GetFilteredDevices(all, config, 0) Expect(err).NotTo(HaveOccurred()) Expect(actual).To(HaveLen(len(tc.expected))) Expect(actual).To(ConsistOf(tc.expected)) } + By("GetFilteredDevices uses the specified selector index") + selectors := []*types.AuxNetDeviceSelectors{ + { + DeviceSelectors: types.DeviceSelectors{ + Vendors: []string{"None"}, + }, + }, { + DeviceSelectors: types.DeviceSelectors{ + Vendors: []string{"8086"}, + }, + }, + } + matchingDevices := []types.HostDevice{all[0], all[4]} + + selectorObjs := make([]interface{}, len(selectors)) + for index := range selectors { + selectorObjs[index] = selectors[index] + } + + config := &types.ResourceConfig{SelectorObjs: selectorObjs} + + actual, err := p.GetFilteredDevices(all, config, 0) + Expect(err).NotTo(HaveOccurred()) + Expect(actual).To(BeEmpty()) + + actual, err = p.GetFilteredDevices(all, config, 1) + Expect(err).NotTo(HaveOccurred()) + Expect(actual).To(HaveLen(len(matchingDevices))) + Expect(actual).To(ConsistOf(matchingDevices)) + }) + It("should error if the selector index is out of bounds", func() { + rf := factory.NewResourceFactory("fake", "fake", false) + p := auxnetdevice.NewAuxNetDeviceProvider(rf) + devs := make([]types.HostDevice, 0) + + rc := &types.ResourceConfig{} + + _, err := p.GetFilteredDevices(devs, rc, 0) + + Expect(err).To(HaveOccurred()) + + rc = &types.ResourceConfig{ + SelectorObjs: []interface{}{ + &types.AuxNetDeviceSelectors{}, + }, + } + _, err = p.GetFilteredDevices(devs, rc, 1) + + Expect(err).To(HaveOccurred()) }) }) }) diff --git a/pkg/auxnetdevice/auxNetDevice_test.go b/pkg/auxnetdevice/auxNetDevice_test.go index e09253d36..19ac4f452 100644 --- a/pkg/auxnetdevice/auxNetDevice_test.go +++ b/pkg/auxnetdevice/auxNetDevice_test.go @@ -77,7 +77,7 @@ var _ = Describe("AuxNetDevice", func() { in := newPciDevice("0000:00:00.1") rc := &types.ResourceConfig{} - dev, err := auxnetdevice.NewAuxNetDevice(in, auxDevID, f, rc) + dev, err := auxnetdevice.NewAuxNetDevice(in, auxDevID, f, rc, 0) Expect(err).NotTo(HaveOccurred()) Expect(dev).NotTo(BeNil()) Expect(dev.GetDriver()).To(Equal("mlx5_core")) @@ -101,10 +101,10 @@ var _ = Describe("AuxNetDevice", func() { ResourceName: "fake", ResourcePrefix: "fake", DeviceType: types.AuxNetDeviceType, - SelectorObj: &types.AuxNetDeviceSelectors{ + SelectorObjs: []interface{}{&types.AuxNetDeviceSelectors{ GenericNetDeviceSelectors: types.GenericNetDeviceSelectors{IsRdma: true}, }, - } + }} fs := &utils.FakeFilesystem{ Dirs: []string{ "sys/bus/pci/devices/0000:00:00.1", @@ -167,7 +167,7 @@ var _ = Describe("AuxNetDevice", func() { It("should populate Rdma device specs if isRdma", func() { defer fs.Use()() utils.SetSriovnetProviderInst(&fakeSriovnetProvider) - dev, err := auxnetdevice.NewAuxNetDevice(in1, auxDevName1, f, rc) + dev, err := auxnetdevice.NewAuxNetDevice(in1, auxDevName1, f, rc, 0) Expect(err).NotTo(HaveOccurred()) Expect(dev.GetDriver()).To(Equal("mlx5_core")) @@ -189,7 +189,7 @@ var _ = Describe("AuxNetDevice", func() { It("but not otherwise", func() { defer fs.Use()() utils.SetSriovnetProviderInst(&fakeSriovnetProvider) - dev, err := auxnetdevice.NewAuxNetDevice(in2, auxDevName2, f, rc) + dev, err := auxnetdevice.NewAuxNetDevice(in2, auxDevName2, f, rc, 0) Expect(err).NotTo(HaveOccurred()) Expect(dev.GetDriver()).To(Equal("mlx5_core")) @@ -208,6 +208,38 @@ var _ = Describe("AuxNetDevice", func() { mockInfo2.AssertExpectations(t) rdma2.AssertExpectations(t) }) + It("should not populate Rdma device specs if the selector index does not specify isRdma", func() { + defer fs.Use()() + utils.SetSriovnetProviderInst(&fakeSriovnetProvider) + rc = &types.ResourceConfig{ + ResourceName: "fake", + ResourcePrefix: "fake", + DeviceType: types.AuxNetDeviceType, + SelectorObjs: []interface{}{&types.AuxNetDeviceSelectors{ + GenericNetDeviceSelectors: types.GenericNetDeviceSelectors{IsRdma: true}, + }, &types.AuxNetDeviceSelectors{ + GenericNetDeviceSelectors: types.GenericNetDeviceSelectors{IsRdma: false}, + }}} + // passing an RDMA capable device, but selector index chooses the IsRdma: false selector + dev, err := auxnetdevice.NewAuxNetDevice(in1, auxDevName1, f, rc, 1) + + Expect(err).NotTo(HaveOccurred()) + Expect(dev.GetDriver()).To(Equal("mlx5_core")) + envs := dev.GetEnvVal() + Expect(envs).To(HaveLen(1)) + _, exist := envs["generic"] + Expect(exist).To(BeTrue()) + pci, exist := envs["generic"]["deviceID"] + Expect(exist).To(BeTrue()) + Expect(pci).To(Equal(auxDevName1)) + Expect(exist).To(BeTrue()) + Expect(dev.IsRdma()).To(BeFalse()) + Expect(dev.GetDeviceSpecs()).To(HaveLen(0)) + Expect(dev.GetMounts()).To(HaveLen(0)) + Expect(dev.GetAuxType()).To(Equal("eth")) + mockInfo1.AssertExpectations(t) + rdma1.AssertExpectations(t) + }) }) }) }) diff --git a/pkg/auxnetdevice/auxNetResourcePool_test.go b/pkg/auxnetdevice/auxNetResourcePool_test.go index c5972e4af..63fd0b122 100644 --- a/pkg/auxnetdevice/auxNetResourcePool_test.go +++ b/pkg/auxnetdevice/auxNetResourcePool_test.go @@ -33,7 +33,7 @@ var _ = Describe("AuxNetResourcePool", func() { rc := &types.ResourceConfig{ ResourceName: "fake", ResourcePrefix: "fake", - SelectorObj: &types.AuxNetDeviceSelectors{}, + SelectorObjs: []interface{}{&types.AuxNetDeviceSelectors{}}, } devs := map[string]types.HostDevice{} @@ -48,10 +48,10 @@ var _ = Describe("AuxNetResourcePool", func() { rc := &types.ResourceConfig{ ResourceName: "fake", ResourcePrefix: "fake", - SelectorObj: &types.AuxNetDeviceSelectors{ + SelectorObjs: []interface{}{&types.AuxNetDeviceSelectors{ GenericNetDeviceSelectors: types.GenericNetDeviceSelectors{IsRdma: false}, }, - } + }} // fake1 will have 2 device specs fake1 := &mocks.AuxNetDevice{} diff --git a/pkg/factory/factory.go b/pkg/factory/factory.go index 73293b05a..7c2743a39 100644 --- a/pkg/factory/factory.go +++ b/pkg/factory/factory.go @@ -177,37 +177,41 @@ func (rf *resourceFactory) GetDeviceProvider(dt types.DeviceType) types.DevicePr } } -// GetDeviceFilter unmarshal the "selector" values from ResourceConfig and returns an instance of DeviceSelector based on -// DeviceType in the ResourceConfig -func (rf *resourceFactory) GetDeviceFilter(rc *types.ResourceConfig) (interface{}, error) { - switch rc.DeviceType { - case types.NetDeviceType: - netDeviceSelector := &types.NetDeviceSelectors{} - - if err := json.Unmarshal(*rc.Selectors, netDeviceSelector); err != nil { - return nil, fmt.Errorf("error unmarshalling NetDevice selector bytes %v", err) +// parseObjectOrSlice unmarshal's the "Selector" values from the ResourceConfig into a slice of *DeviceSelectors. +// Each *DeviceSelector has been converted to any before being returned. parseObjectOrSlice will parse both +// kinds of valid "selector" values - a slice or a single object. +func parseObjectOrSlice[O types.NetDeviceSelectors | types.AccelDeviceSelectors | types.AuxNetDeviceSelectors]( + rc *types.ResourceConfig) ([]any, error) { + slice := make([]*O, 1) + + if err := json.Unmarshal(*rc.Selectors, &slice[0]); err != nil { + if err = json.Unmarshal(*rc.Selectors, &slice); err != nil { + return nil, fmt.Errorf("error unmarshalling %T bytes %v", slice[0], err) } - - glog.Infof("net device selector for resource %s is %+v", rc.ResourceName, netDeviceSelector) - return netDeviceSelector, nil - case types.AcceleratorType: - accelDeviceSelector := &types.AccelDeviceSelectors{} - - if err := json.Unmarshal(*rc.Selectors, accelDeviceSelector); err != nil { - return nil, fmt.Errorf("error unmarshalling Accelerator selector bytes %v", err) + if len(slice) == 0 { + return nil, fmt.Errorf("error, need at least one selector, got 0") } + } - glog.Infof("accelerator device selector for resource %s is %+v", rc.ResourceName, accelDeviceSelector) - return accelDeviceSelector, nil - case types.AuxNetDeviceType: - auxNetDeviceSelector := &types.AuxNetDeviceSelectors{} + glog.Infof("%T for resource %s is %+v", slice[0], rc.ResourceName, slice) + interfaceArray := make([]any, len(slice)) + for i := range slice { + interfaceArray[i] = slice[i] + } - if err := json.Unmarshal(*rc.Selectors, auxNetDeviceSelector); err != nil { - return nil, fmt.Errorf("error unmarshalling AuxNetDevice selector bytes %v", err) - } + return interfaceArray, nil +} - glog.Infof("auxiliary network device selector for resource %s is %+v", rc.ResourceName, auxNetDeviceSelector) - return auxNetDeviceSelector, nil +// GetDeviceFilter unmarshal the "selector" values from ResourceConfig and returns a slice of *DeviceSelectors based on +// DeviceType in the ResourceConfig +func (rf *resourceFactory) GetDeviceFilter(rc *types.ResourceConfig) ([]interface{}, error) { + switch rc.DeviceType { + case types.NetDeviceType: + return parseObjectOrSlice[types.NetDeviceSelectors](rc) + case types.AcceleratorType: + return parseObjectOrSlice[types.AccelDeviceSelectors](rc) + case types.AuxNetDeviceType: + return parseObjectOrSlice[types.AuxNetDeviceSelectors](rc) default: return nil, fmt.Errorf("unable to get deviceFilter, invalid deviceType %s", rc.DeviceType) } diff --git a/pkg/factory/factory_test.go b/pkg/factory/factory_test.go index 201cb91ef..bd1589af8 100644 --- a/pkg/factory/factory_test.go +++ b/pkg/factory/factory_test.go @@ -52,7 +52,7 @@ var _ = Describe("Factory", func() { func(name string, expected reflect.Type) { f := factory.NewResourceFactory("fake", "fake", true) p := f.GetDefaultInfoProvider("fakePCIAddr", name) - Expect(len(p)).To(Equal(2)) // for all the providers expect netdevice we expect 2 info providers + Expect(p).To(HaveLen(2)) // for all the providers except netdevice we expect 2 info providers Expect(reflect.TypeOf(p[1])).To(Equal(expected)) }, @@ -64,7 +64,7 @@ var _ = Describe("Factory", func() { Describe("getting info provider for generic netdevice", func() { f := factory.NewResourceFactory("fake", "fake", true) p := f.GetDefaultInfoProvider("fakePCIAddr", "netdevice") - Expect(len(p)).To(Equal(1)) // for all the providers expect netdevice we expect 2 info providers + Expect(p).To(HaveLen(1)) // for all the providers except netdevice we expect 2 info providers Expect(reflect.TypeOf(p[0])).To(Equal(reflect.TypeOf(infoprovider.NewGenericInfoProvider("fakePCIAddr")))) }) @@ -171,6 +171,123 @@ var _ = Describe("Factory", func() { }) }) }) + DescribeTable("getting resource pool", + func(selectorBytes []byte, hasDevices []string) { + // create factory + f := factory.NewResourceFactory("fake", "fake", true) + + // parse selector configuration & create resource config + var selectors json.RawMessage + err := selectors.UnmarshalJSON(selectorBytes) + Expect(err).NotTo(HaveOccurred()) + + c := &types.ResourceConfig{ + ResourceName: "fake", + Selectors: &selectors, + DeviceType: types.NetDeviceType, + } + + // create mock devices + devs := make([]types.HostDevice, 4) + vendors := []string{"8086", "8086", "8086", "8086"} + codes := []string{"1111", "1111", "1111", "1111"} + drivers := []string{"iavf", "iavf", "vfio-pci", "vfio-pci"} + pciAddr := []string{"0000:03:02.0", "0000:03:02.1", "0000:03:02.2", "0000:03:02.3"} + pfNames := []string{"enp2s0f2", "ens0", "eth0", "net2"} + rootDevices := []string{"0000:86:00.0", "0000:86:00.1", "0000:86:00.2", "0000:86:00.3"} + linkTypes := []string{"ether", "infiniband", "other", "other2"} + ddpProfiles := []string{"GTP", "PPPoE", "GTP", "PPPoE"} + for i := range devs { + d := &mocks.PciNetDevice{} + d.On("GetVendor").Return(vendors[i]). + On("GetDeviceCode").Return(codes[i]). + On("GetDriver").Return(drivers[i]). + On("GetPciAddr").Return(pciAddr[i]). + On("GetDeviceID").Return(pciAddr[i]). + On("GetPfNetName").Return(pfNames[i]). + On("GetPfPciAddr").Return(rootDevices[i]). + On("GetAPIDevice").Return(&pluginapi.Device{}). + On("GetLinkType").Return(linkTypes[i]). + On("GetDDPProfiles").Return(ddpProfiles[i]). + On("GetFuncID").Return(-1) + devs[i] = d + } + + deviceAllocated := make(map[string]bool) + dp := f.GetDeviceProvider(c.DeviceType) + c.SelectorObjs, err = f.GetDeviceFilter(c) + Expect(err).NotTo(HaveOccurred()) + filteredDevices := make([]types.HostDevice, 0) + for index := range c.SelectorObjs { + currentSelectorFilteredDevices, err := dp.GetFilteredDevices(devs, c, index) + Expect(err).NotTo(HaveOccurred()) + + unallocatedDevices := []types.HostDevice{} + for _, dev := range currentSelectorFilteredDevices { + if !deviceAllocated[dev.GetDeviceID()] { + deviceAllocated[dev.GetDeviceID()] = true + unallocatedDevices = append(unallocatedDevices, dev) + } + } + filteredDevices = append(filteredDevices, unallocatedDevices...) + } + + rp, err := f.GetResourcePool(c, filteredDevices) + Expect(err).NotTo(HaveOccurred()) + + if hasDevices == nil { + Expect(rp).Should(BeNil()) + } else { + Expect(rp).NotTo(BeNil()) + Expect(rp.GetDevices()).To(HaveLen(len(hasDevices))) + for _, devAddr := range hasDevices { + Expect(rp.GetDevices()).To(HaveKey(devAddr)) + } + } + }, + Entry("with a single selector object should match devices", []byte(` + { + "vendors": ["8086"], + "devices": ["1111"], + "drivers": ["iavf","vfio-pci"], + "pciAddresses": ["0000:03:02.0"], + "pfNames": ["enp2s0f2"], + "rootDevices": ["0000:86:00.0"], + "linkTypes": ["ether"], + "ddpProfiles": ["GTP"] + }`), []string{"0000:03:02.0"}), + Entry("with a slice of one selector object it should match devices", []byte(` + [{ + "vendors": ["8086"], + "devices": ["1111"], + "drivers": ["iavf","vfio-pci"], + "pciAddresses": ["0000:03:02.0"], + "pfNames": ["enp2s0f2"], + "rootDevices": ["0000:86:00.0"], + "linkTypes": ["ether"], + "ddpProfiles": ["GTP"] + }]`), []string{"0000:03:02.0"}), + Entry("with more than one selector object, it should match devices from all selector objects", []byte(` + [{ + "vendors": ["8086"], + "devices": ["1111"], + "drivers": ["iavf"], + "pciAddresses": ["0000:03:02.0"], + "pfNames": ["enp2s0f2"], + "rootDevices": ["0000:86:00.0"], + "linkTypes": ["ether"], + "ddpProfiles": ["GTP"] + }, { + "vendors": ["8086"], + "devices": ["1111"], + "drivers": ["vfio-pci"], + "pciAddresses": ["0000:03:02.3"], + "pfNames": ["net2"], + "rootDevices": ["0000:86:00.3"], + "linkTypes": ["other2"], + "ddpProfiles": ["PPPoE"] + }]`), []string{"0000:03:02.0", "0000:03:02.3"}), + ) Describe("getting exclusive resource pool for netdevice", func() { Context("with all types of selectors used and matching devices found", func() { utils.SetDefaultMockNetlinkProvider() @@ -225,7 +342,7 @@ var _ = Describe("Factory", func() { var selectors2 json.RawMessage err = selectors2.UnmarshalJSON([]byte(` - { + [{ "vendors": ["8086"], "devices": ["1111"], "drivers": ["iavf","vfio-pci"], @@ -234,7 +351,7 @@ var _ = Describe("Factory", func() { "rootDevices": ["0000:86:00.0"], "linkTypes": ["ether"], "ddpProfiles": ["GTP"] - } + }] `), ) Expect(err).NotTo(HaveOccurred()) @@ -246,9 +363,9 @@ var _ = Describe("Factory", func() { } deviceAllocated := make(map[string]bool) dp := f.GetDeviceProvider(c.DeviceType) - c.SelectorObj, err = f.GetDeviceFilter(c) + c.SelectorObjs, err = f.GetDeviceFilter(c) Expect(err).NotTo(HaveOccurred()) - filteredDevices, err := dp.GetFilteredDevices(devs, c) + filteredDevices, err := dp.GetFilteredDevices(devs, c, 0) Expect(err).NotTo(HaveOccurred()) filteredDevicesTemp := []types.HostDevice{} @@ -271,9 +388,9 @@ var _ = Describe("Factory", func() { } dp2 := f.GetDeviceProvider(c2.DeviceType) - c2.SelectorObj, err = f.GetDeviceFilter(c2) + c2.SelectorObjs, err = f.GetDeviceFilter(c2) Expect(err).NotTo(HaveOccurred()) - filteredDevices, err = dp2.GetFilteredDevices(devs, c2) + filteredDevices, err = dp2.GetFilteredDevices(devs, c2, 0) Expect(err).NotTo(HaveOccurred()) filteredDevicesTemp = []types.HostDevice{} diff --git a/pkg/netdevice/netDeviceProvider.go b/pkg/netdevice/netDeviceProvider.go index 0365139e5..f106d87fa 100644 --- a/pkg/netdevice/netDeviceProvider.go +++ b/pkg/netdevice/netDeviceProvider.go @@ -41,10 +41,10 @@ func (np *netDeviceProvider) GetDiscoveredDevices() []*ghw.PCIDevice { return np.deviceList } -func (np *netDeviceProvider) GetDevices(rc *types.ResourceConfig) []types.HostDevice { +func (np *netDeviceProvider) GetDevices(rc *types.ResourceConfig, selectorIndex int) []types.HostDevice { newHostDevices := make([]types.HostDevice, 0) for _, device := range np.deviceList { - if newDevice, err := NewPciNetDevice(device, np.rFactory, rc); err == nil { + if newDevice, err := NewPciNetDevice(device, np.rFactory, rc, selectorIndex); err == nil { newHostDevices = append(newHostDevices, newDevice) } else { glog.Errorf("netdevice GetDevices(): error creating new device: %q", err) @@ -81,9 +81,14 @@ func (np *netDeviceProvider) AddTargetDevices(devices []*ghw.PCIDevice, deviceCo } //nolint:gocyclo -func (np *netDeviceProvider) GetFilteredDevices(devices []types.HostDevice, rc *types.ResourceConfig) ([]types.HostDevice, error) { +func (np *netDeviceProvider) GetFilteredDevices(devices []types.HostDevice, + rc *types.ResourceConfig, selectorIndex int) ([]types.HostDevice, error) { filteredDevice := devices - nf, ok := rc.SelectorObj.(*types.NetDeviceSelectors) + if selectorIndex < 0 || selectorIndex >= len(rc.SelectorObjs) { + return filteredDevice, fmt.Errorf("invalid selectorIndex %d, resource config only has %d selector objects", + selectorIndex, len(rc.SelectorObjs)) + } + nf, ok := rc.SelectorObjs[selectorIndex].(*types.NetDeviceSelectors) if !ok { return filteredDevice, fmt.Errorf("unable to convert SelectorObj to NetDeviceSelectors") } @@ -179,14 +184,16 @@ func (np *netDeviceProvider) GetFilteredDevices(devices []types.HostDevice, rc * // ValidConfig performs validation of NetDeviceSelectors func (np *netDeviceProvider) ValidConfig(rc *types.ResourceConfig) bool { - nf, ok := rc.SelectorObj.(*types.NetDeviceSelectors) - if !ok { - glog.Errorf("unable to convert SelectorObj to NetDeviceSelectors") - return false - } - if nf.IsRdma && nf.VdpaType != "" { - glog.Errorf("invalid config: VdpaType and IsRdma are mutually exclusive options") - return false + for _, selector := range rc.SelectorObjs { + nf, ok := selector.(*types.NetDeviceSelectors) + if !ok { + glog.Errorf("unable to convert SelectorObj to NetDeviceSelectors") + return false + } + if nf.IsRdma && nf.VdpaType != "" { + glog.Errorf("invalid config: VdpaType and IsRdma are mutually exclusive options") + return false + } } return true } diff --git a/pkg/netdevice/netDeviceProvider_test.go b/pkg/netdevice/netDeviceProvider_test.go index 82cac19d1..004647b87 100644 --- a/pkg/netdevice/netDeviceProvider_test.go +++ b/pkg/netdevice/netDeviceProvider_test.go @@ -44,12 +44,32 @@ var _ = Describe("NetDeviceProvider", func() { p := netdevice.NewNetDeviceProvider(rf) config := &types.ResourceConfig{} dDevs := p.GetDiscoveredDevices() - devs := p.GetDevices(config) + devs := p.GetDevices(config, 0) It("should return empty slice", func() { Expect(dDevs).To(BeEmpty()) Expect(devs).To(BeEmpty()) }) }) + Context("with an invalid selector index", func() { + rf := &mocks.ResourceFactory{} + p := netdevice.NewNetDeviceProvider(rf) + config := &types.ResourceConfig{} + dDevs := p.GetDiscoveredDevices() + devs := p.GetDevices(config, 0) + It("should return empty slice when SelectorObjs is nil", func() { + Expect(dDevs).To(BeEmpty()) + Expect(devs).To(BeEmpty()) + }) + + It("should return empty slice when selector index is out of range", func() { + netDeviceSelector := types.NetDeviceSelectors{} + config = &types.ResourceConfig{SelectorObjs: []interface{}{&netDeviceSelector}} + devs = p.GetDevices(config, 1) + + Expect(dDevs).To(BeEmpty()) + Expect(devs).To(BeEmpty()) + }) + }) }) Describe("adding 3 target devices", func() { Context("when 2 are valid devices, but 1 is a PF with SRIOV configured and 1 is invalid", func() { @@ -76,10 +96,10 @@ var _ = Describe("NetDeviceProvider", func() { p := netdevice.NewNetDeviceProvider(rf) config := &types.ResourceConfig{ DeviceType: types.NetDeviceType, - SelectorObj: types.NetDeviceSelectors{ + SelectorObjs: []interface{}{types.NetDeviceSelectors{ DeviceSelectors: types.DeviceSelectors{}, }, - } + }} dev1 := &ghw.PCIDevice{ Address: "0000:00:00.1", Class: &pcidb.Class{ID: "1024"}, @@ -104,7 +124,7 @@ var _ = Describe("NetDeviceProvider", func() { err := p.AddTargetDevices(devsToAdd, 0x1024) dDevs := p.GetDiscoveredDevices() - devs := p.GetDevices(config) + devs := p.GetDevices(config, 0) It("shouldn't return an error", func() { Expect(err).NotTo(HaveOccurred()) }) @@ -193,12 +213,61 @@ var _ = Describe("NetDeviceProvider", func() { for _, tc := range testCases { By(tc.name) - config := &types.ResourceConfig{SelectorObj: tc.sel} - actual, err := p.GetFilteredDevices(all, config) + config := &types.ResourceConfig{SelectorObjs: []interface{}{tc.sel}} + actual, err := p.GetFilteredDevices(all, config, 0) Expect(err).NotTo(HaveOccurred()) Expect(actual).To(HaveLen(len(tc.expected))) Expect(actual).To(ConsistOf(tc.expected)) } + + By("GetFilteredDevices uses the specified selector index") + selectors := []*types.NetDeviceSelectors{ + { + DeviceSelectors: types.DeviceSelectors{ + Vendors: []string{"None"}, + }, + }, { + DeviceSelectors: types.DeviceSelectors{ + Vendors: []string{"8086"}, + }, + }, + } + matchingDevices := []types.HostDevice{all[0], all[1]} + + selectorObjs := make([]interface{}, len(selectors)) + for index := range selectors { + selectorObjs[index] = selectors[index] + } + config := &types.ResourceConfig{SelectorObjs: selectorObjs} + + actual, err := p.GetFilteredDevices(all, config, 0) + Expect(err).NotTo(HaveOccurred()) + Expect(actual).To(BeEmpty()) + + actual, err = p.GetFilteredDevices(all, config, 1) + Expect(err).NotTo(HaveOccurred()) + Expect(actual).To(HaveLen(len(matchingDevices))) + Expect(actual).To(ConsistOf(matchingDevices)) + }) + It("should error if the selector index is out of bounds", func() { + rf := factory.NewResourceFactory("fake", "fake", false) + p := netdevice.NewNetDeviceProvider(rf) + devs := make([]types.HostDevice, 0) + + rc := &types.ResourceConfig{} + + _, err := p.GetFilteredDevices(devs, rc, 0) + + Expect(err).To(HaveOccurred()) + + rc = &types.ResourceConfig{ + SelectorObjs: []interface{}{ + &types.NetDeviceSelectors{}, + }, + } + _, err = p.GetFilteredDevices(devs, rc, 1) + + Expect(err).To(HaveOccurred()) }) }) }) diff --git a/pkg/netdevice/netResourcePool_test.go b/pkg/netdevice/netResourcePool_test.go index e29f5037a..7c062a1a6 100644 --- a/pkg/netdevice/netResourcePool_test.go +++ b/pkg/netdevice/netResourcePool_test.go @@ -37,7 +37,7 @@ var _ = Describe("NetResourcePool", func() { rc := &types.ResourceConfig{ ResourceName: "fake", ResourcePrefix: "fake", - SelectorObj: &types.NetDeviceSelectors{}, + SelectorObjs: []interface{}{&types.NetDeviceSelectors{}}, } pcis := map[string]types.HostDevice{} @@ -54,12 +54,12 @@ var _ = Describe("NetResourcePool", func() { rc := &types.ResourceConfig{ ResourceName: "fake", ResourcePrefix: "fake", - SelectorObj: &types.NetDeviceSelectors{ + SelectorObjs: []interface{}{&types.NetDeviceSelectors{ GenericNetDeviceSelectors: types.GenericNetDeviceSelectors{ IsRdma: false, }, }, - } + }} // fake1 will have 2 device specs fake1 := &mocks.PciNetDevice{} @@ -104,12 +104,12 @@ var _ = Describe("NetResourcePool", func() { rc := &types.ResourceConfig{ ResourceName: "fakeResource", ResourcePrefix: "fakeOrg.io", - SelectorObj: &types.NetDeviceSelectors{ + SelectorObjs: []interface{}{&types.NetDeviceSelectors{ GenericNetDeviceSelectors: types.GenericNetDeviceSelectors{ IsRdma: true, }, }, - } + }} fake1 := &mocks.PciNetDevice{} fake1.On("GetPciAddr").Return("0000:01:00.1"). @@ -154,10 +154,10 @@ var _ = Describe("NetResourcePool", func() { rc := &types.ResourceConfig{ ResourceName: "fakeResource", ResourcePrefix: "fakeOrg.io", - SelectorObj: &types.NetDeviceSelectors{ + SelectorObjs: []interface{}{&types.NetDeviceSelectors{ VdpaType: "vhost", }, - } + }} fakeVdpa1 := &mocks.VdpaDevice{} fakeVdpa1.On("GetParent").Return("vdpa1"). diff --git a/pkg/netdevice/pciNetDevice.go b/pkg/netdevice/pciNetDevice.go index 7f87a654c..b200ed8e3 100644 --- a/pkg/netdevice/pciNetDevice.go +++ b/pkg/netdevice/pciNetDevice.go @@ -33,8 +33,10 @@ type pciNetDevice struct { } // NewPciNetDevice returns an instance of PciNetDevice interface -func NewPciNetDevice(dev *ghw.PCIDevice, rFactory types.ResourceFactory, rc *types.ResourceConfig) (types.PciNetDevice, error) { +func NewPciNetDevice(dev *ghw.PCIDevice, + rFactory types.ResourceFactory, rc *types.ResourceConfig, selectorIndex int) (types.PciNetDevice, error) { var vdpaDev types.VdpaDevice + var nf *types.NetDeviceSelectors driverName, err := utils.GetDriverName(dev.Address) if err != nil { @@ -47,7 +49,10 @@ func NewPciNetDevice(dev *ghw.PCIDevice, rFactory types.ResourceFactory, rc *typ } isRdma := false - nf, ok := rc.SelectorObj.(*types.NetDeviceSelectors) + ok := false + if selectorIndex >= 0 && selectorIndex < len(rc.SelectorObjs) { + nf, ok = rc.SelectorObjs[selectorIndex].(*types.NetDeviceSelectors) + } if ok { // Add InfoProviders based on Selector data if nf.VdpaType != "" { diff --git a/pkg/netdevice/pciNetDevice_test.go b/pkg/netdevice/pciNetDevice_test.go index 7215c4461..977a1c9ae 100644 --- a/pkg/netdevice/pciNetDevice_test.go +++ b/pkg/netdevice/pciNetDevice_test.go @@ -67,7 +67,7 @@ var _ = Describe("PciNetDevice", func() { in := newPciDeviceFn("0000:00:00.1") rc := &types.ResourceConfig{} - dev, err := netdevice.NewPciNetDevice(in, f, rc) + dev, err := netdevice.NewPciNetDevice(in, f, rc, 0) Expect(dev.GetDriver()).To(Equal("vfio-pci")) Expect(dev.GetNetName()).To(Equal("eth0")) @@ -100,11 +100,11 @@ var _ = Describe("PciNetDevice", func() { rc := &types.ResourceConfig{ ResourceName: "fake", ResourcePrefix: "fake", - SelectorObj: &types.NetDeviceSelectors{ + SelectorObjs: []interface{}{&types.NetDeviceSelectors{ GenericNetDeviceSelectors: types.GenericNetDeviceSelectors{ IsRdma: true, }, - }, + }}, } fs := &utils.FakeFilesystem{ Dirs: []string{ @@ -156,7 +156,7 @@ var _ = Describe("PciNetDevice", func() { It("should populate Rdma device specs if isRdma", func() { defer fs.Use()() utils.SetDefaultMockNetlinkProvider() - dev, err := netdevice.NewPciNetDevice(in1, f, rc) + dev, err := netdevice.NewPciNetDevice(in1, f, rc, 0) Expect(dev.GetDriver()).To(Equal("mlx5_core")) Expect(dev.IsRdma()).To(BeTrue()) @@ -178,7 +178,7 @@ var _ = Describe("PciNetDevice", func() { It("but not otherwise", func() { defer fs.Use()() utils.SetDefaultMockNetlinkProvider() - dev, err := netdevice.NewPciNetDevice(in2, f, rc) + dev, err := netdevice.NewPciNetDevice(in2, f, rc, 0) Expect(dev.GetDriver()).To(Equal("mlx5_core")) envs := dev.GetEnvVal() @@ -197,15 +197,55 @@ var _ = Describe("PciNetDevice", func() { mockInfo2.AssertExpectations(t) rdma2.AssertExpectations(t) }) + It("should use isRdma from the selector chosen by selector index", func() { + defer fs.Use()() + utils.SetDefaultMockNetlinkProvider() + rc := &types.ResourceConfig{ + ResourceName: "fake", + ResourcePrefix: "fake", + SelectorObjs: []interface{}{&types.NetDeviceSelectors{ + GenericNetDeviceSelectors: types.GenericNetDeviceSelectors{ + IsRdma: true, + }, + }, &types.NetDeviceSelectors{ + GenericNetDeviceSelectors: types.GenericNetDeviceSelectors{ + IsRdma: false, + }, + }, + }} + + // passing an RDMA capable device, but selector index chooses the IsRdma: false selector + dev, err := netdevice.NewPciNetDevice(in1, f, rc, 1) + + Expect(dev.GetDriver()).To(Equal("mlx5_core")) + envs := dev.GetEnvVal() + Expect(envs).To(HaveLen(1)) + _, exist := envs["generic"] + Expect(exist).To(BeTrue()) + _, exist = envs["rdma"] + Expect(exist).To(BeFalse()) + pci, exist := envs["generic"]["deviceID"] + Expect(exist).To(BeTrue()) + Expect(pci).To(Equal(pciAddr1)) + Expect(dev.IsRdma()).To(BeFalse()) + Expect(dev.GetDeviceSpecs()).To(HaveLen(0)) + Expect(dev.GetMounts()).To(HaveLen(0)) + Expect(err).NotTo(HaveOccurred()) + mockInfo1.AssertExpectations(t) + rdma1.AssertExpectations(t) + }) }) Context("With needsVhostNet", func() { rc := &types.ResourceConfig{ ResourceName: "fake", ResourcePrefix: "fake", - SelectorObj: &types.NetDeviceSelectors{ - NeedVhostNet: true, - }, - } + SelectorObjs: []interface{}{&types.NetDeviceSelectors{}, + &types.NetDeviceSelectors{ + NeedVhostNet: true, + }, + }} + no_vhost_net_selector_index := 0 + vhost_net_selector_index := 1 fs := &utils.FakeFilesystem{ Dirs: []string{ @@ -226,7 +266,7 @@ var _ = Describe("PciNetDevice", func() { defer fs.Use()() utils.SetDefaultMockNetlinkProvider() - dev, err := netdevice.NewPciNetDevice(in, f, rc) + dev, err := netdevice.NewPciNetDevice(in, f, rc, vhost_net_selector_index) Expect(dev.GetDriver()).To(Equal("vfio-pci")) Expect(dev.GetDeviceSpecs()).To(HaveLen(4)) // /dev/vfio/0 and default /dev/vfio/vfio + vhost-net + tun @@ -255,6 +295,36 @@ var _ = Describe("PciNetDevice", func() { Expect(exist).To(BeTrue()) Expect(generic).To(Equal("0000:00:00.1")) + Expect(dev.IsRdma()).To(BeFalse()) + Expect(err).NotTo(HaveOccurred()) + }) + It("but only if the selector index has the selector set", func() { + defer fs.Use()() + utils.SetDefaultMockNetlinkProvider() + + dev, err := netdevice.NewPciNetDevice(in, f, rc, no_vhost_net_selector_index) + + Expect(dev.GetDriver()).To(Equal("vfio-pci")) + Expect(dev.GetDeviceSpecs()).To(HaveLen(2)) // /dev/vfio/0 and default /dev/vfio/vfio + vhost-net + tun + envs := dev.GetEnvVal() + Expect(envs).To(HaveLen(2)) + _, exist := envs["vfio"] + Expect(exist).To(BeTrue()) + vfio, exist := envs["vfio"]["mount"] + Expect(exist).To(BeTrue()) + Expect(vfio).To(Equal("/dev/vfio/vfio")) + vfio, exist = envs["vfio"]["dev-mount"] + Expect(exist).To(BeTrue()) + Expect(vfio).To(Equal("/dev/vfio/0")) + _, exist = envs["vhost"] + Expect(exist).To(BeFalse()) + genericMap, exist := envs["generic"] + Expect(exist).To(BeTrue()) + Expect(genericMap).To(HaveLen(1)) + generic, exist := envs["generic"]["deviceID"] + Expect(exist).To(BeTrue()) + Expect(generic).To(Equal("0000:00:00.1")) + Expect(dev.IsRdma()).To(BeFalse()) Expect(err).NotTo(HaveOccurred()) }) @@ -275,7 +345,7 @@ var _ = Describe("PciNetDevice", func() { in := newPciDeviceFn("0000:00:00.1") rc := &types.ResourceConfig{} - dev, err := netdevice.NewPciNetDevice(in, f, rc) + dev, err := netdevice.NewPciNetDevice(in, f, rc, 0) Expect(err).NotTo(HaveOccurred()) Expect(dev).NotTo(BeNil()) @@ -297,20 +367,17 @@ var _ = Describe("PciNetDevice", func() { }, } - rc_vhost := &types.ResourceConfig{ + rc := &types.ResourceConfig{ ResourceName: "fake", ResourcePrefix: "fake", - SelectorObj: &types.NetDeviceSelectors{ + SelectorObjs: []interface{}{&types.NetDeviceSelectors{ VdpaType: "vhost", - }, - } - rc_virtio := &types.ResourceConfig{ - ResourceName: "fake", - ResourcePrefix: "fake", - SelectorObj: &types.NetDeviceSelectors{ + }, &types.NetDeviceSelectors{ VdpaType: "virtio", }, - } + }} + vhost_selector_index := 0 + virtio_selector_index := 1 defaultInfo1 := &mocks.DeviceInfoProvider{} mockEnv1 := types.AdditionalInfo{"deviceID": "0000:00:00.1"} @@ -350,8 +417,8 @@ var _ = Describe("PciNetDevice", func() { defer fs.Use()() utils.SetDefaultMockNetlinkProvider() - dev1, err1 := netdevice.NewPciNetDevice(in1, f, rc_vhost) - dev2, err2 := netdevice.NewPciNetDevice(in2, f, rc_virtio) + dev1, err1 := netdevice.NewPciNetDevice(in1, f, rc, vhost_selector_index) + dev2, err2 := netdevice.NewPciNetDevice(in2, f, rc, virtio_selector_index) Expect(dev1.GetDriver()).To(Equal("mlx5_core")) envs := dev1.GetEnvVal() @@ -396,8 +463,8 @@ var _ = Describe("PciNetDevice", func() { defer fs.Use()() utils.SetDefaultMockNetlinkProvider() - dev1, err1 := netdevice.NewPciNetDevice(in1, f, rc_virtio) - dev2, err2 := netdevice.NewPciNetDevice(in2, f, rc_vhost) + dev1, err1 := netdevice.NewPciNetDevice(in1, f, rc, virtio_selector_index) + dev2, err2 := netdevice.NewPciNetDevice(in2, f, rc, vhost_selector_index) envs := dev1.GetEnvVal() Expect(len(envs)).To(Equal(2)) diff --git a/pkg/resources/pool_stub_test.go b/pkg/resources/pool_stub_test.go index 7decf9bfb..7c50fc9d1 100644 --- a/pkg/resources/pool_stub_test.go +++ b/pkg/resources/pool_stub_test.go @@ -51,7 +51,7 @@ var _ = Describe("ResourcePool", func() { }, } f = factory.NewResourceFactory("fake", "fake", true) - rc = &types.ResourceConfig{SelectorObj: types.NetDeviceSelectors{}} + rc = &types.ResourceConfig{SelectorObjs: []interface{}{types.NetDeviceSelectors{}}} devs = []string{"0000:00:00.1", "0000:00:00.2"} }) Describe("getting device specs", func() { @@ -60,8 +60,8 @@ var _ = Describe("ResourcePool", func() { defer fs.Use()() utils.SetDefaultMockNetlinkProvider() - d1, _ = netdevice.NewPciNetDevice(newPciDeviceFn("0000:00:00.1"), f, rc) - d2, _ = netdevice.NewPciNetDevice(newPciDeviceFn("0000:00:00.2"), f, rc) + d1, _ = netdevice.NewPciNetDevice(newPciDeviceFn("0000:00:00.1"), f, rc, 0) + d2, _ = netdevice.NewPciNetDevice(newPciDeviceFn("0000:00:00.2"), f, rc, 0) rp = resources.NewResourcePool(rc, map[string]types.HostDevice{ "0000:00:00.1": d1, @@ -86,8 +86,8 @@ var _ = Describe("ResourcePool", func() { defer fs.Use()() utils.SetDefaultMockNetlinkProvider() - d1, _ = netdevice.NewPciNetDevice(newPciDeviceFn("0000:00:00.1"), f, rc) - d2, _ = netdevice.NewPciNetDevice(newPciDeviceFn("0000:00:00.2"), f, rc) + d1, _ = netdevice.NewPciNetDevice(newPciDeviceFn("0000:00:00.1"), f, rc, 0) + d2, _ = netdevice.NewPciNetDevice(newPciDeviceFn("0000:00:00.2"), f, rc, 0) rp = resources.NewResourcePool(rc, map[string]types.HostDevice{ "0000:00:00.1": d1, @@ -109,8 +109,8 @@ var _ = Describe("ResourcePool", func() { defer fs.Use()() utils.SetDefaultMockNetlinkProvider() - d1, _ = netdevice.NewPciNetDevice(newPciDeviceFn("0000:00:00.1"), f, rc) - d2, _ = netdevice.NewPciNetDevice(newPciDeviceFn("0000:00:00.2"), f, rc) + d1, _ = netdevice.NewPciNetDevice(newPciDeviceFn("0000:00:00.1"), f, rc, 0) + d2, _ = netdevice.NewPciNetDevice(newPciDeviceFn("0000:00:00.2"), f, rc, 0) rp = resources.NewResourcePool(rc, map[string]types.HostDevice{ "0000:00:00.1": d1, diff --git a/pkg/types/mocks/APIDevice.go b/pkg/types/mocks/APIDevice.go index c50169891..55cd1e96b 100644 --- a/pkg/types/mocks/APIDevice.go +++ b/pkg/types/mocks/APIDevice.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks diff --git a/pkg/types/mocks/AccelDevice.go b/pkg/types/mocks/AccelDevice.go index 51dfd53d0..6ad0cea54 100644 --- a/pkg/types/mocks/AccelDevice.go +++ b/pkg/types/mocks/AccelDevice.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks diff --git a/pkg/types/mocks/AuxNetDevice.go b/pkg/types/mocks/AuxNetDevice.go index aaa442f76..0d05df75c 100644 --- a/pkg/types/mocks/AuxNetDevice.go +++ b/pkg/types/mocks/AuxNetDevice.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks diff --git a/pkg/types/mocks/DeviceInfoProvider.go b/pkg/types/mocks/DeviceInfoProvider.go index 0f0cec033..fdaaf7d8a 100644 --- a/pkg/types/mocks/DeviceInfoProvider.go +++ b/pkg/types/mocks/DeviceInfoProvider.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks diff --git a/pkg/types/mocks/DeviceProvider.go b/pkg/types/mocks/DeviceProvider.go index ddd510eec..de3dd3610 100644 --- a/pkg/types/mocks/DeviceProvider.go +++ b/pkg/types/mocks/DeviceProvider.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks @@ -28,13 +28,13 @@ func (_m *DeviceProvider) AddTargetDevices(_a0 []*pci.Device, _a1 int) error { return r0 } -// GetDevices provides a mock function with given fields: _a0 -func (_m *DeviceProvider) GetDevices(_a0 *types.ResourceConfig) []types.HostDevice { - ret := _m.Called(_a0) +// GetDevices provides a mock function with given fields: _a0, _a1 +func (_m *DeviceProvider) GetDevices(_a0 *types.ResourceConfig, _a1 int) []types.HostDevice { + ret := _m.Called(_a0, _a1) var r0 []types.HostDevice - if rf, ok := ret.Get(0).(func(*types.ResourceConfig) []types.HostDevice); ok { - r0 = rf(_a0) + if rf, ok := ret.Get(0).(func(*types.ResourceConfig, int) []types.HostDevice); ok { + r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]types.HostDevice) @@ -60,22 +60,25 @@ func (_m *DeviceProvider) GetDiscoveredDevices() []*pci.Device { return r0 } -// GetFilteredDevices provides a mock function with given fields: _a0, _a1 -func (_m *DeviceProvider) GetFilteredDevices(_a0 []types.HostDevice, _a1 *types.ResourceConfig) ([]types.HostDevice, error) { - ret := _m.Called(_a0, _a1) +// GetFilteredDevices provides a mock function with given fields: _a0, _a1, _a2 +func (_m *DeviceProvider) GetFilteredDevices(_a0 []types.HostDevice, _a1 *types.ResourceConfig, _a2 int) ([]types.HostDevice, error) { + ret := _m.Called(_a0, _a1, _a2) var r0 []types.HostDevice - if rf, ok := ret.Get(0).(func([]types.HostDevice, *types.ResourceConfig) []types.HostDevice); ok { - r0 = rf(_a0, _a1) + var r1 error + if rf, ok := ret.Get(0).(func([]types.HostDevice, *types.ResourceConfig, int) ([]types.HostDevice, error)); ok { + return rf(_a0, _a1, _a2) + } + if rf, ok := ret.Get(0).(func([]types.HostDevice, *types.ResourceConfig, int) []types.HostDevice); ok { + r0 = rf(_a0, _a1, _a2) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]types.HostDevice) } } - var r1 error - if rf, ok := ret.Get(1).(func([]types.HostDevice, *types.ResourceConfig) error); ok { - r1 = rf(_a0, _a1) + if rf, ok := ret.Get(1).(func([]types.HostDevice, *types.ResourceConfig, int) error); ok { + r1 = rf(_a0, _a1, _a2) } else { r1 = ret.Error(1) } diff --git a/pkg/types/mocks/DeviceSelector.go b/pkg/types/mocks/DeviceSelector.go index d4c71c34f..f6181d116 100644 --- a/pkg/types/mocks/DeviceSelector.go +++ b/pkg/types/mocks/DeviceSelector.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks diff --git a/pkg/types/mocks/HostDevice.go b/pkg/types/mocks/HostDevice.go index 40f35a66f..11cbb36bb 100644 --- a/pkg/types/mocks/HostDevice.go +++ b/pkg/types/mocks/HostDevice.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks diff --git a/pkg/types/mocks/LinkWatcher.go b/pkg/types/mocks/LinkWatcher.go index 10d74ede0..db1ac07a7 100644 --- a/pkg/types/mocks/LinkWatcher.go +++ b/pkg/types/mocks/LinkWatcher.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks diff --git a/pkg/types/mocks/NadUtils.go b/pkg/types/mocks/NadUtils.go index a3c642237..5736379f7 100644 --- a/pkg/types/mocks/NadUtils.go +++ b/pkg/types/mocks/NadUtils.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks diff --git a/pkg/types/mocks/NetDevice.go b/pkg/types/mocks/NetDevice.go index f27b2d4e0..f4f3a74a8 100644 --- a/pkg/types/mocks/NetDevice.go +++ b/pkg/types/mocks/NetDevice.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks diff --git a/pkg/types/mocks/PciDevice.go b/pkg/types/mocks/PciDevice.go index c7531a93e..2963d1073 100644 --- a/pkg/types/mocks/PciDevice.go +++ b/pkg/types/mocks/PciDevice.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks diff --git a/pkg/types/mocks/PciNetDevice.go b/pkg/types/mocks/PciNetDevice.go index e11dff850..7e1faff18 100644 --- a/pkg/types/mocks/PciNetDevice.go +++ b/pkg/types/mocks/PciNetDevice.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks diff --git a/pkg/types/mocks/RdmaSpec.go b/pkg/types/mocks/RdmaSpec.go index fde710260..6a4da24fb 100644 --- a/pkg/types/mocks/RdmaSpec.go +++ b/pkg/types/mocks/RdmaSpec.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks diff --git a/pkg/types/mocks/ResourceFactory.go b/pkg/types/mocks/ResourceFactory.go index 0d63b7b5e..54f171fb2 100644 --- a/pkg/types/mocks/ResourceFactory.go +++ b/pkg/types/mocks/ResourceFactory.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks @@ -29,19 +29,22 @@ func (_m *ResourceFactory) GetDefaultInfoProvider(_a0 string, _a1 string) []type } // GetDeviceFilter provides a mock function with given fields: _a0 -func (_m *ResourceFactory) GetDeviceFilter(_a0 *types.ResourceConfig) (interface{}, error) { +func (_m *ResourceFactory) GetDeviceFilter(_a0 *types.ResourceConfig) ([]interface{}, error) { ret := _m.Called(_a0) - var r0 interface{} - if rf, ok := ret.Get(0).(func(*types.ResourceConfig) interface{}); ok { + var r0 []interface{} + var r1 error + if rf, ok := ret.Get(0).(func(*types.ResourceConfig) ([]interface{}, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(*types.ResourceConfig) []interface{}); ok { r0 = rf(_a0) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(interface{}) + r0 = ret.Get(0).([]interface{}) } } - var r1 error if rf, ok := ret.Get(1).(func(*types.ResourceConfig) error); ok { r1 = rf(_a0) } else { @@ -104,6 +107,10 @@ func (_m *ResourceFactory) GetResourcePool(rc *types.ResourceConfig, deviceList ret := _m.Called(rc, deviceList) var r0 types.ResourcePool + var r1 error + if rf, ok := ret.Get(0).(func(*types.ResourceConfig, []types.HostDevice) (types.ResourcePool, error)); ok { + return rf(rc, deviceList) + } if rf, ok := ret.Get(0).(func(*types.ResourceConfig, []types.HostDevice) types.ResourcePool); ok { r0 = rf(rc, deviceList) } else { @@ -112,7 +119,6 @@ func (_m *ResourceFactory) GetResourcePool(rc *types.ResourceConfig, deviceList } } - var r1 error if rf, ok := ret.Get(1).(func(*types.ResourceConfig, []types.HostDevice) error); ok { r1 = rf(rc, deviceList) } else { @@ -127,6 +133,10 @@ func (_m *ResourceFactory) GetResourceServer(_a0 types.ResourcePool) (types.Reso ret := _m.Called(_a0) var r0 types.ResourceServer + var r1 error + if rf, ok := ret.Get(0).(func(types.ResourcePool) (types.ResourceServer, error)); ok { + return rf(_a0) + } if rf, ok := ret.Get(0).(func(types.ResourcePool) types.ResourceServer); ok { r0 = rf(_a0) } else { @@ -135,7 +145,6 @@ func (_m *ResourceFactory) GetResourceServer(_a0 types.ResourcePool) (types.Reso } } - var r1 error if rf, ok := ret.Get(1).(func(types.ResourcePool) error); ok { r1 = rf(_a0) } else { @@ -150,6 +159,10 @@ func (_m *ResourceFactory) GetSelector(_a0 string, _a1 []string) (types.DeviceSe ret := _m.Called(_a0, _a1) var r0 types.DeviceSelector + var r1 error + if rf, ok := ret.Get(0).(func(string, []string) (types.DeviceSelector, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(string, []string) types.DeviceSelector); ok { r0 = rf(_a0, _a1) } else { @@ -158,7 +171,6 @@ func (_m *ResourceFactory) GetSelector(_a0 string, _a1 []string) (types.DeviceSe } } - var r1 error if rf, ok := ret.Get(1).(func(string, []string) error); ok { r1 = rf(_a0, _a1) } else { diff --git a/pkg/types/mocks/ResourcePool.go b/pkg/types/mocks/ResourcePool.go index 5b37e868a..f3d209c25 100644 --- a/pkg/types/mocks/ResourcePool.go +++ b/pkg/types/mocks/ResourcePool.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks @@ -64,6 +64,10 @@ func (_m *ResourcePool) GetEnvs(prefix string, deviceIDs []string) (map[string]s ret := _m.Called(prefix, deviceIDs) var r0 map[string]string + var r1 error + if rf, ok := ret.Get(0).(func(string, []string) (map[string]string, error)); ok { + return rf(prefix, deviceIDs) + } if rf, ok := ret.Get(0).(func(string, []string) map[string]string); ok { r0 = rf(prefix, deviceIDs) } else { @@ -72,7 +76,6 @@ func (_m *ResourcePool) GetEnvs(prefix string, deviceIDs []string) (map[string]s } } - var r1 error if rf, ok := ret.Get(1).(func(string, []string) error); ok { r1 = rf(prefix, deviceIDs) } else { diff --git a/pkg/types/mocks/ResourceServer.go b/pkg/types/mocks/ResourceServer.go index 059e7aab6..43a2bea24 100644 --- a/pkg/types/mocks/ResourceServer.go +++ b/pkg/types/mocks/ResourceServer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ func (_m *ResourceServer) Allocate(_a0 context.Context, _a1 *v1beta1.AllocateReq ret := _m.Called(_a0, _a1) var r0 *v1beta1.AllocateResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *v1beta1.AllocateRequest) (*v1beta1.AllocateResponse, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, *v1beta1.AllocateRequest) *v1beta1.AllocateResponse); ok { r0 = rf(_a0, _a1) } else { @@ -28,7 +32,6 @@ func (_m *ResourceServer) Allocate(_a0 context.Context, _a1 *v1beta1.AllocateReq } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *v1beta1.AllocateRequest) error); ok { r1 = rf(_a0, _a1) } else { @@ -43,6 +46,10 @@ func (_m *ResourceServer) GetDevicePluginOptions(_a0 context.Context, _a1 *v1bet ret := _m.Called(_a0, _a1) var r0 *v1beta1.DevicePluginOptions + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *v1beta1.Empty) (*v1beta1.DevicePluginOptions, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, *v1beta1.Empty) *v1beta1.DevicePluginOptions); ok { r0 = rf(_a0, _a1) } else { @@ -51,7 +58,6 @@ func (_m *ResourceServer) GetDevicePluginOptions(_a0 context.Context, _a1 *v1bet } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *v1beta1.Empty) error); ok { r1 = rf(_a0, _a1) } else { @@ -66,6 +72,10 @@ func (_m *ResourceServer) GetPreferredAllocation(_a0 context.Context, _a1 *v1bet ret := _m.Called(_a0, _a1) var r0 *v1beta1.PreferredAllocationResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *v1beta1.PreferredAllocationRequest) (*v1beta1.PreferredAllocationResponse, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, *v1beta1.PreferredAllocationRequest) *v1beta1.PreferredAllocationResponse); ok { r0 = rf(_a0, _a1) } else { @@ -74,7 +84,6 @@ func (_m *ResourceServer) GetPreferredAllocation(_a0 context.Context, _a1 *v1bet } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *v1beta1.PreferredAllocationRequest) error); ok { r1 = rf(_a0, _a1) } else { @@ -117,6 +126,10 @@ func (_m *ResourceServer) PreStartContainer(_a0 context.Context, _a1 *v1beta1.Pr ret := _m.Called(_a0, _a1) var r0 *v1beta1.PreStartContainerResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *v1beta1.PreStartContainerRequest) (*v1beta1.PreStartContainerResponse, error)); ok { + return rf(_a0, _a1) + } if rf, ok := ret.Get(0).(func(context.Context, *v1beta1.PreStartContainerRequest) *v1beta1.PreStartContainerResponse); ok { r0 = rf(_a0, _a1) } else { @@ -125,7 +138,6 @@ func (_m *ResourceServer) PreStartContainer(_a0 context.Context, _a1 *v1beta1.Pr } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *v1beta1.PreStartContainerRequest) error); ok { r1 = rf(_a0, _a1) } else { diff --git a/pkg/types/mocks/VdpaDevice.go b/pkg/types/mocks/VdpaDevice.go index 6dd0e35c0..3144c74dc 100644 --- a/pkg/types/mocks/VdpaDevice.go +++ b/pkg/types/mocks/VdpaDevice.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks diff --git a/pkg/types/types.go b/pkg/types/types.go index 8976d6763..17590f856 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -101,7 +101,7 @@ type ResourceConfig struct { ExcludeTopology bool `json:"excludeTopology,omitempty"` Selectors *json.RawMessage `json:"selectors,omitempty"` AdditionalInfo map[string]AdditionalInfo `json:"additionalInfo,omitempty"` - SelectorObj interface{} + SelectorObjs []interface{} } // DeviceSelectors contains common device selectors fields @@ -177,7 +177,7 @@ type ResourceFactory interface { GetRdmaSpec(DeviceType, string) RdmaSpec GetVdpaDevice(string) VdpaDevice GetDeviceProvider(DeviceType) DeviceProvider - GetDeviceFilter(*ResourceConfig) (interface{}, error) + GetDeviceFilter(*ResourceConfig) ([]interface{}, error) GetNadUtils() NadUtils } @@ -202,9 +202,11 @@ type DeviceProvider interface { GetDiscoveredDevices() []*ghw.PCIDevice // GetDevices runs through the Discovered Devices and returns a list of fully populated HostDevices according to the given ResourceConfig - GetDevices(*ResourceConfig) []HostDevice + GetDevices(*ResourceConfig, int) []HostDevice - GetFilteredDevices([]HostDevice, *ResourceConfig) ([]HostDevice, error) + // GetFilteredDevices runs through the provided []HostDevice and filters eligible devices based on the selectors in ResourceConfig. Since + // the ResourceConfig contains a slice of selectors, the third argument is the index into that array to get the correct selectors to apply. + GetFilteredDevices([]HostDevice, *ResourceConfig, int) ([]HostDevice, error) // ValidConfig performs validation of DeviceType-specific configuration ValidConfig(*ResourceConfig) bool diff --git a/pkg/utils/mocks/NetlinkProvider.go b/pkg/utils/mocks/NetlinkProvider.go index 617f931a8..f6d8f5a69 100644 --- a/pkg/utils/mocks/NetlinkProvider.go +++ b/pkg/utils/mocks/NetlinkProvider.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ func (_m *NetlinkProvider) GetDevLinkDeviceEswitchAttrs(ifName string) (*netlink ret := _m.Called(ifName) var r0 *netlink.DevlinkDevEswitchAttr + var r1 error + if rf, ok := ret.Get(0).(func(string) (*netlink.DevlinkDevEswitchAttr, error)); ok { + return rf(ifName) + } if rf, ok := ret.Get(0).(func(string) *netlink.DevlinkDevEswitchAttr); ok { r0 = rf(ifName) } else { @@ -25,7 +29,6 @@ func (_m *NetlinkProvider) GetDevLinkDeviceEswitchAttrs(ifName string) (*netlink } } - var r1 error if rf, ok := ret.Get(1).(func(string) error); ok { r1 = rf(ifName) } else { @@ -40,6 +43,10 @@ func (_m *NetlinkProvider) GetIPv4RouteList(ifName string) ([]netlink.Route, err ret := _m.Called(ifName) var r0 []netlink.Route + var r1 error + if rf, ok := ret.Get(0).(func(string) ([]netlink.Route, error)); ok { + return rf(ifName) + } if rf, ok := ret.Get(0).(func(string) []netlink.Route); ok { r0 = rf(ifName) } else { @@ -48,7 +55,6 @@ func (_m *NetlinkProvider) GetIPv4RouteList(ifName string) ([]netlink.Route, err } } - var r1 error if rf, ok := ret.Get(1).(func(string) error); ok { r1 = rf(ifName) } else { @@ -63,6 +69,10 @@ func (_m *NetlinkProvider) GetLinkAttrs(ifName string) (*netlink.LinkAttrs, erro ret := _m.Called(ifName) var r0 *netlink.LinkAttrs + var r1 error + if rf, ok := ret.Get(0).(func(string) (*netlink.LinkAttrs, error)); ok { + return rf(ifName) + } if rf, ok := ret.Get(0).(func(string) *netlink.LinkAttrs); ok { r0 = rf(ifName) } else { @@ -71,7 +81,6 @@ func (_m *NetlinkProvider) GetLinkAttrs(ifName string) (*netlink.LinkAttrs, erro } } - var r1 error if rf, ok := ret.Get(1).(func(string) error); ok { r1 = rf(ifName) } else { diff --git a/pkg/utils/mocks/RdmaProvider.go b/pkg/utils/mocks/RdmaProvider.go index 0e0bce2ad..a37180521 100644 --- a/pkg/utils/mocks/RdmaProvider.go +++ b/pkg/utils/mocks/RdmaProvider.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks diff --git a/pkg/utils/mocks/SriovnetProvider.go b/pkg/utils/mocks/SriovnetProvider.go index a64b6c295..60afe2271 100644 --- a/pkg/utils/mocks/SriovnetProvider.go +++ b/pkg/utils/mocks/SriovnetProvider.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks @@ -14,6 +14,10 @@ func (_m *SriovnetProvider) GetAuxNetDevicesFromPci(pciAddr string) ([]string, e ret := _m.Called(pciAddr) var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func(string) ([]string, error)); ok { + return rf(pciAddr) + } if rf, ok := ret.Get(0).(func(string) []string); ok { r0 = rf(pciAddr) } else { @@ -22,7 +26,6 @@ func (_m *SriovnetProvider) GetAuxNetDevicesFromPci(pciAddr string) ([]string, e } } - var r1 error if rf, ok := ret.Get(1).(func(string) error); ok { r1 = rf(pciAddr) } else { @@ -37,6 +40,10 @@ func (_m *SriovnetProvider) GetNetDevicesFromAux(auxDev string) ([]string, error ret := _m.Called(auxDev) var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func(string) ([]string, error)); ok { + return rf(auxDev) + } if rf, ok := ret.Get(0).(func(string) []string); ok { r0 = rf(auxDev) } else { @@ -45,7 +52,6 @@ func (_m *SriovnetProvider) GetNetDevicesFromAux(auxDev string) ([]string, error } } - var r1 error if rf, ok := ret.Get(1).(func(string) error); ok { r1 = rf(auxDev) } else { @@ -60,13 +66,16 @@ func (_m *SriovnetProvider) GetPfPciFromAux(auxDev string) (string, error) { ret := _m.Called(auxDev) var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(string) (string, error)); ok { + return rf(auxDev) + } if rf, ok := ret.Get(0).(func(string) string); ok { r0 = rf(auxDev) } else { r0 = ret.Get(0).(string) } - var r1 error if rf, ok := ret.Get(1).(func(string) error); ok { r1 = rf(auxDev) } else { @@ -81,13 +90,16 @@ func (_m *SriovnetProvider) GetSfIndexByAuxDev(auxDev string) (int, error) { ret := _m.Called(auxDev) var r0 int + var r1 error + if rf, ok := ret.Get(0).(func(string) (int, error)); ok { + return rf(auxDev) + } if rf, ok := ret.Get(0).(func(string) int); ok { r0 = rf(auxDev) } else { r0 = ret.Get(0).(int) } - var r1 error if rf, ok := ret.Get(1).(func(string) error); ok { r1 = rf(auxDev) } else { @@ -102,13 +114,16 @@ func (_m *SriovnetProvider) GetUplinkRepresentor(vfPciAddress string) (string, e ret := _m.Called(vfPciAddress) var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(string) (string, error)); ok { + return rf(vfPciAddress) + } if rf, ok := ret.Get(0).(func(string) string); ok { r0 = rf(vfPciAddress) } else { r0 = ret.Get(0).(string) } - var r1 error if rf, ok := ret.Get(1).(func(string) error); ok { r1 = rf(vfPciAddress) } else { @@ -123,13 +138,16 @@ func (_m *SriovnetProvider) GetUplinkRepresentorFromAux(auxDev string) (string, ret := _m.Called(auxDev) var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(string) (string, error)); ok { + return rf(auxDev) + } if rf, ok := ret.Get(0).(func(string) string); ok { r0 = rf(auxDev) } else { r0 = ret.Get(0).(string) } - var r1 error if rf, ok := ret.Get(1).(func(string) error); ok { r1 = rf(auxDev) } else { diff --git a/pkg/utils/mocks/VdpaProvider.go b/pkg/utils/mocks/VdpaProvider.go index 3e50077ad..71d896370 100644 --- a/pkg/utils/mocks/VdpaProvider.go +++ b/pkg/utils/mocks/VdpaProvider.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.15.0. DO NOT EDIT. +// Code generated by mockery v2.26.1. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ func (_m *VdpaProvider) GetVdpaDeviceByPci(pciAddr string) (kvdpa.VdpaDevice, er ret := _m.Called(pciAddr) var r0 kvdpa.VdpaDevice + var r1 error + if rf, ok := ret.Get(0).(func(string) (kvdpa.VdpaDevice, error)); ok { + return rf(pciAddr) + } if rf, ok := ret.Get(0).(func(string) kvdpa.VdpaDevice); ok { r0 = rf(pciAddr) } else { @@ -25,7 +29,6 @@ func (_m *VdpaProvider) GetVdpaDeviceByPci(pciAddr string) (kvdpa.VdpaDevice, er } } - var r1 error if rf, ok := ret.Get(1).(func(string) error); ok { r1 = rf(pciAddr) } else {