Skip to content

Commit 4a76a74

Browse files
committed
feat: Go implement lsmod and rmmod
Signed-off-by: Fred Rolland <frolland@nvidia.com>
1 parent cd40b4c commit 4a76a74

File tree

3 files changed

+502
-4
lines changed

3 files changed

+502
-4
lines changed

entrypoint/internal/utils/host/host.go

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ package host
1818

1919
import (
2020
"context"
21+
"fmt"
22+
"strconv"
23+
"strings"
2124

2225
"github.com/Mellanox/doca-driver-build/entrypoint/internal/utils/cmd"
2326
"github.com/Mellanox/doca-driver-build/entrypoint/internal/wrappers"
@@ -73,13 +76,76 @@ type LoadedModule struct {
7376

7477
// LsMod is the default implementation of the host.Interface.
7578
func (h *host) LsMod(ctx context.Context) (map[string]LoadedModule, error) {
76-
// TODO: add implementation
77-
//nolint:nilnil
78-
return nil, nil
79+
// Execute lsmod command
80+
stdout, stderr, err := h.cmd.RunCommand(ctx, "lsmod")
81+
if err != nil {
82+
return nil, fmt.Errorf("failed to execute lsmod command: %w, stderr: %s", err, stderr)
83+
}
84+
85+
// Parse the output
86+
modules := make(map[string]LoadedModule)
87+
lines := strings.Split(strings.TrimSpace(stdout), "\n")
88+
89+
// Skip the header line
90+
for i, line := range lines {
91+
if i == 0 {
92+
continue // Skip header line "Module Size Used by"
93+
}
94+
95+
line = strings.TrimSpace(line)
96+
if line == "" {
97+
continue
98+
}
99+
100+
// Parse each line: module_name size ref_count [dependent_modules]
101+
fields := strings.Fields(line)
102+
if len(fields) < 3 {
103+
continue // Skip malformed lines
104+
}
105+
106+
moduleName := fields[0]
107+
refCountStr := fields[2]
108+
109+
// Parse reference count
110+
refCount, err := strconv.Atoi(refCountStr)
111+
if err != nil {
112+
// If we can't parse the ref count, set it to 0
113+
refCount = 0
114+
}
115+
116+
// Parse dependent modules (everything after the ref count)
117+
var usedBy []string
118+
if len(fields) > 3 {
119+
// Join all fields after ref count and split by comma
120+
dependentStr := strings.Join(fields[3:], " ")
121+
if dependentStr != "-" {
122+
// Split by comma and clean up each module name
123+
dependentModules := strings.Split(dependentStr, ",")
124+
for _, dep := range dependentModules {
125+
dep = strings.TrimSpace(dep)
126+
if dep != "" {
127+
usedBy = append(usedBy, dep)
128+
}
129+
}
130+
}
131+
}
132+
133+
modules[moduleName] = LoadedModule{
134+
Name: moduleName,
135+
RefCount: refCount,
136+
UsedBy: usedBy,
137+
}
138+
}
139+
140+
return modules, nil
79141
}
80142

81143
// RmMod is the default implementation of the host.Interface.
82144
func (h *host) RmMod(ctx context.Context, module string) error {
83-
// TODO: add implementation
145+
// Execute rmmod command to unload the kernel module
146+
_, stderr, err := h.cmd.RunCommand(ctx, "rmmod", module)
147+
if err != nil {
148+
return fmt.Errorf("failed to unload kernel module %s: %w, stderr: %s", module, err, stderr)
149+
}
84150
return nil
85151
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
Copyright 2025, NVIDIA CORPORATION & AFFILIATES
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package host
18+
19+
import (
20+
"testing"
21+
22+
. "github.com/onsi/ginkgo/v2"
23+
. "github.com/onsi/gomega"
24+
)
25+
26+
func TestHost(t *testing.T) {
27+
RegisterFailHandler(Fail)
28+
RunSpecs(t, "Host Suite")
29+
}

0 commit comments

Comments
 (0)