1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-03-28 18:57:10 +00:00

Implement kernel config detection

This implementation only detects kconfig options ("NO_HZ", "NO_HZ_IDLE",
"NO_HZ_FULL" and "PREEMPT"). The corresponding node labels will be
  node.alpha.kubernetes-incubator.io/nfd-kernel-config.<option name>

Currently, only bool and tristate (i.e. '=y' or '=m') kernel config
options are supported. Other kconfig types (e.g. string or int) are
simply ignored. If the kconfig flag is set to '=y' or '=m', the
corresponding node label will be present and it's value will be 'true'.
This commit is contained in:
Markus Lehtonen 2018-07-05 16:29:38 +03:00
parent 607e95f290
commit ce129aef88
4 changed files with 113 additions and 8 deletions

View file

@ -116,6 +116,7 @@ the only label value published for features is the string `"true"`._
"feature.node.kubernetes.io/node-feature-discovery.version": "v0.3.0",
"feature.node.kubernetes.io/nfd-cpuid-<feature-name>": "true",
"feature.node.kubernetes.io/nfd-iommu-<feature-name>": "true",
"feature.node.kubernetes.io/kernel-config.<option-name>": "true",
"feature.node.kubernetes.io/nfd-kernel-version.<version component>": "<version number>",
"feature.node.kubernetes.io/nfd-memory-<feature-name>": "true",
"feature.node.kubernetes.io/nfd-network-<feature-name>": "true",
@ -171,12 +172,16 @@ such as restricting discovered features with the --label-whitelist option._
### Kernel Features
| Feature | Attribute | Description |
| ------- | --------- | ------------------------------------------------------ |
| version | full | Full kernel version as reported by `/proc/sys/kernel/osrelease` (e.g. '4.5.6-7-g123abcde')
| <br> | major | First component of the kernel version (e.g. '4')
| <br> | minor | Second component of the kernel version (e.g. '5')
| <br> | revision | Third component of the kernel version (e.g. '6')
| Feature | Attribute | Description |
| ------- | ----------- | ---------------------------------------------------- |
| config | NO_HZ | Kernel config option is enabled
| <br> | NO_HZ_FULL |
| <br> | NO_HZ_IDLE |
| <br> | PREEMPT |
| version | full | Full kernel version as reported by `/proc/sys/kernel/osrelease` (e.g. '4.5.6-7-g123abcde')
| <br> | major | First component of the kernel version (e.g. '4')
| <br> | minor | Second component of the kernel version (e.g. '5')
| <br> | revision | Third component of the kernel version (e.g. '6')
### Local (User-specific Features)

View file

@ -26,9 +26,15 @@ spec:
args:
- "--sleep-interval=60s"
volumeMounts:
- name: host-boot
mountPath: "/host-boot"
readOnly: true
- name: host-sys
mountPath: "/host-sys"
volumes:
- name: host-boot
hostPath:
path: "/boot"
- name: host-sys
hostPath:
path: "/sys"

View file

@ -28,10 +28,16 @@ spec:
- containerPort: 7156
hostPort: 7156
volumeMounts:
- name: host-boot
mountPath: "/host-boot"
readOnly: true
- name: host-sys
mountPath: "/host-sys"
restartPolicy: Never
volumes:
- name: host-boot
hostPath:
path: "/boot"
- name: host-sys
hostPath:
path: "/sys"

View file

@ -17,14 +17,27 @@ limitations under the License.
package kernel
import (
"bytes"
"compress/gzip"
"io/ioutil"
"log"
"os"
"regexp"
"strings"
"github.com/golang/glog"
"github.com/kubernetes-incubator/node-feature-discovery/source"
)
// Default kconfig flags
var defaultKconfigFlags = [...]string{
"NO_HZ",
"NO_HZ_IDLE",
"NO_HZ_FULL",
"PREEMPT",
}
var logger = log.New(os.Stderr, "", log.LstdFlags)
// Implement FeatureSource interface
type Source struct{}
@ -36,12 +49,26 @@ func (s Source) Discover() (source.Features, error) {
// Read kernel version
version, err := parseVersion()
if err != nil {
glog.Errorf("Failed to get kernel version: %v", err)
logger.Printf("ERROR: Failed to get kernel version: %s", err)
} else {
for key := range version {
features["version."+key] = version[key]
}
}
// Read kconfig
kconfig, err := parseKconfig()
if err != nil {
logger.Printf("ERROR: Failed to read kconfig: %s", err)
}
// Check flags
for _, flag := range defaultKconfigFlags {
if _, ok := kconfig[flag]; ok {
features["config."+flag] = true
}
}
return features, nil
}
@ -70,3 +97,64 @@ func parseVersion() (map[string]string, error) {
return version, nil
}
// Read gzipped kernel config
func readKconfigGzip(filename string) ([]byte, error) {
// Open file for reading
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer f.Close()
// Uncompress data
r, err := gzip.NewReader(f)
if err != nil {
return nil, err
}
defer r.Close()
return ioutil.ReadAll(r)
}
// Read kconfig into a map
func parseKconfig() (map[string]bool, error) {
kconfig := map[string]bool{}
raw := []byte(nil)
// First, try to read from /proc as this is the most reliable source
raw, err := readKconfigGzip("/proc/config.gz")
if err != nil {
logger.Printf("ERROR: Failed to read /proc/config.gz: %s", err)
}
// Last, try to read from /boot/
if raw == nil {
// Get kernel version
unameRaw, err := ioutil.ReadFile("/proc/sys/kernel/osrelease")
uname := strings.TrimSpace(string(unameRaw))
if err != nil {
return nil, err
}
// Read kconfig
raw, err = ioutil.ReadFile("/host-boot/config-" + uname)
if err != nil {
return nil, err
}
}
// Regexp for matching kconfig flags
re := regexp.MustCompile(`^CONFIG_(?P<flag>\w+)=(?P<value>.+)`)
// Process data, line-by-line
lines := bytes.Split(raw, []byte("\n"))
for _, line := range lines {
if m := re.FindStringSubmatch(string(line)); m != nil {
if m[2] == "y" || m[2] == "m" {
kconfig[m[1]] = true
}
}
}
return kconfig, nil
}