Skip to content

Commit f9d52e1

Browse files
committed
Fix handling for adding/deleting programs from an existing BpfApp CRD
Also cleaned up a couple of log messages. Fixes: #347 Signed-off-by: Andre Fredette <[email protected]>
1 parent 7c11035 commit f9d52e1

File tree

8 files changed

+143
-9
lines changed

8 files changed

+143
-9
lines changed

apis/v1alpha1/shared_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,8 @@ const (
352352
AppUnloadError AppLoadStatus = "UnloadError"
353353
// The app is not selected to run on the node
354354
NotSelected AppLoadStatus = "NotSelected"
355+
// The app is not selected to run on the node
356+
ProgListChangedError AppLoadStatus = "ProgramListChangedError"
355357
)
356358

357359
type ProgramLinkStatus string

bundle/manifests/bpfman-operator.clusterserviceversion.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -861,7 +861,7 @@ metadata:
861861
capabilities: Basic Install
862862
categories: OpenShift Optional
863863
containerImage: quay.io/bpfman/bpfman-operator:latest
864-
createdAt: "2025-03-03T23:26:55Z"
864+
createdAt: "2025-03-04T15:37:43Z"
865865
description: The bpfman Operator is designed to manage eBPF programs for applications.
866866
features.operators.openshift.io/cnf: "false"
867867
features.operators.openshift.io/cni: "false"
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
apiVersion: bpfman.io/v1alpha1
2+
kind: ClusterBpfApplication
3+
metadata:
4+
labels:
5+
app.kubernetes.io/name: clusterbpfapplication
6+
name: clusterbpfapplication-sample-test3
7+
spec:
8+
nodeSelector: {}
9+
byteCode:
10+
image:
11+
url: quay.io/bpfman-bytecode/app-test:latest
12+
programs:
13+
- name: kprobe_test
14+
type: kprobe
15+
kprobeInfo:
16+
links:
17+
- function: try_to_wake_up
18+
offset: 0
19+
- name: tracepoint_test
20+
type: tracepoint
21+
tracepointInfo:
22+
links:
23+
- name: syscalls/sys_enter_openat
24+
- name: fentry_test
25+
type: fentry
26+
fentryInfo:
27+
function: do_unlinkat
28+
links:
29+
- attach: true
30+
# - name: tcx_next_test
31+
# type: tcx
32+
# tcxInfo:
33+
# links:
34+
# - interfaceSelector:
35+
# primaryNodeInterface: true
36+
# priority: 500
37+
# direction: ingress

controllers/bpfman-agent/cl_application_program.go

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ func (r *ClBpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Req
175175
bpfAppStateOriginal = r.currentAppState.DeepCopy()
176176
}
177177

178-
r.Logger.Info("From getBpfAppState", "new", bpfAppStateNew)
178+
r.Logger.Info("BpfApplicationState status", "new", bpfAppStateNew)
179179

180180
if bpfAppStateNew {
181181
// Create the object and return. We'll get the updated object in the
@@ -248,9 +248,9 @@ func (r *ClBpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Req
248248

249249
err = rec.reconcileProgram(ctx, rec, r.isBeingDeleted())
250250
if err != nil {
251-
r.Logger.Info("Error reconciling program", "Name", rec.getProgName(), "Index", appProgramIndex)
251+
r.Logger.Info("Error reconciling program", "Name", rec.getProgName())
252252
} else {
253-
r.Logger.Info("Successfully reconciled program", "Name", rec.getProgName(), "Index", appProgramIndex)
253+
r.Logger.Info("Successfully reconciled program", "Name", rec.getProgName())
254254
}
255255
}
256256

@@ -789,3 +789,47 @@ func (r *ClBpfApplicationReconciler) deleteLinks(program *bpfmaniov1alpha1.ClBpf
789789
r.Logger.Error(fmt.Errorf("unexpected EBPFProgType"), "unexpected EBPFProgType", "Type", program.Type)
790790
}
791791
}
792+
793+
// validateProgramList checks the BpfApplicationPrograms to ensure that none
794+
// have been added or deleted.
795+
func (r *ClBpfApplicationReconciler) validateProgramList() error {
796+
// Create a map of the programs in r.currentAppState.Spec.Programs to make
797+
// the checks more efficient.
798+
appStateProgMap := make(map[string]bool)
799+
for _, program := range r.currentAppState.Spec.Programs {
800+
appStateProgMap[program.Name] = true
801+
}
802+
803+
// Check that all the programs in r.currentApp.Spec.Programs are on the
804+
// list. If not, that indicates that the program has been added, which is
805+
// not allowed. Remove them if they are on the list so we can check if any
806+
// are left over which would indicate that they have been removed from the
807+
// list.
808+
addedPrograms := ""
809+
for _, program := range r.currentApp.Spec.Programs {
810+
if _, ok := appStateProgMap[program.Name]; !ok {
811+
addedPrograms = addedPrograms + program.Name + " "
812+
} else {
813+
delete(appStateProgMap, program.Name)
814+
}
815+
}
816+
817+
if addedPrograms != "" {
818+
r.Logger.Info("Programs added error", "Programs", addedPrograms)
819+
return fmt.Errorf("programs have been added: %s", addedPrograms)
820+
}
821+
822+
// Now, see if there are any programs left on the list, which would indicate that
823+
// they have been removed from the list.
824+
if len(appStateProgMap) > 0 {
825+
// create a string containing the names of the programs that have been removed
826+
removedPrograms := ""
827+
for program := range appStateProgMap {
828+
removedPrograms = removedPrograms + program + " "
829+
}
830+
r.Logger.Info("Programs removed error", "Programs", removedPrograms)
831+
return fmt.Errorf("programs have been removed: %s", removedPrograms)
832+
}
833+
834+
return nil
835+
}

