1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2024-12-14 11:57:51 +00:00

Implement PCI feature source

This feature source detects the presence of PCI devices. At the moment,
it only advertises GPUs and accelerator cards, i.e. device classes 0x03,
0x0b40 and 0x12.

The label format is:
  node.alpha.kubernetes-incubator.io/nfd-pci-<device label>.present
where <device label> is composed of raw PCI IDs:
  <class id>_<vendor id>
This commit is contained in:
Markus Lehtonen 2018-09-20 15:49:45 +03:00
parent 244e049729
commit 74d6993e9b
4 changed files with 133 additions and 4 deletions

View file

@ -54,7 +54,7 @@ node-feature-discovery.
will override settings read from the config file.
[Default: ]
--sources=<sources> Comma separated list of feature sources.
[Default: cpuid,iommu,memory,network,pstate,rdt,selinux,storage]
[Default: cpuid,iommu,memory,network,pci,pstate,rdt,selinux,storage]
--no-publish Do not publish discovered features to the
cluster-local Kubernetes API server.
--label-whitelist=<pattern> Regular expression to filter label names to
@ -115,6 +115,7 @@ the only label value published for features is the string `"true"`._
"node.alpha.kubernetes-incubator.io/nfd-iommu-<feature-name>": "true",
"node.alpha.kubernetes-incubator.io/nfd-memory-<feature-name>": "true",
"node.alpha.kubernetes-incubator.io/nfd-network-<feature-name>": "true",
"node.alpha.kubernetes-incubator.io/nfd-pci-<device label>.present": "true",
"node.alpha.kubernetes-incubator.io/nfd-pstate-<feature-name>": "true",
"node.alpha.kubernetes-incubator.io/nfd-rdt-<feature-name>": "true",
"node.alpha.kubernetes-incubator.io/nfd-selinux-<feature-name>": "true",
@ -176,6 +177,21 @@ such as restricting discovered features with the --label-whitelist option._
| sriov | capable | [Single Root Input/Output Virtualization][sriov] (SR-IOV) enabled Network Interface Card(s) present
| <br> | configured | SR-IOV virtual functions have been configured
### PCI Features
| Feature | Attribute | Description |
| -------------------- | --------- | ----------------------------------------- |
| &lt;device label&gt; | present | PCI device is detected
The `<device label>` part is composed of raw PCI IDs, and has the following
format: `<class>_<vendor>`. E.g.
```
node.alpha.kubernetes-incubator.io/nfd-pci-1200_8086.present=true
```
Only device classes (0x)03, (0x)0b40 and (0x)12, i.e. GPUs, co-processors and
accelerator cards are deteted.
### RDT (Intel Resource Director Technology) Features
| Feature name | Description |

View file

