diff --git a/.github/workflows/build-test-lint.yml b/.github/workflows/build-test-lint.yml index 6988a3255..2baece2e1 100644 --- a/.github/workflows/build-test-lint.yml +++ b/.github/workflows/build-test-lint.yml @@ -5,7 +5,7 @@ jobs: name: build strategy: matrix: - go-version: [1.17.x, 1.18.x] + go-version: [1.20.x] goarch: [amd64] os: [ubuntu-latest] runs-on: ${{ matrix.os }} @@ -32,7 +32,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.20.x - name: Check out code into the Go module directory uses: actions/checkout@v3 @@ -41,7 +41,7 @@ jobs: run: sudo apt-get install hwdata -y - name: Go test - run: make test + run: make test-race test-coverage: runs-on: ubuntu-latest @@ -51,7 +51,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.20.x - uses: actions/checkout@v3 @@ -74,13 +74,13 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.20.x - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.46.2 + version: v1.52.2 shellcheck: name: Shellcheck @@ -104,10 +104,6 @@ jobs: with: dockerfile: ./images/Dockerfile ignore: DL3018 # DL3018: GH issue 368 - - uses: brpaz/hadolint-action@v1.5.0 - with: - dockerfile: Dockerfile.rhel7 - ignore: DL3018 DL3033 # DL3018/DL3033: GH issue 368 go-check: runs-on: ubuntu-latest @@ -117,7 +113,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.20.x # if this fails, run go mod tidy - name: Check if module files are consistent with code diff --git a/.github/workflows/image-push-master.yml b/.github/workflows/image-push-master.yml index 7177e0817..16c0e4429 100644 --- a/.github/workflows/image-push-master.yml +++ b/.github/workflows/image-push-master.yml @@ -5,7 +5,6 @@ on: - master jobs: build-and-push-amd64-device-plugin: - if: github.repository_owner == 'k8snetworkplumbingwg' name: Image push AMD64 runs-on: ubuntu-20.04 env: @@ -36,7 +35,6 @@ jobs: file: images/Dockerfile build-and-push-arm64-device-plugin: - if: github.repository_owner == 'k8snetworkplumbingwg' name: Image push ARM64 runs-on: ubuntu-20.04 env: @@ -69,7 +67,6 @@ jobs: file: images/Dockerfile.arm64 build-and-push-ppc64le-device-plugin: - if: github.repository_owner == 'k8snetworkplumbingwg' name: Image push ppc64le runs-on: ubuntu-20.04 env: @@ -119,15 +116,7 @@ jobs: - name: Create manifest for multi-arch images run: | - # pull - docker pull ${{ env.IMAGE_NAME }}:latest-amd64 - docker pull ${{ env.IMAGE_NAME }}:latest-arm64 - docker pull ${{ env.IMAGE_NAME }}:latest-ppc64le - # create - docker manifest create ${{ env.IMAGE_NAME }}:latest ${{ env.IMAGE_NAME }}:latest-amd64 ${{ env.IMAGE_NAME }}:latest-arm64 ${{ env.IMAGE_NAME }}:latest-ppc64le - # annotate - docker manifest annotate ${{ env.IMAGE_NAME }}:latest ${{ env.IMAGE_NAME }}:latest-amd64 --arch amd64 - docker manifest annotate ${{ env.IMAGE_NAME }}:latest ${{ env.IMAGE_NAME }}:latest-arm64 --arch arm64 - docker manifest annotate ${{ env.IMAGE_NAME }}:latest ${{ env.IMAGE_NAME }}:latest-ppc64le --arch ppc64le - # push - docker manifest push ${{ env.IMAGE_NAME }}:latest + docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:latest \ + ${{ env.IMAGE_NAME }}:latest-amd64 \ + ${{ env.IMAGE_NAME }}:latest-arm64 \ + ${{ env.IMAGE_NAME }}:latest-ppc64le diff --git a/.github/workflows/image-push-release.yml b/.github/workflows/image-push-release.yml index 0aeb4b40d..4129e1b1c 100644 --- a/.github/workflows/image-push-release.yml +++ b/.github/workflows/image-push-release.yml @@ -5,7 +5,6 @@ on: - v* jobs: build-and-push-amd64-device-plugin: - if: github.repository_owner == 'k8snetworkplumbingwg' name: Image push AMD64 runs-on: ubuntu-20.04 env: @@ -29,7 +28,8 @@ jobs: uses: docker/metadata-action@v4 with: images: ${{ env.IMAGE_NAME }} - tag-latest: false + tags: | + type=ref,event=tag - name: Build and push sriov-network-device-plugin uses: docker/build-push-action@v4 @@ -42,7 +42,6 @@ jobs: file: images/Dockerfile build-and-push-arm64-device-plugin: - if: github.repository_owner == 'k8snetworkplumbingwg' name: Image push ARM64 runs-on: ubuntu-20.04 env: @@ -69,7 +68,9 @@ jobs: uses: docker/metadata-action@v4 with: images: ${{ env.IMAGE_NAME }} - tag-latest: false + tags: | + type=ref,event=tag + - name: Build and push sriov-network-device-plugin uses: docker/build-push-action@v4 @@ -82,7 +83,6 @@ jobs: file: images/Dockerfile.arm64 build-and-push-ppc64le-device-plugin: - if: github.repository_owner == 'k8snetworkplumbingwg' name: Image push ppc64le runs-on: ubuntu-20.04 env: @@ -109,7 +109,8 @@ jobs: uses: docker/metadata-action@v4 with: images: ${{ env.IMAGE_NAME }} - tag-latest: false + tags: | + type=ref,event=tag - name: Build and push sriov-network-device-plugin uses: docker/build-push-action@v4 @@ -133,7 +134,8 @@ jobs: uses: docker/metadata-action@v4 with: images: ${{ env.IMAGE_NAME }} - tag-latest: false + tags: | + type=ref,event=tag - name: Login to GitHub Container Registry uses: docker/login-action@v2 @@ -144,15 +146,7 @@ jobs: - name: Create manifest for multi-arch images run: | - # pull - docker pull ${{ steps.docker_meta.outputs.tags }}-amd64 - docker pull ${{ steps.docker_meta.outputs.tags }}-arm64 - docker pull ${{ steps.docker_meta.outputs.tags }}-ppc64le - # create - docker manifest create ${{ steps.docker_meta.outputs.tags }} ${{ steps.docker_meta.outputs.tags }}-amd64 ${{ steps.docker_meta.outputs.tags }}-arm64 ${{ steps.docker_meta.outputs.tags }}-ppc64le - # annotate - docker manifest annotate ${{ steps.docker_meta.outputs.tags }} ${{ steps.docker_meta.outputs.tags }}-amd64 --arch amd64 - docker manifest annotate ${{ steps.docker_meta.outputs.tags }} ${{ steps.docker_meta.outputs.tags }}-arm64 --arch arm64 - docker manifest annotate ${{ steps.docker_meta.outputs.tags }} ${{ steps.docker_meta.outputs.tags }}-ppc64le --arch ppc64le - # push - docker manifest push ${{ steps.docker_meta.outputs.tags }} + docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${{ steps.docker_meta.outputs.tags }} \ + ${{ env.IMAGE_NAME }}:${{ steps.docker_meta.outputs.tags }}-amd64 \ + ${{ env.IMAGE_NAME }}:${{ steps.docker_meta.outputs.tags }}-arm64 \ + ${{ env.IMAGE_NAME }}:${{ steps.docker_meta.outputs.tags }}-ppc64le diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index bf53f84ad..000000000 --- a/.travis.yml +++ /dev/null @@ -1,55 +0,0 @@ -language: go - -go: - "1.13" - -matrix: - include: - - name: amd64 - os: linux - env: ARCH=amd64 - # - name: ppc64le - # os: linux-ppc64le - # env: - # - ARCH=ppc64le - # - DOCKERFILE=images/Dockerfile.ppc64le - -before_install: - - sudo apt-get update -qq - - sudo apt-get install hwdata -yq - - sudo systemctl restart docker - -script: - - make test - - make build - - make - - make image TAG="$REGISTRY_USER/sriov-device-plugin" - -before_deploy: - - docker login -u "$LOGIN_USER" -p "$REGISTRY_PASS" - -deploy: - # Push image to Dockerhub on merge to master - - provider: script - skip_cleanup: true - script: > - bash -c ' - if [[ "${ARCH}" == "amd64" ]]; then docker push $REGISTRY_USER/sriov-device-plugin; fi; - docker tag $REGISTRY_USER/sriov-device-plugin $REGISTRY_USER/sriov-device-plugin:$ARCH; - docker push $REGISTRY_USER/sriov-device-plugin:$ARCH; - echo done' - on: - branch: master - # Push image to Dockerhub on tag - - provider: script - skip_cleanup: true - script: > - bash -c ' - if [[ "${ARCH}" == "amd64" ]]; then docker tag $REGISTRY_USER/sriov-device-plugin $REGISTRY_USER/sriov-device-plugin:"$TRAVIS_TAG"; docker push $REGISTRY_USER/sriov-device-plugin:"$TRAVIS_TAG"; fi; - docker tag $REGISTRY_USER/sriov-device-plugin $REGISTRY_USER/sriov-device-plugin:"$TRAVIS_TAG-$ARCH"; - docker push $REGISTRY_USER/sriov-device-plugin:"$TRAVIS_TAG-$ARCH"; - echo done' - on: - tags: true - all_branches: true - condition: "$TRAVIS_TAG =~ ^v[0-9].*$" 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 e07fe2711..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 @@ -160,7 +217,7 @@ var _ = Describe("Resource manager", func() { } err = os.WriteFile("/tmp/sriovdp/test_config", []byte(`{ "resourceList": [{ - "resourceName": "invalid-name", + "resourceName": "invalid.name", "selectors": { "isRdma": false, "vendors": ["8086"], @@ -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/README.md b/docs/rdma/README.md index b5ea7b127..f601093d1 100644 --- a/docs/rdma/README.md +++ b/docs/rdma/README.md @@ -5,13 +5,16 @@ RDMA supports zero-copy networking by enabling the network adapter to transfer d ## Supported NICs: * Mellanox ConnectX®-4 Lx Adapter * Mellanox ConnectX®-5 Adapter +* Intel E810-C Adapter ## RDMA Capable Hardware: * Mellanox ConnectX®-4 Lx Adapter * Mellanox ConnectX®-5 Adapter +* Intel E810-C Adapter ## RDMA modules: * Mellanox ConnectX®-4 Lx, ConnectX®-5 Adapters mlx5_core or mlx5_ib +* Intel E810-C Adapter ice and iavf ## Privileges IPC_LOCK capability privilege is required for RMA application to function properly in Kubernetes Pod. @@ -22,4 +25,4 @@ Using Rdma requires mounting special files from `/dev/infiniband` in the contain # ls /dev/infiniband issm2 rdma_cm ucm2 umad1 uverbs2 ``` -The digit after the file name is the index of the VF \ No newline at end of file +__Note__: rdma character devices mounted under `/dev/infiniband` may vary depending on the vendor and loaded kernel modules. diff --git a/docs/rdma/configMap.yaml b/docs/rdma/configMap.yaml index 5e0b58b90..ebc8b2dc9 100644 --- a/docs/rdma/configMap.yaml +++ b/docs/rdma/configMap.yaml @@ -10,11 +10,20 @@ data: { "resourceName": "mlnx_rdma", "resourcePrefix": "mellanox.com", - "selectors": { + "selectors": [{ "vendors": ["15b3"], "devices": ["1016", "1018"], "drivers": ["mlx5_core"], "isRdma": true + }] + }, + { + "resourceName": "intel_rdma", + "selectors": { + "vendors": ["8086"], + "devices": ["1889"], + "drivers": ["iavf"], + "isRdma": true } } ] diff --git a/docs/rdma/crd-rdma-intel.yaml b/docs/rdma/crd-rdma-intel.yaml new file mode 100644 index 000000000..6fe24fe60 --- /dev/null +++ b/docs/rdma/crd-rdma-intel.yaml @@ -0,0 +1,11 @@ +apiVersion: "k8s.cni.cncf.io/v1" +kind: NetworkAttachmentDefinition +metadata: + name: sriov-rdma-intel + annotations: + k8s.v1.cni.cncf.io/resourceName: intel.com/intel_rdma +spec: + config: '{ + "type": "sriov", + "name": "sriov-rdma" +}' diff --git a/docs/rdma/pod_intel_rdma_test.yaml b/docs/rdma/pod_intel_rdma_test.yaml new file mode 100644 index 000000000..2be9ef986 --- /dev/null +++ b/docs/rdma/pod_intel_rdma_test.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Pod +metadata: + name: rdma-app + annotations: + k8s.v1.cni.cncf.io/networks: sriov-rdma-intel +spec: + containers: + - name: test-rdma + image: + imagePullPolicy: Never + securityContext: + capabilities: + add: ["IPC_LOCK"] + resources: + requests: + intel.com/intel_rdma: 1 + limits: + intel.com/intel_rdma: 1 + command: ["sleep", "infinity"] + diff --git a/docs/rdma/pod_mlx_rdma_test.yaml b/docs/rdma/pod_mlx_rdma_test.yaml new file mode 100644 index 000000000..d3a69d1c5 --- /dev/null +++ b/docs/rdma/pod_mlx_rdma_test.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Pod +metadata: + name: rdma-app + annotations: + k8s.v1.cni.cncf.io/networks: sriov-rdma-mlnx +spec: + containers: + - name: testpmd + image: + imagePullPolicy: Never + securityContext: + capabilities: + add: ["IPC_LOCK"] + resources: + requests: + mellanox.com/mlnx_rdma: 2 + limits: + mellanox.com/mlnx_rdma: 2 + command: ["sleep", "infinity"] 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/go.mod b/go.mod index c1c8a5a25..f91d07661 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/k8snetworkplumbingwg/sriov-network-device-plugin -go 1.17 +go 1.20 require ( github.com/Mellanox/rdmamap v1.1.0 @@ -9,12 +9,12 @@ require ( github.com/jaypipes/pcidb v1.0.0 github.com/k8snetworkplumbingwg/govdpa v0.1.4 github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.1.1-0.20201119153432-9d213757d22d - github.com/k8snetworkplumbingwg/sriovnet v1.1.1-0.20221018183610-ecc82a4b8cfd + github.com/k8snetworkplumbingwg/sriovnet v1.2.0 github.com/onsi/ginkgo v1.14.0 github.com/onsi/gomega v1.10.1 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.7.1 - github.com/vishvananda/netlink v1.1.1-0.20211101163509-b10eb8fe5cf6 + github.com/vishvananda/netlink v1.2.1-beta.2 google.golang.org/grpc v1.40.0 k8s.io/kubelet v0.24.0 ) @@ -47,14 +47,14 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nxadm/tail v1.4.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/spf13/afero v1.4.1 // indirect + github.com/spf13/afero v1.9.4 // indirect github.com/stretchr/objx v0.2.0 // indirect - github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae // indirect - golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + github.com/vishvananda/netns v0.0.4 // indirect + golang.org/x/net v0.7.0 // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect - golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/term v0.5.0 // indirect + golang.org/x/text v0.8.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 75543520a..0ea7890d7 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -15,6 +16,7 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= @@ -35,6 +37,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= @@ -93,8 +96,6 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containernetworking/cni v0.8.1 h1:7zpDnQ3T3s4ucOuJ/ZCLrYBxzkg0AELFfII3Epo9TmI= github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -234,6 +235,7 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -245,6 +247,7 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -279,8 +282,8 @@ github.com/k8snetworkplumbingwg/govdpa v0.1.4 h1:e6mM7JFZkLVJeMQw3px96EigHAhnb4V github.com/k8snetworkplumbingwg/govdpa v0.1.4/go.mod h1:UQR1xu7A+nnRK1dkLEi12OnNL0OiBPpIKOYDuaQQkck= github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.1.1-0.20201119153432-9d213757d22d h1:9QbZltQGRFe7temwcTDjj8rIbow48Gv6mIKOxuks+OI= github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.1.1-0.20201119153432-9d213757d22d/go.mod h1:+1DpV8uIwteAhxNO0lgRox8gHkTG6w3OeDfAlg+qqjA= -github.com/k8snetworkplumbingwg/sriovnet v1.1.1-0.20221018183610-ecc82a4b8cfd h1:5su0j908djTCco0QDSy02R8t4tTl/AvO2CC/Soy2NBQ= -github.com/k8snetworkplumbingwg/sriovnet v1.1.1-0.20221018183610-ecc82a4b8cfd/go.mod h1:ayPUsmD4bA0nnlw6RT4di6WFRafn9kbfKcYbyZ792PU= +github.com/k8snetworkplumbingwg/sriovnet v1.2.0 h1:6ELfAxCB1dvosGUy3DVRmfH+HWTzmPD3W67HKQvMR1M= +github.com/k8snetworkplumbingwg/sriovnet v1.2.0/go.mod h1:jyWzGe6ZtYiPq6ih6aXCOy6mZ49Y9mNyBOLBBXnli+k= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -341,7 +344,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -364,16 +367,14 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.4.1 h1:asw9sl74539yqavKaglDM5hFpdJVK0Y5Dr/JOgQ89nQ= -github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.9.4 h1:Sd43wM1IWz/s1aVXdOBkjJvuP8UdyqioeE4AmM0QsBs= +github.com/spf13/afero v1.9.4/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -394,13 +395,13 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netlink v1.1.1-0.20211101163509-b10eb8fe5cf6 h1:167a2omrzz+nN9Of6lN/0yOB9itzw+IOioRThNZ30jA= -github.com/vishvananda/netlink v1.1.1-0.20211101163509-b10eb8fe5cf6/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= +github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= +github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -435,12 +436,13 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -515,6 +517,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= @@ -522,8 +525,9 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -601,11 +605,13 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -614,11 +620,13 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -628,8 +636,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -689,6 +698,7 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= @@ -762,7 +772,9 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -858,7 +870,6 @@ k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8 k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= diff --git a/images/Dockerfile b/images/Dockerfile index 8ac7512d7..a7292076d 100644 --- a/images/Dockerfile +++ b/images/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.18-alpine as builder +FROM golang:1.20-alpine as builder COPY . /usr/src/sriov-network-device-plugin @@ -10,7 +10,7 @@ WORKDIR /usr/src/sriov-network-device-plugin RUN make clean && \ make build -FROM golang:1.18-alpine3.16 as ddp-builder +FROM golang:1.20-alpine3.16 as ddp-builder ADD images/ddptool-1.0.1.12.tar.gz /tmp/ddptool/ 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 1ffd39af0..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", @@ -83,18 +83,21 @@ func (ap *auxNetDeviceProvider) AddTargetDevices(devices []*ghw.PCIDevice, devic productName := utils.NormalizeProductName(device.Product.Name) glog.Infof("auxnetdevice AddTargetDevices(): device found: %-12s\t%-12s\t%-20s\t%-40s", device.Address, device.Class.ID, vendorName, productName) - if isDefaultRoute, _ := utils.HasDefaultRoute(device.Address); !isDefaultRoute { - ap.deviceList = append(ap.deviceList, device) - } + ap.deviceList = append(ap.deviceList, device) } } return nil } //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") } @@ -168,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/devices/devices_test.go b/pkg/devices/devices_test.go index d20a51326..7a756a66f 100644 --- a/pkg/devices/devices_test.go +++ b/pkg/devices/devices_test.go @@ -23,6 +23,8 @@ import ( "github.com/jaypipes/ghw" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/stretchr/testify/mock" + nl "github.com/vishvananda/netlink" "github.com/k8snetworkplumbingwg/sriov-network-device-plugin/pkg/devices" "github.com/k8snetworkplumbingwg/sriov-network-device-plugin/pkg/types" @@ -104,6 +106,44 @@ var _ = Describe("Devices", func() { Expect(dev).NotTo(BeNil()) Expect(dev.GetPfNetName()).To(Equal("")) }) + It("should use PF linkType if own ifName is not available", func() { + fs := &utils.FakeFilesystem{ + Dirs: []string{ + "sys/bus/pci/devices/0000:00:00.0/net/ens1f0", + "sys/bus/pci/devices/0000:00:00.1/net/", + }, + Symlinks: map[string]string{ + "sys/bus/pci/devices/0000:00:00.1/physfn": "../0000:00:00.0", + "sys/bus/pci/devices/0000:00:00.0/virtfn0": "../0000:00:00.1", + }, + } + defer fs.Use()() + testMockProvider := mocks.NetlinkProvider{} + + testMockProvider. + On("GetLinkAttrs", "fakeIfName"). + Return(&nl.LinkAttrs{EncapType: ""}, nil) + testMockProvider. + On("GetLinkAttrs", "ens1f0"). + Return(&nl.LinkAttrs{EncapType: "pfLinkType"}, nil) + testMockProvider. + On("GetDevLinkDeviceEswitchAttrs", mock.AnythingOfType("string")). + Return(&nl.DevlinkDevEswitchAttr{Mode: "fakeMode"}, nil) + testMockProvider. + On("GetIPv4RouteList", mock.AnythingOfType("string")). + Return([]nl.Route{{Dst: nil}}, nil) + utils.SetNetlinkProviderInst(&testMockProvider) + + pciAddr := "0000:00:00.1" + dev, err := devices.NewGenNetDevice(pciAddr, types.NetDeviceType, true) + + Expect(err).NotTo(HaveOccurred()) + Expect(dev).NotTo(BeNil()) + Expect(dev.GetPfNetName()).To(Equal("ens1f0")) + Expect(dev.GetPfPciAddr()).To(Equal("0000:00:00.0")) + Expect(dev.GetNetName()).To(Equal("")) + Expect(dev.GetLinkType()).To(Equal("pfLinkType")) + }) }) Context("Create new GenNetDevice for AuxNetDeviceType", func() { It("should populate fields", func() { @@ -114,6 +154,7 @@ var _ = Describe("Devices", func() { On("GetSfIndexByAuxDev", "foo.bar.0").Return(1, nil). On("GetNetDevicesFromAux", "foo.bar.0").Return([]string{"fakeIfName"}, nil) utils.SetSriovnetProviderInst(&fakeSriovnetProvider) + utils.SetDefaultMockNetlinkProvider() dev, err := devices.NewGenNetDevice("foo.bar.0", types.AuxNetDeviceType, true) diff --git a/pkg/devices/gen_net.go b/pkg/devices/gen_net.go index cc4df0782..e92b94d61 100644 --- a/pkg/devices/gen_net.go +++ b/pkg/devices/gen_net.go @@ -45,7 +45,7 @@ func NewGenNetDevice(deviceID string, dt types.DeviceType, isRdma bool) (*GenNet var funcID int var err error - //nolint: exhaustive + // nolint: exhaustive switch dt { case types.NetDeviceType: if pfName, err = utils.GetPfName(deviceID); err != nil { @@ -82,8 +82,13 @@ func NewGenNetDevice(deviceID string, dt types.DeviceType, isRdma bool) (*GenNet } linkType := "" - if len(ifName) > 0 { - la, err := utils.GetNetlinkProvider().GetLinkAttrs(ifName) + linkTypeProviderDevice := ifName + // If interface name is not available, derive link type from PF + if linkTypeProviderDevice == "" { + linkTypeProviderDevice = pfName + } + if linkTypeProviderDevice != "" { + la, err := utils.GetNetlinkProvider().GetLinkAttrs(linkTypeProviderDevice) if err != nil { return nil, err } 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 9ef170fc2..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 @@ -214,7 +216,7 @@ type DeviceProvider interface { type APIDevice interface { // GetDeviceSpecs returns a list of specs which describes host devices GetDeviceSpecs() []*pluginapi.DeviceSpec - // GetEnvVal returns environment variable associated with device + // GetEnvVal returns device information to be exposed via environment variable GetEnvVal() map[string]AdditionalInfo // GetMounts returns a list of host volumes associated with device GetMounts() []*pluginapi.Mount 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 { diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 256054e9c..9ee66261e 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -273,7 +273,7 @@ func SriovConfigured(addr string) bool { // ValidResourceName returns true if it contains permitted characters otherwise false func ValidResourceName(name string) bool { // name regex - var validString = regexp.MustCompile(`^[a-zA-Z0-9_]+$`) + var validString = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`) return validString.MatchString(name) } diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go index a251a5045..51b6d2c66 100644 --- a/pkg/utils/utils_test.go +++ b/pkg/utils/utils_test.go @@ -296,8 +296,8 @@ var _ = Describe("In the utils package", func() { func(name string, expected bool) { Expect(ValidResourceName(name)).To(Equal(expected)) }, - Entry("resource name is valid", "sriov_net_0", true), - Entry("resource name is invalid", "junk-net-0", false), + Entry("resource name is valid", "sriov-net_0", true), + Entry("resource name is invalid", "junk.net.0", false), ) DescribeTable("getting VFIO device file", diff --git a/vendor/github.com/spf13/afero/README.md b/vendor/github.com/spf13/afero/README.md index c3e807aef..3bafbfdfc 100644 --- a/vendor/github.com/spf13/afero/README.md +++ b/vendor/github.com/spf13/afero/README.md @@ -2,7 +2,7 @@ A FileSystem Abstraction System for Go -[![Build Status](https://travis-ci.org/spf13/afero.svg)](https://travis-ci.org/spf13/afero) [![Build status](https://ci.appveyor.com/api/projects/status/github/spf13/afero?branch=master&svg=true)](https://ci.appveyor.com/project/spf13/afero) [![GoDoc](https://godoc.org/github.com/spf13/afero?status.svg)](https://godoc.org/github.com/spf13/afero) [![Join the chat at https://gitter.im/spf13/afero](https://badges.gitter.im/Dev%20Chat.svg)](https://gitter.im/spf13/afero?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Test](https://github.com/spf13/afero/actions/workflows/test.yml/badge.svg)](https://github.com/spf13/afero/actions/workflows/test.yml) [![GoDoc](https://godoc.org/github.com/spf13/afero?status.svg)](https://godoc.org/github.com/spf13/afero) [![Join the chat at https://gitter.im/spf13/afero](https://badges.gitter.im/Dev%20Chat.svg)](https://gitter.im/spf13/afero?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) # Overview @@ -33,7 +33,7 @@ filesystem for full interoperability. * Support for compositional (union) file systems by combining multiple file systems acting as one * Specialized backends which modify existing filesystems (Read Only, Regexp filtered) * A set of utility functions ported from io, ioutil & hugo to be afero aware - +* Wrapper for go 1.16 filesystem abstraction `io/fs.FS` # Using Afero @@ -79,11 +79,11 @@ would. So if my application before had: ```go -os.Open('/tmp/foo') +os.Open("/tmp/foo") ``` We would replace it with: ```go -AppFs.Open('/tmp/foo') +AppFs.Open("/tmp/foo") ``` `AppFs` being the variable we defined above. @@ -94,6 +94,7 @@ AppFs.Open('/tmp/foo') File System Methods Available: ```go Chmod(name string, mode os.FileMode) : error +Chown(name string, uid, gid int) : error Chtimes(name string, atime time.Time, mtime time.Time) : error Create(name string) : File, error Mkdir(name string, perm os.FileMode) : error @@ -258,6 +259,18 @@ system using InMemoryFile. Afero has experimental support for secure file transfer protocol (sftp). Which can be used to perform file operations over a encrypted channel. +### GCSFs + +Afero has experimental support for Google Cloud Storage (GCS). You can either set the +`GOOGLE_APPLICATION_CREDENTIALS_JSON` env variable to your JSON credentials or use `opts` in +`NewGcsFS` to configure access to your GCS bucket. + +Some known limitations of the existing implementation: +* No Chmod support - The GCS ACL could probably be mapped to *nix style permissions but that would add another level of complexity and is ignored in this version. +* No Chtimes support - Could be simulated with attributes (gcs a/m-times are set implicitly) but that's is left for another version. +* Not thread safe - Also assumes all file operations are done through the same instance of the GcsFs. File operations between different GcsFs instances are not guaranteed to be consistent. + + ## Filtering Backends ### BasePathFs diff --git a/vendor/github.com/spf13/afero/afero.go b/vendor/github.com/spf13/afero/afero.go index f5b5e127c..39f658520 100644 --- a/vendor/github.com/spf13/afero/afero.go +++ b/vendor/github.com/spf13/afero/afero.go @@ -91,17 +91,20 @@ type Fs interface { // The name of this FileSystem Name() string - //Chmod changes the mode of the named file to mode. + // Chmod changes the mode of the named file to mode. Chmod(name string, mode os.FileMode) error - //Chtimes changes the access and modification times of the named file + // Chown changes the uid and gid of the named file. + Chown(name string, uid, gid int) error + + // Chtimes changes the access and modification times of the named file Chtimes(name string, atime time.Time, mtime time.Time) error } var ( ErrFileClosed = errors.New("File is closed") - ErrOutOfRange = errors.New("Out of range") - ErrTooLarge = errors.New("Too large") + ErrOutOfRange = errors.New("out of range") + ErrTooLarge = errors.New("too large") ErrFileNotFound = os.ErrNotExist ErrFileExists = os.ErrExist ErrDestinationExists = os.ErrExist diff --git a/vendor/github.com/spf13/afero/appveyor.yml b/vendor/github.com/spf13/afero/appveyor.yml index 5d2f34bf1..65e20e8ca 100644 --- a/vendor/github.com/spf13/afero/appveyor.yml +++ b/vendor/github.com/spf13/afero/appveyor.yml @@ -1,3 +1,5 @@ +# This currently does nothing. We have moved to GitHub action, but this is kept +# until spf13 has disabled this project in AppVeyor. version: '{build}' clone_folder: C:\gopath\src\github.com\spf13\afero environment: @@ -6,10 +8,3 @@ build_script: - cmd: >- go version - go env - - go get -v github.com/spf13/afero/... - - go build -v github.com/spf13/afero/... -test_script: -- cmd: go test -count=1 -cover -race -v github.com/spf13/afero/... diff --git a/vendor/github.com/spf13/afero/basepath.go b/vendor/github.com/spf13/afero/basepath.go index 3a14b833e..2e72793a3 100644 --- a/vendor/github.com/spf13/afero/basepath.go +++ b/vendor/github.com/spf13/afero/basepath.go @@ -1,6 +1,7 @@ package afero import ( + "io/fs" "os" "path/filepath" "runtime" @@ -8,7 +9,10 @@ import ( "time" ) -var _ Lstater = (*BasePathFs)(nil) +var ( + _ Lstater = (*BasePathFs)(nil) + _ fs.ReadDirFile = (*BasePathFile)(nil) +) // The BasePathFs restricts all operations to a given path within an Fs. // The given file name to the operations on this Fs will be prepended with @@ -33,6 +37,13 @@ func (f *BasePathFile) Name() string { return strings.TrimPrefix(sourcename, filepath.Clean(f.path)) } +func (f *BasePathFile) ReadDir(n int) ([]fs.DirEntry, error) { + if rdf, ok := f.File.(fs.ReadDirFile); ok { + return rdf.ReadDir(n) + } + return readDirFile{f.File}.ReadDir(n) +} + func NewBasePathFs(source Fs, path string) Fs { return &BasePathFs{source: source, path: path} } @@ -83,6 +94,13 @@ func (b *BasePathFs) Chmod(name string, mode os.FileMode) (err error) { return b.source.Chmod(name, mode) } +func (b *BasePathFs) Chown(name string, uid, gid int) (err error) { + if name, err = b.RealPath(name); err != nil { + return &os.PathError{Op: "chown", Path: name, Err: err} + } + return b.source.Chown(name, uid, gid) +} + func (b *BasePathFs) Name() string { return "BasePathFs" } @@ -202,5 +220,3 @@ func (b *BasePathFs) ReadlinkIfPossible(name string) (string, error) { } return "", &os.PathError{Op: "readlink", Path: name, Err: ErrNoReadlink} } - -// vim: ts=4 sw=4 noexpandtab nolist syn=go diff --git a/vendor/github.com/spf13/afero/cacheOnReadFs.go b/vendor/github.com/spf13/afero/cacheOnReadFs.go index 29a26c67d..017d344fd 100644 --- a/vendor/github.com/spf13/afero/cacheOnReadFs.go +++ b/vendor/github.com/spf13/afero/cacheOnReadFs.go @@ -75,6 +75,10 @@ func (u *CacheOnReadFs) copyToLayer(name string) error { return copyToLayer(u.base, u.layer, name) } +func (u *CacheOnReadFs) copyFileToLayer(name string, flag int, perm os.FileMode) error { + return copyFileToLayer(u.base, u.layer, name, flag, perm) +} + func (u *CacheOnReadFs) Chtimes(name string, atime, mtime time.Time) error { st, _, err := u.cacheStatus(name) if err != nil { @@ -117,6 +121,27 @@ func (u *CacheOnReadFs) Chmod(name string, mode os.FileMode) error { return u.layer.Chmod(name, mode) } +func (u *CacheOnReadFs) Chown(name string, uid, gid int) error { + st, _, err := u.cacheStatus(name) + if err != nil { + return err + } + switch st { + case cacheLocal: + case cacheHit: + err = u.base.Chown(name, uid, gid) + case cacheStale, cacheMiss: + if err := u.copyToLayer(name); err != nil { + return err + } + err = u.base.Chown(name, uid, gid) + } + if err != nil { + return err + } + return u.layer.Chown(name, uid, gid) +} + func (u *CacheOnReadFs) Stat(name string) (os.FileInfo, error) { st, fi, err := u.cacheStatus(name) if err != nil { @@ -191,7 +216,7 @@ func (u *CacheOnReadFs) OpenFile(name string, flag int, perm os.FileMode) (File, switch st { case cacheLocal, cacheHit: default: - if err := u.copyToLayer(name); err != nil { + if err := u.copyFileToLayer(name, flag, perm); err != nil { return nil, err } } diff --git a/vendor/github.com/spf13/afero/const_bsds.go b/vendor/github.com/spf13/afero/const_bsds.go index 18b45824b..eed0f225f 100644 --- a/vendor/github.com/spf13/afero/const_bsds.go +++ b/vendor/github.com/spf13/afero/const_bsds.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build aix || darwin || openbsd || freebsd || netbsd || dragonfly // +build aix darwin openbsd freebsd netbsd dragonfly package afero diff --git a/vendor/github.com/spf13/afero/const_win_unix.go b/vendor/github.com/spf13/afero/const_win_unix.go index 2b850e4dd..004d57e2f 100644 --- a/vendor/github.com/spf13/afero/const_win_unix.go +++ b/vendor/github.com/spf13/afero/const_win_unix.go @@ -10,12 +10,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -// +build !darwin -// +build !openbsd -// +build !freebsd -// +build !dragonfly -// +build !netbsd -// +build !aix +//go:build !darwin && !openbsd && !freebsd && !dragonfly && !netbsd && !aix +// +build !darwin,!openbsd,!freebsd,!dragonfly,!netbsd,!aix package afero diff --git a/vendor/github.com/spf13/afero/copyOnWriteFs.go b/vendor/github.com/spf13/afero/copyOnWriteFs.go index 96b770126..184d6dd70 100644 --- a/vendor/github.com/spf13/afero/copyOnWriteFs.go +++ b/vendor/github.com/spf13/afero/copyOnWriteFs.go @@ -14,7 +14,7 @@ var _ Lstater = (*CopyOnWriteFs)(nil) // a possibly writeable layer on top. Changes to the file system will only // be made in the overlay: Changing an existing file in the base layer which // is not present in the overlay will copy the file to the overlay ("changing" -// includes also calls to e.g. Chtimes() and Chmod()). +// includes also calls to e.g. Chtimes(), Chmod() and Chown()). // // Reading directories is currently only supported via Open(), not OpenFile(). type CopyOnWriteFs struct { @@ -75,6 +75,19 @@ func (u *CopyOnWriteFs) Chmod(name string, mode os.FileMode) error { return u.layer.Chmod(name, mode) } +func (u *CopyOnWriteFs) Chown(name string, uid, gid int) error { + b, err := u.isBaseFile(name) + if err != nil { + return err + } + if b { + if err := u.copyToLayer(name); err != nil { + return err + } + } + return u.layer.Chown(name, uid, gid) +} + func (u *CopyOnWriteFs) Stat(name string) (os.FileInfo, error) { fi, err := u.layer.Stat(name) if err != nil { @@ -210,7 +223,7 @@ func (u *CopyOnWriteFs) OpenFile(name string, flag int, perm os.FileMode) (File, return nil, err } if isaDir { - if err = u.layer.MkdirAll(dir, 0777); err != nil { + if err = u.layer.MkdirAll(dir, 0o777); err != nil { return nil, err } return u.layer.OpenFile(name, flag, perm) @@ -234,8 +247,9 @@ func (u *CopyOnWriteFs) OpenFile(name string, flag int, perm os.FileMode) (File, // This function handles the 9 different possibilities caused // by the union which are the intersection of the following... -// layer: doesn't exist, exists as a file, and exists as a directory -// base: doesn't exist, exists as a file, and exists as a directory +// +// layer: doesn't exist, exists as a file, and exists as a directory +// base: doesn't exist, exists as a file, and exists as a directory func (u *CopyOnWriteFs) Open(name string) (File, error) { // Since the overlay overrides the base we check that first b, err := u.isBaseFile(name) @@ -309,5 +323,5 @@ func (u *CopyOnWriteFs) MkdirAll(name string, perm os.FileMode) error { } func (u *CopyOnWriteFs) Create(name string) (File, error) { - return u.OpenFile(name, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0666) + return u.OpenFile(name, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0o666) } diff --git a/vendor/github.com/spf13/afero/httpFs.go b/vendor/github.com/spf13/afero/httpFs.go index c42193688..ac0de6d51 100644 --- a/vendor/github.com/spf13/afero/httpFs.go +++ b/vendor/github.com/spf13/afero/httpFs.go @@ -29,7 +29,7 @@ type httpDir struct { } func (d httpDir) Open(name string) (http.File, error) { - if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 || + if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) || strings.Contains(name, "\x00") { return nil, errors.New("http: invalid character in file path") } @@ -67,6 +67,10 @@ func (h HttpFs) Chmod(name string, mode os.FileMode) error { return h.source.Chmod(name, mode) } +func (h HttpFs) Chown(name string, uid, gid int) error { + return h.source.Chown(name, uid, gid) +} + func (h HttpFs) Chtimes(name string, atime time.Time, mtime time.Time) error { return h.source.Chtimes(name, atime, mtime) } diff --git a/vendor/github.com/spf13/afero/internal/common/adapters.go b/vendor/github.com/spf13/afero/internal/common/adapters.go new file mode 100644 index 000000000..60685caa5 --- /dev/null +++ b/vendor/github.com/spf13/afero/internal/common/adapters.go @@ -0,0 +1,27 @@ +// Copyright © 2022 Steve Francia . +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package common + +import "io/fs" + +// FileInfoDirEntry provides an adapter from os.FileInfo to fs.DirEntry +type FileInfoDirEntry struct { + fs.FileInfo +} + +var _ fs.DirEntry = FileInfoDirEntry{} + +func (d FileInfoDirEntry) Type() fs.FileMode { return d.FileInfo.Mode().Type() } + +func (d FileInfoDirEntry) Info() (fs.FileInfo, error) { return d.FileInfo, nil } diff --git a/vendor/github.com/spf13/afero/iofs.go b/vendor/github.com/spf13/afero/iofs.go new file mode 100644 index 000000000..938b9316e --- /dev/null +++ b/vendor/github.com/spf13/afero/iofs.go @@ -0,0 +1,298 @@ +//go:build go1.16 +// +build go1.16 + +package afero + +import ( + "io" + "io/fs" + "os" + "path" + "sort" + "time" + + "github.com/spf13/afero/internal/common" +) + +// IOFS adopts afero.Fs to stdlib io/fs.FS +type IOFS struct { + Fs +} + +func NewIOFS(fs Fs) IOFS { + return IOFS{Fs: fs} +} + +var ( + _ fs.FS = IOFS{} + _ fs.GlobFS = IOFS{} + _ fs.ReadDirFS = IOFS{} + _ fs.ReadFileFS = IOFS{} + _ fs.StatFS = IOFS{} + _ fs.SubFS = IOFS{} +) + +func (iofs IOFS) Open(name string) (fs.File, error) { + const op = "open" + + // by convention for fs.FS implementations we should perform this check + if !fs.ValidPath(name) { + return nil, iofs.wrapError(op, name, fs.ErrInvalid) + } + + file, err := iofs.Fs.Open(name) + if err != nil { + return nil, iofs.wrapError(op, name, err) + } + + // file should implement fs.ReadDirFile + if _, ok := file.(fs.ReadDirFile); !ok { + file = readDirFile{file} + } + + return file, nil +} + +func (iofs IOFS) Glob(pattern string) ([]string, error) { + const op = "glob" + + // afero.Glob does not perform this check but it's required for implementations + if _, err := path.Match(pattern, ""); err != nil { + return nil, iofs.wrapError(op, pattern, err) + } + + items, err := Glob(iofs.Fs, pattern) + if err != nil { + return nil, iofs.wrapError(op, pattern, err) + } + + return items, nil +} + +func (iofs IOFS) ReadDir(name string) ([]fs.DirEntry, error) { + f, err := iofs.Fs.Open(name) + if err != nil { + return nil, iofs.wrapError("readdir", name, err) + } + + defer f.Close() + + if rdf, ok := f.(fs.ReadDirFile); ok { + items, err := rdf.ReadDir(-1) + if err != nil { + return nil, iofs.wrapError("readdir", name, err) + } + sort.Slice(items, func(i, j int) bool { return items[i].Name() < items[j].Name() }) + return items, nil + } + + items, err := f.Readdir(-1) + if err != nil { + return nil, iofs.wrapError("readdir", name, err) + } + sort.Sort(byName(items)) + + ret := make([]fs.DirEntry, len(items)) + for i := range items { + ret[i] = common.FileInfoDirEntry{FileInfo: items[i]} + } + + return ret, nil +} + +func (iofs IOFS) ReadFile(name string) ([]byte, error) { + const op = "readfile" + + if !fs.ValidPath(name) { + return nil, iofs.wrapError(op, name, fs.ErrInvalid) + } + + bytes, err := ReadFile(iofs.Fs, name) + if err != nil { + return nil, iofs.wrapError(op, name, err) + } + + return bytes, nil +} + +func (iofs IOFS) Sub(dir string) (fs.FS, error) { return IOFS{NewBasePathFs(iofs.Fs, dir)}, nil } + +func (IOFS) wrapError(op, path string, err error) error { + if _, ok := err.(*fs.PathError); ok { + return err // don't need to wrap again + } + + return &fs.PathError{ + Op: op, + Path: path, + Err: err, + } +} + +// readDirFile provides adapter from afero.File to fs.ReadDirFile needed for correct Open +type readDirFile struct { + File +} + +var _ fs.ReadDirFile = readDirFile{} + +func (r readDirFile) ReadDir(n int) ([]fs.DirEntry, error) { + items, err := r.File.Readdir(n) + if err != nil { + return nil, err + } + + ret := make([]fs.DirEntry, len(items)) + for i := range items { + ret[i] = common.FileInfoDirEntry{FileInfo: items[i]} + } + + return ret, nil +} + +// FromIOFS adopts io/fs.FS to use it as afero.Fs +// Note that io/fs.FS is read-only so all mutating methods will return fs.PathError with fs.ErrPermission +// To store modifications you may use afero.CopyOnWriteFs +type FromIOFS struct { + fs.FS +} + +var _ Fs = FromIOFS{} + +func (f FromIOFS) Create(name string) (File, error) { return nil, notImplemented("create", name) } + +func (f FromIOFS) Mkdir(name string, perm os.FileMode) error { return notImplemented("mkdir", name) } + +func (f FromIOFS) MkdirAll(path string, perm os.FileMode) error { + return notImplemented("mkdirall", path) +} + +func (f FromIOFS) Open(name string) (File, error) { + file, err := f.FS.Open(name) + if err != nil { + return nil, err + } + + return fromIOFSFile{File: file, name: name}, nil +} + +func (f FromIOFS) OpenFile(name string, flag int, perm os.FileMode) (File, error) { + return f.Open(name) +} + +func (f FromIOFS) Remove(name string) error { + return notImplemented("remove", name) +} + +func (f FromIOFS) RemoveAll(path string) error { + return notImplemented("removeall", path) +} + +func (f FromIOFS) Rename(oldname, newname string) error { + return notImplemented("rename", oldname) +} + +func (f FromIOFS) Stat(name string) (os.FileInfo, error) { return fs.Stat(f.FS, name) } + +func (f FromIOFS) Name() string { return "fromiofs" } + +func (f FromIOFS) Chmod(name string, mode os.FileMode) error { + return notImplemented("chmod", name) +} + +func (f FromIOFS) Chown(name string, uid, gid int) error { + return notImplemented("chown", name) +} + +func (f FromIOFS) Chtimes(name string, atime time.Time, mtime time.Time) error { + return notImplemented("chtimes", name) +} + +type fromIOFSFile struct { + fs.File + name string +} + +func (f fromIOFSFile) ReadAt(p []byte, off int64) (n int, err error) { + readerAt, ok := f.File.(io.ReaderAt) + if !ok { + return -1, notImplemented("readat", f.name) + } + + return readerAt.ReadAt(p, off) +} + +func (f fromIOFSFile) Seek(offset int64, whence int) (int64, error) { + seeker, ok := f.File.(io.Seeker) + if !ok { + return -1, notImplemented("seek", f.name) + } + + return seeker.Seek(offset, whence) +} + +func (f fromIOFSFile) Write(p []byte) (n int, err error) { + return -1, notImplemented("write", f.name) +} + +func (f fromIOFSFile) WriteAt(p []byte, off int64) (n int, err error) { + return -1, notImplemented("writeat", f.name) +} + +func (f fromIOFSFile) Name() string { return f.name } + +func (f fromIOFSFile) Readdir(count int) ([]os.FileInfo, error) { + rdfile, ok := f.File.(fs.ReadDirFile) + if !ok { + return nil, notImplemented("readdir", f.name) + } + + entries, err := rdfile.ReadDir(count) + if err != nil { + return nil, err + } + + ret := make([]os.FileInfo, len(entries)) + for i := range entries { + ret[i], err = entries[i].Info() + + if err != nil { + return nil, err + } + } + + return ret, nil +} + +func (f fromIOFSFile) Readdirnames(n int) ([]string, error) { + rdfile, ok := f.File.(fs.ReadDirFile) + if !ok { + return nil, notImplemented("readdir", f.name) + } + + entries, err := rdfile.ReadDir(n) + if err != nil { + return nil, err + } + + ret := make([]string, len(entries)) + for i := range entries { + ret[i] = entries[i].Name() + } + + return ret, nil +} + +func (f fromIOFSFile) Sync() error { return nil } + +func (f fromIOFSFile) Truncate(size int64) error { + return notImplemented("truncate", f.name) +} + +func (f fromIOFSFile) WriteString(s string) (ret int, err error) { + return -1, notImplemented("writestring", f.name) +} + +func notImplemented(op, path string) error { + return &fs.PathError{Op: op, Path: path, Err: fs.ErrPermission} +} diff --git a/vendor/github.com/spf13/afero/ioutil.go b/vendor/github.com/spf13/afero/ioutil.go index a403133e2..fa6abe1ee 100644 --- a/vendor/github.com/spf13/afero/ioutil.go +++ b/vendor/github.com/spf13/afero/ioutil.go @@ -141,8 +141,10 @@ func WriteFile(fs Fs, filename string, data []byte, perm os.FileMode) error { // We generate random temporary file names so that there's a good // chance the file doesn't exist yet - keeps the number of tries in // TempFile to a minimum. -var rand uint32 -var randmu sync.Mutex +var ( + randNum uint32 + randmu sync.Mutex +) func reseed() uint32 { return uint32(time.Now().UnixNano() + int64(os.Getpid())) @@ -150,12 +152,12 @@ func reseed() uint32 { func nextRandom() string { randmu.Lock() - r := rand + r := randNum if r == 0 { r = reseed() } r = r*1664525 + 1013904223 // constants from Numerical Recipes - rand = r + randNum = r randmu.Unlock() return strconv.Itoa(int(1e9 + r%1e9))[1:] } @@ -190,11 +192,11 @@ func TempFile(fs Fs, dir, pattern string) (f File, err error) { nconflict := 0 for i := 0; i < 10000; i++ { name := filepath.Join(dir, prefix+nextRandom()+suffix) - f, err = fs.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) + f, err = fs.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o600) if os.IsExist(err) { if nconflict++; nconflict > 10 { randmu.Lock() - rand = reseed() + randNum = reseed() randmu.Unlock() } continue @@ -214,6 +216,7 @@ func TempFile(fs Fs, dir, pattern string) (f File, err error) { func (a Afero) TempDir(dir, prefix string) (name string, err error) { return TempDir(a.Fs, dir, prefix) } + func TempDir(fs Fs, dir, prefix string) (name string, err error) { if dir == "" { dir = os.TempDir() @@ -222,11 +225,11 @@ func TempDir(fs Fs, dir, prefix string) (name string, err error) { nconflict := 0 for i := 0; i < 10000; i++ { try := filepath.Join(dir, prefix+nextRandom()) - err = fs.Mkdir(try, 0700) + err = fs.Mkdir(try, 0o700) if os.IsExist(err) { if nconflict++; nconflict > 10 { randmu.Lock() - rand = reseed() + randNum = reseed() randmu.Unlock() } continue diff --git a/vendor/github.com/spf13/afero/mem/file.go b/vendor/github.com/spf13/afero/mem/file.go index 07b2e12ae..62fe4498e 100644 --- a/vendor/github.com/spf13/afero/mem/file.go +++ b/vendor/github.com/spf13/afero/mem/file.go @@ -18,16 +18,20 @@ import ( "bytes" "errors" "io" + "io/fs" "os" "path/filepath" "sync" "sync/atomic" -) + "time" -import "time" + "github.com/spf13/afero/internal/common" +) const FilePathSeparator = string(filepath.Separator) +var _ fs.ReadDirFile = &File{} + type File struct { // atomic requires 64-bit alignment for struct field access at int64 @@ -57,6 +61,8 @@ type FileData struct { dir bool mode os.FileMode modtime time.Time + uid int + gid int } func (d *FileData) Name() string { @@ -70,7 +76,7 @@ func CreateFile(name string) *FileData { } func CreateDir(name string) *FileData { - return &FileData{name: name, memDir: &DirMap{}, dir: true} + return &FileData{name: name, memDir: &DirMap{}, dir: true, modtime: time.Now()} } func ChangeFileName(f *FileData, newname string) { @@ -95,6 +101,18 @@ func setModTime(f *FileData, mtime time.Time) { f.modtime = mtime } +func SetUID(f *FileData, uid int) { + f.Lock() + f.uid = uid + f.Unlock() +} + +func SetGID(f *FileData, gid int) { + f.Lock() + f.gid = gid + f.Unlock() +} + func GetFileInfo(f *FileData) *FileInfo { return &FileInfo{f} } @@ -170,10 +188,23 @@ func (f *File) Readdirnames(n int) (names []string, err error) { return names, err } +// Implements fs.ReadDirFile +func (f *File) ReadDir(n int) ([]fs.DirEntry, error) { + fi, err := f.Readdir(n) + if err != nil { + return nil, err + } + di := make([]fs.DirEntry, len(fi)) + for i, f := range fi { + di[i] = common.FileInfoDirEntry{FileInfo: f} + } + return di, nil +} + func (f *File) Read(b []byte) (n int, err error) { f.fileData.Lock() defer f.fileData.Unlock() - if f.closed == true { + if f.closed { return 0, ErrFileClosed } if len(b) > 0 && int(f.at) == len(f.fileData.data) { @@ -201,7 +232,7 @@ func (f *File) ReadAt(b []byte, off int64) (n int, err error) { } func (f *File) Truncate(size int64) error { - if f.closed == true { + if f.closed { return ErrFileClosed } if f.readOnly { @@ -210,9 +241,11 @@ func (f *File) Truncate(size int64) error { if size < 0 { return ErrOutOfRange } + f.fileData.Lock() + defer f.fileData.Unlock() if size > int64(len(f.fileData.data)) { diff := size - int64(len(f.fileData.data)) - f.fileData.data = append(f.fileData.data, bytes.Repeat([]byte{00}, int(diff))...) + f.fileData.data = append(f.fileData.data, bytes.Repeat([]byte{0o0}, int(diff))...) } else { f.fileData.data = f.fileData.data[0:size] } @@ -221,7 +254,7 @@ func (f *File) Truncate(size int64) error { } func (f *File) Seek(offset int64, whence int) (int64, error) { - if f.closed == true { + if f.closed { return 0, ErrFileClosed } switch whence { @@ -236,7 +269,7 @@ func (f *File) Seek(offset int64, whence int) (int64, error) { } func (f *File) Write(b []byte) (n int, err error) { - if f.closed == true { + if f.closed { return 0, ErrFileClosed } if f.readOnly { @@ -252,7 +285,7 @@ func (f *File) Write(b []byte) (n int, err error) { tail = f.fileData.data[n+int(cur):] } if diff > 0 { - f.fileData.data = append(bytes.Repeat([]byte{00}, int(diff)), b...) + f.fileData.data = append(f.fileData.data, append(bytes.Repeat([]byte{0o0}, int(diff)), b...)...) f.fileData.data = append(f.fileData.data, tail...) } else { f.fileData.data = append(f.fileData.data[:cur], b...) @@ -288,16 +321,19 @@ func (s *FileInfo) Name() string { s.Unlock() return name } + func (s *FileInfo) Mode() os.FileMode { s.Lock() defer s.Unlock() return s.mode } + func (s *FileInfo) ModTime() time.Time { s.Lock() defer s.Unlock() return s.modtime } + func (s *FileInfo) IsDir() bool { s.Lock() defer s.Unlock() @@ -315,8 +351,8 @@ func (s *FileInfo) Size() int64 { var ( ErrFileClosed = errors.New("File is closed") - ErrOutOfRange = errors.New("Out of range") - ErrTooLarge = errors.New("Too large") + ErrOutOfRange = errors.New("out of range") + ErrTooLarge = errors.New("too large") ErrFileNotFound = os.ErrNotExist ErrFileExists = os.ErrExist ErrDestinationExists = os.ErrExist diff --git a/vendor/github.com/spf13/afero/memmap.go b/vendor/github.com/spf13/afero/memmap.go index 0fa959249..3f4ef42de 100644 --- a/vendor/github.com/spf13/afero/memmap.go +++ b/vendor/github.com/spf13/afero/memmap.go @@ -43,7 +43,7 @@ func (m *MemMapFs) getData() map[string]*mem.FileData { // Root should always exist, right? // TODO: what about windows? root := mem.CreateDir(FilePathSeparator) - mem.SetMode(root, os.ModeDir|0755) + mem.SetMode(root, os.ModeDir|0o755) m.data[FilePathSeparator] = root }) return m.data @@ -96,12 +96,12 @@ func (m *MemMapFs) registerWithParent(f *mem.FileData, perm os.FileMode) { pdir := filepath.Dir(filepath.Clean(f.Name())) err := m.lockfreeMkdir(pdir, perm) if err != nil { - //log.Println("Mkdir error:", err) + // log.Println("Mkdir error:", err) return } parent, err = m.lockfreeOpen(pdir) if err != nil { - //log.Println("Open after Mkdir error:", err) + // log.Println("Open after Mkdir error:", err) return } } @@ -142,6 +142,11 @@ func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error { } m.mu.Lock() + // Dobule check that it doesn't exist. + if _, ok := m.getData()[name]; ok { + m.mu.Unlock() + return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists} + } item := mem.CreateDir(name) mem.SetMode(item, os.ModeDir|perm) m.getData()[name] = item @@ -279,7 +284,7 @@ func (m *MemMapFs) RemoveAll(path string) error { defer m.mu.RUnlock() for p := range m.getData() { - if strings.HasPrefix(p, path) { + if p == path || strings.HasPrefix(p, path+FilePathSeparator) { m.mu.RUnlock() m.mu.Lock() delete(m.getData(), p) @@ -314,6 +319,18 @@ func (m *MemMapFs) Rename(oldname, newname string) error { } else { return &os.PathError{Op: "rename", Path: oldname, Err: ErrFileNotFound} } + + for p, fileData := range m.getData() { + if strings.HasPrefix(p, oldname+FilePathSeparator) { + m.mu.RUnlock() + m.mu.Lock() + delete(m.getData(), p) + p := strings.Replace(p, oldname, newname, 1) + m.getData()[p] = fileData + m.mu.Unlock() + m.mu.RLock() + } + } return nil } @@ -363,6 +380,22 @@ func (m *MemMapFs) setFileMode(name string, mode os.FileMode) error { return nil } +func (m *MemMapFs) Chown(name string, uid, gid int) error { + name = normalizePath(name) + + m.mu.RLock() + f, ok := m.getData()[name] + m.mu.RUnlock() + if !ok { + return &os.PathError{Op: "chown", Path: name, Err: ErrFileNotFound} + } + + mem.SetUID(f, uid) + mem.SetGID(f, gid) + + return nil +} + func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error { name = normalizePath(name) @@ -386,9 +419,3 @@ func (m *MemMapFs) List() { fmt.Println(x.Name(), y.Size()) } } - -// func debugMemMapList(fs Fs) { -// if x, ok := fs.(*MemMapFs); ok { -// x.List() -// } -// } diff --git a/vendor/github.com/spf13/afero/os.go b/vendor/github.com/spf13/afero/os.go index 4761db5d7..f1366321e 100644 --- a/vendor/github.com/spf13/afero/os.go +++ b/vendor/github.com/spf13/afero/os.go @@ -91,6 +91,10 @@ func (OsFs) Chmod(name string, mode os.FileMode) error { return os.Chmod(name, mode) } +func (OsFs) Chown(name string, uid, gid int) error { + return os.Chown(name, uid, gid) +} + func (OsFs) Chtimes(name string, atime time.Time, mtime time.Time) error { return os.Chtimes(name, atime, mtime) } diff --git a/vendor/github.com/spf13/afero/readonlyfs.go b/vendor/github.com/spf13/afero/readonlyfs.go index f94b181b6..bd8f9264d 100644 --- a/vendor/github.com/spf13/afero/readonlyfs.go +++ b/vendor/github.com/spf13/afero/readonlyfs.go @@ -28,6 +28,10 @@ func (r *ReadOnlyFs) Chmod(n string, m os.FileMode) error { return syscall.EPERM } +func (r *ReadOnlyFs) Chown(n string, uid, gid int) error { + return syscall.EPERM +} + func (r *ReadOnlyFs) Name() string { return "ReadOnlyFilter" } diff --git a/vendor/github.com/spf13/afero/regexpfs.go b/vendor/github.com/spf13/afero/regexpfs.go index c8fc00867..218f3b235 100644 --- a/vendor/github.com/spf13/afero/regexpfs.go +++ b/vendor/github.com/spf13/afero/regexpfs.go @@ -10,7 +10,6 @@ import ( // The RegexpFs filters files (not directories) by regular expression. Only // files matching the given regexp will be allowed, all others get a ENOENT error ( // "No such file or directory"). -// type RegexpFs struct { re *regexp.Regexp source Fs @@ -60,6 +59,13 @@ func (r *RegexpFs) Chmod(name string, mode os.FileMode) error { return r.source.Chmod(name, mode) } +func (r *RegexpFs) Chown(name string, uid, gid int) error { + if err := r.dirOrMatches(name); err != nil { + return err + } + return r.source.Chown(name, uid, gid) +} + func (r *RegexpFs) Name() string { return "RegexpFs" } diff --git a/vendor/github.com/spf13/afero/symlink.go b/vendor/github.com/spf13/afero/symlink.go index d1c6ea53d..aa6ae125b 100644 --- a/vendor/github.com/spf13/afero/symlink.go +++ b/vendor/github.com/spf13/afero/symlink.go @@ -21,9 +21,9 @@ import ( // filesystems saying so. // It indicates support for 3 symlink related interfaces that implement the // behaviors of the os methods: -// - Lstat -// - Symlink, and -// - Readlink +// - Lstat +// - Symlink, and +// - Readlink type Symlinker interface { Lstater Linker diff --git a/vendor/github.com/spf13/afero/unionFile.go b/vendor/github.com/spf13/afero/unionFile.go index 985363eea..f02e75532 100644 --- a/vendor/github.com/spf13/afero/unionFile.go +++ b/vendor/github.com/spf13/afero/unionFile.go @@ -65,7 +65,7 @@ func (f *UnionFile) ReadAt(s []byte, o int64) (int, error) { if f.Layer != nil { n, err := f.Layer.ReadAt(s, o) if (err == nil || err == io.EOF) && f.Base != nil { - _, err = f.Base.Seek(o+int64(n), os.SEEK_SET) + _, err = f.Base.Seek(o+int64(n), io.SeekStart) } return n, err } @@ -130,7 +130,7 @@ func (f *UnionFile) Name() string { type DirsMerger func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error) var defaultUnionMergeDirsFn = func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error) { - var files = make(map[string]os.FileInfo) + files := make(map[string]os.FileInfo) for _, fi := range lofi { files[fi.Name()] = fi @@ -151,7 +151,6 @@ var defaultUnionMergeDirsFn = func(lofi, bofi []os.FileInfo) ([]os.FileInfo, err } return rfi, nil - } // Readdir will weave the two directories together and @@ -268,20 +267,14 @@ func (f *UnionFile) WriteString(s string) (n int, err error) { return 0, BADFD } -func copyToLayer(base Fs, layer Fs, name string) error { - bfh, err := base.Open(name) - if err != nil { - return err - } - defer bfh.Close() - +func copyFile(base Fs, layer Fs, name string, bfh File) error { // First make sure the directory exists exists, err := Exists(layer, filepath.Dir(name)) if err != nil { return err } if !exists { - err = layer.MkdirAll(filepath.Dir(name), 0777) // FIXME? + err = layer.MkdirAll(filepath.Dir(name), 0o777) // FIXME? if err != nil { return err } @@ -315,3 +308,23 @@ func copyToLayer(base Fs, layer Fs, name string) error { } return layer.Chtimes(name, bfi.ModTime(), bfi.ModTime()) } + +func copyToLayer(base Fs, layer Fs, name string) error { + bfh, err := base.Open(name) + if err != nil { + return err + } + defer bfh.Close() + + return copyFile(base, layer, name, bfh) +} + +func copyFileToLayer(base Fs, layer Fs, name string, flag int, perm os.FileMode) error { + bfh, err := base.OpenFile(name, flag, perm) + if err != nil { + return err + } + defer bfh.Close() + + return copyFile(base, layer, name, bfh) +} diff --git a/vendor/github.com/spf13/afero/util.go b/vendor/github.com/spf13/afero/util.go index 4f253f481..9e4cba274 100644 --- a/vendor/github.com/spf13/afero/util.go +++ b/vendor/github.com/spf13/afero/util.go @@ -25,6 +25,7 @@ import ( "strings" "unicode" + "golang.org/x/text/runes" "golang.org/x/text/transform" "golang.org/x/text/unicode/norm" ) @@ -42,7 +43,7 @@ func WriteReader(fs Fs, path string, r io.Reader) (err error) { ospath := filepath.FromSlash(dir) if ospath != "" { - err = fs.MkdirAll(ospath, 0777) // rwx, rw, r + err = fs.MkdirAll(ospath, 0o777) // rwx, rw, r if err != nil { if err != os.ErrExist { return err @@ -70,7 +71,7 @@ func SafeWriteReader(fs Fs, path string, r io.Reader) (err error) { ospath := filepath.FromSlash(dir) if ospath != "" { - err = fs.MkdirAll(ospath, 0777) // rwx, rw, r + err = fs.MkdirAll(ospath, 0o777) // rwx, rw, r if err != nil { return } @@ -123,7 +124,7 @@ func GetTempDir(fs Fs, subPath string) string { return addSlash(dir) } - err := fs.MkdirAll(dir, 0777) + err := fs.MkdirAll(dir, 0o777) if err != nil { panic(err) } @@ -158,16 +159,12 @@ func UnicodeSanitize(s string) string { // Transform characters with accents into plain forms. func NeuterAccents(s string) string { - t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC) + t := transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC) result, _, _ := transform.String(t, string(s)) return result } -func isMn(r rune) bool { - return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks -} - func (a Afero) FileContainsBytes(filename string, subslice []byte) (bool, error) { return FileContainsBytes(a.Fs, filename, subslice) } @@ -200,7 +197,6 @@ func FileContainsAnyBytes(fs Fs, filename string, subslices [][]byte) (bool, err // readerContains reports whether any of the subslices is within r. func readerContainsAny(r io.Reader, subslices ...[]byte) bool { - if r == nil || len(subslices) == 0 { return false } @@ -299,6 +295,9 @@ func IsEmpty(fs Fs, path string) (bool, error) { } defer f.Close() list, err := f.Readdir(-1) + if err != nil { + return false, err + } return len(list) == 0, nil } return fi.Size() == 0, nil diff --git a/vendor/github.com/vishvananda/netlink/.travis.yml b/vendor/github.com/vishvananda/netlink/.travis.yml deleted file mode 100644 index 80219c69d..000000000 --- a/vendor/github.com/vishvananda/netlink/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: go -go: - - "1.12.x" - - "1.13.x" - - "1.14.x" -before_script: - # make sure we keep path in tact when we sudo - - sudo sed -i -e 's/^Defaults\tsecure_path.*$//' /etc/sudoers - # modprobe ip_gre or else the first gre device can't be deleted - - sudo modprobe ip_gre - # modprobe nf_conntrack for the conntrack testing - - sudo modprobe nf_conntrack - - sudo modprobe nf_conntrack_netlink - - sudo modprobe nf_conntrack_ipv4 - - sudo modprobe nf_conntrack_ipv6 - - sudo modprobe sch_hfsc - - sudo modprobe sch_sfq -install: - - go get -v -t ./... -go_import_path: github.com/vishvananda/netlink diff --git a/vendor/github.com/vishvananda/netlink/README.md b/vendor/github.com/vishvananda/netlink/README.md index 0e4ddb016..0128bc67d 100644 --- a/vendor/github.com/vishvananda/netlink/README.md +++ b/vendor/github.com/vishvananda/netlink/README.md @@ -1,6 +1,6 @@ # netlink - netlink library for go # -[![Build Status](https://app.travis-ci.com/vishvananda/netlink.svg?branch=master)](https://app.travis-ci.com/github/vishvananda/netlink) [![GoDoc](https://godoc.org/github.com/vishvananda/netlink?status.svg)](https://godoc.org/github.com/vishvananda/netlink) +![Build Status](https://github.com/vishvananda/netlink/actions/workflows/main.yml/badge.svg) [![GoDoc](https://godoc.org/github.com/vishvananda/netlink?status.svg)](https://godoc.org/github.com/vishvananda/netlink) The netlink package provides a simple netlink library for go. Netlink is the interface a user-space program in linux uses to communicate with diff --git a/vendor/github.com/vishvananda/netlink/addr_linux.go b/vendor/github.com/vishvananda/netlink/addr_linux.go index e4a167dda..72862ce1f 100644 --- a/vendor/github.com/vishvananda/netlink/addr_linux.go +++ b/vendor/github.com/vishvananda/netlink/addr_linux.go @@ -176,7 +176,7 @@ func AddrList(link Link, family int) ([]Addr, error) { // The list can be filtered by link and ip family. func (h *Handle) AddrList(link Link, family int) ([]Addr, error) { req := h.newNetlinkRequest(unix.RTM_GETADDR, unix.NLM_F_DUMP) - msg := nl.NewIfInfomsg(family) + msg := nl.NewIfAddrmsg(family) req.AddData(msg) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR) @@ -296,13 +296,13 @@ type AddrUpdate struct { // AddrSubscribe takes a chan down which notifications will be sent // when addresses change. Close the 'done' chan to stop subscription. func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error { - return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0) + return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0, nil) } // AddrSubscribeAt works like AddrSubscribe plus it allows the caller // to choose the network namespace in which to subscribe (ns). func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error { - return addrSubscribeAt(ns, netns.None(), ch, done, nil, false, 0) + return addrSubscribeAt(ns, netns.None(), ch, done, nil, false, 0, nil) } // AddrSubscribeOptions contains a set of options to use with @@ -312,6 +312,7 @@ type AddrSubscribeOptions struct { ErrorCallback func(error) ListExisting bool ReceiveBufferSize int + ReceiveTimeout *unix.Timeval } // AddrSubscribeWithOptions work like AddrSubscribe but enable to @@ -322,14 +323,20 @@ func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, option none := netns.None() options.Namespace = &none } - return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting, options.ReceiveBufferSize) + return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting, options.ReceiveBufferSize, options.ReceiveTimeout) } -func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool, rcvbuf int) error { +func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool, rcvbuf int, rcvTimeout *unix.Timeval) error { s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_IFADDR, unix.RTNLGRP_IPV6_IFADDR) if err != nil { return err } + if rcvTimeout != nil { + if err := s.SetReceiveTimeout(rcvTimeout); err != nil { + return err + } + } + if done != nil { go func() { <-done diff --git a/vendor/github.com/vishvananda/netlink/filter.go b/vendor/github.com/vishvananda/netlink/filter.go index 2dc34b995..2d798b0fb 100644 --- a/vendor/github.com/vishvananda/netlink/filter.go +++ b/vendor/github.com/vishvananda/netlink/filter.go @@ -157,6 +157,39 @@ func NewConnmarkAction() *ConnmarkAction { } } +type CsumUpdateFlags uint32 + +const ( + TCA_CSUM_UPDATE_FLAG_IPV4HDR CsumUpdateFlags = 1 + TCA_CSUM_UPDATE_FLAG_ICMP CsumUpdateFlags = 2 + TCA_CSUM_UPDATE_FLAG_IGMP CsumUpdateFlags = 4 + TCA_CSUM_UPDATE_FLAG_TCP CsumUpdateFlags = 8 + TCA_CSUM_UPDATE_FLAG_UDP CsumUpdateFlags = 16 + TCA_CSUM_UPDATE_FLAG_UDPLITE CsumUpdateFlags = 32 + TCA_CSUM_UPDATE_FLAG_SCTP CsumUpdateFlags = 64 +) + +type CsumAction struct { + ActionAttrs + UpdateFlags CsumUpdateFlags +} + +func (action *CsumAction) Type() string { + return "csum" +} + +func (action *CsumAction) Attrs() *ActionAttrs { + return &action.ActionAttrs +} + +func NewCsumAction() *CsumAction { + return &CsumAction{ + ActionAttrs: ActionAttrs{ + Action: TC_ACT_PIPE, + }, + } +} + type MirredAct uint8 func (a MirredAct) String() string { @@ -260,6 +293,40 @@ func NewSkbEditAction() *SkbEditAction { } } +type PoliceAction struct { + ActionAttrs + Rate uint32 // in byte per second + Burst uint32 // in byte + RCellLog int + Mtu uint32 + Mpu uint16 // in byte + PeakRate uint32 // in byte per second + PCellLog int + AvRate uint32 // in byte per second + Overhead uint16 + LinkLayer int + ExceedAction TcPolAct + NotExceedAction TcPolAct +} + +func (action *PoliceAction) Type() string { + return "police" +} + +func (action *PoliceAction) Attrs() *ActionAttrs { + return &action.ActionAttrs +} + +func NewPoliceAction() *PoliceAction { + return &PoliceAction{ + RCellLog: -1, + PCellLog: -1, + LinkLayer: 1, // ETHERNET + ExceedAction: TC_POLICE_RECLASSIFY, + NotExceedAction: TC_POLICE_OK, + } +} + // MatchAll filters match all packets type MatchAll struct { FilterAttrs @@ -275,20 +342,20 @@ func (filter *MatchAll) Type() string { return "matchall" } -type FilterFwAttrs struct { - ClassId uint32 - InDev string - Mask uint32 - Index uint32 - Buffer uint32 - Mtu uint32 - Mpu uint16 - Rate uint32 - AvRate uint32 - PeakRate uint32 - Action TcPolAct - Overhead uint16 - LinkLayer int +type FwFilter struct { + FilterAttrs + ClassId uint32 + InDev string + Mask uint32 + Police *PoliceAction +} + +func (filter *FwFilter) Attrs() *FilterAttrs { + return &filter.FilterAttrs +} + +func (filter *FwFilter) Type() string { + return "fw" } type BpfFilter struct { diff --git a/vendor/github.com/vishvananda/netlink/filter_linux.go b/vendor/github.com/vishvananda/netlink/filter_linux.go index d5d45c872..4c6d1cf7d 100644 --- a/vendor/github.com/vishvananda/netlink/filter_linux.go +++ b/vendor/github.com/vishvananda/netlink/filter_linux.go @@ -51,76 +51,6 @@ func (filter *U32) Type() string { return "u32" } -// Fw filter filters on firewall marks -// NOTE: this is in filter_linux because it refers to nl.TcPolice which -// is defined in nl/tc_linux.go -type Fw struct { - FilterAttrs - ClassId uint32 - // TODO remove nl type from interface - Police nl.TcPolice - InDev string - // TODO Action - Mask uint32 - AvRate uint32 - Rtab [256]uint32 - Ptab [256]uint32 -} - -func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) { - var rtab [256]uint32 - var ptab [256]uint32 - rcellLog := -1 - pcellLog := -1 - avrate := fattrs.AvRate / 8 - police := nl.TcPolice{} - police.Rate.Rate = fattrs.Rate / 8 - police.PeakRate.Rate = fattrs.PeakRate / 8 - buffer := fattrs.Buffer - linklayer := nl.LINKLAYER_ETHERNET - - if fattrs.LinkLayer != nl.LINKLAYER_UNSPEC { - linklayer = fattrs.LinkLayer - } - - police.Action = int32(fattrs.Action) - if police.Rate.Rate != 0 { - police.Rate.Mpu = fattrs.Mpu - police.Rate.Overhead = fattrs.Overhead - if CalcRtable(&police.Rate, rtab[:], rcellLog, fattrs.Mtu, linklayer) < 0 { - return nil, errors.New("TBF: failed to calculate rate table") - } - police.Burst = Xmittime(uint64(police.Rate.Rate), uint32(buffer)) - } - police.Mtu = fattrs.Mtu - if police.PeakRate.Rate != 0 { - police.PeakRate.Mpu = fattrs.Mpu - police.PeakRate.Overhead = fattrs.Overhead - if CalcRtable(&police.PeakRate, ptab[:], pcellLog, fattrs.Mtu, linklayer) < 0 { - return nil, errors.New("POLICE: failed to calculate peak rate table") - } - } - - return &Fw{ - FilterAttrs: attrs, - ClassId: fattrs.ClassId, - InDev: fattrs.InDev, - Mask: fattrs.Mask, - Police: police, - AvRate: avrate, - Rtab: rtab, - Ptab: ptab, - }, nil -} - -func (filter *Fw) Attrs() *FilterAttrs { - return &filter.FilterAttrs -} - -func (filter *Fw) Type() string { - return "fw" -} - type Flower struct { FilterAttrs DestIP net.IP @@ -362,7 +292,7 @@ func (h *Handle) filterModify(filter Filter, flags int) error { if err := EncodeActions(actionsAttr, filter.Actions); err != nil { return err } - case *Fw: + case *FwFilter: if filter.Mask != 0 { b := make([]byte, 4) native.PutUint32(b, filter.Mask) @@ -371,17 +301,10 @@ func (h *Handle) filterModify(filter Filter, flags int) error { if filter.InDev != "" { options.AddRtAttr(nl.TCA_FW_INDEV, nl.ZeroTerminated(filter.InDev)) } - if (filter.Police != nl.TcPolice{}) { - + if filter.Police != nil { police := options.AddRtAttr(nl.TCA_FW_POLICE, nil) - police.AddRtAttr(nl.TCA_POLICE_TBF, filter.Police.Serialize()) - if (filter.Police.Rate != nl.TcRateSpec{}) { - payload := SerializeRtab(filter.Rtab) - police.AddRtAttr(nl.TCA_POLICE_RATE, payload) - } - if (filter.Police.PeakRate != nl.TcRateSpec{}) { - payload := SerializeRtab(filter.Ptab) - police.AddRtAttr(nl.TCA_POLICE_PEAKRATE, payload) + if err := encodePolice(police, filter.Police); err != nil { + return err } } if filter.ClassId != 0 { @@ -479,7 +402,7 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) { case "u32": filter = &U32{} case "fw": - filter = &Fw{} + filter = &FwFilter{} case "bpf": filter = &BpfFilter{} case "matchall": @@ -551,6 +474,53 @@ func toAttrs(tcgen *nl.TcGen, attrs *ActionAttrs) { attrs.Bindcnt = int(tcgen.Bindcnt) } +func encodePolice(attr *nl.RtAttr, action *PoliceAction) error { + var rtab [256]uint32 + var ptab [256]uint32 + police := nl.TcPolice{} + police.Index = uint32(action.Attrs().Index) + police.Bindcnt = int32(action.Attrs().Bindcnt) + police.Capab = uint32(action.Attrs().Capab) + police.Refcnt = int32(action.Attrs().Refcnt) + police.Rate.Rate = action.Rate + police.PeakRate.Rate = action.PeakRate + police.Action = int32(action.ExceedAction) + + if police.Rate.Rate != 0 { + police.Rate.Mpu = action.Mpu + police.Rate.Overhead = action.Overhead + if CalcRtable(&police.Rate, rtab[:], action.RCellLog, action.Mtu, action.LinkLayer) < 0 { + return errors.New("TBF: failed to calculate rate table") + } + police.Burst = Xmittime(uint64(police.Rate.Rate), action.Burst) + } + + police.Mtu = action.Mtu + if police.PeakRate.Rate != 0 { + police.PeakRate.Mpu = action.Mpu + police.PeakRate.Overhead = action.Overhead + if CalcRtable(&police.PeakRate, ptab[:], action.PCellLog, action.Mtu, action.LinkLayer) < 0 { + return errors.New("POLICE: failed to calculate peak rate table") + } + } + + attr.AddRtAttr(nl.TCA_POLICE_TBF, police.Serialize()) + if police.Rate.Rate != 0 { + attr.AddRtAttr(nl.TCA_POLICE_RATE, SerializeRtab(rtab)) + } + if police.PeakRate.Rate != 0 { + attr.AddRtAttr(nl.TCA_POLICE_PEAKRATE, SerializeRtab(ptab)) + } + if action.AvRate != 0 { + attr.AddRtAttr(nl.TCA_POLICE_AVRATE, nl.Uint32Attr(action.AvRate)) + } + if action.NotExceedAction != 0 { + attr.AddRtAttr(nl.TCA_POLICE_RESULT, nl.Uint32Attr(uint32(action.NotExceedAction))) + } + + return nil +} + func EncodeActions(attr *nl.RtAttr, actions []Action) error { tabIndex := int(nl.TCA_ACT_TAB) @@ -558,6 +528,14 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error { switch action := action.(type) { default: return fmt.Errorf("unknown action type %s", action.Type()) + case *PoliceAction: + table := attr.AddRtAttr(tabIndex, nil) + tabIndex++ + table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("police")) + aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil) + if err := encodePolice(aopts, action); err != nil { + return err + } case *MirredAction: table := attr.AddRtAttr(tabIndex, nil) tabIndex++ @@ -629,6 +607,16 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error { } toTcGen(action.Attrs(), &connmark.TcGen) aopts.AddRtAttr(nl.TCA_CONNMARK_PARMS, connmark.Serialize()) + case *CsumAction: + table := attr.AddRtAttr(tabIndex, nil) + tabIndex++ + table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("csum")) + aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil) + csum := nl.TcCsum{ + UpdateFlags: uint32(action.UpdateFlags), + } + toTcGen(action.Attrs(), &csum.TcGen) + aopts.AddRtAttr(nl.TCA_CSUM_PARMS, csum.Serialize()) case *BpfAction: table := attr.AddRtAttr(tabIndex, nil) tabIndex++ @@ -652,6 +640,29 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error { return nil } +func parsePolice(data syscall.NetlinkRouteAttr, police *PoliceAction) { + switch data.Attr.Type { + case nl.TCA_POLICE_RESULT: + police.NotExceedAction = TcPolAct(native.Uint32(data.Value[0:4])) + case nl.TCA_POLICE_AVRATE: + police.AvRate = native.Uint32(data.Value[0:4]) + case nl.TCA_POLICE_TBF: + p := *nl.DeserializeTcPolice(data.Value) + police.ActionAttrs = ActionAttrs{} + police.Attrs().Index = int(p.Index) + police.Attrs().Bindcnt = int(p.Bindcnt) + police.Attrs().Capab = int(p.Capab) + police.Attrs().Refcnt = int(p.Refcnt) + police.ExceedAction = TcPolAct(p.Action) + police.Rate = p.Rate.Rate + police.PeakRate = p.PeakRate.Rate + police.Burst = Xmitsize(uint64(p.Rate.Rate), p.Burst) + police.Mtu = p.Mtu + police.LinkLayer = int(p.Rate.Linklayer) & nl.TC_LINKLAYER_MASK + police.Overhead = p.Rate.Overhead + } +} + func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) { var actions []Action for _, table := range tables { @@ -674,12 +685,16 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) { action = &BpfAction{} case "connmark": action = &ConnmarkAction{} + case "csum": + action = &CsumAction{} case "gact": action = &GenericAction{} case "tunnel_key": action = &TunnelKeyAction{} case "skbedit": action = &SkbEditAction{} + case "police": + action = &PoliceAction{} default: break nextattr } @@ -752,12 +767,22 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) { toAttrs(&connmark.TcGen, action.Attrs()) action.(*ConnmarkAction).Zone = connmark.Zone } + case "csum": + switch adatum.Attr.Type { + case nl.TCA_CSUM_PARMS: + csum := *nl.DeserializeTcCsum(adatum.Value) + action.(*CsumAction).ActionAttrs = ActionAttrs{} + toAttrs(&csum.TcGen, action.Attrs()) + action.(*CsumAction).UpdateFlags = CsumUpdateFlags(csum.UpdateFlags) + } case "gact": switch adatum.Attr.Type { case nl.TCA_GACT_PARMS: gen := *nl.DeserializeTcGen(adatum.Value) toAttrs(&gen, action.Attrs()) } + case "police": + parsePolice(adatum, action.(*PoliceAction)) } } } @@ -813,7 +838,7 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) } func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { - fw := filter.(*Fw) + fw := filter.(*FwFilter) detailed := true for _, datum := range data { switch datum.Attr.Type { @@ -824,17 +849,12 @@ func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { case nl.TCA_FW_INDEV: fw.InDev = string(datum.Value[:len(datum.Value)-1]) case nl.TCA_FW_POLICE: + var police PoliceAction adata, _ := nl.ParseRouteAttr(datum.Value) for _, aattr := range adata { - switch aattr.Attr.Type { - case nl.TCA_POLICE_TBF: - fw.Police = *nl.DeserializeTcPolice(aattr.Value) - case nl.TCA_POLICE_RATE: - fw.Rtab = DeserializeRtab(aattr.Value) - case nl.TCA_POLICE_PEAKRATE: - fw.Ptab = DeserializeRtab(aattr.Value) - } + parsePolice(aattr, &police) } + fw.Police = &police } } return detailed, nil @@ -859,7 +879,7 @@ func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) case nl.TCA_BPF_ID: bpf.Id = int(native.Uint32(datum.Value[0:4])) case nl.TCA_BPF_TAG: - bpf.Tag = hex.EncodeToString(datum.Value[:len(datum.Value)-1]) + bpf.Tag = hex.EncodeToString(datum.Value) } } return detailed, nil diff --git a/vendor/github.com/vishvananda/netlink/handle_linux.go b/vendor/github.com/vishvananda/netlink/handle_linux.go index c02bfb7e6..4cb011687 100644 --- a/vendor/github.com/vishvananda/netlink/handle_linux.go +++ b/vendor/github.com/vishvananda/netlink/handle_linux.go @@ -107,6 +107,21 @@ func (h *Handle) GetSocketReceiveBufferSize() ([]int, error) { return results, nil } +// SetStrictCheck sets the strict check socket option for each socket in the netlink handle. Returns early if any set operation fails +func (h *Handle) SetStrictCheck(state bool) error { + for _, sh := range h.sockets { + var stateInt int = 0 + if state { + stateInt = 1 + } + err := unix.SetsockoptInt(sh.Socket.GetFd(), unix.SOL_NETLINK, unix.NETLINK_GET_STRICT_CHK, stateInt) + if err != nil { + return err + } + } + return nil +} + // NewHandleAt returns a netlink handle on the network namespace // specified by ns. If ns=netns.None(), current network namespace // will be assumed diff --git a/vendor/github.com/vishvananda/netlink/link.go b/vendor/github.com/vishvananda/netlink/link.go index bdcb994ca..33c872336 100644 --- a/vendor/github.com/vishvananda/netlink/link.go +++ b/vendor/github.com/vishvananda/netlink/link.go @@ -1038,6 +1038,7 @@ type Iptun struct { EncapType uint16 EncapFlags uint16 FlowBased bool + Proto uint8 } func (iptun *Iptun) Attrs() *LinkAttrs { @@ -1073,6 +1074,37 @@ func (ip6tnl *Ip6tnl) Type() string { return "ip6tnl" } +// from https://elixir.bootlin.com/linux/v5.15.4/source/include/uapi/linux/if_tunnel.h#L84 +type TunnelEncapType uint16 + +const ( + None TunnelEncapType = iota + FOU + GUE +) + +// from https://elixir.bootlin.com/linux/v5.15.4/source/include/uapi/linux/if_tunnel.h#L91 +type TunnelEncapFlag uint16 + +const ( + CSum TunnelEncapFlag = 1 << 0 + CSum6 = 1 << 1 + RemCSum = 1 << 2 +) + +// from https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/ip6_tunnel.h#L12 +type IP6TunnelFlag uint16 + +const ( + IP6_TNL_F_IGN_ENCAP_LIMIT IP6TunnelFlag = 1 // don't add encapsulation limit if one isn't present in inner packet + IP6_TNL_F_USE_ORIG_TCLASS = 2 // copy the traffic class field from the inner packet + IP6_TNL_F_USE_ORIG_FLOWLABEL = 4 // copy the flowlabel from the inner packet + IP6_TNL_F_MIP6_DEV = 8 // being used for Mobile IPv6 + IP6_TNL_F_RCV_DSCP_COPY = 10 // copy DSCP from the outer packet + IP6_TNL_F_USE_ORIG_FWMARK = 20 // copy fwmark from inner packet + IP6_TNL_F_ALLOW_LOCAL_REMOTE = 40 // allow remote endpoint on the local node +) + type Sittun struct { LinkAttrs Link uint32 diff --git a/vendor/github.com/vishvananda/netlink/link_linux.go b/vendor/github.com/vishvananda/netlink/link_linux.go index ad8447b2b..276947a00 100644 --- a/vendor/github.com/vishvananda/netlink/link_linux.go +++ b/vendor/github.com/vishvananda/netlink/link_linux.go @@ -1146,6 +1146,10 @@ func (h *Handle) LinkAdd(link Link) error { return h.linkModify(link, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK) } +func LinkModify(link Link) error { + return pkgHandle.LinkModify(link) +} + func (h *Handle) LinkModify(link Link) error { return h.linkModify(link, unix.NLM_F_REQUEST|unix.NLM_F_ACK) } @@ -2870,6 +2874,7 @@ func addIptunAttrs(iptun *Iptun, linkInfo *nl.RtAttr) { data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(iptun.EncapFlags)) data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_SPORT, htons(iptun.EncapSport)) data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_DPORT, htons(iptun.EncapDport)) + data.AddRtAttr(nl.IFLA_IPTUN_PROTO, nl.Uint8Attr(iptun.Proto)) } func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) { @@ -2900,6 +2905,8 @@ func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) { iptun.EncapFlags = native.Uint16(datum.Value[0:2]) case nl.IFLA_IPTUN_COLLECT_METADATA: iptun.FlowBased = true + case nl.IFLA_IPTUN_PROTO: + iptun.Proto = datum.Value[0] } } } @@ -3222,8 +3229,9 @@ func parseVfInfo(data []syscall.NetlinkRouteAttr, id int) VfInfo { func addXfrmiAttrs(xfrmi *Xfrmi, linkInfo *nl.RtAttr) { data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) data.AddRtAttr(nl.IFLA_XFRM_LINK, nl.Uint32Attr(uint32(xfrmi.ParentIndex))) - data.AddRtAttr(nl.IFLA_XFRM_IF_ID, nl.Uint32Attr(xfrmi.Ifid)) - + if xfrmi.Ifid != 0 { + data.AddRtAttr(nl.IFLA_XFRM_IF_ID, nl.Uint32Attr(xfrmi.Ifid)) + } } func parseXfrmiData(link Link, data []syscall.NetlinkRouteAttr) { diff --git a/vendor/github.com/vishvananda/netlink/nl/nl_linux.go b/vendor/github.com/vishvananda/netlink/nl/nl_linux.go index dcd4b9469..600b942b1 100644 --- a/vendor/github.com/vishvananda/netlink/nl/nl_linux.go +++ b/vendor/github.com/vishvananda/netlink/nl/nl_linux.go @@ -27,7 +27,8 @@ const ( // tc rules or filters, or other more memory requiring data. RECEIVE_BUFFER_SIZE = 65536 // Kernel netlink pid - PidKernel uint32 = 0 + PidKernel uint32 = 0 + SizeofCnMsgOp = 0x18 ) // SupportedNlFamilies contains the list of netlink families this netlink package supports @@ -38,6 +39,9 @@ var nextSeqNr uint32 // Default netlink socket timeout, 60s var SocketTimeoutTv = unix.Timeval{Sec: 60, Usec: 0} +// ErrorMessageReporting is the default error message reporting configuration for the new netlink sockets +var EnableErrorMessageReporting bool = false + // GetIPFamily returns the family type of a net.IP. func GetIPFamily(ip net.IP) int { if len(ip) <= net.IPv4len { @@ -80,11 +84,69 @@ func Swap32(i uint32) uint32 { return (i&0xff000000)>>24 | (i&0xff0000)>>8 | (i&0xff00)<<8 | (i&0xff)<<24 } +const ( + NLMSGERR_ATTR_UNUSED = 0 + NLMSGERR_ATTR_MSG = 1 + NLMSGERR_ATTR_OFFS = 2 + NLMSGERR_ATTR_COOKIE = 3 + NLMSGERR_ATTR_POLICY = 4 +) + type NetlinkRequestData interface { Len() int Serialize() []byte } +const ( + PROC_CN_MCAST_LISTEN = 1 + PROC_CN_MCAST_IGNORE +) + +type CbID struct { + Idx uint32 + Val uint32 +} + +type CnMsg struct { + ID CbID + Seq uint32 + Ack uint32 + Length uint16 + Flags uint16 +} + +type CnMsgOp struct { + CnMsg + // here we differ from the C header + Op uint32 +} + +func NewCnMsg(idx, val, op uint32) *CnMsgOp { + var cm CnMsgOp + + cm.ID.Idx = idx + cm.ID.Val = val + + cm.Ack = 0 + cm.Seq = 1 + cm.Length = uint16(binary.Size(op)) + cm.Op = op + + return &cm +} + +func (msg *CnMsgOp) Serialize() []byte { + return (*(*[SizeofCnMsgOp]byte)(unsafe.Pointer(msg)))[:] +} + +func DeserializeCnMsgOp(b []byte) *CnMsgOp { + return (*CnMsgOp)(unsafe.Pointer(&b[0:SizeofCnMsgOp][0])) +} + +func (msg *CnMsgOp) Len() int { + return SizeofCnMsgOp +} + // IfInfomsg is related to links, but it is used for list requests as well type IfInfomsg struct { unix.IfInfomsg @@ -252,6 +314,12 @@ func (msg *IfInfomsg) EncapType() string { return fmt.Sprintf("unknown%d", msg.Type) } +// Round the length of a netlink message up to align it properly. +// Taken from syscall/netlink_linux.go by The Go Authors under BSD-style license. +func nlmAlignOf(msglen int) int { + return (msglen + syscall.NLMSG_ALIGNTO - 1) & ^(syscall.NLMSG_ALIGNTO - 1) +} + func rtaAlignOf(attrlen int) int { return (attrlen + unix.RTA_ALIGNTO - 1) & ^(unix.RTA_ALIGNTO - 1) } @@ -436,6 +504,11 @@ func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, erro if err := s.SetReceiveTimeout(&SocketTimeoutTv); err != nil { return nil, err } + if EnableErrorMessageReporting { + if err := s.SetExtAck(true); err != nil { + return nil, err + } + } defer s.Close() } else { @@ -475,11 +548,37 @@ done: } if m.Header.Type == unix.NLMSG_DONE || m.Header.Type == unix.NLMSG_ERROR { native := NativeEndian() - error := int32(native.Uint32(m.Data[0:4])) - if error == 0 { + errno := int32(native.Uint32(m.Data[0:4])) + if errno == 0 { break done } - return nil, syscall.Errno(-error) + var err error + err = syscall.Errno(-errno) + + unreadData := m.Data[4:] + if m.Header.Flags|unix.NLM_F_ACK_TLVS != 0 && len(unreadData) > syscall.SizeofNlMsghdr { + // Skip the echoed request message. + echoReqH := (*syscall.NlMsghdr)(unsafe.Pointer(&unreadData[0])) + unreadData = unreadData[nlmAlignOf(int(echoReqH.Len)):] + + // Annotate `err` using nlmsgerr attributes. + for len(unreadData) >= syscall.SizeofRtAttr { + attr := (*syscall.RtAttr)(unsafe.Pointer(&unreadData[0])) + attrData := unreadData[syscall.SizeofRtAttr:attr.Len] + + switch attr.Type { + case NLMSGERR_ATTR_MSG: + err = fmt.Errorf("%w: %s", err, string(attrData)) + + default: + // TODO: handle other NLMSGERR_ATTR types + } + + unreadData = unreadData[rtaAlignOf(int(attr.Len)):] + } + } + + return nil, err } if resType != 0 && m.Header.Type != resType { continue @@ -694,6 +793,16 @@ func (s *NetlinkSocket) SetReceiveTimeout(timeout *unix.Timeval) error { return unix.SetsockoptTimeval(int(s.fd), unix.SOL_SOCKET, unix.SO_RCVTIMEO, timeout) } +// SetExtAck requests error messages to be reported on the socket +func (s *NetlinkSocket) SetExtAck(enable bool) error { + var enableN int + if enable { + enableN = 1 + } + + return unix.SetsockoptInt(int(s.fd), unix.SOL_NETLINK, unix.NETLINK_EXT_ACK, enableN) +} + func (s *NetlinkSocket) GetPid() (uint32, error) { fd := int(atomic.LoadInt32(&s.fd)) lsa, err := unix.Getsockname(fd) diff --git a/vendor/github.com/vishvananda/netlink/nl/tc_linux.go b/vendor/github.com/vishvananda/netlink/nl/tc_linux.go index 002beda92..eb05ff1cd 100644 --- a/vendor/github.com/vishvananda/netlink/nl/tc_linux.go +++ b/vendor/github.com/vishvananda/netlink/nl/tc_linux.go @@ -90,6 +90,7 @@ const ( SizeofTcU32Sel = 0x10 // without keys SizeofTcGen = 0x14 SizeofTcConnmark = SizeofTcGen + 0x04 + SizeofTcCsum = SizeofTcGen + 0x04 SizeofTcMirred = SizeofTcGen + 0x08 SizeofTcTunnelKey = SizeofTcGen + 0x04 SizeofTcSkbEdit = SizeofTcGen @@ -694,6 +695,36 @@ func (x *TcConnmark) Serialize() []byte { return (*(*[SizeofTcConnmark]byte)(unsafe.Pointer(x)))[:] } +const ( + TCA_CSUM_UNSPEC = iota + TCA_CSUM_PARMS + TCA_CSUM_TM + TCA_CSUM_PAD + TCA_CSUM_MAX = TCA_CSUM_PAD +) + +// struct tc_csum { +// tc_gen; +// __u32 update_flags; +// } + +type TcCsum struct { + TcGen + UpdateFlags uint32 +} + +func (msg *TcCsum) Len() int { + return SizeofTcCsum +} + +func DeserializeTcCsum(b []byte) *TcCsum { + return (*TcCsum)(unsafe.Pointer(&b[0:SizeofTcCsum][0])) +} + +func (x *TcCsum) Serialize() []byte { + return (*(*[SizeofTcCsum]byte)(unsafe.Pointer(x)))[:] +} + const ( TCA_ACT_MIRRED = 8 ) diff --git a/vendor/github.com/vishvananda/netlink/proc_event_linux.go b/vendor/github.com/vishvananda/netlink/proc_event_linux.go new file mode 100644 index 000000000..53bc59a6e --- /dev/null +++ b/vendor/github.com/vishvananda/netlink/proc_event_linux.go @@ -0,0 +1,217 @@ +package netlink + +import ( + "bytes" + "encoding/binary" + "fmt" + "os" + "syscall" + + "github.com/vishvananda/netlink/nl" + "github.com/vishvananda/netns" + "golang.org/x/sys/unix" +) + +const CN_IDX_PROC = 0x1 + +const ( + PROC_EVENT_NONE = 0x00000000 + PROC_EVENT_FORK = 0x00000001 + PROC_EVENT_EXEC = 0x00000002 + PROC_EVENT_UID = 0x00000004 + PROC_EVENT_GID = 0x00000040 + PROC_EVENT_SID = 0x00000080 + PROC_EVENT_PTRACE = 0x00000100 + PROC_EVENT_COMM = 0x00000200 + PROC_EVENT_COREDUMP = 0x40000000 + PROC_EVENT_EXIT = 0x80000000 +) + +const ( + CN_VAL_PROC = 0x1 + PROC_CN_MCAST_LISTEN = 0x1 +) + +type ProcEventMsg interface { + Pid() uint32 + Tgid() uint32 +} + +type ProcEventHeader struct { + What uint32 + CPU uint32 + Timestamp uint64 +} + +type ProcEvent struct { + ProcEventHeader + Msg ProcEventMsg +} + +func (pe *ProcEvent) setHeader(h ProcEventHeader) { + pe.What = h.What + pe.CPU = h.CPU + pe.Timestamp = h.Timestamp +} + +type ExitProcEvent struct { + ProcessPid uint32 + ProcessTgid uint32 + ExitCode uint32 + ExitSignal uint32 + ParentPid uint32 + ParentTgid uint32 +} + +type ExitProcEvent2 struct { + ProcessPid uint32 + ProcessTgid uint32 + ExitCode uint32 + ExitSignal uint32 + ParentPid uint32 + ParentTgid uint32 +} + +func (e *ExitProcEvent) Pid() uint32 { + return e.ProcessPid +} + +func (e *ExitProcEvent) Tgid() uint32 { + return e.ProcessTgid +} + +type ExecProcEvent struct { + ProcessPid uint32 + ProcessTgid uint32 +} + +func (e *ExecProcEvent) Pid() uint32 { + return e.ProcessPid +} + +func (e *ExecProcEvent) Tgid() uint32 { + return e.ProcessTgid +} + +type ForkProcEvent struct { + ParentPid uint32 + ParentTgid uint32 + ChildPid uint32 + ChildTgid uint32 +} + +func (e *ForkProcEvent) Pid() uint32 { + return e.ParentPid +} + +func (e *ForkProcEvent) Tgid() uint32 { + return e.ParentTgid +} + +type CommProcEvent struct { + ProcessPid uint32 + ProcessTgid uint32 + Comm [16]byte +} + +func (e *CommProcEvent) Pid() uint32 { + return e.ProcessPid +} + +func (e *CommProcEvent) Tgid() uint32 { + return e.ProcessTgid +} + +func ProcEventMonitor(ch chan<- ProcEvent, done <-chan struct{}, errorChan chan<- error) error { + h, err := NewHandle() + if err != nil { + return err + } + defer h.Delete() + + s, err := nl.SubscribeAt(netns.None(), netns.None(), unix.NETLINK_CONNECTOR, CN_IDX_PROC) + if err != nil { + return err + } + + var nlmsg nl.NetlinkRequest + + nlmsg.Pid = uint32(os.Getpid()) + nlmsg.Type = unix.NLMSG_DONE + nlmsg.Len = uint32(unix.SizeofNlMsghdr) + + cm := nl.NewCnMsg(CN_IDX_PROC, CN_VAL_PROC, PROC_CN_MCAST_LISTEN) + nlmsg.AddData(cm) + + s.Send(&nlmsg) + + if done != nil { + go func() { + <-done + s.Close() + }() + } + + go func() { + defer close(ch) + for { + msgs, from, err := s.Receive() + if err != nil { + errorChan <- err + return + } + if from.Pid != nl.PidKernel { + errorChan <- fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel) + return + } + + for _, m := range msgs { + e := parseNetlinkMessage(m) + if e != nil { + ch <- *e + } + } + + } + }() + + return nil +} + +func parseNetlinkMessage(m syscall.NetlinkMessage) *ProcEvent { + if m.Header.Type == unix.NLMSG_DONE { + buf := bytes.NewBuffer(m.Data) + msg := &nl.CnMsg{} + hdr := &ProcEventHeader{} + binary.Read(buf, nl.NativeEndian(), msg) + binary.Read(buf, nl.NativeEndian(), hdr) + + pe := &ProcEvent{} + pe.setHeader(*hdr) + switch hdr.What { + case PROC_EVENT_EXIT: + event := &ExitProcEvent{} + binary.Read(buf, nl.NativeEndian(), event) + pe.Msg = event + return pe + case PROC_EVENT_FORK: + event := &ForkProcEvent{} + binary.Read(buf, nl.NativeEndian(), event) + pe.Msg = event + return pe + case PROC_EVENT_EXEC: + event := &ExecProcEvent{} + binary.Read(buf, nl.NativeEndian(), event) + pe.Msg = event + return pe + case PROC_EVENT_COMM: + event := &CommProcEvent{} + binary.Read(buf, nl.NativeEndian(), event) + pe.Msg = event + return pe + } + return nil + } + + return nil +} diff --git a/vendor/github.com/vishvananda/netlink/qdisc_linux.go b/vendor/github.com/vishvananda/netlink/qdisc_linux.go index 9fc4b3d24..e182e1cfe 100644 --- a/vendor/github.com/vishvananda/netlink/qdisc_linux.go +++ b/vendor/github.com/vishvananda/netlink/qdisc_linux.go @@ -706,3 +706,7 @@ func Xmittime(rate uint64, size uint32) uint32 { // https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/tc/tc_core.c#n62 return time2Tick(uint32(TIME_UNITS_PER_SEC * (float64(size) / float64(rate)))) } + +func Xmitsize(rate uint64, ticks uint32) uint32 { + return uint32((float64(rate) * float64(tick2Time(ticks))) / TIME_UNITS_PER_SEC) +} diff --git a/vendor/github.com/vishvananda/netlink/route.go b/vendor/github.com/vishvananda/netlink/route.go index ffad5d398..79cc218ec 100644 --- a/vendor/github.com/vishvananda/netlink/route.go +++ b/vendor/github.com/vishvananda/netlink/route.go @@ -11,6 +11,24 @@ type Scope uint8 type NextHopFlag int +const ( + RT_FILTER_PROTOCOL uint64 = 1 << (1 + iota) + RT_FILTER_SCOPE + RT_FILTER_TYPE + RT_FILTER_TOS + RT_FILTER_IIF + RT_FILTER_OIF + RT_FILTER_DST + RT_FILTER_SRC + RT_FILTER_GW + RT_FILTER_TABLE + RT_FILTER_HOPLIMIT + RT_FILTER_PRIORITY + RT_FILTER_MARK + RT_FILTER_MASK + RT_FILTER_REALM +) + type Destination interface { Family() int Decode([]byte) error diff --git a/vendor/github.com/vishvananda/netlink/route_linux.go b/vendor/github.com/vishvananda/netlink/route_linux.go index b059d4a9e..8da886657 100644 --- a/vendor/github.com/vishvananda/netlink/route_linux.go +++ b/vendor/github.com/vishvananda/netlink/route_linux.go @@ -41,23 +41,6 @@ func (s Scope) String() string { } } -const ( - RT_FILTER_PROTOCOL uint64 = 1 << (1 + iota) - RT_FILTER_SCOPE - RT_FILTER_TYPE - RT_FILTER_TOS - RT_FILTER_IIF - RT_FILTER_OIF - RT_FILTER_DST - RT_FILTER_SRC - RT_FILTER_GW - RT_FILTER_TABLE - RT_FILTER_HOPLIMIT - RT_FILTER_PRIORITY - RT_FILTER_MARK - RT_FILTER_MASK - RT_FILTER_REALM -) const ( FLAG_ONLINK NextHopFlag = unix.RTNH_F_ONLINK @@ -1030,8 +1013,9 @@ func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, e // All rules must be defined in RouteFilter struct func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) { req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_DUMP) - infmsg := nl.NewIfInfomsg(family) - req.AddData(infmsg) + rtmsg := nl.NewRtMsg() + rtmsg.Family = uint8(family) + req.AddData(rtmsg) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE) if err != nil { diff --git a/vendor/github.com/vishvananda/netlink/rule.go b/vendor/github.com/vishvananda/netlink/rule.go index 9b7b0af49..53cd3d4f6 100644 --- a/vendor/github.com/vishvananda/netlink/rule.go +++ b/vendor/github.com/vishvananda/netlink/rule.go @@ -25,6 +25,7 @@ type Rule struct { Invert bool Dport *RulePortRange Sport *RulePortRange + IPProto int } func (r Rule) String() string { diff --git a/vendor/github.com/vishvananda/netlink/rule_linux.go b/vendor/github.com/vishvananda/netlink/rule_linux.go index 9c426cbd3..3ae213880 100644 --- a/vendor/github.com/vishvananda/netlink/rule_linux.go +++ b/vendor/github.com/vishvananda/netlink/rule_linux.go @@ -152,6 +152,12 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error { req.AddData(nl.NewRtAttr(nl.FRA_GOTO, b)) } + if rule.IPProto > 0 { + b := make([]byte, 4) + native.PutUint32(b, uint32(rule.IPProto)) + req.AddData(nl.NewRtAttr(nl.FRA_IP_PROTO, b)) + } + if rule.Dport != nil { b := rule.Dport.toRtAttrData() req.AddData(nl.NewRtAttr(nl.FRA_DPORT_RANGE, b)) @@ -250,6 +256,8 @@ func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) ( rule.Goto = int(native.Uint32(attrs[j].Value[0:4])) case nl.FRA_PRIORITY: rule.Priority = int(native.Uint32(attrs[j].Value[0:4])) + case nl.FRA_IP_PROTO: + rule.IPProto = int(native.Uint32(attrs[j].Value[0:4])) case nl.FRA_DPORT_RANGE: rule.Dport = NewRulePortRange(native.Uint16(attrs[j].Value[0:2]), native.Uint16(attrs[j].Value[2:4])) case nl.FRA_SPORT_RANGE: diff --git a/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go b/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go index 694bd74e6..358496804 100644 --- a/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go +++ b/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go @@ -93,8 +93,10 @@ func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error { req.AddData(out) } - ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid))) - req.AddData(ifId) + if policy.Ifid != 0 { + ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid))) + req.AddData(ifId) + } _, err := req.Execute(unix.NETLINK_XFRM, 0) return err @@ -189,8 +191,10 @@ func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPo req.AddData(out) } - ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid))) - req.AddData(ifId) + if policy.Ifid != 0 { + ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid))) + req.AddData(ifId) + } resType := nl.XFRM_MSG_NEWPOLICY if nlProto == nl.XFRM_MSG_DELPOLICY { diff --git a/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go b/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go index 3b37b87d3..61a2d2dea 100644 --- a/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go +++ b/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go @@ -167,8 +167,10 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error { } } - ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid))) - req.AddData(ifId) + if state.Ifid != 0 { + ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid))) + req.AddData(ifId) + } _, err := req.Execute(unix.NETLINK_XFRM, 0) return err @@ -281,8 +283,10 @@ func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState req.AddData(out) } - ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid))) - req.AddData(ifId) + if state.Ifid != 0 { + ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid))) + req.AddData(ifId) + } resType := nl.XFRM_MSG_NEWSA if nlProto == nl.XFRM_MSG_DELSA { diff --git a/vendor/github.com/vishvananda/netns/.golangci.yml b/vendor/github.com/vishvananda/netns/.golangci.yml new file mode 100644 index 000000000..600bef78e --- /dev/null +++ b/vendor/github.com/vishvananda/netns/.golangci.yml @@ -0,0 +1,2 @@ +run: + timeout: 5m diff --git a/vendor/github.com/vishvananda/netns/README.md b/vendor/github.com/vishvananda/netns/README.md index 6b45cfb89..bdfedbe81 100644 --- a/vendor/github.com/vishvananda/netns/README.md +++ b/vendor/github.com/vishvananda/netns/README.md @@ -23,6 +23,7 @@ import ( "fmt" "net" "runtime" + "github.com/vishvananda/netns" ) diff --git a/vendor/github.com/vishvananda/netns/doc.go b/vendor/github.com/vishvananda/netns/doc.go new file mode 100644 index 000000000..cd4093a4d --- /dev/null +++ b/vendor/github.com/vishvananda/netns/doc.go @@ -0,0 +1,9 @@ +// Package netns allows ultra-simple network namespace handling. NsHandles +// can be retrieved and set. Note that the current namespace is thread +// local so actions that set and reset namespaces should use LockOSThread +// to make sure the namespace doesn't change due to a goroutine switch. +// It is best to close NsHandles when you are done with them. This can be +// accomplished via a `defer ns.Close()` on the handle. Changing namespaces +// requires elevated privileges, so in most cases this code needs to be run +// as root. +package netns diff --git a/vendor/github.com/vishvananda/netns/netns_linux.go b/vendor/github.com/vishvananda/netns/netns_linux.go index c76acd087..2ed7c7e2f 100644 --- a/vendor/github.com/vishvananda/netns/netns_linux.go +++ b/vendor/github.com/vishvananda/netns/netns_linux.go @@ -1,33 +1,31 @@ -// +build linux - package netns import ( "fmt" - "io/ioutil" "os" "path" "path/filepath" "strconv" "strings" - "syscall" "golang.org/x/sys/unix" ) -// Deprecated: use syscall pkg instead (go >= 1.5 needed). +// Deprecated: use golang.org/x/sys/unix pkg instead. const ( - CLONE_NEWUTS = 0x04000000 /* New utsname group? */ - CLONE_NEWIPC = 0x08000000 /* New ipcs */ - CLONE_NEWUSER = 0x10000000 /* New user namespace */ - CLONE_NEWPID = 0x20000000 /* New pid namespace */ - CLONE_NEWNET = 0x40000000 /* New network namespace */ - CLONE_IO = 0x80000000 /* Get io context */ - bindMountPath = "/run/netns" /* Bind mount path for named netns */ + CLONE_NEWUTS = unix.CLONE_NEWUTS /* New utsname group? */ + CLONE_NEWIPC = unix.CLONE_NEWIPC /* New ipcs */ + CLONE_NEWUSER = unix.CLONE_NEWUSER /* New user namespace */ + CLONE_NEWPID = unix.CLONE_NEWPID /* New pid namespace */ + CLONE_NEWNET = unix.CLONE_NEWNET /* New network namespace */ + CLONE_IO = unix.CLONE_IO /* Get io context */ ) -// Setns sets namespace using syscall. Note that this should be a method -// in syscall but it has not been added. +const bindMountPath = "/run/netns" /* Bind mount path for named netns */ + +// Setns sets namespace using golang.org/x/sys/unix.Setns. +// +// Deprecated: Use golang.org/x/sys/unix.Setns instead. func Setns(ns NsHandle, nstype int) (err error) { return unix.Setns(int(ns), nstype) } @@ -35,19 +33,20 @@ func Setns(ns NsHandle, nstype int) (err error) { // Set sets the current network namespace to the namespace represented // by NsHandle. func Set(ns NsHandle) (err error) { - return Setns(ns, CLONE_NEWNET) + return unix.Setns(int(ns), unix.CLONE_NEWNET) } // New creates a new network namespace, sets it as current and returns // a handle to it. func New() (ns NsHandle, err error) { - if err := unix.Unshare(CLONE_NEWNET); err != nil { + if err := unix.Unshare(unix.CLONE_NEWNET); err != nil { return -1, err } return Get() } -// NewNamed creates a new named network namespace and returns a handle to it +// NewNamed creates a new named network namespace, sets it as current, +// and returns a handle to it func NewNamed(name string) (NsHandle, error) { if _, err := os.Stat(bindMountPath); os.IsNotExist(err) { err = os.MkdirAll(bindMountPath, 0755) @@ -65,13 +64,15 @@ func NewNamed(name string) (NsHandle, error) { f, err := os.OpenFile(namedPath, os.O_CREATE|os.O_EXCL, 0444) if err != nil { + newNs.Close() return None(), err } f.Close() - nsPath := fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid()) - err = syscall.Mount(nsPath, namedPath, "bind", syscall.MS_BIND, "") + nsPath := fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), unix.Gettid()) + err = unix.Mount(nsPath, namedPath, "bind", unix.MS_BIND, "") if err != nil { + newNs.Close() return None(), err } @@ -82,7 +83,7 @@ func NewNamed(name string) (NsHandle, error) { func DeleteNamed(name string) error { namedPath := path.Join(bindMountPath, name) - err := syscall.Unmount(namedPath, syscall.MNT_DETACH) + err := unix.Unmount(namedPath, unix.MNT_DETACH) if err != nil { return err } @@ -108,7 +109,7 @@ func GetFromPath(path string) (NsHandle, error) { // GetFromName gets a handle to a named network namespace such as one // created by `ip netns add`. func GetFromName(name string) (NsHandle, error) { - return GetFromPath(fmt.Sprintf("/var/run/netns/%s", name)) + return GetFromPath(filepath.Join(bindMountPath, name)) } // GetFromPid gets a handle to the network namespace of a given pid. @@ -133,33 +134,38 @@ func GetFromDocker(id string) (NsHandle, error) { } // borrowed from docker/utils/utils.go -func findCgroupMountpoint(cgroupType string) (string, error) { - output, err := ioutil.ReadFile("/proc/mounts") +func findCgroupMountpoint(cgroupType string) (int, string, error) { + output, err := os.ReadFile("/proc/mounts") if err != nil { - return "", err + return -1, "", err } // /proc/mounts has 6 fields per line, one mount per line, e.g. // cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0 for _, line := range strings.Split(string(output), "\n") { parts := strings.Split(line, " ") - if len(parts) == 6 && parts[2] == "cgroup" { - for _, opt := range strings.Split(parts[3], ",") { - if opt == cgroupType { - return parts[1], nil + if len(parts) == 6 { + switch parts[2] { + case "cgroup2": + return 2, parts[1], nil + case "cgroup": + for _, opt := range strings.Split(parts[3], ",") { + if opt == cgroupType { + return 1, parts[1], nil + } } } } } - return "", fmt.Errorf("cgroup mountpoint not found for %s", cgroupType) + return -1, "", fmt.Errorf("cgroup mountpoint not found for %s", cgroupType) } // Returns the relative path to the cgroup docker is running in. // borrowed from docker/utils/utils.go // modified to get the docker pid instead of using /proc/self -func getThisCgroup(cgroupType string) (string, error) { - dockerpid, err := ioutil.ReadFile("/var/run/docker.pid") +func getDockerCgroup(cgroupVer int, cgroupType string) (string, error) { + dockerpid, err := os.ReadFile("/var/run/docker.pid") if err != nil { return "", err } @@ -171,14 +177,15 @@ func getThisCgroup(cgroupType string) (string, error) { if err != nil { return "", err } - output, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cgroup", pid)) + output, err := os.ReadFile(fmt.Sprintf("/proc/%d/cgroup", pid)) if err != nil { return "", err } for _, line := range strings.Split(string(output), "\n") { parts := strings.Split(line, ":") // any type used by docker should work - if parts[1] == cgroupType { + if (cgroupVer == 1 && parts[1] == cgroupType) || + (cgroupVer == 2 && parts[1] == "") { return parts[2], nil } } @@ -190,40 +197,56 @@ func getThisCgroup(cgroupType string) (string, error) { // modified to only return the first pid // modified to glob with id // modified to search for newer docker containers +// modified to look for cgroups v2 func getPidForContainer(id string) (int, error) { pid := 0 // memory is chosen randomly, any cgroup used by docker works cgroupType := "memory" - cgroupRoot, err := findCgroupMountpoint(cgroupType) + cgroupVer, cgroupRoot, err := findCgroupMountpoint(cgroupType) if err != nil { return pid, err } - cgroupThis, err := getThisCgroup(cgroupType) + cgroupDocker, err := getDockerCgroup(cgroupVer, cgroupType) if err != nil { return pid, err } id += "*" + var pidFile string + if cgroupVer == 1 { + pidFile = "tasks" + } else if cgroupVer == 2 { + pidFile = "cgroup.procs" + } else { + return -1, fmt.Errorf("Invalid cgroup version '%d'", cgroupVer) + } + attempts := []string{ - filepath.Join(cgroupRoot, cgroupThis, id, "tasks"), + filepath.Join(cgroupRoot, cgroupDocker, id, pidFile), // With more recent lxc versions use, cgroup will be in lxc/ - filepath.Join(cgroupRoot, cgroupThis, "lxc", id, "tasks"), + filepath.Join(cgroupRoot, cgroupDocker, "lxc", id, pidFile), // With more recent docker, cgroup will be in docker/ - filepath.Join(cgroupRoot, cgroupThis, "docker", id, "tasks"), + filepath.Join(cgroupRoot, cgroupDocker, "docker", id, pidFile), // Even more recent docker versions under systemd use docker-.scope/ - filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", "tasks"), + filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", pidFile), // Even more recent docker versions under cgroup/systemd/docker// - filepath.Join(cgroupRoot, "..", "systemd", "docker", id, "tasks"), - // Kubernetes with docker and CNI is even more different - filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "*", "pod*", id, "tasks"), - // Another flavor of containers location in recent kubernetes 1.11+ - filepath.Join(cgroupRoot, cgroupThis, "kubepods.slice", "kubepods-besteffort.slice", "*", "docker-"+id+".scope", "tasks"), - // When runs inside of a container with recent kubernetes 1.11+ - filepath.Join(cgroupRoot, "kubepods.slice", "kubepods-besteffort.slice", "*", "docker-"+id+".scope", "tasks"), + filepath.Join(cgroupRoot, "..", "systemd", "docker", id, pidFile), + // Kubernetes with docker and CNI is even more different. Works for BestEffort and Burstable QoS + filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "*", "pod*", id, pidFile), + // Same as above but for Guaranteed QoS + filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "pod*", id, pidFile), + // Another flavor of containers location in recent kubernetes 1.11+. Works for BestEffort and Burstable QoS + filepath.Join(cgroupRoot, cgroupDocker, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", pidFile), + // Same as above but for Guaranteed QoS + filepath.Join(cgroupRoot, cgroupDocker, "kubepods.slice", "*", "docker-"+id+".scope", pidFile), + // When runs inside of a container with recent kubernetes 1.11+. Works for BestEffort and Burstable QoS + filepath.Join(cgroupRoot, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", pidFile), + // Same as above but for Guaranteed QoS + filepath.Join(cgroupRoot, "kubepods.slice", "*", "docker-"+id+".scope", pidFile), } var filename string @@ -241,7 +264,7 @@ func getPidForContainer(id string) (int, error) { return pid, fmt.Errorf("Unable to find container: %v", id[:len(id)-1]) } - output, err := ioutil.ReadFile(filename) + output, err := os.ReadFile(filename) if err != nil { return pid, err } diff --git a/vendor/github.com/vishvananda/netns/netns_unspecified.go b/vendor/github.com/vishvananda/netns/netns_others.go similarity index 63% rename from vendor/github.com/vishvananda/netns/netns_unspecified.go rename to vendor/github.com/vishvananda/netns/netns_others.go index d06af62b6..048983774 100644 --- a/vendor/github.com/vishvananda/netns/netns_unspecified.go +++ b/vendor/github.com/vishvananda/netns/netns_others.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package netns @@ -10,6 +11,14 @@ var ( ErrNotImplemented = errors.New("not implemented") ) +// Setns sets namespace using golang.org/x/sys/unix.Setns on Linux. It +// is not implemented on other platforms. +// +// Deprecated: Use golang.org/x/sys/unix.Setns instead. +func Setns(ns NsHandle, nstype int) (err error) { + return ErrNotImplemented +} + func Set(ns NsHandle) (err error) { return ErrNotImplemented } @@ -18,6 +27,14 @@ func New() (ns NsHandle, err error) { return -1, ErrNotImplemented } +func NewNamed(name string) (NsHandle, error) { + return -1, ErrNotImplemented +} + +func DeleteNamed(name string) error { + return ErrNotImplemented +} + func Get() (NsHandle, error) { return -1, ErrNotImplemented } diff --git a/vendor/github.com/vishvananda/netns/netns.go b/vendor/github.com/vishvananda/netns/nshandle_linux.go similarity index 75% rename from vendor/github.com/vishvananda/netns/netns.go rename to vendor/github.com/vishvananda/netns/nshandle_linux.go index 116befd54..1baffb66a 100644 --- a/vendor/github.com/vishvananda/netns/netns.go +++ b/vendor/github.com/vishvananda/netns/nshandle_linux.go @@ -1,11 +1,3 @@ -// Package netns allows ultra-simple network namespace handling. NsHandles -// can be retrieved and set. Note that the current namespace is thread -// local so actions that set and reset namespaces should use LockOSThread -// to make sure the namespace doesn't change due to a goroutine switch. -// It is best to close NsHandles when you are done with them. This can be -// accomplished via a `defer ns.Close()` on the handle. Changing namespaces -// requires elevated privileges, so in most cases this code needs to be run -// as root. package netns import ( @@ -38,7 +30,7 @@ func (ns NsHandle) Equal(other NsHandle) bool { // String shows the file descriptor number and its dev and inode. func (ns NsHandle) String() string { if ns == -1 { - return "NS(None)" + return "NS(none)" } var s unix.Stat_t if err := unix.Fstat(int(ns), &s); err != nil { @@ -71,7 +63,7 @@ func (ns *NsHandle) Close() error { if err := unix.Close(int(*ns)); err != nil { return err } - (*ns) = -1 + *ns = -1 return nil } diff --git a/vendor/github.com/vishvananda/netns/nshandle_others.go b/vendor/github.com/vishvananda/netns/nshandle_others.go new file mode 100644 index 000000000..af727bc09 --- /dev/null +++ b/vendor/github.com/vishvananda/netns/nshandle_others.go @@ -0,0 +1,45 @@ +//go:build !linux +// +build !linux + +package netns + +// NsHandle is a handle to a network namespace. It can only be used on Linux, +// but provides stub methods on other platforms. +type NsHandle int + +// Equal determines if two network handles refer to the same network +// namespace. It is only implemented on Linux. +func (ns NsHandle) Equal(_ NsHandle) bool { + return false +} + +// String shows the file descriptor number and its dev and inode. +// It is only implemented on Linux, and returns "NS(none)" on other +// platforms. +func (ns NsHandle) String() string { + return "NS(none)" +} + +// UniqueId returns a string which uniquely identifies the namespace +// associated with the network handle. It is only implemented on Linux, +// and returns "NS(none)" on other platforms. +func (ns NsHandle) UniqueId() string { + return "NS(none)" +} + +// IsOpen returns true if Close() has not been called. It is only implemented +// on Linux and always returns false on other platforms. +func (ns NsHandle) IsOpen() bool { + return false +} + +// Close closes the NsHandle and resets its file descriptor to -1. +// It is only implemented on Linux. +func (ns *NsHandle) Close() error { + return nil +} + +// None gets an empty (closed) NsHandle. +func None() NsHandle { + return NsHandle(-1) +} diff --git a/vendor/golang.org/x/net/AUTHORS b/vendor/golang.org/x/net/AUTHORS deleted file mode 100644 index 15167cd74..000000000 --- a/vendor/golang.org/x/net/AUTHORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code refers to The Go Authors for copyright purposes. -# The master list of authors is in the main Go distribution, -# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/net/CONTRIBUTORS b/vendor/golang.org/x/net/CONTRIBUTORS deleted file mode 100644 index 1c4577e96..000000000 --- a/vendor/golang.org/x/net/CONTRIBUTORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code was written by the Go contributors. -# The master list of contributors is in the main Go distribution, -# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/net/context/context.go b/vendor/golang.org/x/net/context/context.go index a3c021d3f..cf66309c4 100644 --- a/vendor/golang.org/x/net/context/context.go +++ b/vendor/golang.org/x/net/context/context.go @@ -21,9 +21,9 @@ // explicitly to each function that needs it. The Context should be the first // parameter, typically named ctx: // -// func DoSomething(ctx context.Context, arg Arg) error { -// // ... use ctx ... -// } +// func DoSomething(ctx context.Context, arg Arg) error { +// // ... use ctx ... +// } // // Do not pass a nil Context, even if a function permits it. Pass context.TODO // if you are unsure about which Context to use. diff --git a/vendor/golang.org/x/net/context/go17.go b/vendor/golang.org/x/net/context/go17.go index 344bd1433..2cb9c408f 100644 --- a/vendor/golang.org/x/net/context/go17.go +++ b/vendor/golang.org/x/net/context/go17.go @@ -32,7 +32,7 @@ var DeadlineExceeded = context.DeadlineExceeded // call cancel as soon as the operations running in this Context complete. func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { ctx, f := context.WithCancel(parent) - return ctx, CancelFunc(f) + return ctx, f } // WithDeadline returns a copy of the parent context with the deadline adjusted @@ -46,7 +46,7 @@ func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { // call cancel as soon as the operations running in this Context complete. func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { ctx, f := context.WithDeadline(parent, deadline) - return ctx, CancelFunc(f) + return ctx, f } // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). @@ -54,11 +54,11 @@ func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete: // -// func slowOperationWithTimeout(ctx context.Context) (Result, error) { -// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) -// defer cancel() // releases resources if slowOperation completes before timeout elapses -// return slowOperation(ctx) -// } +// func slowOperationWithTimeout(ctx context.Context) (Result, error) { +// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) +// defer cancel() // releases resources if slowOperation completes before timeout elapses +// return slowOperation(ctx) +// } func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { return WithDeadline(parent, time.Now().Add(timeout)) } diff --git a/vendor/golang.org/x/net/context/pre_go17.go b/vendor/golang.org/x/net/context/pre_go17.go index 5270db5db..7b6b68511 100644 --- a/vendor/golang.org/x/net/context/pre_go17.go +++ b/vendor/golang.org/x/net/context/pre_go17.go @@ -264,11 +264,11 @@ func (c *timerCtx) cancel(removeFromParent bool, err error) { // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete: // -// func slowOperationWithTimeout(ctx context.Context) (Result, error) { -// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) -// defer cancel() // releases resources if slowOperation completes before timeout elapses -// return slowOperation(ctx) -// } +// func slowOperationWithTimeout(ctx context.Context) (Result, error) { +// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) +// defer cancel() // releases resources if slowOperation completes before timeout elapses +// return slowOperation(ctx) +// } func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { return WithDeadline(parent, time.Now().Add(timeout)) } diff --git a/vendor/golang.org/x/net/html/parse.go b/vendor/golang.org/x/net/html/parse.go index 038941d70..46a89eda6 100644 --- a/vendor/golang.org/x/net/html/parse.go +++ b/vendor/golang.org/x/net/html/parse.go @@ -184,7 +184,7 @@ func (p *parser) clearStackToContext(s scope) { } } -// parseGenericRawTextElements implements the generic raw text element parsing +// parseGenericRawTextElement implements the generic raw text element parsing // algorithm defined in 12.2.6.2. // https://html.spec.whatwg.org/multipage/parsing.html#parsing-elements-that-contain-only-text // TODO: Since both RAWTEXT and RCDATA states are treated as tokenizer's part @@ -734,7 +734,7 @@ func inHeadIM(p *parser) bool { return false } -// 12.2.6.4.5. +// Section 12.2.6.4.5. func inHeadNoscriptIM(p *parser) bool { switch p.tok.Type { case DoctypeToken: diff --git a/vendor/golang.org/x/net/html/render.go b/vendor/golang.org/x/net/html/render.go index b46d81ca6..497e13204 100644 --- a/vendor/golang.org/x/net/html/render.go +++ b/vendor/golang.org/x/net/html/render.go @@ -85,7 +85,7 @@ func render1(w writer, n *Node) error { if _, err := w.WriteString(""); err != nil { @@ -96,7 +96,7 @@ func render1(w writer, n *Node) error { if _, err := w.WriteString("" case CommentToken: - return "" + return "" case DoctypeToken: - return "" + return "" } return "Invalid(" + strconv.Itoa(int(t.Type)) + ")" } @@ -598,6 +598,11 @@ scriptDataDoubleEscapeEnd: // readComment reads the next comment token starting with "") return } @@ -628,17 +632,50 @@ func (z *Tokenizer) readComment() { if dashCount >= 2 { c = z.readByte() if z.err != nil { - z.data.end = z.raw.end + z.data.end = z.calculateAbruptCommentDataEnd() return - } - if c == '>' { + } else if c == '>' { z.data.end = z.raw.end - len("--!>") return + } else if c == '-' { + dashCount = 1 + beginning = false + continue } } } dashCount = 0 + beginning = false + } +} + +func (z *Tokenizer) calculateAbruptCommentDataEnd() int { + raw := z.Raw() + const prefixLen = len("