controllers/bpfman-agent/common.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ type ApplicationReconciler interface {
8787
isBeingDeleted() bool
8888
updateBpfAppStatus(ctx context.Context, condition metav1.Condition) error
8989
updateLoadStatus(updateStatus bpfmaniov1alpha1.AppLoadStatus)
90+
validateProgramList() error
9091
load(ctx context.Context) error
9192
isLoaded(ctx context.Context) bool
9293
getLoadRequest() (*gobpfman.LoadRequest, error)
@@ -120,7 +121,7 @@ type ProgramReconciler interface {
120121
func (r *ReconcilerCommon) reconcileLoad(ctx context.Context, rec ApplicationReconciler) error {
121122
isNodeSelected, err := isNodeSelected(rec.getNodeSelector(), rec.getNode().Labels)
122123
if err != nil {
123-
return fmt.Errorf("failed to check if node is selected: %v", err)
124+
return fmt.Errorf("check if node is selected failed: %v", err)
124125
}
125126

126127
if !isNodeSelected {
@@ -132,7 +133,11 @@ func (r *ReconcilerCommon) reconcileLoad(ctx context.Context, rec ApplicationRec
132133
rec.unload(ctx)
133134
rec.updateLoadStatus(bpfmaniov1alpha1.AppUnLoadSuccess)
134135
} else {
135-
// The program should be loaded. Load it if necessary.
136+
err := rec.validateProgramList()
137+
if err != nil {
138+
rec.updateLoadStatus(bpfmaniov1alpha1.ProgListChangedError)
139+
return err
140+
}
136141
if rec.isLoaded(ctx) {
137142
rec.updateLoadStatus(bpfmaniov1alpha1.AppLoadSuccess)
138143
} else {

controllers/bpfman-agent/ns_application_program.go

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ func (r *NsBpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Req
176176
bpfAppStateOriginal = r.currentAppState.DeepCopy()
177177
}
178178

179-
r.Logger.Info("From getBpfAppState", "new", bpfAppStateNew)
179+
r.Logger.Info("BpfApplicationState status", "new", bpfAppStateNew)
180180

181181
if bpfAppStateNew {
182182
// Create the object and return. We'll get the updated object in the
@@ -249,9 +249,9 @@ func (r *NsBpfApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Req
249249

250250
err = rec.reconcileProgram(ctx, rec, r.isBeingDeleted())
251251
if err != nil {
252-
r.Logger.Info("Error reconciling program", "Name", rec.getProgName(), "Index", appProgramIndex)
252+
r.Logger.Info("Error reconciling program", "Name", rec.getProgName())
253253
} else {
254-
r.Logger.Info("Successfully reconciled program", "Name", rec.getProgName(), "Index", appProgramIndex)
254+
r.Logger.Info("Successfully reconciled program", "Name", rec.getProgName())
255255
}
256256
}
257257

@@ -717,3 +717,49 @@ func (r *NsBpfApplicationReconciler) deleteLinks(program *bpfmaniov1alpha1.BpfAp
717717
r.Logger.Error(fmt.Errorf("unexpected EBPFProgType"), "unexpected EBPFProgType", "Type", program.Type)
718718
}
719719
}
720+
721+
// validateProgramList checks the BpfApplicationPrograms to ensure that none
722+
// have been added or deleted.
723+
func (r *NsBpfApplicationReconciler) validateProgramList() error {
724+
if len(r.currentAppState.Spec.Programs) != len(r.currentApp.Spec.Programs) {
725+
return fmt.Errorf("program list has changed")
726+
}
727+
728+
// Create a map of the programs in r.currentAppState.Spec.Programs so we can
729+
// quickly check if a program is in the list.
730+
appStateProgMap := make(map[string]bool)
731+
for _, program := range r.currentAppState.Spec.Programs {
732+
appStateProgMap[program.Name] = true
733+
}
734+
735+
// Check that all the programs in r.currentApp.Spec.Programs are on the
736+
// list. If not, that indicates that the program has been added, which is
737+
// not allowed. Remove them if they are on the list so we can check if any
738+
// are left over which would indicate that they have been removed from the
739+
// list.
740+
addedPrograms := ""
741+
for _, program := range r.currentApp.Spec.Programs {
742+
if _, ok := appStateProgMap[program.Name]; !ok {
743+
addedPrograms = addedPrograms + program.Name + " "
744+
} else {
745+
delete(appStateProgMap, program.Name)
746+
}
747+
}
748+
749+
if addedPrograms != "" {
750+
return fmt.Errorf("programs have been added: %s", addedPrograms)
751+
}
752+
753+
// Now, see if there are any programs left on the list, which would indicate that
754+
// they have been removed from the list.
755+
if len(appStateProgMap) > 0 {
756+
// create a string containing the names of the programs that have been removed
757+
removedPrograms := ""
758+
for program := range appStateProgMap {
759+
removedPrograms = removedPrograms + program + " "
760+
}
761+
return fmt.Errorf("programs have been removed: %s", removedPrograms)
762+
}
763+
764+
return nil
765+
}

0 commit comments

Comments
 (0)