@ -18,6 +18,7 @@ import (
"github.com/kubernetes-incubator/node-feature-discovery/source/memory"
"github.com/kubernetes-incubator/node-feature-discovery/source/network"
"github.com/kubernetes-incubator/node-feature-discovery/source/panic_fake"
"github.com/kubernetes-incubator/node-feature-discovery/source/pci"
"github.com/kubernetes-incubator/node-feature-discovery/source/pstate"
"github.com/kubernetes-incubator/node-feature-discovery/source/rdt"
"github.com/kubernetes-incubator/node-feature-discovery/source/selinux"
@ -163,7 +164,7 @@ func argsParse(argv []string) (args Args) {
will override settings read from the config file.
[Default: ]
--sources=<sources> Comma separated list of feature sources.
[Default: cpuid,iommu,memory,network,pstate,rdt,selinux,storage]
[Default: cpuid,iommu,memory,network,pci,pstate,rdt,selinux,storage]
--no-publish Do not publish discovered features to the
cluster-local Kubernetes API server.
--label-whitelist=<pattern> Regular expression to filter label names to
@ -242,6 +243,7 @@ func configureParameters(sourcesWhiteList []string, labelWhiteListStr string) (e
memory.Source{},
network.Source{},
panic_fake.Source{},
pci.Source{},
pstate.Source{},
rdt.Source{},
selinux.Source{},

View file

@ -137,7 +137,7 @@ func TestArgsParse(t *testing.T) {
So(args.sleepInterval, ShouldEqual, 60*time.Second)
So(args.noPublish, ShouldBeTrue)
So(args.oneshot, ShouldBeTrue)
So(args.sources, ShouldResemble, []string{"cpuid", "iommu", "memory", "network", "pstate", "rdt", "selinux", "storage"})
So(args.sources, ShouldResemble, []string{"cpuid", "iommu", "memory", "network", "pci", "pstate", "rdt", "selinux", "storage"})
So(len(args.labelWhiteList), ShouldEqual, 0)
})
})
@ -159,7 +159,7 @@ func TestArgsParse(t *testing.T) {
Convey("args.labelWhiteList is set to appropriate value and args.sources is set to default value", func() {
So(args.noPublish, ShouldBeFalse)
So(args.sources, ShouldResemble, []string{"cpuid", "iommu", "memory", "network", "pstate", "rdt", "selinux", "storage"})
So(args.sources, ShouldResemble, []string{"cpuid", "iommu", "memory", "network", "pci", "pstate", "rdt", "selinux", "storage"})
So(args.labelWhiteList, ShouldResemble, ".*rdt.*")
})
})

111
source/pci/pci.go Normal file
View file

@ -0,0 +1,111 @@
/*
Copyright 2018 The Kubernetes Authors.
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 pci
import (
"fmt"
"io/ioutil"
"log"
"os"
"path"
"strings"
)
type pciDeviceInfo map[string]string
var logger = log.New(os.Stderr, "", log.LstdFlags)
var deviceClassWhitelist = []string{"03", "0b40", "12"}
// Implement FeatureSource interface
type Source struct{}
// Return name of the feature source
func (s Source) Name() string { return "pci" }
// Discover features
func (s Source) Discover() ([]string, error) {
features := map[string]bool{}
devs, err := detectPci()
if err != nil {
return nil, fmt.Errorf("Failed to detect PCI devices: %s", err.Error())
}
for class, classDevs := range devs {
for _, white := range deviceClassWhitelist {
if strings.HasPrefix(class, white) {
for _, dev := range classDevs {
features[fmt.Sprintf("%s_%s.present", dev["class"], dev["vendor"])] = true
}
}
}
}
feature_list := []string{}
for feature := range features {
feature_list = append(feature_list, feature)
}
return feature_list, nil
}
// Read information of one PCI device
func readDevInfo(devPath string) (pciDeviceInfo, error) {
info := pciDeviceInfo{}
attrs := []string{"class", "vendor", "device", "subsystem_vendor", "subsystem_device"}
for _, attr := range attrs {
data, err := ioutil.ReadFile(path.Join(devPath, attr))
if err != nil {
return info, fmt.Errorf("Failed to read device %s: %s", attr, err)
}
// Strip whitespace and '0x' prefix
info[attr] = strings.TrimSpace(strings.TrimPrefix(string(data), "0x"))
if attr == "class" && len(info[attr]) > 4 {
// Take four first characters, so that the programming
// interface identifier gets stripped from the raw class code
info[attr] = info[attr][0:4]
}
}
return info, nil
}
// List available PCI devices
func detectPci() (map[string][]pciDeviceInfo, error) {
const basePath = "/sys/bus/pci/devices/"
devInfo := make(map[string][]pciDeviceInfo)
devices, err := ioutil.ReadDir(basePath)
if err != nil {
return nil, err
}
// Iterate over devices
for _, device := range devices {
info, err := readDevInfo(path.Join(basePath, device.Name()))
if err != nil {
log.Print(err)
continue
}
class := info["class"]
devInfo[class] = append(devInfo[class], info)
}
return devInfo, nil
}