Skip to content

Commit 3e45d88

Browse files
committed
Refactor network namespace cache into mockable interface
Extract the NetnsCache map and getNetnsId method from ReconcilerCommon into a new NetNsCache interface with ReconcilerNetNsCache implementation. This enables proper unit testing by allowing tests to inject a MockNetNsCache instead of relying on actual filesystem operations. Changes: - Define NetNsCache interface with GetNetNsId and Reset methods - Implement ReconcilerNetNsCache with the original caching logic - Update all reconcilers to use NetNsCache.GetNetNsId() instead of ReconcilerCommon.getNetnsId() - Add MockNetNsCache for testing with predefined namespace mappings - Initialize NetNsCache in main.go and test setup Signed-off-by: Andreas Karis <[email protected]>
1 parent 97c3106 commit 3e45d88

13 files changed

+76
-51
lines changed

cmd/bpfman-agent/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ func main() {
395395
NodeName: nodeName,
396396
Containers: containerGetter,
397397
Interfaces: &sync.Map{},
398+
NetNsCache: &bpfmanagent.ReconcilerNetNsCache{},
398399
}
399400

400401
if err = (&bpfmanagent.ClBpfApplicationReconciler{

controllers/bpfman-agent/cl_application_program.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ func (r *ClBpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Req
125125
r.Logger = ctrl.Log.WithName("cluster-app")
126126
r.finalizer = internal.ClBpfApplicationControllerFinalizer
127127
r.recType = internal.ApplicationString
128-
r.NetnsCache = make(map[string]uint64)
128+
r.NetNsCache.Reset()
129129

130130
r.Logger.Info("Enter ClusterBpfApplication Reconcile", "Name", req.Name)
131131

controllers/bpfman-agent/cl_application_program_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ func createFakeClusterReconciler(objs []runtime.Object, bpfApp *bpfmaniov1alpha1
313313
BpfmanClient: cli,
314314
NodeName: fakeNode.Name,
315315
ourNode: fakeNode,
316+
NetNsCache: MockNetNsCache{"": ptr.To(uint64(12345))},
316317
}
317318
r := &ClBpfApplicationReconciler{
318319
ReconcilerCommon: rc,

controllers/bpfman-agent/cl_tc_program.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ func (r *ClTcProgramReconciler) printAttachInfo(attachInfoState bpfmaniov1alpha1
213213
}
214214

215215
func (r *ClTcProgramReconciler) findLink(attachInfoState bpfmaniov1alpha1.ClTcAttachInfoState) (*int, error) {
216-
newNetnsId := r.getNetnsId(attachInfoState.NetnsPath)
216+
newNetnsId := r.NetNsCache.GetNetNsId(attachInfoState.NetnsPath)
217217
if newNetnsId == nil {
218218
return nil, fmt.Errorf("failed to get netnsId for path %s", attachInfoState.NetnsPath)
219219
}
@@ -225,7 +225,7 @@ func (r *ClTcProgramReconciler) findLink(attachInfoState bpfmaniov1alpha1.ClTcAt
225225
a.Direction == attachInfoState.Direction &&
226226
helpers.GetPriority(a.Priority) == helpers.GetPriority(attachInfoState.Priority) &&
227227
reflect.DeepEqual(a.ProceedOn, attachInfoState.ProceedOn) &&
228-
reflect.DeepEqual(r.getNetnsId(a.NetnsPath), newNetnsId) {
228+
reflect.DeepEqual(r.NetNsCache.GetNetNsId(a.NetnsPath), newNetnsId) {
229229
return &i, nil
230230
}
231231
}

controllers/bpfman-agent/cl_tcx_program.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func (r *ClTcxProgramReconciler) printAttachInfo(attachInfoState bpfmaniov1alpha
178178
}
179179

180180
func (r *ClTcxProgramReconciler) findLink(attachInfoState bpfmaniov1alpha1.ClTcxAttachInfoState) (*int, error) {
181-
newNetnsId := r.getNetnsId(attachInfoState.NetnsPath)
181+
newNetnsId := r.NetNsCache.GetNetNsId(attachInfoState.NetnsPath)
182182
if newNetnsId == nil {
183183
return nil, fmt.Errorf("failed to get netnsId for path %s", attachInfoState.NetnsPath)
184184
}
@@ -189,7 +189,7 @@ func (r *ClTcxProgramReconciler) findLink(attachInfoState bpfmaniov1alpha1.ClTcx
189189
if a.InterfaceName == attachInfoState.InterfaceName &&
190190
a.Direction == attachInfoState.Direction &&
191191
helpers.GetPriority(a.Priority) == helpers.GetPriority(attachInfoState.Priority) &&
192-
reflect.DeepEqual(r.getNetnsId(a.NetnsPath), newNetnsId) {
192+
reflect.DeepEqual(r.NetNsCache.GetNetNsId(a.NetnsPath), newNetnsId) {
193193
return &i, nil
194194
}
195195
}

controllers/bpfman-agent/cl_xdp_program.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ func (r *ClXdpProgramReconciler) printAttachInfo(attachInfoState bpfmaniov1alpha
202202
}
203203

204204
func (r *ClXdpProgramReconciler) findLink(attachInfoState bpfmaniov1alpha1.ClXdpAttachInfoState) (*int, error) {
205-
newNetnsId := r.getNetnsId(attachInfoState.NetnsPath)
205+
newNetnsId := r.NetNsCache.GetNetNsId(attachInfoState.NetnsPath)
206206
if newNetnsId == nil {
207207
return nil, fmt.Errorf("failed to get netnsId for path %s", attachInfoState.NetnsPath)
208208
}
@@ -213,7 +213,7 @@ func (r *ClXdpProgramReconciler) findLink(attachInfoState bpfmaniov1alpha1.ClXdp
213213
if a.InterfaceName == attachInfoState.InterfaceName &&
214214
helpers.GetPriority(a.Priority) == helpers.GetPriority(attachInfoState.Priority) &&
215215
reflect.DeepEqual(a.ProceedOn, attachInfoState.ProceedOn) &&
216-
reflect.DeepEqual(r.getNetnsId(a.NetnsPath), newNetnsId) {
216+
reflect.DeepEqual(r.NetNsCache.GetNetNsId(a.NetnsPath), newNetnsId) {
217217
return &i, nil
218218
}
219219
}

controllers/bpfman-agent/common.go

Lines changed: 51 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,57 @@ type ReconcilerCommon struct {
7474
Containers ContainerGetter
7575
ourNode *v1.Node
7676
Interfaces *sync.Map
77-
NetnsCache map[string]uint64
77+
NetNsCache NetNsCache
78+
}
79+
80+
type NetNsCache interface {
81+
GetNetNsId(path string) *uint64
82+
Reset()
83+
}
84+
85+
type ReconcilerNetNsCache struct {
86+
logger logr.Logger
87+
cache map[string]uint64
88+
}
89+
90+
// getNetnsId returns the network namespace ID from the given path. If the path
91+
// is empty, it defaults to "/host/proc/1/ns/net". If the file is a hard link,
92+
// it returns the inode number of the file. If the file is a soft link, it
93+
// returns the inode of the file linked. If the path is not valid or the
94+
// conversion to Stat_t fails, it returns nil.
95+
func (rnnc *ReconcilerNetNsCache) GetNetNsId(path string) *uint64 {
96+
if path == "" {
97+
rnnc.logger.V(1).Info("Enter getNetnsId: Path is empty. Using /host/proc/1/ns/net")
98+
path = "/host/proc/1/ns/net"
99+
} else {
100+
rnnc.logger.V(1).Info("Enter getNetnsId", "Path", path)
101+
}
102+
103+
// If path is in the cache, return the cached value
104+
if id, ok := rnnc.cache[path]; ok {
105+
rnnc.logger.V(1).Info("Exit getNetnsId: Found in cache", "Path", path, "inode", id)
106+
return &id
107+
}
108+
109+
info, err := os.Stat(path)
110+
if err != nil {
111+
rnnc.logger.V(1).Info("Exit getNetnsId: Failed to stat file", "path", path, "error", err)
112+
return nil
113+
}
114+
115+
stat, ok := info.Sys().(*syscall.Stat_t)
116+
if !ok {
117+
rnnc.logger.V(1).Info("Exit getNetnsId: Failed to convert to Stat_t", "path", path)
118+
return nil
119+
}
120+
121+
rnnc.cache[path] = stat.Ino
122+
rnnc.logger.V(1).Info("Exit getNetnsId", "Path", path, "inode", stat.Ino)
123+
return &stat.Ino
124+
}
125+
126+
func (rnnc *ReconcilerNetNsCache) Reset() {
127+
rnnc.cache = make(map[string]uint64)
78128
}
79129

80130
// ApplicationReconciler is an interface that defines the methods needed to
@@ -609,39 +659,3 @@ func isInterfacesDiscoveryEnabled(interfaceSelector *bpfmaniov1alpha1.InterfaceS
609659
}
610660
return false
611661
}
612-
613-
// getNetnsId returns the network namespace ID from the given path. If the path
614-
// is empty, it defaults to "/host/proc/1/ns/net". If the file is a hard link,
615-
// it returns the inode number of the file. If the file is a soft link, it
616-
// returns the inode of the file linked. If the path is not valid or the
617-
// conversion to Stat_t fails, it returns nil.
618-
func (r *ReconcilerCommon) getNetnsId(path string) *uint64 {
619-
if path == "" {
620-
r.Logger.V(1).Info("Enter getNetnsId: Path is empty. Using /host/proc/1/ns/net")
621-
path = "/host/proc/1/ns/net"
622-
} else {
623-
r.Logger.V(1).Info("Enter getNetnsId", "Path", path)
624-
}
625-
626-
// If path is in the cache, return the cached value
627-
if id, ok := r.NetnsCache[path]; ok {
628-
r.Logger.V(1).Info("Exit getNetnsId: Found in cache", "Path", path, "inode", id)
629-
return &id
630-
}
631-
632-
info, err := os.Stat(path)
633-
if err != nil {
634-
r.Logger.V(1).Info("Exit getNetnsId: Failed to stat file", "path", path, "error", err)
635-
return nil
636-
}
637-
638-
stat, ok := info.Sys().(*syscall.Stat_t)
639-
if !ok {
640-
r.Logger.V(1).Info("Exit getNetnsId: Failed to convert to Stat_t", "path", path)
641-
return nil
642-
}
643-
644-
r.NetnsCache[path] = stat.Ino
645-
r.Logger.V(1).Info("Exit getNetnsId", "Path", path, "inode", stat.Ino)
646-
return &stat.Ino
647-
}

controllers/bpfman-agent/ns_application_program.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ func (r *NsBpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Req
126126
r.Logger = ctrl.Log.WithName("namespace-app")
127127
r.finalizer = internal.NsBpfApplicationControllerFinalizer
128128
r.recType = internal.ApplicationString
129-
r.NetnsCache = make(map[string]uint64)
129+
r.NetNsCache.Reset()
130130

131131
r.Logger.Info("Enter BpfApplication Reconcile", "Name", req.Name)
132132

controllers/bpfman-agent/ns_application_program_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ func createFakeNamespaceReconciler(objs []runtime.Object, bpfApp *bpfmaniov1alph
284284
NodeName: fakeNode.Name,
285285
ourNode: fakeNode,
286286
Containers: testContainers,
287+
NetNsCache: MockNetNsCache{"": ptr.To(uint64(12345))},
287288
}
288289
r := &NsBpfApplicationReconciler{
289290
ReconcilerCommon: rc,

controllers/bpfman-agent/ns_tc_program.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ func (r *NsTcProgramReconciler) printAttachInfo(attachInfoState bpfmaniov1alpha1
177177
}
178178

179179
func (r *NsTcProgramReconciler) findLink(attachInfoState bpfmaniov1alpha1.TcAttachInfoState) (*int, error) {
180-
newNetnsId := r.getNetnsId(attachInfoState.NetnsPath)
180+
newNetnsId := r.NetNsCache.GetNetNsId(attachInfoState.NetnsPath)
181181
if newNetnsId == nil {
182182
return nil, fmt.Errorf("failed to get netnsId for path %s", attachInfoState.NetnsPath)
183183
}
@@ -189,7 +189,7 @@ func (r *NsTcProgramReconciler) findLink(attachInfoState bpfmaniov1alpha1.TcAtta
189189
a.Direction == attachInfoState.Direction &&
190190
helpers.GetPriority(a.Priority) == helpers.GetPriority(attachInfoState.Priority) &&
191191
reflect.DeepEqual(a.ProceedOn, attachInfoState.ProceedOn) &&
192-
reflect.DeepEqual(r.getNetnsId(a.NetnsPath), newNetnsId) {
192+
reflect.DeepEqual(r.NetNsCache.GetNetNsId(a.NetnsPath), newNetnsId) {
193193
return &i, nil
194194
}
195195
}

0 commit comments

Comments
 (0)