Skip to content

Commit bf51d66

Browse files
authored
Merge pull request #492 from vteratipally/module_stats_branch
add code to retrieve kernel modules in a linux system from /proc/modules
2 parents 1e917af + 2b50e4a commit bf51d66

File tree

5 files changed

+253
-0
lines changed

5 files changed

+253
-0
lines changed

pkg/util/metrics/system/common.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors All rights reserved.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package system
15+
16+
import (
17+
"bufio"
18+
"os"
19+
)
20+
21+
// ReadFile reads contents from a file and returns lines.
22+
func ReadFileIntoLines(filename string) ([]string, error) {
23+
file, err := os.Open(filename)
24+
if err != nil {
25+
return nil, err
26+
}
27+
defer file.Close()
28+
29+
var result []string
30+
s := bufio.NewScanner(file)
31+
for s.Scan() {
32+
result = append(result, s.Text())
33+
}
34+
if s.Err() != nil {
35+
return nil, err
36+
}
37+
return result, nil
38+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors All rights reserved.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package system
15+
16+
import (
17+
"encoding/json"
18+
"fmt"
19+
"strconv"
20+
"strings"
21+
)
22+
23+
var modulesFilePath = "/proc/modules"
24+
25+
type Module struct {
26+
ModuleName string `json:"moduleName"`
27+
Instances uint64 `json:"instances"`
28+
Proprietary bool `json:"proprietary"`
29+
OutOfTree bool `json:"outOfTree"`
30+
Unsigned bool `json:"unsigned"`
31+
}
32+
33+
func (d Module) String() string {
34+
s, _ := json.Marshal(d)
35+
return string(s)
36+
}
37+
38+
// Module returns all the kernel modules and their
39+
// usage. It is read from cat /proc/modules.
40+
func Modules() ([]Module, error) {
41+
lines, err := ReadFileIntoLines(modulesFilePath)
42+
if err != nil {
43+
return nil, fmt.Errorf("error reading the contents of %s: %s", modulesFilePath, err)
44+
}
45+
var result = make([]Module, 0, len(lines))
46+
47+
/* a line of /proc/modules has the following structure
48+
nf_nat 61440 2 xt_MASQUERADE,iptable_nat, Live 0x0000000000000000 (O)
49+
(1) (2) (3) (4) (5) (6) (7)
50+
(1) name of the module
51+
(2) memory size of the module, in bytes
52+
(3) instances of the module are currently loaded
53+
(4) module dependencies
54+
(5) load state of the module: live, loading or unloading
55+
(6) memory offset for the loaded module.
56+
(7) return a string to represent the kernel taint state. (used here: "P" - Proprietary, "O" - out of tree kernel module, "E" - unsigned module
57+
*/
58+
for _, line := range lines {
59+
fields := strings.Fields(line)
60+
moduleName := fields[0] // name of the module
61+
numberOfInstances, err :=
62+
strconv.ParseUint((fields[2]), 10, 64) // instances of the module are currently loaded
63+
if err != nil {
64+
numberOfInstances = 0
65+
}
66+
67+
var module = Module{
68+
ModuleName: moduleName,
69+
Instances: numberOfInstances,
70+
}
71+
// if the len of the fields is greater than 6, then the kernel taint state is available.
72+
if len(fields) > 6 {
73+
module.Proprietary = strings.Contains(fields[6], "P")
74+
module.OutOfTree = strings.Contains(fields[6], "O")
75+
module.Unsigned = strings.Contains(fields[6], "E")
76+
}
77+
78+
result = append(result, module)
79+
}
80+
return result, nil
81+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors All rights reserved.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package system
15+
16+
import (
17+
"fmt"
18+
"testing"
19+
20+
"github.com/stretchr/testify/assert"
21+
)
22+
23+
func TestModules(t *testing.T) {
24+
testcases := []struct {
25+
name string
26+
fakeModuleFilePath string
27+
expectedModules []Module
28+
}{
29+
{
30+
name: "default_cos",
31+
fakeModuleFilePath: "testdata/modules_cos.txt",
32+
expectedModules: []Module{
33+
{
34+
ModuleName: "crypto_simd",
35+
Instances: 0x1,
36+
Proprietary: false,
37+
OutOfTree: false,
38+
Unsigned: false,
39+
},
40+
{
41+
ModuleName: "virtio_balloon",
42+
Instances: 0x0,
43+
Proprietary: false,
44+
OutOfTree: false,
45+
Unsigned: false,
46+
},
47+
{
48+
ModuleName: "cryptd",
49+
Instances: 0x1,
50+
Proprietary: false,
51+
OutOfTree: false,
52+
Unsigned: false,
53+
},
54+
{
55+
ModuleName: "loadpin_trigger",
56+
Instances: 0x0,
57+
Proprietary: false,
58+
OutOfTree: true,
59+
Unsigned: false,
60+
},
61+
},
62+
},
63+
{
64+
name: "default_ubuntu",
65+
fakeModuleFilePath: "testdata/modules_ubuntu.txt",
66+
expectedModules: []Module{
67+
{
68+
ModuleName: "drm",
69+
Instances: 0x0,
70+
Proprietary: false,
71+
OutOfTree: false,
72+
Unsigned: false,
73+
},
74+
{
75+
ModuleName: "virtio_rng",
76+
Instances: 0x0,
77+
Proprietary: false,
78+
OutOfTree: false,
79+
Unsigned: false,
80+
},
81+
{
82+
ModuleName: "x_tables",
83+
Instances: 0x1,
84+
Proprietary: false,
85+
OutOfTree: false,
86+
Unsigned: false,
87+
},
88+
{
89+
ModuleName: "autofs4",
90+
Instances: 0x2,
91+
Proprietary: false,
92+
OutOfTree: false,
93+
Unsigned: false,
94+
},
95+
},
96+
},
97+
}
98+
for _, test := range testcases {
99+
t.Run(test.name, func(t *testing.T) {
100+
originalModuleFilePath := modulesFilePath
101+
defer func() {
102+
modulesFilePath = originalModuleFilePath
103+
}()
104+
105+
modulesFilePath = test.fakeModuleFilePath
106+
modules, err := Modules()
107+
if err != nil {
108+
t.Errorf("Unexpected error retrieving modules: %v\nModulesFilePath: %s\n", err, modulesFilePath)
109+
}
110+
assert.Equal(t, modules, test.expectedModules, "unpected modules retrieved: %v, expected: %v", modules, test.expectedModules)
111+
})
112+
}
113+
}
114+
115+
func TestModuleStat_String(t *testing.T) {
116+
v := Module{
117+
ModuleName: "test",
118+
Instances: 2,
119+
OutOfTree: false,
120+
Unsigned: false,
121+
}
122+
e := `{"moduleName":"test","instances":2,"proprietary":false,"outOfTree":false,"unsigned":false}`
123+
assert.Equal(t,
124+
e, fmt.Sprintf("%v", v), "Module string is invalid: %v", v)
125+
126+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
crypto_simd 16384 1 aesni_intel, Live 0x0000000000000000
2+
virtio_balloon 24576 0 - Live 0x0000000000000000
3+
cryptd 24576 1 crypto_simd, Live 0x0000000000000000
4+
loadpin_trigger 12288 0 [permanent], Live 0x0000000000000000 (O)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
drm 491520 0 - Live 0x0000000000000000
2+
virtio_rng 16384 0 - Live 0x0000000000000000
3+
x_tables 40960 1 ip_tables, Live 0x0000000000000000
4+
autofs4 45056 2 - Live 0x0000000000000000

0 commit comments

Comments
 (0)